diff options
| author | Robin Christ <robinchrist@users.noreply.github.com> | 2026-05-13 17:03:50 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-13 18:03:50 +0300 |
| commit | 69b6be91d0eacfd23feb13f96325923f6e26ed25 (patch) | |
| tree | 17e6d2a5dd5022272abdfa096662a5abc0682c88 /src | |
| parent | db23d7201c9df78c91aeeeade6963f2cc12b50b1 (diff) | |
| download | vyos-1x-69b6be91d0eacfd23feb13f96325923f6e26ed25.tar.gz vyos-1x-69b6be91d0eacfd23feb13f96325923f6e26ed25.zip | |
bgp: T8588: Add match source-peer to policy route-map (#5149)
Diffstat (limited to 'src')
| -rwxr-xr-x | src/completion/list_bgp_neighbors.sh | 169 |
1 files changed, 133 insertions, 36 deletions
diff --git a/src/completion/list_bgp_neighbors.sh b/src/completion/list_bgp_neighbors.sh index 72c4fcbcb..7342813ba 100755 --- a/src/completion/list_bgp_neighbors.sh +++ b/src/completion/list_bgp_neighbors.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # This program is free software; you can redistribute it and/or modify @@ -13,55 +13,152 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# Return BGP neighbor addresses from CLI, can either request IPv4 only, IPv6 -# only or both address-family neighbors +# Return BGP neighbor identifiers from CLI. Selectors: +# --ipv4 IPv4 address peers +# --ipv6 IPv6 address peers +# --interfaces peers that are neither IPv4 nor IPv6 addresses (interfaces) +# --peer-groups configured peer-group names +# Selectors are additive and may be combined freely. With --all-vrfs, neighbors +# from the default VRF and every configured VRF are merged and deduplicated. ipv4=0 ipv6=0 -vrf="" +interfaces=0 +vrf_name="" +all_vrfs=0 +peer_groups=0 while [[ "$#" -gt 0 ]]; do case $1 in -4|--ipv4) ipv4=1 ;; -6|--ipv6) ipv6=1 ;; - -b|--both) ipv4=1; ipv6=1 ;; - --vrf) vrf="vrf name $2"; shift ;; - *) echo "Unknown parameter passed: $1" ;; + -b|--both) + # Deprecated: alias for --ipv4 --ipv6 --interfaces + ipv4=1; ipv6=1; interfaces=1 + ;; + --interfaces) interfaces=1 ;; + --vrf) vrf_name=$2; shift ;; + --all-vrfs) all_vrfs=1 ;; + --peer-groups) peer_groups=1 ;; + *) echo "Unknown parameter passed: $1" >&2 ;; esac shift done -declare -a vals -eval "vals=($(cli-shell-api listActiveNodes $vrf protocols bgp neighbor))" - -if [ $ipv4 -eq 1 ] && [ $ipv6 -eq 1 ]; then - echo -n '<x.x.x.x>' '<h:h:h:h:h:h:h:h>' ${vals[@]} -elif [ $ipv4 -eq 1 ] ; then - echo -n '<x.x.x.x> ' - for peer in "${vals[@]}" - do - ipaddrcheck --is-ipv4-single $peer - if [ $? -eq "0" ]; then - echo -n "$peer " - fi - done -elif [ $ipv6 -eq 1 ] ; then - echo -n '<h:h:h:h:h:h:h:h> ' - for peer in "${vals[@]}" - do - ipaddrcheck --is-ipv6-single $peer - if [ $? -eq "0" ]; then - echo -n "$peer " +if [[ $all_vrfs -eq 1 && -n $vrf_name ]]; then + echo "Error: --all-vrfs and --vrf are mutually exclusive" >&2 + exit 1 +fi + +# Wrap `cli-shell-api listActiveNodes` and append its (shell-quoted) output +# to the named array. The API is trusted to return safely quoted tokens, +# which is why `eval` is acceptable here -- it is the documented contract +# of cli-shell-api. Keeping the eval in one place makes the trust boundary +# explicit and easy to audit. +# +# Usage: _list_active_nodes <out_array_name> <path...> +_list_active_nodes() { + local _out=$1; shift + local _raw + if ! _raw=$(cli-shell-api listActiveNodes "$@" 2>/dev/null); then + return 0 # node missing or no config session -- treat as empty + fi + + eval "${_out}+=(${_raw})" +} + +declare -a vals=() +declare -a pg_vals=() + +# Build the list of VRFs to traverse. The empty string represents the default +# VRF (no `vrf name <X>` prefix); any other value is the name of a configured +# VRF. This unifies the three cases (--all-vrfs, --vrf <name>, neither) into a +# single loop and avoids duplicating the collection logic. +declare -a _vrf_list=("") # default VRF is always included + +if (( all_vrfs )); then + _list_active_nodes _vrf_list vrf name +elif [[ -n $vrf_name ]]; then + _vrf_list=("$vrf_name") +fi + +# Collect neighbors -- and optionally peer-groups -- from every VRF in the list. +for _vrf in "${_vrf_list[@]}"; do + declare -a _path=() + [[ -n $_vrf ]] && _path=(vrf name "$_vrf") + _list_active_nodes vals "${_path[@]}" protocols bgp neighbor + if (( peer_groups )); then + _list_active_nodes pg_vals "${_path[@]}" protocols bgp peer-group + fi +done + +# Deduplicate when multiple VRFs may have contributed entries. A single source +# cannot produce duplicates, so the sort pipe is skipped in that case. +if (( ${#_vrf_list[@]} > 1 )); then + if (( ${#vals[@]} > 1 )); then + mapfile -t vals < <(printf '%s\n' "${vals[@]}" | LC_ALL=C sort -u) + fi + if (( ${#pg_vals[@]} > 1 )); then + mapfile -t pg_vals < <(printf '%s\n' "${pg_vals[@]}" | LC_ALL=C sort -u) + fi +fi + +# Print neighbors from `vals` matching the requested selectors. The fast path +# below avoids any per-token filtering when all three neighbor categories +# (--ipv4, --ipv6, --interfaces) are requested -- in that case every entry in +# `vals` matches by definition. +_print_neighbors() { + # Fast path: every neighbor is either v4, v6 or an interface, so when all + # three are requested no classification is needed. + if (( ipv4 && ipv6 && interfaces )); then + (( ${#vals[@]} )) && printf '%s ' "${vals[@]}" + return + fi + + local peer + for peer in "${vals[@]}"; do + if ipaddrcheck --is-ipv4-single "$peer" >/dev/null 2>&1; then + (( ipv4 )) && printf '%s ' "$peer" + elif ipaddrcheck --is-ipv6-single "$peer" >/dev/null 2>&1; then + (( ipv6 )) && printf '%s ' "$peer" + else + # Anything that is neither an IPv4 nor an IPv6 address is treated + # as an interface name. + (( interfaces )) && printf '%s ' "$peer" fi - done -else - echo "Usage:" - echo "-4|--ipv4 list only IPv4 peers" - echo "-6|--ipv6 list only IPv6 peers" - echo "--both list both IP4 and IPv6 peers" - echo "--vrf <name> apply command to given VRF (optional)" - echo "" + done +} + +# Require at least one selector. +if (( ipv4 == 0 && ipv6 == 0 && interfaces == 0 && peer_groups == 0 )); then + cat >&2 <<'EOF' +Usage: + -4|--ipv4 list IPv4 address peers + -6|--ipv6 list IPv6 address peers + --interfaces list interface peers (peers that are not IP addresses) + --peer-groups list configured peer-group names + -b|--both deprecated -- alias for --ipv4 --ipv6 --interfaces + --vrf <name> apply command to given VRF (optional) + --all-vrfs list neighbors across all VRFs (deduplicated) +EOF exit 1 fi +# Build the leading completion-help placeholders shown to the user. +declare -a _hdr=() +(( ipv4 )) && _hdr+=('<x.x.x.x>') +(( ipv6 )) && _hdr+=('<h:h:h:h:h:h:h:h>') +(( interfaces )) && _hdr+=('<interface>') +(( peer_groups )) && _hdr+=('<text>') + +(( ${#_hdr[@]} )) && printf '%s ' "${_hdr[@]}" + +if (( ipv4 || ipv6 || interfaces )); then + _print_neighbors +fi + +if (( peer_groups )) && (( ${#pg_vals[@]} )); then + printf '%s ' "${pg_vals[@]}" +fi + exit 0 |
