diff --git a/.clang-format b/.clang-format index 3971384a3659..7aefafa58fbf 100644 --- a/.clang-format +++ b/.clang-format @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # clang-format configuration file. Intended for clang-format >= 11. +# If the version is changed also check that CI tool frrbot is updated. # # For more information, see: # @@ -77,10 +78,11 @@ FixNamespaceComments: false ForEachMacros: # lib: outliers: - 'FOR_ALL_INTERFACES' - - 'FOR_ALL_INTERFACES_ADDRESSES' # libyang outliers: - 'LY_FOR_KEYS' - 'LY_LIST_FOR' + - 'LYD_LIST_FOR_INST' + - 'LYD_LIST_FOR_INST_SAFE' - 'LY_TREE_FOR' - 'LY_TREE_DFS_BEGIN' - 'LYD_TREE_DFS_BEGIN' @@ -103,6 +105,7 @@ ForEachMacros: - 'FOREACH_AFI_SAFI' - 'FOREACH_AFI_SAFI_NSF' - 'FOREACH_BE_APPLY_BATCH_IN_LIST' + - 'FOREACH_BE_CLIENT_BITS' - 'FOREACH_BE_TXN_BATCH_IN_LIST' - 'FOREACH_BE_TXN_IN_LIST' - 'FOREACH_CMT_REC' @@ -204,4 +207,25 @@ SpacesInSquareBrackets: false Standard: Cpp03 TabWidth: 8 UseTab: Always +WhitespaceSensitiveMacros: + - "DEFPY" + - "DEFPY_HIDDEN" + - "DEFPY_NOSH" + - "DEFPY_YANG" + - "DEFPY_YANG_HIDDEN" + - "DEFPY_YANG_NOSH" + - "DEFSH" + - "DEFSH_HIDDEN" + - "DEFUN" + - "DEFUN_HIDDEN" + - "DEFUN_NOSH" + - "DEFUN_YANG" + - "DEFUN_YANG_HIDDEN" + - "DEFUN_YANG_NOSH" + - "DEFUNSH" + - "DEFUNSH_HIDDEN" + - "ALIAS" + - "ALIAS_HIDDEN" + - "ALIAS_YANG" + - "ALIAS_DEPRECATED" ... diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 1ecdfd2fb30b..9b6932c2854e 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -20,3 +20,5 @@ c14777c6bfd0a446c85243d3a9835054a259c276 8451921b70044a2c1075e7ba391f095fabee2550 bf8d3d6aca3f20255a621ed1c148fd05b3a8ae5c 96941f80927ce31a41f7d1905717f099187be723 +# apply `black` python formatting for all tests/topotests +1a1c2a9f84d0ad1bdadc0cb47d6175d4ccc32544 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 895e8ad0dc4b..000000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: triage -assignees: '' - ---- - - - ---------------- - -**Describe the bug** - - -- [ ] Did you check if this is a duplicate issue? -- [ ] Did you test it on the latest FRRouting/frr master branch? - - -**To Reproduce** - - -**Expected behavior** - - -**Screenshots** - - -**Versions** - - - - OS Version: - - - Kernel: - - - FRR Version: - -**Additional context** - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000000..7319550e849e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,78 @@ +name: Bug report +description: Report a bug in the FRRouting software +labels: triage +body: + - type: markdown + attributes: + value: > + **This form is only for reporting a bug in the FRRouting software.** + If you need help troubleshooting your configuration, have a problem + building or installing the software, or want to ask a question or + discuss the project, learn how to [connect with the FRRouting + community](https://frrouting.org/community/). + + + **Do not include sensitive information in this report.** IP addresses + should be masked (example: 192.XXX.XXX.32/24). + - type: textarea + id: description + attributes: + label: Description + description: Provide a clear and concise description of the bug. + validations: + required: true + - type: textarea + id: version + attributes: + label: Version + description: > + Run the `show version` command in the VTY shell, and provide the output + here. (If possible, test the current development version of FRRouting + for this bug.) + render: text + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce + description: > + Give a list of steps that someone else can follow to observe + the bug. Be as descriptive as possible, including any relevant + configuration files and commands used. Topology diagrams are + helpful when the bug involves more than one router. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: > + What do you expect to happen when following the steps above? + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: > + What actually happens when following the steps above? Include + screenshots, log file snippets, and/or platform routing tables + as appropriate. If a crash occurs, provide a backtrace. + validations: + required: true + - type: textarea + id: additional-context + attributes: + label: Additional context + description: > + Include any other relevant information about this bug here. + - type: checkboxes + id: checklist + attributes: + label: Checklist + options: + - label: I have searched the open issues for this bug. + required: true + - label: I have not included sensitive information in this report. + required: true diff --git a/.github/workflows/build-test-docker.yml b/.github/workflows/build-test-docker.yml new file mode 100644 index 000000000000..3f53f32d3a8c --- /dev/null +++ b/.github/workflows/build-test-docker.yml @@ -0,0 +1,163 @@ +name: build-test + +on: + pull_request: + push: + branches: + - 'master' + - 'stable/**' + +defaults: + run: + shell: bash + +jobs: + build-docker: + name: Build the ubuntu 22.04 docker image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + - name: Build docker image + run: | + docker build -t frr-ubuntu22 -f docker/ubuntu-ci/Dockerfile . + docker save --output /tmp/frr-ubuntu22.tar frr-ubuntu22 + - name: Upload docker image artifact + uses: actions/upload-artifact@v4 + with: + name: ubuntu-image + path: /tmp/frr-ubuntu22.tar + - name: Clear any previous results + # So if all jobs are re-run then all tests will be re-run + run: | + rm -rf test-results* + mkdir -p test-results + touch test-results/cleared-results.txt + - name: Save cleared previous results + uses: actions/upload-artifact@v4 + with: + name: test-results + path: test-results + overwrite: true + - name: Cleanup + if: ${{ always() }} + run: rm -rf test-results* /tmp/frr-ubuntu22.tar + + test-docker: + name: Test ubuntu docker image + needs: build-docker + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + - name: Fetch docker image artifact + uses: actions/download-artifact@v4 + with: + name: ubuntu-image + path: /tmp + - name: Fetch previous results + if: ${{ github.run_attempt > 1 }} + uses: actions/download-artifact@v4 + with: + name: test-results + path: test-results + - name: Run topotests + run: | + uname -a + MODPKGVER=$(uname -r) + sudo apt-get update -y + # Github is running old kernels but installing newer packages :( + sudo apt-get install -y linux-modules-extra-azure linux-modules-${MODPKGVER} linux-modules-extra-${MODPKGVER} python3-xmltodict + sudo modprobe vrf || true + sudo modprobe mpls-iptunnel + sudo modprobe mpls-router + docker load --input /tmp/frr-ubuntu22.tar + + if ! grep CONFIG_IP_MROUTE_MULTIPLE_TABLES=y /boot/config*; then + ADD_DOCKER_ENV+="-e MROUTE_VRF_MISSING=1" + fi + echo "ADD_DOCKER_ENV: ${ADD_DOCKER_ENV}" + + if [ -f test-results/topotests.xml ]; then + ./tests/topotests/analyze.py -r test-results + ls -l test-results/topotests.xml + run_tests=$(./tests/topotests/analyze.py -r test-results | cut -f1 -d: | sort -u) + else + echo "No test results dir" + run_tests="" + fi + rm -rf test-results* /tmp/topotests + + echo RUN_TESTS: $run_tests + if docker run --init -i --privileged --name frr-ubuntu-cont ${ADD_DOCKER_ENV} -v /lib/modules:/lib/modules frr-ubuntu22 \ + bash -c 'cd ~/frr/tests/topotests ; sudo -E pytest -n$(($(nproc) * 5 / 2)) --dist=loadfile '$run_tests; then + echo "All tests passed." + exit 0 + fi + + # Grab the results from the container + if ! ./tests/topotests/analyze.py -Ar test-results -C frr-ubuntu-cont; then + if [ ! -d test-results ]; then + echo "ERROR: Basic failure in docker run, no test results directory available." >&2 + exit 1; + fi + if [ ! -f test-results/topotests.xml ]; then + # In this case we may be missing topotests.xml + echo "ERROR: No topotests.xml available perhaps docker run aborted?" >&2 + exit 1; + fi + echo "WARNING: analyyze.py returned error but grabbed results anyway." >&2 + fi + + # Save some information useful for debugging + cp /boot/config* test-results/ + sysctl -a > test-results/sysctl.out 2> /dev/null + + # Now get the failed tests (if any) from the archived results directory. + rerun_tests=$(./tests/topotests/analyze.py -r test-results | cut -f1 -d: | sort -u) + if [ -z "$rerun_tests" ]; then + echo "All tests passed during parallel run." + exit 0 + fi + + echo "ERROR: Some tests failed during parallel run, rerunning serially." >&2 + echo RERUN_TESTS: $rerun_tests >&2 + docker stop frr-ubuntu-cont + docker rm frr-ubuntu-cont + + mv test-results test-results-initial + if docker run --init -i --privileged --name frr-ubuntu-cont ${ADD_DOCKER_ENV} -v /lib/modules:/lib/modules frr-ubuntu22 \ + bash -c 'cd ~/frr/tests/topotests ; sudo -E pytest '$rerun_tests; then + echo "All rerun tests passed." + exit 0 + fi + echo "Some rerun tests still failed." + exit 1 + - name: Gather results + if: ${{ always() }} + run: | + if [ ! -d test-results ]; then + if ! ./tests/topotests/analyze.py -Ar test-results -C frr-ubuntu-cont; then + echo "ERROR: gathering results produced an error, perhaps due earlier run cancellation." >&2 + fi + fi + - name: Upload test results + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: test-results + path: | + test-results + test-results-initial + overwrite: true + - name: Cleanup + if: ${{ always() }} + run: | + rm -rf test-results* /tmp/frr-ubuntu22.tar + docker stop frr-ubuntu-cont || true + docker rm frr-ubuntu-cont || true + diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml index 100f557e02e0..4b4e99facf9f 100644 --- a/.github/workflows/conflicts.yml +++ b/.github/workflows/conflicts.yml @@ -1,9 +1,8 @@ name: Add a conflict label if PR needs to rebase on: - push: pull_request_target: - types: [synchronize] + types: [opened, reopened, synchronize] jobs: conflicts: diff --git a/.github/workflows/freeze.yml b/.github/workflows/freeze.yml index f3506d0061fb..a780298a425d 100644 --- a/.github/workflows/freeze.yml +++ b/.github/workflows/freeze.yml @@ -1,4 +1,4 @@ -name: Warn before merging if a "freeze" label exists +name: Warn before merging if a "freeze" or "do not merge" label exists on: pull_request_target: @@ -6,12 +6,12 @@ on: jobs: freeze_warning: - if: ${{ contains(github.event.*.labels.*.name, 'freeze') }} - name: Warn before merging if a "freeze" label exists + if: ${{ contains(github.event.*.labels.*.name, 'freeze') || contains(github.event.*.labels.*.name, 'do not merge') }} + name: Warn before merging if a "freeze" or "do not merge" label exists runs-on: ubuntu-latest steps: - name: Check for "freeze" label run: | - echo "Pull request is labeled as 'freeze'" + echo "Pull request is labeled as 'freeze' or 'do not merge'" echo "This workflow fails so that the pull request cannot be merged." exit 1 diff --git a/.gitignore b/.gitignore index a66e3ccd3c6a..60b41899520e 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,7 @@ *.cg.dot *.cg.svg *.xref +*_tsexpand.h ### gcov outputs @@ -117,3 +118,4 @@ refix /test-suite.log pceplib/test/*.log pceplib/test/*.trs +/tests/topotests/lib/mgmt_pb2.py diff --git a/Makefile.am b/Makefile.am index f56e1b8e0bac..0ce716e345c7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,7 @@ MODULE_LDFLAGS = \ $(SAN_FLAGS) \ # end -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) +DEFS = @DEFS@ -DCONFDATE=$(CONFDATE) AR_FLAGS = @AR_FLAGS@ ARFLAGS = @ARFLAGS@ diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 9a29ff3a9636..855b5859039c 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -27,21 +27,22 @@ source="$pkgname-$pkgver.tar.gz" builddir="$srcdir"/$pkgname-$pkgver +_sysconfdir=/etc _sbindir=/usr/lib/frr -_sysconfdir=/etc/frr _libdir=/usr/lib -_localstatedir=/var/run/frr _user=frr build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" + cd "$builddir" ./configure \ --prefix=/usr \ - --sbindir=$_sbindir \ --sysconfdir=$_sysconfdir \ + --localstatedir=/var \ + --sbindir=$_sbindir \ --libdir=$_libdir \ - --localstatedir=$_localstatedir \ --enable-rpki \ --enable-vtysh \ --enable-multipath=64 \ @@ -63,7 +64,9 @@ package() { cd "$builddir" make DESTDIR="$pkgdir" install - install -Dm644 "$builddir"/tools/etc/frr/daemons "$pkgdir"$_sysconfdir/daemons - install -d "$pkgdir"/etc/init.d - ln -s ${_sbindir}/frr "$pkgdir"/etc/init.d/frr + install -d $pkgdir/$_sysconfdir/frr + install -m 0644 tools/etc/frr/daemons $pkgdir/$_sysconfdir/frr/daemons + + install -d $pkgdir/$_sysconfdir/init.d + ln -s ${_sbindir}/frr $pkgdir/$_sysconfdir/init.d/frr } diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index ceff472c2a27..943ae9def1c2 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 == NULL) { babel_ifp->ipv4 = malloc(4); if (babel_ifp->ipv4 == NULL) { @@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 != NULL && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN) == 0) { @@ -542,7 +544,10 @@ DEFPY (babel_set_channel, unsigned jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent) unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent) static int interface_recalculate(struct interface *ifp) { - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned char *tmp = NULL; int mtu, rc; struct ipv6_mreq mreq; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!IS_ENABLE(ifp)) return -1; @@ -656,6 +665,7 @@ interface_reset(struct interface *ifp) int rc; struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP)) return 0; @@ -695,6 +705,11 @@ interface_reset(struct interface *ifp) babel_ifp->cost, babel_ifp->ipv4 ? ", IPv4" : ""); + if (babel_ifp->ipv4 != NULL){ + free(babel_ifp->ipv4); + babel_ifp->ipv4 = NULL; + } + return 1; } @@ -734,12 +749,11 @@ int is_interface_ll_address(struct interface *ifp, const unsigned char *address) { struct connected *connected; - struct listnode *node; if(!if_up(ifp)) return 0; - FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) { + frr_each (if_connected, ifp->connected, connected) { if (connected->address->family == AF_INET6 && memcmp(&connected->address->u.prefix6, address, IPV6_MAX_BYTELEN) @@ -773,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp) return; } babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); vty_out (vty, " Babel protocol is running on this interface\n"); vty_out (vty, " Operating mode is \"%s\"\n", CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless"); @@ -1156,6 +1171,11 @@ DEFUN (show_babel_parameters, return CMD_SUCCESS; } +void babel_if_terminate(void) +{ + vector_free(babel_enable_if); +} + void babel_if_init(void) { @@ -1224,6 +1244,7 @@ interface_config_write (struct vty *vty) if (ifp->desc) vty_out (vty, " description %s\n",ifp->desc); babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); /* wireless is the default*/ if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { @@ -1326,6 +1347,7 @@ babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); + assert (babel_ifp != NULL); /* All flags are unset */ babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; @@ -1345,5 +1367,11 @@ babel_interface_allocate (void) static void babel_interface_free (babel_interface_nfo *babel_ifp) { + assert (babel_ifp != NULL); + + if (babel_ifp->ipv4){ + free(babel_ifp->ipv4); + babel_ifp->ipv4 = NULL; + } XFREE(MTYPE_BABEL_IF, babel_ifp); } diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index 12fa6e2bad9a..ab08ded91a1c 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -82,7 +82,6 @@ static inline int if_up(struct interface *ifp) { return (if_is_operative(ifp) && - ifp->connected != NULL && CHECK_FLAG(babel_get_if_nfo(ifp)->flags, BABEL_IF_IS_UP)); } @@ -95,6 +94,7 @@ struct buffered_update { /* init function */ void babel_if_init(void); +void babel_if_terminate(void); /* Callback functions for zebra client */ int babel_interface_up (int, struct zclient *, zebra_size_t, vrf_id_t); diff --git a/babeld/babel_main.c b/babeld/babel_main.c index b6126d5b7d19..ddc75f7182c2 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -5,6 +5,8 @@ Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek /* include zebra library */ #include +#include + #include "getopt.h" #include "if.h" #include "log.h" @@ -56,7 +58,6 @@ unsigned char protocol_group[16]; /* babel's link-local multicast address */ int protocol_port; /* babel's port */ int protocol_socket = -1; /* socket: communicate with others babeld */ -static const char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; static char *babel_vty_addr = NULL; static int babel_vty_port = BABEL_VTY_PORT; @@ -124,18 +125,20 @@ static const struct frr_yang_module_info *const babeld_yang_modules[] = { &frr_vrf_info, }; +/* clang-format off */ FRR_DAEMON_INFO(babeld, BABELD, - .vty_port = BABEL_VTY_PORT, - .proghelp = "Implementation of the BABEL routing protocol.", + .vty_port = BABEL_VTY_PORT, + .proghelp = "Implementation of the BABEL routing protocol.", - .signals = babel_signals, - .n_signals = array_size(babel_signals), + .signals = babel_signals, + .n_signals = array_size(babel_signals), - .privs = &babeld_privs, + .privs = &babeld_privs, - .yang_modules = babeld_yang_modules, - .n_yang_modules = array_size(babeld_yang_modules), + .yang_modules = babeld_yang_modules, + .n_yang_modules = array_size(babeld_yang_modules), ); +/* clang-format on */ int main(int argc, char **argv) @@ -169,8 +172,8 @@ main(int argc, char **argv) } } - snprintf(state_file, sizeof(state_file), "%s/%s", - frr_vtydir, "babel-state"); + snprintf(state_file, sizeof(state_file), "%s/%s", frr_runstatedir, + "babel-state"); /* create the threads handler */ master = frr_init (); @@ -182,8 +185,10 @@ main(int argc, char **argv) change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE); /* init some quagga's dependencies, and babeld's commands */ - if_zapi_callbacks(babel_ifp_create, babel_ifp_up, - babel_ifp_down, babel_ifp_destroy); + hook_register_prio(if_real, 0, babel_ifp_create); + hook_register_prio(if_up, 0, babel_ifp_up); + hook_register_prio(if_down, 0, babel_ifp_down); + hook_register_prio(if_unreal, 0, babel_ifp_destroy); babeld_quagga_init(); /* init zebra client's structure and it's commands */ /* this replace kernel_setup && kernel_setup_socket */ @@ -300,12 +305,14 @@ babel_exit_properly(void) /* Uninstall and flush all routes. */ debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); - flush_all_routes(); - babel_interface_close_all(); + babel_clean_routing_process(); babel_zebra_close_connexion(); + babel_if_terminate(); babel_save_state_file(); debugf(BABEL_DEBUG_COMMON, "Remove pid file."); debugf(BABEL_DEBUG_COMMON, "Done."); + + vrf_terminate(); frr_fini(); exit(0); @@ -360,7 +367,7 @@ show_babel_main_configuration (struct vty *vty) "id = %s\n" "kernel_metric = %d\n", state_file, - babeld_di.config_file ? babeld_di.config_file : babel_config_default, + babeld_di.config_file, format_address(protocol_group), protocol_port, babel_vty_addr ? babel_vty_addr : "None", diff --git a/babeld/babeld.c b/babeld/babeld.c index ebf8474f4ccf..73deb1dd9254 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -242,7 +242,7 @@ babel_get_myid(void) /* We failed to get a global EUI64 from the interfaces we were given. Let's try to find an interface with a MAC address. */ for(i = 1; i < 256; i++) { - char buf[INTERFACE_NAMSIZ], *ifname; + char buf[IFNAMSIZ], *ifname; unsigned char eui[8]; ifname = if_indextoname(i, buf); if(ifname == NULL) @@ -299,8 +299,7 @@ babel_initial_noise(void) } /* Delete all the added babel routes, make babeld only speak to zebra. */ -static void -babel_clean_routing_process(void) +void babel_clean_routing_process(void) { flush_all_routes(); babel_interface_close_all(); @@ -696,9 +695,8 @@ DEFPY (babel_set_smoothing_half_life, DEFUN (babel_distribute_list, babel_distribute_list_cmd, - "distribute-list [prefix] ACCESSLIST4_NAME [WORD]", + "distribute-list ACCESSLIST4_NAME [WORD]", "Filter networks in routing updates\n" - "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" @@ -710,16 +708,26 @@ DEFUN (babel_distribute_list, if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; - return distribute_list_parser(prefix, true, argv[2 + prefix]->text, + return distribute_list_parser(babel_routing_process->distribute_ctx, + prefix, true, argv[2 + prefix]->text, argv[1 + prefix]->arg, ifname); } +ALIAS (babel_distribute_list, + babel_distribute_list_prefix_cmd, + "distribute-list prefix PREFIXLIST4_NAME [WORD]", + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + DEFUN (babel_no_distribute_list, babel_no_distribute_list_cmd, - "no distribute-list [prefix] ACCESSLIST4_NAME [WORD]", + "no distribute-list ACCESSLIST4_NAME [WORD]", NO_STR "Filter networks in routing updates\n" - "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" @@ -731,17 +739,28 @@ DEFUN (babel_no_distribute_list, if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; - return distribute_list_no_parser(vty, prefix, true, + return distribute_list_no_parser(babel_routing_process->distribute_ctx, + vty, prefix, true, argv[3 + prefix]->text, argv[2 + prefix]->arg, ifname); } +ALIAS (babel_no_distribute_list, + babel_no_distribute_list_prefix_cmd, + "no distribute-list prefix PREFIXLIST4_NAME [WORD]", + NO_STR + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + DEFUN (babel_ipv6_distribute_list, babel_ipv6_distribute_list_cmd, - "ipv6 distribute-list [prefix] ACCESSLIST6_NAME [WORD]", + "ipv6 distribute-list ACCESSLIST6_NAME [WORD]", "IPv6\n" "Filter networks in routing updates\n" - "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" @@ -753,17 +772,28 @@ DEFUN (babel_ipv6_distribute_list, if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; - return distribute_list_parser(prefix, false, argv[3 + prefix]->text, + return distribute_list_parser(babel_routing_process->distribute_ctx, + prefix, false, argv[3 + prefix]->text, argv[2 + prefix]->arg, ifname); } +ALIAS (babel_ipv6_distribute_list, + babel_ipv6_distribute_list_prefix_cmd, + "ipv6 distribute-list prefix PREFIXLIST6_NAME [WORD]", + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + DEFUN (babel_no_ipv6_distribute_list, babel_no_ipv6_distribute_list_cmd, - "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME [WORD]", + "no ipv6 distribute-list ACCESSLIST6_NAME [WORD]", NO_STR "IPv6\n" "Filter networks in routing updates\n" - "Specify a prefix\n" "Access-list name\n" "Filter incoming routing updates\n" "Filter outgoing routing updates\n" @@ -775,11 +805,24 @@ DEFUN (babel_no_ipv6_distribute_list, if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; - return distribute_list_no_parser(vty, prefix, false, + return distribute_list_no_parser(babel_routing_process->distribute_ctx, + vty, prefix, false, argv[4 + prefix]->text, argv[3 + prefix]->arg, ifname); } +ALIAS (babel_no_ipv6_distribute_list, + babel_no_ipv6_distribute_list_prefix_cmd, + "no ipv6 distribute-list prefix PREFIXLIST6_NAME [WORD]", + NO_STR + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") + void babeld_quagga_init(void) { @@ -797,9 +840,13 @@ babeld_quagga_init(void) install_element(BABEL_NODE, &babel_set_smoothing_half_life_cmd); install_element(BABEL_NODE, &babel_distribute_list_cmd); + install_element(BABEL_NODE, &babel_distribute_list_prefix_cmd); install_element(BABEL_NODE, &babel_no_distribute_list_cmd); + install_element(BABEL_NODE, &babel_no_distribute_list_prefix_cmd); install_element(BABEL_NODE, &babel_ipv6_distribute_list_cmd); + install_element(BABEL_NODE, &babel_ipv6_distribute_list_prefix_cmd); install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_cmd); + install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_prefix_cmd); vrf_cmd_init(NULL); diff --git a/babeld/babeld.h b/babeld/babeld.h index 619550f651f7..17a0381d2c50 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -53,7 +53,6 @@ Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek #endif -#define BABEL_VTY_PORT 2609 #define BABEL_DEFAULT_CONFIG "babeld.conf" /* Values in milliseconds */ @@ -99,5 +98,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); extern struct babel *babel_lookup(void); +extern void babel_clean_routing_process(void); #endif /* BABEL_BABELD_H */ diff --git a/babeld/kernel.c b/babeld/kernel.c index 4fe5bcfea68c..4957b04e77d9 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -11,6 +11,7 @@ Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek #include #include #include +#include #include "babeld.h" @@ -91,13 +92,9 @@ kernel_route(enum babel_kernel_routes operation, const unsigned char *pref, case ROUTE_MODIFY: if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) - return 0; - debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); - rc = zebra_route(0, family, pref, plen, gate, ifindex, metric); - if (rc < 0) - return -1; + return 0; - rc = zebra_route(1, family, pref, plen, newgate, newifindex, + rc = zebra_route(1, family, pref, plen, newgate, newifindex, newmetric); return rc; } diff --git a/babeld/message.c b/babeld/message.c index f8549329c603..1b83eb9ebb90 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -139,7 +139,7 @@ static bool parse_update_subtlv(const unsigned char *a, int alen, return false; } - if (type & SUBTLV_MANDATORY) { + if (CHECK_FLAG(type, SUBTLV_MANDATORY)) { /* * RFC 8966 - 4.4 * If the mandatory bit is set, then the whole enclosing @@ -162,8 +162,7 @@ static bool parse_update_subtlv(const unsigned char *a, int alen, } if (memchr(a + i + 2, 0, len) != NULL) { /* 0 is reserved. */ - flog_err(EC_BABEL_PACKET, - "Channel information contains 0!"); + flog_err(EC_BABEL_PACKET, "Channel information contains 0!"); return false; } memset(channels, 0, DIVERSITY_HOPS); @@ -203,7 +202,7 @@ parse_hello_subtlv(const unsigned char *a, int alen, return -1; } - if (type & SUBTLV_MANDATORY) { + if (CHECK_FLAG(type, SUBTLV_MANDATORY)) { /* * RFC 8966 4.4 * If the mandatory bit is set, then the whole enclosing @@ -417,7 +416,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, unsigned int hello_send_us = 0, hello_rtt_receive_time = 0; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - if(babel_ifp->flags & BABEL_IF_TIMESTAMPS) { + if (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS)) { /* We want to track exactly when we received this packet. */ gettime(&babel_now); } @@ -513,8 +512,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, schedule_neighbours_check(interval * 15, 0); /* Sub-TLV handling. */ if (len > 8) { - if (parse_hello_subtlv(message + 8, len - 6, - ×tamp) > 0) { + if (parse_hello_subtlv(message + 8, len - 6, ×tamp) > 0) { neigh->hello_send_us = timestamp; neigh->hello_rtt_receive_time = babel_now; have_hello_rtt = 1; @@ -554,8 +552,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, } else if(type == MESSAGE_NH) { unsigned char nh[16]; int rc; - rc = network_address(message[2], message + 4, len - 2, - nh); + rc = network_address(message[2], message + 4, len - 2, nh); if(rc <= 0) { have_v4_nh = 0; have_v6_nh = 0; @@ -577,9 +574,9 @@ parse_packet(const unsigned char *from, struct interface *ifp, unsigned char channels[DIVERSITY_HOPS]; unsigned short interval, seqno, metric; int rc, parsed_len; - bool ignore_update = false; + bool ignore_update = false; - DO_NTOHS(interval, message + 6); + DO_NTOHS(interval, message + 6); DO_NTOHS(seqno, message + 8); DO_NTOHS(metric, message + 10); if(message[5] == 0 || @@ -651,7 +648,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, goto done; } - if((babel_get_if_nfo(ifp)->flags & BABEL_IF_FARAWAY)) { + if(CHECK_FLAG(babel_get_if_nfo(ifp)->flags, BABEL_IF_FARAWAY)) { channels[0] = 0; } else { /* This will be overwritten by parse_update_subtlv below. */ @@ -665,15 +662,14 @@ parse_packet(const unsigned char *from, struct interface *ifp, } if(parsed_len < len) - ignore_update = - parse_update_subtlv(message + 2 + parsed_len, - len - parsed_len, channels); + ignore_update = + parse_update_subtlv(message + 2 + parsed_len, + len - parsed_len, channels); } if (!ignore_update) update_route(router_id, prefix, plen, seqno, metric, - interval, neigh, nh, channels, - channels_len(channels)); + interval, neigh, nh, channels, channels_len(channels)); } else if(type == MESSAGE_REQUEST) { unsigned char prefix[16], src_prefix[16], plen, src_plen; int rc, is_ss; @@ -738,8 +734,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, format_prefix(prefix, plen), format_address(from), ifp->name, format_eui64(message + 8), seqno); - handle_request(neigh, prefix, plen, message[6], - seqno, message + 8); + handle_request(neigh, prefix, plen, message[6], seqno, message + 8); } else { debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.", type, format_address(from), ifp->name); @@ -821,11 +816,10 @@ check_bucket(struct interface *ifp) } } -static int -fill_rtt_message(struct interface *ifp) +static int fill_rtt_message(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); - if((babel_ifp->flags & BABEL_IF_TIMESTAMPS) && + if(CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) && (babel_ifp->buffered_hello >= 0)) { if(babel_ifp->sendbuf[babel_ifp->buffered_hello + 8] == SUBTLV_PADN && babel_ifp->sendbuf[babel_ifp->buffered_hello + 9] == 4) { @@ -845,8 +839,7 @@ fill_rtt_message(struct interface *ifp) return 0; } -void -flushbuf(struct interface *ifp) +void flushbuf(struct interface *ifp) { int rc; struct sockaddr_in6 sin6; @@ -888,8 +881,7 @@ flushbuf(struct interface *ifp) babel_ifp->flush_timeout.tv_usec = 0; } -static void -schedule_flush(struct interface *ifp) +static void schedule_flush(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned msecs = jitter(babel_ifp, 0); @@ -899,8 +891,7 @@ schedule_flush(struct interface *ifp) set_timeout(&babel_ifp->flush_timeout, msecs); } -static void -schedule_flush_now(struct interface *ifp) +static void schedule_flush_now(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); /* Almost now */ @@ -911,8 +902,7 @@ schedule_flush_now(struct interface *ifp) set_timeout(&babel_ifp->flush_timeout, msecs); } -static void -schedule_unicast_flush(unsigned msecs) +static void schedule_unicast_flush(unsigned msecs) { if(!unicast_neighbour) return; @@ -924,16 +914,14 @@ schedule_unicast_flush(unsigned msecs) babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000; } -static void -ensure_space(struct interface *ifp, int space) +static void ensure_space(struct interface *ifp, int space) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bufsize - babel_ifp->buffered < space) flushbuf(ifp); } -static void -start_message(struct interface *ifp, int type, int len) +static void start_message(struct interface *ifp, int type, int len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bufsize - babel_ifp->buffered < len + 2) @@ -942,8 +930,7 @@ start_message(struct interface *ifp, int type, int len) babel_ifp->sendbuf[babel_ifp->buffered++] = len; } -static void -end_message(struct interface *ifp, int type, int bytes) +static void end_message(struct interface *ifp, int type, int bytes) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); assert(babel_ifp->buffered >= bytes + 2 && @@ -952,23 +939,20 @@ end_message(struct interface *ifp, int type, int bytes) schedule_flush(ifp); } -static void -accumulate_byte(struct interface *ifp, unsigned char value) +static void accumulate_byte(struct interface *ifp, unsigned char value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); babel_ifp->sendbuf[babel_ifp->buffered++] = value; } -static void -accumulate_short(struct interface *ifp, unsigned short value) +static void accumulate_short(struct interface *ifp, unsigned short value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value); babel_ifp->buffered += 2; } -static void -accumulate_int(struct interface *ifp, unsigned int value) +static void accumulate_int(struct interface *ifp, unsigned int value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); DO_HTONL(babel_ifp->sendbuf + babel_ifp->buffered, value); @@ -984,8 +968,7 @@ accumulate_bytes(struct interface *ifp, babel_ifp->buffered += len; } -static int -start_unicast_message(struct neighbour *neigh, int type, int len) +static int start_unicast_message(struct neighbour *neigh, int type, int len) { if(unicast_neighbour) { if(neigh != unicast_neighbour || @@ -1008,8 +991,7 @@ start_unicast_message(struct neighbour *neigh, int type, int len) return 1; } -static void -end_unicast_message(struct neighbour *neigh, int type, int bytes) +static void end_unicast_message(struct neighbour *neigh, int type, int bytes) { assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 && unicast_buffer[unicast_buffered - bytes - 2] == type && @@ -1030,8 +1012,7 @@ accumulate_unicast_short(struct neighbour *neigh, unsigned short value) unicast_buffered += 2; } -static void -accumulate_unicast_int(struct neighbour *neigh, unsigned int value) +static void accumulate_unicast_int(struct neighbour *neigh, unsigned int value) { DO_HTONL(unicast_buffer + unicast_buffered, value); unicast_buffered += 4; @@ -1051,15 +1032,16 @@ send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) int rc; debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.", nonce, format_address(neigh->address), neigh->ifp->name); - rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; + rc = start_unicast_message(neigh, MESSAGE_ACK, 2); + if(rc < 0) + return; accumulate_unicast_short(neigh, nonce); end_unicast_message(neigh, MESSAGE_ACK, 2); /* Roughly yields a value no larger than 3/2, so this meets the deadline */ schedule_unicast_flush(roughly(interval * 6)); } -void -send_hello_noupdate(struct interface *ifp, unsigned interval) +void send_hello_noupdate(struct interface *ifp, unsigned interval) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); /* This avoids sending multiple hellos in a single packet, which breaks @@ -1082,7 +1064,7 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) accumulate_short(ifp, 0); accumulate_short(ifp, babel_ifp->hello_seqno); accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); - if(babel_ifp->flags & BABEL_IF_TIMESTAMPS) { + if (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS)) { /* Sub-TLV containing the local time of emission. We use a Pad4 sub-TLV, which we'll fill just before sending. */ accumulate_byte(ifp, SUBTLV_PADN); @@ -1090,11 +1072,10 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) accumulate_int(ifp, 0); } end_message(ifp, MESSAGE_HELLO, - (babel_ifp->flags & BABEL_IF_TIMESTAMPS) ? 12 : 6); + CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) ? 12 : 6); } -void -send_hello(struct interface *ifp) +void send_hello(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); @@ -1105,8 +1086,7 @@ send_hello(struct interface *ifp) send_marginal_ihu(ifp); } -void -flush_unicast(int dofree) +void flush_unicast(int dofree) { struct sockaddr_in6 sin6; int rc; @@ -1183,7 +1163,7 @@ really_send_update(struct interface *ifp, /* Worst case */ ensure_space(ifp, 20 + 12 + 28); - v4 = plen >= 96 && v4mapped(prefix); + v4 = (plen >= 96) && v4mapped(prefix); if(v4) { if(!babel_ifp->ipv4) @@ -1208,7 +1188,7 @@ really_send_update(struct interface *ifp, omit++; } if(!babel_ifp->have_buffered_prefix || plen >= 48) - flags |= 0x80; + SET_FLAG(flags, 0x80); real_prefix = prefix; real_plen = plen; } @@ -1216,7 +1196,7 @@ really_send_update(struct interface *ifp, if(!babel_ifp->have_buffered_id || memcmp(id, babel_ifp->buffered_id, 8) != 0) { if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) { - flags |= 0x40; + SET_FLAG(flags, 0x40); } else { start_message(ifp, MESSAGE_ROUTER_ID, 10); accumulate_short(ifp, 0); @@ -1248,14 +1228,13 @@ really_send_update(struct interface *ifp, end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); - if(flags & 0x80) { + if (CHECK_FLAG(flags, 0x80)) { memcpy(babel_ifp->buffered_prefix, prefix, 16); babel_ifp->have_buffered_prefix = 1; } } -static int -compare_buffered_updates(const void *av, const void *bv) +static int compare_buffered_updates(const void *av, const void *bv) { const struct buffered_update *a = av, *b = bv; int rc, v4a, v4b, ma, mb; @@ -1288,8 +1267,7 @@ compare_buffered_updates(const void *av, const void *bv) return memcmp(a->prefix, b->prefix, 16); } -void -flushupdates(struct interface *ifp) +void flushupdates(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; struct xroute *xroute; @@ -1299,7 +1277,7 @@ flushupdates(struct interface *ifp) int i; if(ifp == NULL) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp_aux; FOR_ALL_INTERFACES(vrf, ifp_aux) flushupdates(ifp_aux); @@ -1372,7 +1350,7 @@ flushupdates(struct interface *ifp) if(metric < INFINITY) satisfy_request(route->src->prefix, route->src->plen, seqno, route->src->id, ifp); - if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && + if(CHECK_FLAG(babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) && route->neigh->ifp == ifp) continue; @@ -1414,11 +1392,11 @@ flushupdates(struct interface *ifp) babel_ifp->update_flush_timeout.tv_usec = 0; } -static void -schedule_update_flush(struct interface *ifp, int urgent) +static void schedule_update_flush(struct interface *ifp, int urgent) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned msecs; + msecs = update_jitter(babel_ifp, urgent); if(babel_ifp->update_flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs) @@ -1528,10 +1506,10 @@ send_update_resend(struct interface *ifp, record_resend(RESEND_UPDATE, prefix, plen, 0, NULL, NULL, resend_delay); } -void -send_wildcard_retraction(struct interface *ifp) +void send_wildcard_retraction(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; + if(ifp == NULL) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp_aux; @@ -1557,14 +1535,12 @@ send_wildcard_retraction(struct interface *ifp) babel_ifp->have_buffered_id = 0; } -void -update_myseqno(void) +void update_myseqno(void) { myseqno = seqno_plus(myseqno, 1); } -void -send_self_update(struct interface *ifp) +void send_self_update(struct interface *ifp) { struct xroute_stream *xroutes; if(ifp == NULL) { @@ -1592,8 +1568,7 @@ send_self_update(struct interface *ifp) } } -void -send_ihu(struct neighbour *neigh, struct interface *ifp) +void send_ihu(struct neighbour *neigh, struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; int rxcost, interval; @@ -1645,7 +1620,7 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) ll = linklocal(neigh->address); - if((babel_ifp->flags & BABEL_IF_TIMESTAMPS) && neigh->hello_send_us + if(CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS) && neigh->hello_send_us /* Checks whether the RTT data is not too old to be sent. */ && timeval_minus_msec(&babel_now, &neigh->hello_rtt_receive_time) < 1000000) { @@ -1700,14 +1675,13 @@ send_ihu(struct neighbour *neigh, struct interface *ifp) } /* Send IHUs to all marginal neighbours */ -void -send_marginal_ihu(struct interface *ifp) +void send_marginal_ihu(struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { if(ifp && neigh->ifp != ifp) continue; - if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) + if(neigh->txcost >= 384 || CHECK_FLAG(neigh->reach, 0xF000) != 0xF000) send_ihu(neigh, ifp); } } diff --git a/babeld/neighbour.c b/babeld/neighbour.c index 51e595a84ba8..65e613cc8b6a 100644 --- a/babeld/neighbour.c +++ b/babeld/neighbour.c @@ -34,15 +34,13 @@ find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { - if(memcmp(address, neigh->address, 16) == 0 && - neigh->ifp == ifp) + if(memcmp(address, neigh->address, 16) == 0 && neigh->ifp == ifp) return neigh; } return NULL; } -void -flush_neighbour(struct neighbour *neigh) +void flush_neighbour(struct neighbour *neigh) { debugf(BABEL_DEBUG_COMMON,"Flushing neighbour %s (reach 0x%04x)", format_address(neigh->address), neigh->reach); @@ -102,8 +100,7 @@ find_neighbour(const unsigned char *address, struct interface *ifp) } /* Recompute a neighbour's rxcost. Return true if anything changed. */ -int -update_neighbour(struct neighbour *neigh, int hello, int hello_interval) +int update_neighbour(struct neighbour *neigh, int hello, int hello_interval) { int missed_hellos; int rc = 0; @@ -160,26 +157,26 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval) if(hello >= 0) { neigh->hello_seqno = hello; neigh->reach >>= 1; - neigh->reach |= 0x8000; - if((neigh->reach & 0xFC00) != 0xFC00) + SET_FLAG(neigh->reach, 0x8000); + if(CHECK_FLAG(neigh->reach, 0xFC00) != 0xFC00) rc = 1; } /* Make sure to give neighbours some feedback early after association */ - if((neigh->reach & 0xBF00) == 0x8000) { + if(CHECK_FLAG(neigh->reach, 0xBF00) == 0x8000) { /* A new neighbour */ send_hello(neigh->ifp); } else { /* Don't send hellos, in order to avoid a positive feedback loop. */ - int a = (neigh->reach & 0xC000); - int b = (neigh->reach & 0x3000); + int a = CHECK_FLAG(neigh->reach, 0xC000); + int b = CHECK_FLAG(neigh->reach, 0x3000); if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { /* Reachability is either 1100 or 0011 */ send_self_update(neigh->ifp); } } - if((neigh->reach & 0xFC00) == 0xC000) { + if(CHECK_FLAG(neigh->reach, 0xFC00) == 0xC000) { /* This is a newish neighbour, let's request a full route dump. We ought to avoid this when the network is dense */ send_unicast_request(neigh, NULL, 0); @@ -188,8 +185,7 @@ update_neighbour(struct neighbour *neigh, int hello, int hello_interval) return rc; } -static int -reset_txcost(struct neighbour *neigh) +static int reset_txcost(struct neighbour *neigh) { unsigned delay; @@ -199,9 +195,8 @@ reset_txcost(struct neighbour *neigh) return 0; /* If we're losing a lot of packets, we probably lost an IHU too */ - if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || - (neigh->ihu_interval > 0 && - delay >= neigh->ihu_interval * 10U * 10U)) { + if (delay >= 180000 || CHECK_FLAG(neigh->reach, 0xFFF0) == 0 || + (neigh->ihu_interval > 0 && delay >= neigh->ihu_interval * 10U * 10U)) { neigh->txcost = INFINITY; neigh->ihu_time = babel_now; return 1; @@ -210,14 +205,12 @@ reset_txcost(struct neighbour *neigh) return 0; } -unsigned -neighbour_txcost(struct neighbour *neigh) +unsigned neighbour_txcost(struct neighbour *neigh) { return neigh->txcost; } -unsigned -check_neighbours(void) +unsigned check_neighbours(void) { struct neighbour *neigh; int changed, rc; @@ -253,21 +246,20 @@ check_neighbours(void) return msecs; } -unsigned -neighbour_rxcost(struct neighbour *neigh) +unsigned neighbour_rxcost(struct neighbour *neigh) { unsigned delay; unsigned short reach = neigh->reach; delay = timeval_minus_msec(&babel_now, &neigh->hello_time); - if((reach & 0xFFF0) == 0 || delay >= 180000) { + if(CHECK_FLAG(reach, 0xFFF0) == 0 || delay >= 180000) { return INFINITY; - } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { + } else if (CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ)) { int sreach = - ((reach & 0x8000) >> 2) + - ((reach & 0x4000) >> 1) + - (reach & 0x3FFF); + (CHECK_FLAG(reach, 0x8000) >> 2) + + (CHECK_FLAG(reach, 0x4000) >> 1) + + CHECK_FLAG(reach, 0x3FFF); /* 0 <= sreach <= 0x7FFF */ int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); /* cost >= interface->cost */ @@ -276,19 +268,18 @@ neighbour_rxcost(struct neighbour *neigh) return MIN(cost, INFINITY); } else { /* To lose one hello is a misfortune, to lose two is carelessness. */ - if((reach & 0xC000) == 0xC000) + if (CHECK_FLAG(reach, 0xC000) == 0xC000) return babel_get_if_nfo(neigh->ifp)->cost; - else if((reach & 0xC000) == 0) + else if (CHECK_FLAG(reach, 0xC000) == 0) return INFINITY; - else if((reach & 0x2000)) + else if (CHECK_FLAG(reach, 0x2000)) return babel_get_if_nfo(neigh->ifp)->cost; else return INFINITY; } } -unsigned -neighbour_rttcost(struct neighbour *neigh) +unsigned neighbour_rttcost(struct neighbour *neigh) { struct interface *ifp = neigh->ifp; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); @@ -304,15 +295,14 @@ neighbour_rttcost(struct neighbour *neigh) (unsigned long long)babel_ifp->max_rtt_penalty * (neigh->rtt - babel_ifp->rtt_min) / (babel_ifp->rtt_max - babel_ifp->rtt_min); - assert((tmp & 0x7FFFFFFF) == tmp); + assert(CHECK_FLAG(tmp, 0x7FFFFFFF) == tmp); return tmp; } else { return babel_ifp->max_rtt_penalty; } } -unsigned -neighbour_cost(struct neighbour *neigh) +unsigned neighbour_cost(struct neighbour *neigh) { unsigned a, b, cost; @@ -328,7 +318,7 @@ neighbour_cost(struct neighbour *neigh) if(b >= INFINITY) return INFINITY; - if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) + if (!CHECK_FLAG(babel_get_if_nfo(neigh->ifp)->flags, BABEL_IF_LQ) || (a < 256 && b < 256)) { cost = a; } else { @@ -347,8 +337,7 @@ neighbour_cost(struct neighbour *neigh) return MIN(cost, INFINITY); } -int -valid_rtt(struct neighbour *neigh) +int valid_rtt(struct neighbour *neigh) { return (timeval_minus_msec(&babel_now, &neigh->rtt_time) < 180000) ? 1 : 0; } diff --git a/babeld/route.c b/babeld/route.c index 2c7e92374896..466f41383cb8 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -352,7 +352,7 @@ route_stream_done(struct route_stream *stream) static int metric_to_kernel(int metric) { - return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; + return metric < INFINITY ? metric : KERNEL_INFINITY; } /* This is used to maintain the invariant that the installed route is at diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 3096f47d5c2b..eb9c3003135f 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -256,19 +256,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { - struct bfd_session *bs; - struct peer_label *pl; struct bfd_key key; - /* Try to find label first. */ - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl != NULL) { - bs = pl->pl_bs; - return bs; - } - } - /* Otherwise fallback to peer/local hash lookup. */ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, bpc->bpc_localif, bpc->bpc_vrfname); @@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs) bs->ifp = ifp; /* Attempt to use data plane. */ - if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) { - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs); + if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) return 0; - } /* Sanity check: don't leak open sockets. */ if (bs->sock != -1) { @@ -410,8 +397,8 @@ static uint32_t ptm_bfd_gen_ID(void) * random session identification numbers. */ do { - session_id = ((frr_weak_random() << 16) & 0xFFFF0000) - | (frr_weak_random() & 0x0000FFFF); + session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) | + CHECK_FLAG(frr_weak_random(), 0x0000FFFF); } while (session_id == 0 || bfd_id_lookup(session_id) != NULL); return session_id; @@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd) /* Start sending control packets with poll bit immediately. */ ptm_bfd_snd(bfd, 0); - control_notify(bfd, bfd->ses_state); + ptm_bfd_notify(bfd, bfd->ses_state); if (old_state != bfd->ses_state) { bfd->stats.session_up++; @@ -538,7 +525,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) - control_notify(bfd, PTM_BFD_DOWN); + ptm_bfd_notify(bfd, PTM_BFD_DOWN); /* Stop echo packet transmission if they are active */ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) @@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void) return bs; } -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel) -{ - /* New label treatment: - * - Check if the label is taken; - * - Try to allocate the memory for it and register; - */ - if (bs->pl == NULL) { - if (pl_find(nlabel) != NULL) { - /* Someone is already using it. */ - return -1; - } - - pl_new(nlabel, bs); - - return 0; - } - - /* - * Test label change consistency: - * - Do nothing if it's the same label; - * - Check if the future label is already taken; - * - Change label; - */ - if (strcmp(nlabel, bs->pl->pl_label) == 0) - return -1; - if (pl_find(nlabel) != NULL) - return -1; - - strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label)); - return 0; -} - static void _bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) { @@ -750,9 +705,6 @@ static void _bfd_session_update(struct bfd_session *bs, bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx; } - if (bpc->bpc_has_label) - bfd_session_update_label(bs, bpc->bpc_label); - if (bpc->bpc_cbit) SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); else @@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) _bfd_session_update(bs, bpc); - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); - return 0; } @@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs) if (bso != NULL) bs_observer_del(bso); - pl_free(bs->pl); - XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); XFREE(MTYPE_BFDD_CONFIG, bs); } @@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd) if (bglobal.debug_peer_event) zlog_debug("session-new: %s", bs_to_string(bfd)); - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd); - return bfd; } @@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc) if (bglobal.debug_peer_event) zlog_debug("%s: %s", __func__, bs_to_string(bs)); - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); - bfd_session_free(bs); return 0; @@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs) * When using demand mode we must disable the detection timer * for lost control packets. */ - if (bs->demand_mode) { - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); + if (bs->demand_mode) return; - } /* * Calculate transmission time based on new timers. @@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs) /* Apply new transmission timer immediately. */ ptm_bfd_start_xmt_timer(bs, false); - - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); } void bs_set_slow_timers(struct bfd_session *bs) @@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_ADM_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } @@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) /* Change and notify state change. */ bs->ses_state = PTM_BFD_ADM_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Don't try to send packets with a disabled session. */ if (bs->sock != -1) @@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } /* Change and notify state change. */ bs->ses_state = PTM_BFD_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Enable timers if non passive, otherwise stop them. */ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) { diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 6c5a1e921618..2f83b245eb28 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -20,17 +20,73 @@ #include "lib/queue.h" #include "lib/vrf.h" -#include "bfdctl.h" - #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #else #define BFDD_JSON_CONV_OPTIONS (0) #endif +#ifndef MAXNAMELEN +#define MAXNAMELEN 32 +#endif + +#define BPC_DEF_DETECTMULTIPLIER 3 +#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ +#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ +#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ +#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ + DECLARE_MGROUP(BFDD); -DECLARE_MTYPE(BFDD_CONTROL); -DECLARE_MTYPE(BFDD_NOTIFICATION); +DECLARE_MTYPE(BFDD_CLIENT); +DECLARE_MTYPE(BFDD_CLIENT_NOTIFICATION); + +struct sockaddr_any { + union { + struct sockaddr_in sa_sin; + struct sockaddr_in6 sa_sin6; + }; +}; + +struct bfd_peer_cfg { + bool bpc_mhop; + bool bpc_ipv4; + struct sockaddr_any bpc_peer; + struct sockaddr_any bpc_local; + + bool bpc_has_localif; + char bpc_localif[MAXNAMELEN + 1]; + + bool bpc_has_vrfname; + char bpc_vrfname[MAXNAMELEN + 1]; + + bool bpc_has_detectmultiplier; + uint8_t bpc_detectmultiplier; + + bool bpc_has_recvinterval; + uint64_t bpc_recvinterval; + + bool bpc_has_txinterval; + uint64_t bpc_txinterval; + + bool bpc_has_echorecvinterval; + uint64_t bpc_echorecvinterval; + + bool bpc_has_echotxinterval; + uint64_t bpc_echotxinterval; + + bool bpc_has_minimum_ttl; + uint8_t bpc_minimum_ttl; + + bool bpc_echo; + bool bpc_createonly; + bool bpc_shutdown; + + bool bpc_cbit; + bool bpc_passive; + + bool bpc_has_profile; + char bpc_profile[64]; +}; /* bfd Authentication Type. */ #define BFD_AUTH_NULL 0 @@ -95,43 +151,46 @@ struct bfd_echo_pkt { /* Macros for manipulating control packets */ #define BFD_VERMASK 0x07 #define BFD_DIAGMASK 0x1F -#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK) -#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5) +#define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK)) +#define BFD_SETVER(diag, val) \ + SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5) #define BFD_VERSION 1 #define BFD_PBIT 0x20 #define BFD_FBIT 0x10 #define BFD_CBIT 0x08 #define BFD_ABIT 0x04 #define BFD_DEMANDBIT 0x02 +#define BFD_MBIT 0x01 +#define BFD_GETMBIT(flags) (CHECK_FLAG(flags, BFD_MBIT)) #define BFD_SETDEMANDBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_DEMANDBIT; \ + SET_FLAG(flags, BFD_DEMANDBIT); \ } #define BFD_SETPBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_PBIT; \ + SET_FLAG(flags, BFD_PBIT); \ } -#define BFD_GETPBIT(flags) (flags & BFD_PBIT) +#define BFD_GETPBIT(flags) (CHECK_FLAG(flags, BFD_PBIT)) #define BFD_SETFBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_FBIT; \ + SET_FLAG(flags, BFD_FBIT); \ } -#define BFD_GETFBIT(flags) (flags & BFD_FBIT) +#define BFD_GETFBIT(flags) (CHECK_FLAG(flags, BFD_FBIT)) #define BFD_SETSTATE(flags, val) \ { \ if ((val)) \ - flags |= (val & 0x3) << 6; \ + SET_FLAG(flags, (CHECK_FLAG(val, 0x3) << 6)); \ } -#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3) +#define BFD_GETSTATE(flags) (CHECK_FLAG((flags >> 6), 0x3)) #define BFD_SETCBIT(flags, val) \ { \ if ((val)) \ - flags |= val; \ + SET_FLAG(flags, val); \ } -#define BFD_GETCBIT(flags) (flags & BFD_FBIT) +#define BFD_GETCBIT(flags) (CHECK_FLAG(flags, BFD_CBIT)) #define BFD_ECHO_VERSION 1 #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) @@ -193,7 +252,7 @@ struct bfd_key { uint16_t mhop; struct in6_addr peer; struct in6_addr local; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; char vrfname[VRF_NAMSIZ]; } __attribute__((packed)); @@ -241,9 +300,6 @@ struct bfd_profile { /** Profile list type. */ TAILQ_HEAD(bfdproflist, bfd_profile); -/* bfd_session shortcut label forwarding. */ -struct peer_label; - struct bfd_config_timers { uint32_t desired_min_tx; uint32_t required_min_rx; @@ -321,14 +377,6 @@ struct bfd_session { uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */ }; -struct peer_label { - TAILQ_ENTRY(peer_label) pl_entry; - - struct bfd_session *pl_bs; - char pl_label[MAXNAMELEN]; -}; -TAILQ_HEAD(pllist, peer_label); - struct bfd_diag_str_list { const char *str; int type; @@ -380,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 -/* - * control.c - * - * Daemon control code to speak with local consumers. - */ - -/* See 'bfdctrl.h' for client protocol definitions. */ - -struct bfd_control_buffer { - size_t bcb_left; - size_t bcb_pos; - union { - struct bfd_control_msg *bcb_bcm; - uint8_t *bcb_buf; - }; -}; - -struct bfd_control_queue { - TAILQ_ENTRY(bfd_control_queue) bcq_entry; - - struct bfd_control_buffer bcq_bcb; -}; -TAILQ_HEAD(bcqueue, bfd_control_queue); - -struct bfd_notify_peer { - TAILQ_ENTRY(bfd_notify_peer) bnp_entry; - - struct bfd_session *bnp_bs; -}; -TAILQ_HEAD(bnplist, bfd_notify_peer); - -struct bfd_control_socket { - TAILQ_ENTRY(bfd_control_socket) bcs_entry; - - int bcs_sd; - struct event *bcs_ev; - struct event *bcs_outev; - struct bcqueue bcs_bcqueue; - - /* Notification data */ - uint64_t bcs_notify; - struct bnplist bcs_bnplist; - - enum bc_msg_version bcs_version; - enum bc_msg_type bcs_type; - - /* Message buffering */ - struct bfd_control_buffer bcs_bin; - struct bfd_control_buffer *bcs_bout; -}; -TAILQ_HEAD(bcslist, bfd_control_socket); - -int control_init(const char *path); -void control_shutdown(void); -int control_notify(struct bfd_session *bs, uint8_t notify_state); -int control_notify_config(const char *op, struct bfd_session *bs); -void control_accept(struct event *t); - /* * bfdd.c @@ -463,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx); struct bfd_global { int bg_csock; struct event *bg_csockev; - struct bcslist bg_bcslist; - - struct pllist bg_pllist; struct obslist bg_obslist; @@ -511,27 +498,6 @@ extern const struct bfd_state_str_list state_list[]; void socket_close(int *s); -/* - * config.c - * - * Contains the code related with loading/reloading configuration. - */ -int parse_config(const char *fname); -int config_request_add(const char *jsonstr); -int config_request_del(const char *jsonstr); -char *config_response(const char *status, const char *error); -char *config_notify(struct bfd_session *bs); -char *config_notify_config(const char *op, struct bfd_session *bs); - -typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg); -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh); - -struct peer_label *pl_new(const char *label, struct bfd_session *bs); -struct peer_label *pl_find(const char *label); -void pl_free(struct peer_label *pl); - - /* * logging - alias to zebra log */ @@ -616,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel); void bfd_set_polling(struct bfd_session *bs); void bs_state_handler(struct bfd_session *bs, int nstate); void bs_echo_timer_handler(struct bfd_session *bs); @@ -782,6 +747,7 @@ void bfdd_cli_init(void); */ void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv); void bfdd_zclient_stop(void); +void bfdd_zclient_terminate(void); void bfdd_zclient_unregister(vrf_id_t vrf_id); void bfdd_zclient_register(vrf_id_t vrf_id); void bfdd_sessions_enable_vrf(struct vrf *vrf); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 5d8bf47fcd43..f9397fa128db 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -12,6 +12,11 @@ */ #include +#include + +#ifdef GNU_LINUX +#include +#endif #ifdef BFD_LINUX #include @@ -893,6 +898,12 @@ void bfd_recv_cb(struct event *t) return; } + if (BFD_GETMBIT(cp->flags)) { + cp_debug(is_mhop, &peer, &local, ifindex, vrfid, + "detect non-zero Multipoint (M) flag"); + return; + } + if (cp->discrs.my_discr == 0) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "'my discriminator' is zero"); @@ -971,7 +982,7 @@ void bfd_recv_cb(struct event *t) } /* Save remote diagnostics before state switch. */ - bfd->remote_diag = cp->diag & BFD_DIAGMASK; + bfd->remote_diag = CHECK_FLAG(cp->diag, BFD_DIAGMASK); /* Update remote timers settings. */ bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); @@ -1727,7 +1738,7 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd, if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) return; - if (ifp->flags & IFF_NOARP) + if (CHECK_FLAG(ifp->flags, IFF_NOARP)) return; if (peer->sa_sin.sin_family == AF_INET) { diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h deleted file mode 100644 index f1f8185c3bbf..000000000000 --- a/bfdd/bfdctl.h +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * bfdctl.h: all BFDd control socket protocol definitions. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#ifndef _BFDCTRL_H_ -#define _BFDCTRL_H_ - -#include - -#include -#include - -/* - * Auxiliary definitions - */ -struct sockaddr_any { - union { - struct sockaddr_in sa_sin; - struct sockaddr_in6 sa_sin6; - }; -}; - -#ifndef MAXNAMELEN -#define MAXNAMELEN 32 -#endif - -#define BPC_DEF_DETECTMULTIPLIER 3 -#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ -#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ -#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ -#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ - -/* Peer status */ -enum bfd_peer_status { - BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */ - BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */ - BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */ - BPS_UP = 3, /* == PTM_BFD_UP, "up" */ -}; - -struct bfd_peer_cfg { - bool bpc_mhop; - bool bpc_ipv4; - struct sockaddr_any bpc_peer; - struct sockaddr_any bpc_local; - - bool bpc_has_label; - char bpc_label[MAXNAMELEN]; - - bool bpc_has_localif; - char bpc_localif[MAXNAMELEN + 1]; - - bool bpc_has_vrfname; - char bpc_vrfname[MAXNAMELEN + 1]; - - bool bpc_has_detectmultiplier; - uint8_t bpc_detectmultiplier; - - bool bpc_has_recvinterval; - uint64_t bpc_recvinterval; - - bool bpc_has_txinterval; - uint64_t bpc_txinterval; - - bool bpc_has_echorecvinterval; - uint64_t bpc_echorecvinterval; - - bool bpc_has_echotxinterval; - uint64_t bpc_echotxinterval; - - bool bpc_has_minimum_ttl; - uint8_t bpc_minimum_ttl; - - bool bpc_echo; - bool bpc_createonly; - bool bpc_shutdown; - - bool bpc_cbit; - bool bpc_passive; - - bool bpc_has_profile; - char bpc_profile[64]; - - /* Status information */ - enum bfd_peer_status bpc_bps; - uint32_t bpc_id; - uint32_t bpc_remoteid; - uint8_t bpc_diag; - uint8_t bpc_remotediag; - uint8_t bpc_remote_detectmultiplier; - uint64_t bpc_remote_recvinterval; - uint64_t bpc_remote_txinterval; - uint64_t bpc_remote_echointerval; - uint64_t bpc_lastevent; -}; - - -/* - * Protocol definitions - */ -enum bc_msg_version { - BMV_VERSION_1 = 1, -}; - -enum bc_msg_type { - BMT_RESPONSE = 1, - BMT_REQUEST_ADD = 2, - BMT_REQUEST_DEL = 3, - BMT_NOTIFY = 4, - BMT_NOTIFY_ADD = 5, - BMT_NOTIFY_DEL = 6, -}; - -/* Notify flags to use with bcm_notify. */ -#define BCM_NOTIFY_ALL ((uint64_t)-1) -#define BCM_NOTIFY_PEER_STATE (1ULL << 0) -#define BCM_NOTIFY_CONFIG (1ULL << 1) -#define BCM_NOTIFY_NONE 0 - -/* Response 'status' definitions. */ -#define BCM_RESPONSE_OK "ok" -#define BCM_RESPONSE_ERROR "error" - -/* Notify operation. */ -#define BCM_NOTIFY_PEER_STATUS "status" -#define BCM_NOTIFY_CONFIG_ADD "add" -#define BCM_NOTIFY_CONFIG_DELETE "delete" -#define BCM_NOTIFY_CONFIG_UPDATE "update" - -/* Notification special ID. */ -#define BCM_NOTIFY_ID 0 - -struct bfd_control_msg { - /* Total length without the header. */ - uint32_t bcm_length; - /* - * Message request/response id. - * All requests will have a correspondent response with the - * same id. - */ - uint16_t bcm_id; - /* Message type. */ - uint8_t bcm_type; - /* Message version. */ - uint8_t bcm_ver; - /* Message payload. */ - uint8_t bcm_data[0]; -}; - -#endif diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 95066b97ce71..c2d8e926bff6 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -28,8 +28,8 @@ * FRR related code. */ DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); -DEFINE_MTYPE(BFDD, BFDD_CONTROL, "control socket memory"); -DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "control notification data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data"); /* Master of threads. */ struct event_loop *master; @@ -67,14 +67,13 @@ static void sigterm_handler(void) /* Stop receiving message from zebra. */ bfdd_zclient_stop(); - /* Shutdown controller to avoid receiving anymore commands. */ - control_shutdown(); - /* Shutdown and free all protocol related memory. */ bfd_shutdown(); bfd_vrf_terminate(); + bfdd_zclient_terminate(); + /* Terminate and free() FRR related memory. */ frr_fini(); @@ -115,18 +114,23 @@ static const struct frr_yang_module_info *const bfdd_yang_modules[] = { &frr_vrf_info, }; -FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617, - .proghelp = "Implementation of the BFD protocol.", - .signals = bfd_signals, .n_signals = array_size(bfd_signals), - .privs = &bglobal.bfdd_privs, - .yang_modules = bfdd_yang_modules, - .n_yang_modules = array_size(bfdd_yang_modules), +/* clang-format off */ +FRR_DAEMON_INFO(bfdd, BFD, + .vty_port = BFDD_VTY_PORT, + .proghelp = "Implementation of the BFD protocol.", + + .signals = bfd_signals, + .n_signals = array_size(bfd_signals), + + .privs = &bglobal.bfdd_privs, + + .yang_modules = bfdd_yang_modules, + .n_yang_modules = array_size(bfdd_yang_modules), ); +/* clang-format on */ -#define OPTION_CTLSOCK 1001 #define OPTION_DPLANEADDR 2000 static const struct option longopts[] = { - {"bfdctl", required_argument, NULL, OPTION_CTLSOCK}, {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR}, {0} }; @@ -310,7 +314,6 @@ static void bg_init(void) .cap_num_i = 0, }; - TAILQ_INIT(&bglobal.bg_bcslist); TAILQ_INIT(&bglobal.bg_obslist); memcpy(&bglobal.bfdd_privs, &bfdd_privs, @@ -319,8 +322,7 @@ static void bg_init(void) int main(int argc, char *argv[]) { - char ctl_path[512], dplane_addr[512]; - bool ctlsockused = false; + char dplane_addr[512]; int opt; bglobal.bg_use_dplane = false; @@ -330,21 +332,14 @@ int main(int argc, char *argv[]) frr_preinit(&bfdd_di, argc, argv); frr_opt_add("", longopts, - " --bfdctl Specify bfdd control socket\n" " --dplaneaddr Specify BFD data plane address\n"); - snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET, - "", ""); while (true) { opt = frr_getopt(argc, argv, NULL); if (opt == EOF) break; switch (opt) { - case OPTION_CTLSOCK: - strlcpy(ctl_path, optarg, sizeof(ctl_path)); - ctlsockused = true; - break; case OPTION_DPLANEADDR: strlcpy(dplane_addr, optarg, sizeof(dplane_addr)); bglobal.bg_use_dplane = true; @@ -355,16 +350,9 @@ int main(int argc, char *argv[]) } } - if (bfdd_di.pathspace && !ctlsockused) - snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET, - "/", bfdd_di.pathspace); - /* Initialize FRR infrastructure. */ master = frr_init(); - /* Initialize control socket. */ - control_init(ctl_path); - /* Initialize BFD data structures. */ bfd_initialize(); @@ -375,9 +363,6 @@ int main(int argc, char *argv[]) /* Initialize zebra connection. */ bfdd_zclient_init(&bglobal.bfdd_privs); - event_add_read(master, control_accept, NULL, bglobal.bg_csock, - &bglobal.bg_csockev); - /* Install commands. */ bfdd_vty_init(); diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 44439c67565e..75034d220c5e 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -219,24 +219,24 @@ static void _bfd_cli_show_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults __attribute__((__unused__)), bool mhop) { - const char *vrf = yang_dnode_get_string(dnode, "./vrf"); + const char *vrf = yang_dnode_get_string(dnode, "vrf"); vty_out(vty, " peer %s", - yang_dnode_get_string(dnode, "./dest-addr")); + yang_dnode_get_string(dnode, "dest-addr")); if (mhop) vty_out(vty, " multihop"); - if (yang_dnode_exists(dnode, "./source-addr")) + if (yang_dnode_exists(dnode, "source-addr")) vty_out(vty, " local-address %s", - yang_dnode_get_string(dnode, "./source-addr")); + yang_dnode_get_string(dnode, "source-addr")); if (strcmp(vrf, VRF_DEFAULT_NAME)) vty_out(vty, " vrf %s", vrf); if (!mhop) { const char *ifname = - yang_dnode_get_string(dnode, "./interface"); + yang_dnode_get_string(dnode, "interface"); if (strcmp(ifname, "*")) vty_out(vty, " interface %s", ifname); } @@ -567,7 +567,7 @@ DEFPY_YANG(no_bfd_profile, no_bfd_profile_cmd, void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "./name")); + vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "name")); } ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd, diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 8cf2f0a6f12c..48fbe7139c27 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -24,17 +24,17 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode, struct sockaddr_any psa, lsa; /* Required destination parameter. */ - strtosa(yang_dnode_get_string(dnode, "./dest-addr"), &psa); + strtosa(yang_dnode_get_string(dnode, "dest-addr"), &psa); /* Get optional source address. */ memset(&lsa, 0, sizeof(lsa)); - if (yang_dnode_exists(dnode, "./source-addr")) - strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa); + if (yang_dnode_exists(dnode, "source-addr")) + strtosa(yang_dnode_get_string(dnode, "source-addr"), &lsa); - vrfname = yang_dnode_get_string(dnode, "./vrf"); + vrfname = yang_dnode_get_string(dnode, "vrf"); if (!mhop) { - ifname = yang_dnode_get_string(dnode, "./interface"); + ifname = yang_dnode_get_string(dnode, "interface"); if (strcmp(ifname, "*") == 0) ifname = NULL; } @@ -53,7 +53,7 @@ static int session_iter_cb(const struct lyd_node *dnode, void *arg) struct session_iter *iter = arg; const char *ifname; - ifname = yang_dnode_get_string(dnode, "./interface"); + ifname = yang_dnode_get_string(dnode, "interface"); if (strmatch(ifname, "*")) iter->wildcard = true; @@ -76,7 +76,7 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) switch (args->event) { case NB_EV_VALIDATE: - yang_dnode_get_prefix(&p, args->dnode, "./dest-addr"); + yang_dnode_get_prefix(&p, args->dnode, "dest-addr"); if (mhop) { /* @@ -97,7 +97,7 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) * require interface name, otherwise we can't figure * which interface to use to send the packets. */ - ifname = yang_dnode_get_string(args->dnode, "./interface"); + ifname = yang_dnode_get_string(args->dnode, "interface"); if (p.family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6) && strcmp(ifname, "*") == 0) { @@ -112,8 +112,8 @@ static int bfd_session_create(struct nb_cb_create_args *args, bool mhop) sess_dnode = yang_dnode_get_parent(args->dnode, "sessions"); - dest = yang_dnode_get_string(args->dnode, "./dest-addr"); - vrfname = yang_dnode_get_string(args->dnode, "./vrf"); + dest = yang_dnode_get_string(args->dnode, "dest-addr"); + vrfname = yang_dnode_get_string(args->dnode, "vrf"); yang_dnode_iterate(session_iter_cb, &iter, sess_dnode, "./single-hop[dest-addr='%s'][vrf='%s']", @@ -275,7 +275,7 @@ int bfdd_bfd_profile_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - name = yang_dnode_get_string(args->dnode, "./name"); + name = yang_dnode_get_string(args->dnode, "name"); bp = bfd_profile_new(name); nb_running_set_entry(args->dnode, bp); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 496d5019b5e9..26554e1496b8 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) if (bs->key.ifname[0]) vty_out(vty, " interface %s", bs->key.ifname); vty_out(vty, "\n"); - - if (bs->pl) - vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); } static void _display_peer(struct vty *vty, struct bfd_session *bs) @@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs) if (bs->key.ifname[0]) json_object_string_add(jo, "interface", bs->key.ifname); - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - return jo; } @@ -561,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, int idx; bool mhop; struct bfd_session *bs = NULL; - struct peer_label *pl; struct bfd_peer_cfg bpc; struct sockaddr_any psa, lsa, *lsap; char errormsg[128]; - /* Look up the BFD peer. */ - if (label) { - pl = pl_find(label); - if (pl) - bs = pl->pl_bs; - } else if (peer_str) { + if (peer_str) { strtosa(peer_str, &psa); if (local_str) { strtosa(local_str, &lsa); @@ -879,7 +867,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL; bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL; bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL; - bpc->bpc_lastevent = monotime(NULL); /* Safety check: when no error buf is provided len must be zero. */ if (ebuf == NULL) diff --git a/bfdd/config.c b/bfdd/config.c deleted file mode 100644 index 22d7d7deee23..000000000000 --- a/bfdd/config.c +++ /dev/null @@ -1,592 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * config.c: implements the BFD daemon configuration handling. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include - -#include "lib/json.h" - -#include "bfd.h" - -DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory"); - -/* - * Definitions - */ -enum peer_list_type { - PLT_IPV4, - PLT_IPV6, - PLT_LABEL, -}; - - -/* - * Prototypes - */ -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg); -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg); -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc); -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc); - -static int config_add(struct bfd_peer_cfg *bpc, void *arg); -static int config_del(struct bfd_peer_cfg *bpc, void *arg); - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs); - - -/* - * Implementation - */ -static int config_add(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_new(bpc) == NULL; -} - -static int config_del(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_del(bpc) != 0; -} - -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int error = 0; - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "ipv4") == 0) { - error += parse_list(jo_val, PLT_IPV4, h, arg); - } else if (strcmp(key, "ipv6") == 0) { - error += parse_list(jo_val, PLT_IPV6, h, arg); - } else if (strcmp(key, "label") == 0) { - error += parse_list(jo_val, PLT_LABEL, h, arg); - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: %s", __func__, - __LINE__, sval); - error++; - } - } - - /* - * Our callers never call free() on json_object and only expect - * the return value, so lets free() it here. - */ - json_object_put(jo); - - return error; -} - -int parse_config(const char *fname) -{ - struct json_object *jo; - - jo = json_object_from_file(fname); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg) -{ - struct json_object *jo_val; - struct bfd_peer_cfg bpc; - int allen, idx; - int error = 0, result; - - allen = json_object_array_length(jo); - for (idx = 0; idx < allen; idx++) { - jo_val = json_object_array_get_idx(jo, idx); - - /* Set defaults. */ - memset(&bpc, 0, sizeof(bpc)); - bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT; - bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX; - bpc.bpc_txinterval = BFD_DEFDESIREDMINTX; - bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX; - bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX; - - switch (plt) { - case PLT_IPV4: - zlog_debug("ipv4 peers %d:", allen); - bpc.bpc_ipv4 = true; - break; - case PLT_IPV6: - zlog_debug("ipv6 peers %d:", allen); - bpc.bpc_ipv4 = false; - break; - case PLT_LABEL: - zlog_debug("label peers %d:", allen); - if (parse_peer_label_config(jo_val, &bpc) != 0) { - error++; - continue; - } - break; - - default: - error++; - zlog_err("%s:%d: unsupported peer type", __func__, - __LINE__); - break; - } - - result = parse_peer_config(jo_val, &bpc); - error += result; - if (result == 0) - error += (h(&bpc, arg) != 0); - } - - return error; -} - -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; - int error = 0; - - zlog_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6"); - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "multihop") == 0) { - bpc->bpc_mhop = json_object_get_boolean(jo_val); - zlog_debug(" multihop: %s", - bpc->bpc_mhop ? "true" : "false"); - } else if (strcmp(key, "peer-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_peer) != 0 - || bpc->bpc_peer.sa_sin.sin_family != family_type) { - zlog_debug( - "%s:%d failed to parse peer-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" peer-address: %s", sval); - } else if (strcmp(key, "local-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_local) != 0 - || bpc->bpc_local.sa_sin.sin_family - != family_type) { - zlog_debug( - "%s:%d failed to parse local-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" local-address: %s", sval); - } else if (strcmp(key, "local-interface") == 0) { - bpc->bpc_has_localif = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_localif, sval, - sizeof(bpc->bpc_localif)) - > sizeof(bpc->bpc_localif)) { - zlog_debug( - " local-interface: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" local-interface: %s", sval); - } - } else if (strcmp(key, "vrf-name") == 0) { - bpc->bpc_has_vrfname = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_vrfname, sval, - sizeof(bpc->bpc_vrfname)) - > sizeof(bpc->bpc_vrfname)) { - zlog_debug(" vrf-name: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" vrf-name: %s", sval); - } - } else if (strcmp(key, "detect-multiplier") == 0) { - bpc->bpc_detectmultiplier = - json_object_get_int64(jo_val); - bpc->bpc_has_detectmultiplier = true; - zlog_debug(" detect-multiplier: %u", - bpc->bpc_detectmultiplier); - } else if (strcmp(key, "receive-interval") == 0) { - bpc->bpc_recvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_recvinterval = true; - zlog_debug(" receive-interval: %" PRIu64, - bpc->bpc_recvinterval); - } else if (strcmp(key, "transmit-interval") == 0) { - bpc->bpc_txinterval = json_object_get_int64(jo_val); - bpc->bpc_has_txinterval = true; - zlog_debug(" transmit-interval: %" PRIu64, - bpc->bpc_txinterval); - } else if (strcmp(key, "echo-receive-interval") == 0) { - bpc->bpc_echorecvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echorecvinterval = true; - zlog_debug(" echo-receive-interval: %" PRIu64, - bpc->bpc_echorecvinterval); - } else if (strcmp(key, "echo-transmit-interval") == 0) { - bpc->bpc_echotxinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echotxinterval = true; - zlog_debug(" echo-transmit-interval: %" PRIu64, - bpc->bpc_echotxinterval); - } else if (strcmp(key, "create-only") == 0) { - bpc->bpc_createonly = json_object_get_boolean(jo_val); - zlog_debug(" create-only: %s", - bpc->bpc_createonly ? "true" : "false"); - } else if (strcmp(key, "shutdown") == 0) { - bpc->bpc_shutdown = json_object_get_boolean(jo_val); - zlog_debug(" shutdown: %s", - bpc->bpc_shutdown ? "true" : "false"); - } else if (strcmp(key, "echo-mode") == 0) { - bpc->bpc_echo = json_object_get_boolean(jo_val); - zlog_debug(" echo-mode: %s", - bpc->bpc_echo ? "true" : "false"); - } else if (strcmp(key, "label") == 0) { - bpc->bpc_has_label = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_label, sval, - sizeof(bpc->bpc_label)) - > sizeof(bpc->bpc_label)) { - zlog_debug(" label: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" label: %s", sval); - } - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: '%s: %s'", - __func__, __LINE__, key, sval); - error++; - } - } - - if (bpc->bpc_peer.sa_sin.sin_family == 0) { - zlog_debug("%s:%d no peer address provided", __func__, - __LINE__); - error++; - } - - return error; -} - -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - struct json_object *label; - const char *sval; - - /* Get label and translate it to BFD daemon key. */ - if (!json_object_object_get_ex(jo, "label", &label)) - return 1; - - sval = json_object_get_string(label); - - pl = pl_find(sval); - if (pl == NULL) - return 1; - - zlog_debug(" peer-label: %s", sval); - - /* Translate the label into BFD address keys. */ - bs_to_bpc(pl->pl_bs, bpc); - - return 0; -} - - -/* - * Control socket JSON parsing. - */ -int config_request_add(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -int config_request_del(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_del, NULL); -} - -char *config_response(const char *status, const char *error) -{ - struct json_object *resp, *jo; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - /* Add 'status' response key. */ - jo = json_object_new_string(status); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "status", jo); - - /* Add 'error' response key. */ - if (error != NULL) { - jo = json_object_new_string(error); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "error", jo); - } - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify(struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - time_t now; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS); - - json_object_add_peer(resp, bs); - - /* Add status information */ - json_object_int_add(resp, "id", bs->discrs.my_discr); - json_object_int_add(resp, "remote-id", bs->discrs.my_discr); - - switch (bs->ses_state) { - case PTM_BFD_UP: - json_object_string_add(resp, "state", "up"); - - now = monotime(NULL); - json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec); - break; - case PTM_BFD_ADM_DOWN: - json_object_string_add(resp, "state", "adm-down"); - break; - case PTM_BFD_DOWN: - json_object_string_add(resp, "state", "down"); - - now = monotime(NULL); - json_object_int_add(resp, "downtime", - now - bs->downtime.tv_sec); - break; - case PTM_BFD_INIT: - json_object_string_add(resp, "state", "init"); - break; - - default: - json_object_string_add(resp, "state", "unknown"); - break; - } - - json_object_int_add(resp, "diagnostics", bs->local_diag); - json_object_int_add(resp, "remote-diagnostics", bs->remote_diag); - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify_config(const char *op, struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", op); - - json_object_add_peer(resp, bs); - - /* On peer deletion we don't need to add any additional information. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0) - goto skip_config; - - json_object_int_add(resp, "detect-multiplier", bs->detect_mult); - json_object_int_add(resp, "receive-interval", - bs->timers.required_min_rx / 1000); - json_object_int_add(resp, "transmit-interval", - bs->timers.desired_min_tx / 1000); - json_object_int_add(resp, "echo-receive-interval", - bs->timers.required_min_echo_rx / 1000); - json_object_int_add(resp, "echo-transmit-interval", - bs->timers.desired_min_echo_tx / 1000); - - json_object_int_add(resp, "remote-detect-multiplier", - bs->remote_detect_mult); - json_object_int_add(resp, "remote-receive-interval", - bs->remote_timers.required_min_rx / 1000); - json_object_int_add(resp, "remote-transmit-interval", - bs->remote_timers.desired_min_tx / 1000); - json_object_int_add(resp, "remote-echo-receive-interval", - bs->remote_timers.required_min_echo / 1000); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - json_object_boolean_true_add(resp, "echo-mode"); - else - json_object_boolean_false_add(resp, "echo-mode"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) - json_object_boolean_true_add(resp, "shutdown"); - else - json_object_boolean_false_add(resp, "shutdown"); - -skip_config: - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, bh, bcs); -} - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) -{ - char addr_buf[INET6_ADDRSTRLEN]; - - /* Add peer 'key' information. */ - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) - json_object_boolean_true_add(jo, "ipv6"); - else - json_object_boolean_false_add(jo, "ipv6"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - json_object_boolean_true_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - json_object_string_add(jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.vrfname[0]) - json_object_string_add(jo, "vrf-name", bs->key.vrfname); - } else { - json_object_boolean_false_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) - json_object_string_add( - jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.ifname[0]) - json_object_string_add(jo, "local-interface", - bs->key.ifname); - } - - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - - return 0; -} - - -/* - * Label handling - */ -struct peer_label *pl_find(const char *label) -{ - struct peer_label *pl; - - TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) { - if (strcmp(pl->pl_label, label) != 0) - continue; - - return pl; - } - - return NULL; -} - -struct peer_label *pl_new(const char *label, struct bfd_session *bs) -{ - struct peer_label *pl; - - pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl)); - - if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label)) - > sizeof(pl->pl_label)) - zlog_warn("%s:%d: label was truncated", __func__, __LINE__); - - pl->pl_bs = bs; - bs->pl = pl; - - TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry); - - return pl; -} - -void pl_free(struct peer_label *pl) -{ - if (pl == NULL) - return; - - /* Remove the pointer back. */ - pl->pl_bs->pl = NULL; - - TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry); - XFREE(MTYPE_BFDD_LABEL, pl); -} diff --git a/bfdd/control.c b/bfdd/control.c deleted file mode 100644 index f435358f33c3..000000000000 --- a/bfdd/control.c +++ /dev/null @@ -1,841 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * control.c: implements the BFD daemon control socket. It will be used - * to talk with clients daemon/scripts/consumers. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include - -#include "bfd.h" - -/* - * Prototypes - */ -static int sock_set_nonblock(int fd); -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs); -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq); -static int control_queue_dequeue(struct bfd_control_socket *bcs); -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs); -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp); -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -struct bfd_control_socket *control_new(int sd); -static void control_free(struct bfd_control_socket *bcs); -static void control_reset_buf(struct bfd_control_buffer *bcb); -static void control_read(struct event *t); -static void control_write(struct event *t); - -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg); -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg); -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void _control_handle_notify(struct hash_bucket *hb, void *arg); -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error); - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs); -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -/* - * Functions - */ -static int sock_set_nonblock(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) { - zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno)); - return -1; - } - - flags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flags) == -1) { - zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno)); - return -1; - } - - return 0; -} - -int control_init(const char *path) -{ - int sd; - mode_t umval; - struct sockaddr_un sun_ = { - .sun_family = AF_UNIX, - .sun_path = BFDD_CONTROL_SOCKET, - }; - - if (path) - strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path)); - - /* Remove previously created sockets. */ - unlink(sun_.sun_path); - - sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); - if (sd == -1) { - zlog_err("%s: socket: %s", __func__, strerror(errno)); - return -1; - } - - umval = umask(0); - if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) { - zlog_err("%s: bind: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - umask(umval); - - if (listen(sd, SOMAXCONN) == -1) { - zlog_err("%s: listen: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - - sock_set_nonblock(sd); - - bglobal.bg_csock = sd; - - return 0; -} - -void control_shutdown(void) -{ - struct bfd_control_socket *bcs; - - event_cancel(&bglobal.bg_csockev); - - socket_close(&bglobal.bg_csock); - - while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) { - bcs = TAILQ_FIRST(&bglobal.bg_bcslist); - control_free(bcs); - } -} - -void control_accept(struct event *t) -{ - int csock, sd = EVENT_FD(t); - - csock = accept(sd, NULL, 0); - if (csock == -1) { - zlog_warn("%s: accept: %s", __func__, strerror(errno)); - return; - } - - control_new(csock); - - event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev); -} - - -/* - * Client handling - */ -struct bfd_control_socket *control_new(int sd) -{ - struct bfd_control_socket *bcs; - - bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs)); - - /* Disable notifications by default. */ - bcs->bcs_notify = 0; - - bcs->bcs_sd = sd; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); - - TAILQ_INIT(&bcs->bcs_bcqueue); - TAILQ_INIT(&bcs->bcs_bnplist); - TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry); - - return bcs; -} - -static void control_free(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - struct bfd_notify_peer *bnp; - - event_cancel(&(bcs->bcs_ev)); - event_cancel(&(bcs->bcs_outev)); - - close(bcs->bcs_sd); - - TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry); - - /* Empty output queue. */ - while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) { - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - } - - /* Empty notification list. */ - while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) { - bnp = TAILQ_FIRST(&bcs->bcs_bnplist); - control_notifypeer_free(bcs, bnp); - } - - control_reset_buf(&bcs->bcs_bin); - XFREE(MTYPE_BFDD_CONTROL, bcs); -} - -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - return bnp; - - bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp)); - - TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs = bs; - bs->refcount++; - - return bnp; -} - -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp) -{ - TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs->refcount--; - XFREE(MTYPE_BFDD_CONTROL, bnp); -} - -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) { - if (bnp->bnp_bs == bs) - return bnp; - } - - return NULL; -} - -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq)); - - control_reset_buf(&bcq->bcq_bcb); - TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry); - - return bcq; -} - -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq) -{ - control_reset_buf(&bcq->bcq_bcb); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, bcq); -} - -static int control_queue_dequeue(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - /* List is empty, nothing to do. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - - /* Get the next buffer to send. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcs->bcs_bout = &bcq->bcq_bcb; - - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - - return 1; - -empty_list: - event_cancel(&(bcs->bcs_outev)); - bcs->bcs_bout = NULL; - return 0; -} - -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq; - struct bfd_control_buffer *bcb; - - bcq = control_queue_new(bcs); - - bcb = &bcq->bcq_bcb; - bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length); - bcb->bcb_pos = 0; - bcb->bcb_bcm = bcm; - - /* If this is the first item, then dequeue and start using it. */ - if (bcs->bcs_bout == NULL) { - bcs->bcs_bout = bcb; - - /* New messages, active write events. */ - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - } - - return 0; -} - -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq, *bcqn; - struct bfd_control_buffer *bcb; - - /* Enqueue it somewhere. */ - if (control_queue_enqueue(bcs, bcm) == -1) - return -1; - - /* - * The item is either the first or the last. So we must first - * check the best case where the item is already the first. - */ - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcb = &bcq->bcq_bcb; - if (bcm == bcb->bcb_bcm) - return 0; - - /* - * The item was not the first, so it is the last. We'll try to - * assign it to the head of the queue, however if there is a - * transfer in progress, then we have to make the item as the - * next one. - * - * Interrupting the transfer of in progress message will cause - * the client to lose track of the message position/data. - */ - bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry); - if (bcb->bcb_pos != 0) { - /* - * First position is already being sent, insert into - * second position. - */ - TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry); - } else { - /* - * Old message didn't start being sent, we still have - * time to put this one in the head of the queue. - */ - TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry); - bcb = &bcqn->bcq_bcb; - bcs->bcs_bout = bcb; - } - - return 0; -} - -static void control_reset_buf(struct bfd_control_buffer *bcb) -{ - /* Get ride of old data. */ - XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf); - bcb->bcb_pos = 0; - bcb->bcb_left = 0; -} - -static void control_read(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = &bcs->bcs_bin; - int sd = bcs->bcs_sd; - struct bfd_control_msg bcm; - ssize_t bread; - size_t plen; - - /* - * Check if we have already downloaded message content, if so then skip - * to - * download the rest of it and process. - * - * Otherwise download a new message header and allocate the necessary - * memory. - */ - if (bcb->bcb_buf != NULL) - goto skip_header; - - bread = read(sd, &bcm, sizeof(bcm)); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - /* Validate header fields. */ - plen = ntohl(bcm.bcm_length); - if (plen < 2) { - zlog_debug("%s: client closed due small message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - -#define FRR_BFD_MAXLEN 10 * 1024 - - if (plen > FRR_BFD_MAXLEN) { - zlog_debug("%s: client closed, invalid message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - - if (bcm.bcm_ver != BMV_VERSION_1) { - zlog_debug("%s: client closed due bad version: %d", __func__, - bcm.bcm_ver); - control_free(bcs); - return; - } - - /* Prepare the buffer to load the message. */ - bcs->bcs_version = bcm.bcm_ver; - bcs->bcs_type = bcm.bcm_type; - - bcb->bcb_pos = sizeof(bcm); - bcb->bcb_left = plen; - bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(bcm) + bcb->bcb_left + 1); - if (bcb->bcb_buf == NULL) { - zlog_warn("%s: not enough memory for message size: %zu", - __func__, bcb->bcb_left); - control_free(bcs); - return; - } - - memcpy(bcb->bcb_buf, &bcm, sizeof(bcm)); - - /* Terminate data string with NULL for later processing. */ - bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0; - -skip_header: - /* Download the remaining data of the message and process it. */ - bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bread; - bcb->bcb_left -= bread; - /* We need more data, return to wait more. */ - if (bcb->bcb_left > 0) - goto schedule_next_read; - - switch (bcb->bcb_bcm->bcm_type) { - case BMT_REQUEST_ADD: - control_handle_request_add(bcs, bcb->bcb_bcm); - break; - case BMT_REQUEST_DEL: - control_handle_request_del(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY: - control_handle_notify(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_ADD: - control_handle_notify_add(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_DEL: - control_handle_notify_del(bcs, bcb->bcb_bcm); - break; - - default: - zlog_debug("%s: unhandled message type: %d", __func__, - bcb->bcb_bcm->bcm_type); - control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR, - "invalid message type"); - break; - } - - bcs->bcs_version = 0; - bcs->bcs_type = 0; - control_reset_buf(bcb); - -schedule_next_read: - bcs->bcs_ev = NULL; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); -} - -static void control_write(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = bcs->bcs_bout; - int sd = bcs->bcs_sd; - ssize_t bwrite; - - bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bwrite == 0) { - control_free(bcs); - return; - } - if (bwrite < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - zlog_warn("%s: write: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bwrite; - bcb->bcb_left -= bwrite; - if (bcb->bcb_left > 0) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - control_queue_dequeue(bcs); -} - - -/* - * Message processing - */ -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_add(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request add failed"); -} - -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_del(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request del failed"); -} - -static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl) - return pl->pl_bs; - } - - return bs_peer_find(bpc); -} - -static void _control_handle_notify(struct hash_bucket *hb, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = hb->data; - - /* Notify peer configuration. */ - if (bcs->bcs_notify & BCM_NOTIFY_CONFIG) - _control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs); - - /* Notify peer status. */ - if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) - _control_notify(bcs, bs); -} - -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify)); - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - - /* - * If peer asked for notification configuration, send everything that - * was configured until the moment to sync up. - */ - if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE)) - bfd_id_iterate(_control_handle_notify, bcs); -} - -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - - if (bs == NULL) - return -1; - - control_notifypeer_new(bcs, bs); - - /* Notify peer status. */ - _control_notify(bcs, bs); - - return 0; -} - -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - struct bfd_notify_peer *bnp; - - if (bs == NULL) - return -1; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - - return 0; -} - -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_add_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_del_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - - -/* - * Internal functions used by the BFD daemon. - */ -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_response(status, error); - if (jsonstr == NULL) { - zlog_warn("%s: config_response: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_RESPONSE; - bcm->bcm_id = id; - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue_first(bcs, bcm); -} - -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify(bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify(struct bfd_session *bs, uint8_t notify_state) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Notify zebra listeners as well. */ - ptm_bfd_notify(bs, notify_state); - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) { - bnp = control_notifypeer_find(bcs, bs); - /* - * If the notification is not configured here, - * don't send it. - */ - if (bnp == NULL) - continue; - } - - _control_notify(bcs, bs); - } - - return 0; -} - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify_config(op, bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify_config: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify_config(const char *op, struct bfd_session *bs) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Remove the control sockets notification for this peer. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) { - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - } - } - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0) - continue; - - _control_notify_config(bcs, op, bs); - } - - return 0; -} diff --git a/bfdd/dplane.c b/bfdd/dplane.c index d8539812e097..7f55f3407302 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -354,7 +354,7 @@ bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc, bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx); /* Notify and update counters. */ - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* No state change. */ if (old_state == bs->ses_state) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 490bc30d74f4..f6ebefb7becb 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -148,7 +148,6 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag) "ptm-del-session: [%s] session refcount is zero but it was configured by CLI", bs_to_string(bs)); } else { - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); bfd_session_free(bs); } } @@ -756,20 +755,6 @@ static int bfd_ifp_destroy(struct interface *ifp) return 0; } -static int bfdd_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t nvrfid; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, &nvrfid); - if (ifp == NULL) - return 0; - - if_update_to_new_vrf(ifp, nvrfid); - - return 0; -} - static void bfdd_sessions_enable_address(struct connected *ifc) { struct bfd_session_observer *bso; @@ -833,9 +818,6 @@ static zclient_handler *const bfd_handlers[] = { */ [ZEBRA_BFD_DEST_REPLAY] = bfdd_replay, - /* Learn about interface VRF. */ - [ZEBRA_INTERFACE_VRF_UPDATE] = bfdd_interface_vrf_update, - /* Learn about new addresses being registered. */ [ZEBRA_INTERFACE_ADDRESS_ADD] = bfdd_interface_address_update, [ZEBRA_INTERFACE_ADDRESS_DELETE] = bfdd_interface_address_update, @@ -843,7 +825,8 @@ static zclient_handler *const bfd_handlers[] = { void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) { - if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy); + hook_register_prio(if_real, 0, bfd_ifp_create); + hook_register_prio(if_unreal, 0, bfd_ifp_destroy); zclient = zclient_new(master, &zclient_options_default, bfd_handlers, array_size(bfd_handlers)); assert(zclient != NULL); @@ -875,6 +858,11 @@ void bfdd_zclient_stop(void) pc_free_all(); } +void bfdd_zclient_terminate(void) +{ + zclient_free(zclient); +} + /* * Client handling. @@ -903,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid) return pc; /* Allocate the client data and save it. */ - pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc)); + pc = XCALLOC(MTYPE_BFDD_CLIENT, sizeof(*pc)); pc->pc_pid = pid; TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry); @@ -921,7 +909,7 @@ static void pc_free(struct ptm_client *pc) pcn_free(pcn); } - XFREE(MTYPE_BFDD_CONTROL, pc); + XFREE(MTYPE_BFDD_CLIENT, pc); } static void pc_free_all(void) @@ -945,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc, return pcn; /* Save the client notification data. */ - pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn)); + pcn = XCALLOC(MTYPE_BFDD_CLIENT_NOTIFICATION, sizeof(*pcn)); TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry); pcn->pcn_pc = pc; @@ -993,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn) pcn->pcn_pc = NULL; TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, pcn); + XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn); } diff --git a/bfdd/subdir.am b/bfdd/subdir.am index b86a18967e19..5d2d8fda5cc6 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \ bfdd/bfdd_vty.c \ bfdd/bfdd_cli.c \ bfdd/bfd_packet.c \ - bfdd/config.c \ - bfdd/control.c \ bfdd/dplane.c \ bfdd/event.c \ bfdd/ptm_adapter.c \ @@ -37,7 +35,6 @@ clippy_scan += \ # end noinst_HEADERS += \ - bfdd/bfdctl.h \ bfdd/bfdd_nb.h \ bfdd/bfd.h \ # end diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index de4b4a48afb5..f391c138472d 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -10,6 +10,8 @@ #include "bgp_addpath.h" #include "bgp_route.h" +#include "bgp_open.h" +#include "bgp_packet.h" static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = { { @@ -359,6 +361,31 @@ void bgp_addpath_type_changed(struct bgp *bgp) } } +int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, + uint8_t paths) +{ + int action = CAPABILITY_ACTION_UNSET; + + switch (addpath_type) { + case BGP_ADDPATH_ALL: + case BGP_ADDPATH_BEST_PER_AS: + action = CAPABILITY_ACTION_SET; + break; + case BGP_ADDPATH_BEST_SELECTED: + if (paths) + action = CAPABILITY_ACTION_SET; + else + action = CAPABILITY_ACTION_UNSET; + break; + case BGP_ADDPATH_NONE: + case BGP_ADDPATH_MAX: + action = CAPABILITY_ACTION_UNSET; + break; + } + + return action; +} + /* * Change the addpath type assigned to a peer, or peer group. In addition to * adjusting the counts, peer sessions will be reset as needed to make the @@ -373,6 +400,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, struct listnode *node, *nnode; struct peer *tmp_peer; struct peer_group *group; + int action = bgp_addpath_capability_action(addpath_type, paths); if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; @@ -430,9 +458,12 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, } } } else { - peer_change_action(peer, afi, safi, peer_change_reset); + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) + peer_change_action(peer, afi, safi, peer_change_reset); } + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action); } /* diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index 2b91d450bc6f..c267ebe43ece 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -15,6 +15,18 @@ #include "bgpd/bgp_table.h" #include "lib/json.h" +struct bgp_addpath_capability { + uint16_t afi; + uint8_t safi; + uint8_t flags; +}; + +struct bgp_paths_limit_capability { + uint16_t afi; + uint8_t safi; + uint16_t paths_limit; +} __attribute__((packed)); + #define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1 void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d); @@ -57,4 +69,6 @@ void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi); void bgp_addpath_type_changed(struct bgp *bgp); +extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, + uint8_t paths); #endif diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 17d6592c0f78..d5c7e1887b60 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -36,6 +36,8 @@ struct bgp_advertise_attr *bgp_advertise_attr_new(void) void bgp_advertise_attr_free(struct bgp_advertise_attr *baa) { + bgp_advertise_attr_fifo_fini(&baa->fifo); + XFREE(MTYPE_BGP_ADVERTISE_ATTR, baa); } @@ -46,6 +48,9 @@ static void *bgp_advertise_attr_hash_alloc(void *p) baa = bgp_advertise_attr_new(); baa->attr = ref->attr; + + bgp_advertise_attr_fifo_init(&baa->fifo); + return baa; } @@ -83,36 +88,13 @@ void bgp_advertise_free(struct bgp_advertise *adv) void bgp_advertise_add(struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { - struct bgp_advertise *spot, *prev = NULL; - - spot = baa->adv; - - while (spot) { - prev = spot; - spot = spot->next; - } - - if (prev) { - prev->next = adv; - adv->prev = prev; - } else - adv->prev = NULL; - - adv->next = NULL; - - if (!baa->adv) - baa->adv = adv; + bgp_advertise_attr_fifo_add_tail(&baa->fifo, adv); } void bgp_advertise_delete(struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { - if (adv->next) - adv->next->prev = adv->prev; - if (adv->prev) - adv->prev->next = adv->next; - else - baa->adv = adv->next; + bgp_advertise_attr_fifo_del(&baa->fifo, adv); } struct bgp_advertise_attr *bgp_advertise_attr_intern(struct hash *hash, @@ -181,16 +163,20 @@ bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest, void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, - uint32_t addpath_id) + uint32_t addpath_id, struct bgp_labels *labels) { struct bgp_adj_in *adj; for (adj = dest->adj_in; adj; adj = adj->next) { if (adj->peer == peer && adj->addpath_rx_id == addpath_id) { - if (adj->attr != attr) { + if (!attrhash_cmp(adj->attr, attr)) { bgp_attr_unintern(&adj->attr); adj->attr = bgp_attr_intern(attr); } + if (!bgp_labels_cmp(adj->labels, labels)) { + bgp_labels_unintern(&adj->labels); + adj->labels = bgp_labels_intern(labels); + } return; } } @@ -199,13 +185,18 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, adj->attr = bgp_attr_intern(attr); adj->uptime = monotime(NULL); adj->addpath_rx_id = addpath_id; + adj->labels = bgp_labels_intern(labels); BGP_ADJ_IN_ADD(dest, adj); + peer->stat_pfx_adj_rib_in++; bgp_dest_lock_node(dest); } void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai) { bgp_attr_unintern(&bai->attr); + bgp_labels_unintern(&bai->labels); + if (bai->peer) + bai->peer->stat_pfx_adj_rib_in--; BGP_ADJ_IN_DEL(*dest, bai); *dest = bgp_dest_unlock_node(*dest); peer_unlock(bai->peer); /* adj_in peer reference */ diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 94168e2fd7cc..8c831892b33d 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -11,26 +11,19 @@ PREDECL_DLIST(bgp_adv_fifo); struct update_subgroup; +struct bgp_advertise; -/* BGP advertise attribute. */ -struct bgp_advertise_attr { - /* Head of advertisement pointer. */ - struct bgp_advertise *adv; +PREDECL_DLIST(bgp_advertise_attr_fifo); - /* Reference counter. */ - unsigned long refcnt; - - /* Attribute pointer to be announced. */ - struct attr *attr; -}; +struct bgp_advertise_attr; +/* BGP advertise attribute. */ struct bgp_advertise { /* FIFO for advertisement. */ struct bgp_adv_fifo_item fifo; - /* Link list for same attribute advertise. */ - struct bgp_advertise *next; - struct bgp_advertise *prev; + /* FIFO for this item in the bgp_advertise_attr fifo */ + struct bgp_advertise_attr_fifo_item item; /* Prefix information. */ struct bgp_dest *dest; @@ -45,8 +38,21 @@ struct bgp_advertise { struct bgp_path_info *pathi; }; +DECLARE_DLIST(bgp_advertise_attr_fifo, struct bgp_advertise, item); DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo); +/* BGP advertise attribute. */ +struct bgp_advertise_attr { + /* Head of advertisement pointer. */ + struct bgp_advertise_attr_fifo_head fifo; + + /* Reference counter. */ + unsigned long refcnt; + + /* Attribute pointer to be announced. */ + struct attr *attr; +}; + /* BGP adjacency out. */ struct bgp_adj_out { /* RB Tree of adjacency entries */ @@ -63,14 +69,17 @@ struct bgp_adj_out { uint32_t addpath_tx_id; + /* Attribute hash */ + uint32_t attr_hash; + /* Advertised attribute. */ struct attr *attr; + /* VPN label information */ + struct bgp_labels *labels; + /* Advertisement information. */ struct bgp_advertise *adv; - - /* Attribute hash */ - uint32_t attr_hash; }; RB_HEAD(bgp_adj_out_rb, bgp_adj_out); @@ -89,6 +98,9 @@ struct bgp_adj_in { /* Received attribute. */ struct attr *attr; + /* VPN label information */ + struct bgp_labels *labels; + /* timestamp (monotime) */ time_t uptime; @@ -129,7 +141,8 @@ struct bgp_synchronize { extern bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest, uint32_t addpath_tx_id); extern void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, - struct attr *attr, uint32_t addpath_id); + struct attr *attr, uint32_t addpath_id, + struct bgp_labels *labels); extern bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer, uint32_t addpath_id); extern void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index fc13085437f8..4c1615a5c625 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -77,6 +77,9 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; +/* as-path orphan exclude list */ +static struct as_list_list_head as_exclude_list_orphan; + /* Callers are required to initialize the memory */ static as_t *assegment_data_new(int num) { @@ -1016,8 +1019,6 @@ static struct assegment *aspath_aggregate_as_set_add(struct aspath *aspath, seg = seg->next; seg->next = asset; } - asset->type = AS_SET; - asset->length = 1; asset->as[0] = as; } else { /* Check this AS value already exists or not. */ @@ -1409,7 +1410,8 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn) last_new_seg = new_seg; seg = seg->next; } - + if (!aspath->refcnt) + aspath_free(aspath); aspath_str_update(new, false); return new; } @@ -1559,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) /* Not reached */ } +/* insert aspath exclude in head of orphan exclude list*/ +void as_exclude_set_orphan(struct aspath_exclude *ase) +{ + ase->exclude_aspath_acl = NULL; + as_list_list_add_head(&as_exclude_list_orphan, ase); +} + +void as_exclude_remove_orphan(struct aspath_exclude *ase) +{ + if (as_list_list_count(&as_exclude_list_orphan)) + as_list_list_del(&as_exclude_list_orphan, ase); +} + +/* currently provide only one exclude, not a list */ +struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name) +{ + struct aspath_exclude *ase = NULL; + char *name = NULL; + + frr_each (as_list_list, &as_exclude_list_orphan, ase) { + if (ase->exclude_aspath_acl_name) { + name = ase->exclude_aspath_acl_name; + if (!strcmp(name, acl_name)) + break; + } + } + if (ase) + as_exclude_remove_orphan(ase); + + return ase; +} + /* Iterate over AS_PATH segments and wipe all occurrences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter @@ -1894,7 +1928,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath, "[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls across 2/4 ASN boundary somewhere, broken.."); hops = seg->length; } - /* fallthru */ + fallthrough; case AS_SEQUENCE: cpasns = MIN(seg->length, hops); hops -= seg->length; @@ -2237,20 +2271,32 @@ void aspath_init(void) { ashash = hash_create_size(32768, aspath_key_make, aspath_cmp, "BGP AS Path"); + + as_list_list_init(&as_exclude_list_orphan); } void aspath_finish(void) { + struct aspath_exclude *ase; + hash_clean_and_free(&ashash, (void (*)(void *))aspath_free); if (snmp_stream) stream_free(snmp_stream); + + while ((ase = as_list_list_pop(&as_exclude_list_orphan))) { + aspath_free(ase->aspath); + if (ase->exclude_aspath_acl_name) + XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); + XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); + } + as_list_list_fini(&as_exclude_list_orphan); } /* return and as path value */ const char *aspath_print(struct aspath *as) { - return (as ? as->str : NULL); + return as ? as->str : "(null)"; } /* Printing functions */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index ebfc7d087d66..f7e57fd66dda 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -9,6 +9,7 @@ #include "lib/json.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_filter.h" +#include /* AS path segment type. */ #define AS_SET 1 @@ -65,6 +66,17 @@ struct aspath { #define ASPATH_STR_DEFAULT_LEN 32 +/* `set as-path exclude ASn' */ +struct aspath_exclude { + struct as_list_list_item exclude_list; + struct aspath *aspath; + bool exclude_all; + char *exclude_aspath_acl_name; + struct as_list *exclude_aspath_acl; +}; +DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list); + + /* Prototypes. */ extern void aspath_init(void); extern void aspath_finish(void); @@ -75,6 +87,9 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length, extern struct aspath *aspath_dup(struct aspath *aspath); extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2); extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2); +extern void as_exclude_set_orphan(struct aspath_exclude *ase); +extern void as_exclude_remove_orphan(struct aspath_exclude *ase); +extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name); extern struct aspath *aspath_filter_exclude(struct aspath *source, struct aspath *exclude_list); extern struct aspath *aspath_filter_exclude_all(struct aspath *source); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7916233444ec..ec5fa7b74dbe 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -198,6 +198,7 @@ static struct hash *vnc_hash = NULL; #endif static struct hash *srv6_l3vpn_hash; static struct hash *srv6_vpn_hash; +static struct hash *evpn_overlay_hash; struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) { @@ -549,6 +550,81 @@ static bool bgp_attr_aigp_valid(uint8_t *pnt, int length) return true; } +static void *evpn_overlay_hash_alloc(void *p) +{ + return p; +} + +static void evpn_overlay_free(struct bgp_route_evpn *bre) +{ + XFREE(MTYPE_BGP_EVPN_OVERLAY, bre); +} + +static struct bgp_route_evpn *evpn_overlay_intern(struct bgp_route_evpn *bre) +{ + struct bgp_route_evpn *find; + + find = hash_get(evpn_overlay_hash, bre, evpn_overlay_hash_alloc); + if (find != bre) + evpn_overlay_free(bre); + find->refcnt++; + return find; +} + +static void evpn_overlay_unintern(struct bgp_route_evpn **brep) +{ + struct bgp_route_evpn *bre = *brep; + + if (!*brep) + return; + + if (bre->refcnt) + bre->refcnt--; + + if (bre->refcnt == 0) { + hash_release(evpn_overlay_hash, bre); + evpn_overlay_free(bre); + *brep = NULL; + } +} + +static uint32_t evpn_overlay_hash_key_make(const void *p) +{ + const struct bgp_route_evpn *bre = p; + uint32_t key = 0; + + if (IS_IPADDR_V4(&bre->gw_ip)) + key = jhash_1word(bre->gw_ip.ipaddr_v4.s_addr, 0); + else + key = jhash2(bre->gw_ip.ipaddr_v6.s6_addr32, + array_size(bre->gw_ip.ipaddr_v6.s6_addr32), 0); + + key = jhash_1word(bre->type, key); + key = jhash(bre->eth_s_id.val, sizeof(bre->eth_s_id.val), key); + return key; +} + +static bool evpn_overlay_hash_cmp(const void *p1, const void *p2) +{ + const struct bgp_route_evpn *bre1 = p1; + const struct bgp_route_evpn *bre2 = p2; + + return bgp_route_evpn_same(bre1, bre2); +} + +static void evpn_overlay_init(void) +{ + evpn_overlay_hash = hash_create(evpn_overlay_hash_key_make, + evpn_overlay_hash_cmp, + "BGP EVPN Overlay"); +} + +static void evpn_overlay_finish(void) +{ + hash_clean_and_free(&evpn_overlay_hash, + (void (*)(void *))evpn_overlay_free); +} + static void *srv6_l3vpn_hash_alloc(void *p) { return p; @@ -788,6 +864,8 @@ unsigned int attrhash_key_make(const void *p) MIX(encap_hash_key_make(attr->encap_subtlvs)); if (attr->srv6_l3vpn) MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn)); + if (bgp_attr_get_evpn_overlay(attr)) + MIX(evpn_overlay_hash_key_make(bgp_attr_get_evpn_overlay(attr))); if (attr->srv6_vpn) MIX(srv6_vpn_hash_key_make(attr->srv6_vpn)); #ifdef ENABLE_BGP_VNC @@ -864,6 +942,7 @@ bool attrhash_cmp(const void *p1, const void *p2) attr1->df_alg == attr2->df_alg && attr1->nh_ifindex == attr2->nh_ifindex && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex && + attr1->nh_flags == attr2->nh_flags && attr1->distance == attr2->distance && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) && @@ -910,9 +989,17 @@ static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) vty_out(vty, "\tflags: %" PRIu64 - " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n", + " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6 aigp_metric: %" PRIu64 + "\n", attr->flag, attr->distance, attr->med, attr->local_pref, - attr->origin, attr->weight, attr->label, sid); + attr->origin, attr->weight, attr->label, sid, attr->aigp_metric); + vty_out(vty, "\taspath: %s Community: %s Large Community: %s\n", + aspath_print(attr->aspath), + community_str(attr->community, false, false), + lcommunity_str(attr->lcommunity, false, false)); + vty_out(vty, "\tExtended Community: %s Extended IPv6 Community: %s\n", + ecommunity_str(attr->ecommunity), + ecommunity_str(attr->ipv6_ecommunity)); } void attr_show_all(struct vty *vty) @@ -952,6 +1039,7 @@ struct attr *bgp_attr_intern(struct attr *attr) struct ecommunity *ipv6_ecomm = NULL; struct lcommunity *lcomm = NULL; struct community *comm = NULL; + struct bgp_route_evpn *bre = NULL; /* Intern referenced structure. */ if (attr->aspath) { @@ -1018,6 +1106,16 @@ struct attr *bgp_attr_intern(struct attr *attr) else attr->encap_subtlvs->refcnt++; } + + bre = bgp_attr_get_evpn_overlay(attr); + if (bre) { + if (!bre->refcnt) + bgp_attr_set_evpn_overlay(attr, + evpn_overlay_intern(bre)); + else + bre->refcnt++; + } + if (attr->srv6_l3vpn) { if (!attr->srv6_l3vpn->refcnt) attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); @@ -1207,6 +1305,7 @@ void bgp_attr_unintern_sub(struct attr *attr) struct lcommunity *lcomm = NULL; struct community *comm = NULL; struct transit *transit; + struct bgp_route_evpn *bre; /* aspath refcount shoud be decrement. */ aspath_unintern(&attr->aspath); @@ -1248,6 +1347,10 @@ void bgp_attr_unintern_sub(struct attr *attr) srv6_l3vpn_unintern(&attr->srv6_l3vpn); srv6_vpn_unintern(&attr->srv6_vpn); + + bre = bgp_attr_get_evpn_overlay(attr); + evpn_overlay_unintern(&bre); + bgp_attr_set_evpn_overlay(attr, NULL); } /* Free bgp attribute and aspath. */ @@ -1280,6 +1383,7 @@ void bgp_attr_flush(struct attr *attr) struct cluster_list *cluster; struct lcommunity *lcomm; struct community *comm; + struct bgp_route_evpn *bre; if (attr->aspath && !attr->aspath->refcnt) { aspath_free(attr->aspath); @@ -1338,6 +1442,11 @@ void bgp_attr_flush(struct attr *attr) bgp_attr_set_vnc_subtlvs(attr, NULL); } #endif + bre = bgp_attr_get_evpn_overlay(attr); + if (bre && !bre->refcnt) { + evpn_overlay_free(bre); + bgp_attr_set_evpn_overlay(attr, NULL); + } } /* Implement draft-scudder-idr-optional-transitive behaviour and @@ -1381,6 +1490,15 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, (args->startp - STREAM_DATA(BGP_INPUT(peer))) + args->total); + /* Partial optional attributes that are malformed should not cause + * the whole session to be reset. Instead treat it as a withdrawal + * of the routes, if possible. + */ + if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS) && + CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL) && + CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) + return BGP_ATTR_PARSE_WITHDRAW; + switch (args->type) { /* where an attribute is relatively inconsequential, e.g. it does not * affect route selection, and can be safely ignored, then any such @@ -1390,6 +1508,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, case BGP_ATTR_AS4_AGGREGATOR: case BGP_ATTR_AGGREGATOR: case BGP_ATTR_ATOMIC_AGGREGATE: + case BGP_ATTR_PREFIX_SID: return BGP_ATTR_PARSE_PROCEED; /* Core attributes, particularly ones which may influence route @@ -1417,19 +1536,21 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; + default: + /* Unknown attributes, that are handled by this function + * should be treated as withdraw, to prevent one more CVE + * from being introduced. + * RFC 7606 says: + * The "treat-as-withdraw" approach is generally preferred + * and the "session reset" approach is discouraged. + */ + flog_err(EC_BGP_ATTR_FLAG, + "%s(%u) attribute received, while it is not known how to handle it, treating as withdraw", + lookup_msg(attr_str, args->type, NULL), args->type); + break; } - /* Partial optional attributes that are malformed should not cause - * the whole session to be reset. Instead treat it as a withdrawal - * of the routes, if possible. - */ - if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS) - && CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL) - && CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) - return BGP_ATTR_PARSE_WITHDRAW; - - /* default to reset */ - return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; + return BGP_ATTR_PARSE_WITHDRAW; } /* Find out what is wrong with the path attribute flag bits and log the error. @@ -1505,6 +1626,7 @@ static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args *args) uint8_t mask = BGP_ATTR_FLAG_EXTLEN; const uint8_t flags = args->flags; const uint8_t attr_code = args->type; + struct peer *peer = args->peer; /* there may be attributes we don't know about */ if (attr_code > attr_flags_values_max) @@ -1512,6 +1634,14 @@ static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args *args) if (attr_flags_values[attr_code] == 0) return false; + /* If `neighbor X path-attribute ` is + * configured, then ignore checking optional, trasitive flags. + * The attribute/route will be discarded/withdrawned later instead + * of dropping the session. + */ + if (peer->discard_attrs[attr_code] || peer->withdraw_attrs[attr_code]) + return false; + /* RFC4271, "For well-known attributes, the Transitive bit MUST be set * to * 1." @@ -1839,7 +1969,9 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) * UPDATE message SHALL be handled using the approach of "treat-as- * withdraw". */ - if (peer->sort == BGP_PEER_IBGP && length != 4) { + if ((peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) && + length != 4) { flog_err(EC_BGP_ATTR_LEN, "LOCAL_PREF attribute length isn't 4 [%u]", length); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, @@ -1849,7 +1981,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the receiving speaker. */ - if (peer->sort == BGP_PEER_EBGP) { + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) { STREAM_FORWARD_GETP(peer->curr, length); return BGP_ATTR_PARSE_PROCEED; } @@ -2321,11 +2453,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, /* * NOTE: intentional fall through * - for consistency in rx processing - * - * The following comment is to signal GCC this intention - * and suppress the warning */ - /* FALLTHRU */ + fallthrough; case BGP_ATTR_NHLEN_IPV4: stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); /* Probably needed for RFC 2283 */ @@ -2347,6 +2476,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: @@ -2364,6 +2499,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { @@ -2422,7 +2563,7 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, mp_update->afi = afi; mp_update->safi = safi; - return BGP_ATTR_PARSE_EOR; + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_ATTR, 0); } mp_update->afi = afi; @@ -2534,7 +2675,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; - uint8_t sticky = 0; bool proxy = false; struct ecommunity *ecomm; @@ -2564,21 +2704,20 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg); /* Extract MAC mobility sequence number, if any. */ - attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); - attr->sticky = sticky; + attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr); /* Check if this is a Gateway MAC-IP advertisement */ - attr->default_gw = bgp_attr_default_gw(attr); + bgp_attr_default_gw(attr); /* Handle scenario where router flag ecommunity is not * set but default gw ext community is present. * Use default gateway, set and propogate R-bit. */ - if (attr->default_gw) - attr->router_flag = 1; + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER); /* Check EVPN Neighbor advertisement flags, R-bit */ - bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy); + bgp_attr_evpn_na_flag(attr, &proxy); if (proxy) attr->es_flags |= ATTR_ES_PROXY_ADVERT; @@ -2619,10 +2758,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args) if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) goto ipv6_ext_community_ignore; - ipv6_ecomm = ecommunity_parse_ipv6( - stream_pnt(peer->curr), length, - CHECK_FLAG(peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + ipv6_ecomm = ecommunity_parse_ipv6(stream_pnt(peer->curr), length); bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm); /* XXX: fix ecommunity_parse to use stream API */ @@ -2632,6 +2768,10 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args) return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); + /* Extract link bandwidth, if any. */ + (void)ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(attr), + &attr->link_bw); + return BGP_ATTR_PARSE_PROCEED; ipv6_ext_community_ignore: @@ -2679,17 +2819,20 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) } } - while (length >= 4) { + while (STREAM_READABLE(BGP_INPUT(peer)) >= 4) { uint16_t subtype = 0; uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; if (BGP_ATTR_ENCAP == type) { subtype = stream_getc(BGP_INPUT(peer)); - sublength = (subtype < 128) - ? stream_getc(BGP_INPUT(peer)) - : stream_getw(BGP_INPUT(peer)); - length -= 2; + if (subtype < 128) { + sublength = stream_getc(BGP_INPUT(peer)); + length -= 2; + } else { + sublength = stream_getw(BGP_INPUT(peer)); + length -= 3; + } #ifdef ENABLE_BGP_VNC } else { subtype = stream_getw(BGP_INPUT(peer)); @@ -2706,6 +2849,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) args->total); } + if (STREAM_READABLE(BGP_INPUT(peer)) < sublength) { + zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining stream length %zu", + sublength, STREAM_READABLE(BGP_INPUT(peer))); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + } + /* alloc and copy sub-tlv */ /* TBD make sure these are freed when attributes are released */ tlv = XCALLOC(MTYPE_ENCAP_TLV, @@ -3144,8 +3295,6 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; enum bgp_attr_parse_ret ret; - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID); - uint8_t type; uint16_t length; size_t headersz = sizeof(type) + sizeof(length); @@ -3195,6 +3344,8 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args) } } + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)); + return BGP_ATTR_PARSE_PROCEED; } @@ -3267,7 +3418,8 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args) * the default value of AIGP_SESSION SHOULD be "enabled". */ if (peer->sort == BGP_PEER_EBGP && - !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) { + (!CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || + peer->sub_sort != BGP_PEER_EBGP_OAD)) { zlog_warn( "%pBP received AIGP attribute, but eBGP peer do not support it", peer); @@ -3385,23 +3537,19 @@ bgp_attr_unknown(struct bgp_attr_parser_args *args) } /* Well-known attribute check. */ -static int bgp_attr_check(struct peer *peer, struct attr *attr) +static int bgp_attr_check(struct peer *peer, struct attr *attr, + bgp_size_t length) { uint8_t type = 0; /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an - * empty UPDATE. */ - if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag) - return BGP_ATTR_PARSE_PROCEED; - - /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required - to carry any other path attributes.", though if MP_REACH_NLRI or NLRI - are present, it should. Check for any other attribute being present - instead. + * empty UPDATE. Treat-as-withdraw, otherwise if we just ignore it, + * we will pass it to be processed as a normal UPDATE without mandatory + * attributes, that could lead to harmful behavior. */ - if ((!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) && - CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI)))) - return BGP_ATTR_PARSE_PROCEED; + if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag && + !length) + return BGP_ATTR_PARSE_WITHDRAW; if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN))) type = BGP_ATTR_ORIGIN; @@ -3421,6 +3569,16 @@ static int bgp_attr_check(struct peer *peer, struct attr *attr) && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))) type = BGP_ATTR_LOCAL_PREF; + /* An UPDATE message that contains the MP_UNREACH_NLRI is not required + * to carry any other path attributes. Though if MP_REACH_NLRI or NLRI + * are present, it should. Check for any other attribute being present + * instead. + */ + if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) && + CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))) + return type ? BGP_ATTR_PARSE_MISSING_MANDATORY + : BGP_ATTR_PARSE_PROCEED; + /* If any of the well-known mandatory attributes are not present * in an UPDATE message, then "treat-as-withdraw" MUST be used. */ @@ -3443,7 +3601,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, enum bgp_attr_parse_ret ret; uint8_t flag = 0; uint8_t type = 0; - bgp_size_t length; + bgp_size_t length = 0; uint8_t *startp, *endp; uint8_t *attr_endp; uint8_t seen[BGP_ATTR_BITMAP_SIZE]; @@ -3759,10 +3917,6 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, goto done; } - if (ret == BGP_ATTR_PARSE_EOR) { - goto done; - } - if (ret == BGP_ATTR_PARSE_ERROR) { flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR, "%s: Attribute %s, parse error", peer->host, @@ -3835,7 +3989,7 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, } /* Check all mandatory well-known attributes are present */ - ret = bgp_attr_check(peer, attr); + ret = bgp_attr_check(peer, attr, length); if (ret < 0) goto done; @@ -3891,7 +4045,13 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, aspath_unintern(&as4_path); transit = bgp_attr_get_transit(attr); - if (ret != BGP_ATTR_PARSE_ERROR) { + /* If we received an UPDATE with mandatory attributes, then + * the unrecognized transitive optional attribute of that + * path MUST be passed. Otherwise, it's an error, and from + * security perspective it might be very harmful if we continue + * here with the unrecognized attributes. + */ + if (ret == BGP_ATTR_PARSE_PROCEED) { /* Finally intern unknown attribute. */ if (transit) bgp_attr_set_transit(attr, transit_intern(transit)); @@ -4003,6 +4163,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, switch (nh_afi) { case AFI_IP: switch (safi) { + case SAFI_RTC: case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: @@ -4036,6 +4197,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, break; case AFI_IP6: switch (safi) { + case SAFI_RTC: case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: @@ -4107,7 +4269,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, const struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, bool addpath_capable, + uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr) { switch (safi) { @@ -4151,6 +4313,12 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, case SAFI_ENCAP: assert(!"Please add proper encoding of SAFI_ENCAP"); break; + case SAFI_RTC: + stream_putc(s, p->prefixlen); + stream_putl(s, p->u.prefix_rtc.origin_as); + stream_put(s, &p->u.prefix_rtc.route_target, + PSIZE(p->prefixlen) - 4); + break; } } @@ -4189,6 +4357,8 @@ size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, case SAFI_FLOWSPEC: size = ((struct prefix_fs *)p)->prefix.prefixlen; break; + case SAFI_RTC: + size = p->prefixlen; } return size; @@ -4314,13 +4484,76 @@ static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi) return false; } +static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer, + struct ecommunity *ecomm, + bool transparent, int attribute) +{ + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) { + if (ecomm->size * ecomm->unit_size > 255) { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS | + BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, attribute); + stream_putw(s, ecomm->size * ecomm->unit_size); + } else { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS); + stream_putc(s, attribute); + stream_putc(s, ecomm->size * ecomm->unit_size); + } + stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size); + } else { + uint8_t *pnt; + int tbit; + int ecom_tr_size = 0; + uint32_t i; + + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * ecomm->unit_size); + tbit = *pnt; + + if (CHECK_FLAG(tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) + continue; + + ecom_tr_size++; + } + + if (ecom_tr_size) { + if (ecom_tr_size * ecomm->unit_size > 255) { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS | + BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, attribute); + stream_putw(s, ecom_tr_size * ecomm->unit_size); + } else { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS); + stream_putc(s, attribute); + stream_putc(s, ecom_tr_size * ecomm->unit_size); + } + + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * ecomm->unit_size); + tbit = *pnt; + + if (CHECK_FLAG(tbit, + ECOMMUNITY_FLAG_NON_TRANSITIVE)) + continue; + + stream_put(s, pnt, ecomm->unit_size); + } + } + } +} + /* Make attribute packet. */ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct bgp_path_info *bpi) { @@ -4351,6 +4584,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_packet_mpattr_end(s, mpattrlen_pos); } + (void)peer_sort(peer); + /* Origin attribute. */ stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_ORIGIN); @@ -4484,7 +4719,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* Local preference. */ - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD) { stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LOCAL_PREF); stream_putc(s, 4); @@ -4615,82 +4851,31 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } } - /* Extended Communities attribute. */ - if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) - && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { - struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); + /* Extended IPv6/Communities attributes. */ + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) { bool transparent = CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && from && CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT); - if (peer->sort == BGP_PEER_IBGP || - peer->sort == BGP_PEER_CONFED || transparent) { - if (ecomm->size * 8 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); - stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); - stream_putw(s, ecomm->size * 8); - } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); - stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); - stream_putc(s, ecomm->size * 8); - } - stream_put(s, ecomm->val, ecomm->size * 8); - } else { - uint8_t *pnt; - int tbit; - int ecom_tr_size = 0; - uint32_t i; + if (CHECK_FLAG(attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * 8); - tbit = *pnt; - - if (CHECK_FLAG(tbit, - ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; + bgp_packet_ecommunity_attribute(s, peer, ecomm, + transparent, + BGP_ATTR_EXT_COMMUNITIES); + } - ecom_tr_size++; - } + if (CHECK_FLAG(attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = + bgp_attr_get_ipv6_ecommunity(attr); - if (ecom_tr_size) { - if (ecom_tr_size * 8 > 255) { - stream_putc( - s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); - stream_putc(s, - BGP_ATTR_EXT_COMMUNITIES); - stream_putw(s, ecom_tr_size * 8); - } else { - stream_putc( - s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); - stream_putc(s, - BGP_ATTR_EXT_COMMUNITIES); - stream_putc(s, ecom_tr_size * 8); - } - - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * 8); - tbit = *pnt; - - if (CHECK_FLAG( - tbit, - ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; - - stream_put(s, pnt, 8); - } - } + bgp_packet_ecommunity_attribute(s, peer, ecomm, + transparent, + BGP_ATTR_IPV6_EXT_COMMUNITIES); } } @@ -4850,6 +5035,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* AIGP */ if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) && (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || + peer->sub_sort == BGP_PEER_EBGP_OAD || peer->sort != BGP_PEER_EBGP)) { /* At the moment only AIGP Metric TLV exists for AIGP * attribute. If more comes in, do not forget to update @@ -4898,7 +5084,7 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr) { @@ -4930,6 +5116,7 @@ void bgp_attr_init(void) transit_init(); encap_init(); srv6_init(); + evpn_overlay_init(); } void bgp_attr_finish(void) @@ -4943,6 +5130,7 @@ void bgp_attr_finish(void) transit_finish(); encap_finish(); srv6_finish(); + evpn_overlay_finish(); } /* Make attribute packet. */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 961e5f122470..f4b800737e20 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -155,16 +155,61 @@ struct attr { uint32_t med; uint32_t local_pref; ifindex_t nh_ifindex; + uint8_t nh_flags; + +#define BGP_ATTR_NH_VALID 0x01 +#define BGP_ATTR_NH_IF_OPERSTATE 0x02 +#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */ /* Path origin attribute */ uint8_t origin; + /* ES info */ + uint8_t es_flags; + /* Path is not "locally-active" on the advertising VTEP. This is + * translated into an ARP-ND ECOM. + */ +#define ATTR_ES_PROXY_ADVERT (1 << 0) + /* Destination ES is present locally. This flag is set on local + * paths and sync paths + */ +#define ATTR_ES_IS_LOCAL (1 << 1) + /* There are one or more non-best paths from ES peers. Note that + * this flag is only set on the local MAC-IP paths in the VNI + * route table (not set in the global routing table). And only + * non-proxy advertisements from an ES peer can result in this + * flag being set. + */ +#define ATTR_ES_PEER_ACTIVE (1 << 2) + /* There are one or more non-best proxy paths from ES peers */ +#define ATTR_ES_PEER_PROXY (1 << 3) + /* An ES peer has router bit set - only applicable if + * ATTR_ES_PEER_ACTIVE is set + */ +#define ATTR_ES_PEER_ROUTER (1 << 4) + + /* These two flags are only set on L3 routes installed in a + * VRF as a result of EVPN MAC-IP route + * XXX - while splitting up per-family attrs these need to be + * classified as non-EVPN + */ +#define ATTR_ES_L3_NHG_USE (1 << 5) +#define ATTR_ES_L3_NHG_ACTIVE (1 << 6) +#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) + + /* Distance as applied by Route map */ + uint8_t distance; + + /* EVPN DF preference for DF election on local ESs */ + uint8_t df_alg; + uint16_t df_pref; + /* PMSI tunnel type (RFC 6514). */ enum pta_type pmsi_tnl_type; /* has the route-map changed any attribute? Used on the peer outbound side. */ - uint32_t rmap_change_flags; + uint16_t rmap_change_flags; /* Multi-Protocol Nexthop, AFI IPv6 */ struct in6_addr mp_nexthop_global; @@ -173,6 +218,9 @@ struct attr { /* ifIndex corresponding to mp_nexthop_local. */ ifindex_t nh_lla_ifindex; + /* MPLS label */ + mpls_label_t label; + /* Extended Communities attribute. */ struct ecommunity *ecommunity; @@ -205,50 +253,12 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* MP Nexthop preference */ - uint8_t mp_nexthop_prefer_global; - - /* Static MAC for EVPN */ - uint8_t sticky; - - /* Flag for default gateway extended community in EVPN */ - uint8_t default_gw; - - /* NA router flag (R-bit) support in EVPN */ - uint8_t router_flag; - - /* ES info */ - uint8_t es_flags; - /* Path is not "locally-active" on the advertising VTEP. This is - * translated into an ARP-ND ECOM. - */ -#define ATTR_ES_PROXY_ADVERT (1 << 0) - /* Destination ES is present locally. This flag is set on local - * paths and sync paths - */ -#define ATTR_ES_IS_LOCAL (1 << 1) - /* There are one or more non-best paths from ES peers. Note that - * this flag is only set on the local MAC-IP paths in the VNI - * route table (not set in the global routing table). And only - * non-proxy advertisements from an ES peer can result in this - * flag being set. - */ -#define ATTR_ES_PEER_ACTIVE (1 << 2) - /* There are one or more non-best proxy paths from ES peers */ -#define ATTR_ES_PEER_PROXY (1 << 3) - /* An ES peer has router bit set - only applicable if - * ATTR_ES_PEER_ACTIVE is set - */ -#define ATTR_ES_PEER_ROUTER (1 << 4) - - /* These two flags are only set on L3 routes installed in a - * VRF as a result of EVPN MAC-IP route - * XXX - while splitting up per-family attrs these need to be - * classified as non-EVPN - */ -#define ATTR_ES_L3_NHG_USE (1 << 5) -#define ATTR_ES_L3_NHG_ACTIVE (1 << 6) -#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) + /* EVPN flags */ + uint8_t evpn_flags; +#define ATTR_EVPN_FLAG_STICKY (1 << 0) +#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1) +/* NA router flag (R-bit) support in EVPN */ +#define ATTR_EVPN_FLAG_ROUTER (1 << 2) /* route tag */ route_tag_t tag; @@ -256,23 +266,19 @@ struct attr { /* Label index */ uint32_t label_index; - /* MPLS label */ - mpls_label_t label; - /* SRv6 VPN SID */ struct bgp_attr_srv6_vpn *srv6_vpn; /* SRv6 L3VPN SID */ struct bgp_attr_srv6_l3vpn *srv6_l3vpn; - uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ #ifdef ENABLE_BGP_VNC struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */ #endif /* EVPN */ - struct bgp_route_evpn evpn_overlay; + struct bgp_route_evpn *evpn_overlay; /* EVPN MAC Mobility sequence number, if any. */ uint32_t mm_seqnum; @@ -287,14 +293,13 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; - /* Distance as applied by Route map */ - uint8_t distance; + uint8_t encap_tunneltype; /* rmap set table */ uint32_t rmap_table_id; /* Link bandwidth value, if any. */ - uint32_t link_bw; + uint64_t link_bw; /* EVPN ES */ esi_t esi; @@ -302,10 +307,6 @@ struct attr { /* SR-TE Color */ uint32_t srte_color; - /* EVPN DF preference and algorithm for DF election on local ESs */ - uint16_t df_pref; - uint8_t df_alg; - /* Nexthop type */ enum nexthop_types_t nh_type; @@ -364,7 +365,7 @@ enum bgp_attr_parse_ret { /* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR */ BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3, - BGP_ATTR_PARSE_EOR = -4, + BGP_ATTR_PARSE_MISSING_MANDATORY = -4, }; struct bpacket_attr_vec_arr; @@ -390,7 +391,7 @@ extern bgp_size_t bgp_packet_attribute( struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, bool addpath_capable, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct bgp_path_info *bpi); extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, const struct prefix *p); @@ -448,7 +449,7 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, @@ -459,7 +460,7 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix( struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, - const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, + const struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); @@ -613,16 +614,16 @@ static inline void bgp_attr_set_cluster(struct attr *attr, UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)); } -static inline const struct bgp_route_evpn * +static inline struct bgp_route_evpn * bgp_attr_get_evpn_overlay(const struct attr *attr) { - return &attr->evpn_overlay; + return attr->evpn_overlay; } static inline void bgp_attr_set_evpn_overlay(struct attr *attr, - struct bgp_route_evpn *eo) + struct bgp_route_evpn *bre) { - memcpy(&attr->evpn_overlay, eo, sizeof(struct bgp_route_evpn)); + attr->evpn_overlay = bre; } static inline struct bgp_attr_encap_subtlv * diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index bbc4ba9525d4..fc7548d9bf50 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -24,6 +24,13 @@ bool bgp_route_evpn_same(const struct bgp_route_evpn *e1, const struct bgp_route_evpn *e2) { + if (!e1 && e2) + return false; + if (!e2 && e1) + return false; + if (!e1 && !e2) + return true; + return (e1->type == e2->type && !memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) && !ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip))); @@ -115,14 +122,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) /* * return true if attr contains default gw extended community */ -uint8_t bgp_attr_default_gw(struct attr *attr) +void bgp_attr_default_gw(struct attr *attr) { struct ecommunity *ecom; uint32_t i; ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) - return 0; + return; /* If there is a default gw extendd community return true otherwise * return 0 */ @@ -136,10 +143,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr) if ((type == ECOMMUNITY_ENCODE_OPAQUE && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) - return 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } - - return 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } /* @@ -183,7 +189,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. */ -uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) +uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr) { struct ecommunity *ecom; uint32_t i; @@ -213,9 +219,9 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) flags = *pnt++; if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) - *sticky = 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); else - *sticky = 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); pnt++; pnt = ptr_get_be32(pnt, &seq_num); @@ -229,8 +235,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) /* * return true if attr contains router flag extended community */ -void bgp_attr_evpn_na_flag(struct attr *attr, - uint8_t *router_flag, bool *proxy) +void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy) { struct ecommunity *ecom; uint32_t i; @@ -254,7 +259,8 @@ void bgp_attr_evpn_na_flag(struct attr *attr, val = *pnt++; if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) - *router_flag = 1; + SET_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER); if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG) *proxy = true; diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index f8d3978b960b..cc0e3e4400e7 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -23,6 +23,7 @@ enum overlay_index_type { * MAC overlay index is stored in the RMAC attribute. */ struct bgp_route_evpn { + unsigned long refcnt; enum overlay_index_type type; esi_t eth_s_id; struct ipaddr gw_ip; @@ -36,12 +37,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr, extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); -extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, - uint8_t *sticky); -extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr); +extern void bgp_attr_default_gw(struct attr *attr); -extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, - bool *proxy); +extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 21864cf1a695..14ff5f2e1151 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -597,6 +597,9 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd, if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (!peer->bfd_config) + return CMD_SUCCESS; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) bgp_group_configure_bfd(peer); else diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 7270802915e6..43f8006e2d4b 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -38,6 +38,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_trace.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" static void bmp_close(struct bmp *bmp); static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp); @@ -240,60 +241,115 @@ static void bmp_free(struct bmp *bmp) XFREE(MTYPE_BMP_CONN, bmp); } +#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0 +#define BMP_PEER_TYPE_RD_INSTANCE 1 +#define BMP_PEER_TYPE_LOCAL_INSTANCE 2 +#define BMP_PEER_TYPE_LOC_RIB_INSTANCE 3 + +static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, + uint8_t peer_type, + uint64_t *result_ref) +{ + + /* remove this check when the other peer types get correct peer dist. + *(RFC7854) impl. + * for now, always return no error and 0 peer distinguisher as before + */ + if (peer_type != BMP_PEER_TYPE_LOC_RIB_INSTANCE) + return (*result_ref = 0); + + /* sending vrf_id or rd could be turned into an option at some point */ + struct bgp *bgp = bmp->targets->bgp; + + /* vrf default => ok, distinguisher 0 */ + if (bgp->inst_type == VRF_DEFAULT) + return (*result_ref = 0); + + /* use RD if set in VRF config for this AFI */ + struct prefix_rd *prd = &bgp->vpn_policy[afi].tovpn_rd; + + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_RD_SET)) { + memcpy(result_ref, prd->val, sizeof(prd->val)); + return 0; + } + + /* VRF has no id => error => message should be skipped */ + if (bgp->vrf_id == VRF_UNKNOWN) + return 1; + + /* use VRF id converted to ::vrf_id 64bits format */ + *result_ref = ((uint64_t)htonl(bgp->vrf_id)) << 32; + return 0; +} + static void bmp_common_hdr(struct stream *s, uint8_t ver, uint8_t type) { stream_putc(s, ver); - stream_putl(s, 0); //dummy message length. will be set later. + stream_putl(s, 0); /* dummy message length. will be set later. */ stream_putc(s, type); } -static void bmp_per_peer_hdr(struct stream *s, struct peer *peer, - uint8_t flags, const struct timeval *tv) +static void bmp_per_peer_hdr(struct stream *s, struct bgp *bgp, + struct peer *peer, uint8_t flags, + uint8_t peer_type_flag, + uint64_t peer_distinguisher, + const struct timeval *tv) { - char peer_distinguisher[8]; - -#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0 -#define BMP_PEER_TYPE_RD_INSTANCE 1 -#define BMP_PEER_TYPE_LOCAL_INSTANCE 2 - #define BMP_PEER_FLAG_V (1 << 7) #define BMP_PEER_FLAG_L (1 << 6) #define BMP_PEER_FLAG_A (1 << 5) + bool is_locrib = peer_type_flag == BMP_PEER_TYPE_LOC_RIB_INSTANCE; + /* Peer Type */ - stream_putc(s, BMP_PEER_TYPE_GLOBAL_INSTANCE); + stream_putc(s, peer_type_flag); /* Peer Flags */ - if (peer->connection->su.sa.sa_family == AF_INET6) + if (!is_locrib && peer->connection->su.sa.sa_family == AF_INET6) SET_FLAG(flags, BMP_PEER_FLAG_V); else UNSET_FLAG(flags, BMP_PEER_FLAG_V); stream_putc(s, flags); /* Peer Distinguisher */ - memset (&peer_distinguisher[0], 0, 8); - stream_put(s, &peer_distinguisher[0], 8); + stream_put(s, (uint8_t *)&peer_distinguisher, 8); /* Peer Address */ - if (peer->connection->su.sa.sa_family == AF_INET6) - stream_put(s, &peer->connection->su.sin6.sin6_addr, 16); - else if (peer->connection->su.sa.sa_family == AF_INET) { + /* Set to 0 if it's a LOC-RIB INSTANCE (RFC 9069) or if it's not an + * IPv4/6 address + */ + if (is_locrib || (peer->connection->su.sa.sa_family != AF_INET6 && + peer->connection->su.sa.sa_family != AF_INET)) { stream_putl(s, 0); stream_putl(s, 0); stream_putl(s, 0); - stream_put_in_addr(s, &peer->connection->su.sin.sin_addr); - } else { stream_putl(s, 0); + } else if (peer->connection->su.sa.sa_family == AF_INET6) + stream_put(s, &peer->connection->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); + else if (peer->connection->su.sa.sa_family == AF_INET) { stream_putl(s, 0); stream_putl(s, 0); stream_putl(s, 0); + stream_put_in_addr(s, &peer->connection->su.sin.sin_addr); } /* Peer AS */ - stream_putl(s, peer->as); + /* set peer ASN but for LOC-RIB INSTANCE (RFC 9069) put the local bgp + * ASN + */ + as_t asn = !is_locrib ? peer->as : bgp->as; + + stream_putl(s, asn); /* Peer BGP ID */ - stream_put_in_addr(s, &peer->remote_id); + /* set router-id but for LOC-RIB INSTANCE (RFC 9069) put the instance + * router-id + */ + struct in_addr *bgp_id = + !is_locrib ? &peer->remote_id : &bgp->router_id; + + stream_put_in_addr(s, bgp_id); /* Timestamp */ if (tv) { @@ -314,21 +370,36 @@ static void bmp_put_info_tlv(struct stream *s, uint16_t type, stream_put(s, string, len); } +static void __attribute__((unused)) +bmp_put_vrftablename_info_tlv(struct stream *s, struct bmp *bmp) +{ + +#define BMP_INFO_TYPE_VRFTABLENAME 3 + const char *vrftablename = "global"; + if (bmp->targets->bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { + struct vrf *vrf = vrf_lookup_by_id(bmp->targets->bgp->vrf_id); + + vrftablename = vrf ? vrf->name : NULL; + } + if (vrftablename != NULL) + bmp_put_info_tlv(s, BMP_INFO_TYPE_VRFTABLENAME, vrftablename); +} + static int bmp_send_initiation(struct bmp *bmp) { int len; - struct stream *s; - s = stream_new(BGP_MAX_PACKET_SIZE); + struct stream *s = stream_new(BGP_MAX_PACKET_SIZE); + bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION); -#define BMP_INFO_TYPE_SYSDESCR 1 -#define BMP_INFO_TYPE_SYSNAME 2 - bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSDESCR, - FRR_FULL_NAME " " FRR_VER_SHORT); - bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get()); +#define BMP_INIT_INFO_TYPE_SYSDESCR 1 +#define BMP_INIT_INFO_TYPE_SYSNAME 2 + bmp_put_info_tlv(s, BMP_INIT_INFO_TYPE_SYSDESCR, + FRR_FULL_NAME " " FRR_VER_SHORT); + bmp_put_info_tlv(s, BMP_INIT_INFO_TYPE_SYSNAME, cmd_hostname_get()); len = stream_get_endp(s); - stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set. + stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */ pullwr_write_stream(bmp->pullwr, s); stream_free(s); @@ -368,6 +439,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) monotime_to_realtime(&uptime, &uptime_real); #define BGP_BMP_MAX_PACKET_SIZE 1024 +#define BMP_PEERUP_INFO_TYPE_STRING 0 s = stream_new(BGP_MAX_PACKET_SIZE); if (peer_established(peer->connection) && !down) { @@ -375,7 +447,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_UP_NOTIFICATION); - bmp_per_peer_hdr(s, peer, 0, &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, + &uptime_real); /* Local Address (16 bytes) */ if (peer->su_local->sa.sa_family == AF_INET6) @@ -421,14 +495,17 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) } if (peer->desc) - bmp_put_info_tlv(s, 0, peer->desc); + bmp_put_info_tlv(s, BMP_PEERUP_INFO_TYPE_STRING, + peer->desc); } else { uint8_t type; size_t type_pos; bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_DOWN_NOTIFICATION); - bmp_per_peer_hdr(s, peer, 0, &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, + &uptime_real); type_pos = stream_get_endp(s); stream_putc(s, 0); /* placeholder for down reason */ @@ -460,7 +537,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) } len = stream_get_endp(s); - stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set. + stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */ return s; } @@ -618,7 +695,8 @@ static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, bmp->targets->bgp->peer_self, 0, &tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO); stream_putw(s, 2); @@ -656,7 +734,8 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, peer, 0, &bmq->tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &bmq->tv); /* BMP Mirror TLV. */ stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE); @@ -763,7 +842,8 @@ static int bmp_peer_backward(struct peer *peer) return 0; } -static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) +static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags, + uint8_t peer_type_flag) { struct peer *peer; struct listnode *node; @@ -771,7 +851,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) iana_afi_t pkt_afi = IANA_AFI_IPV4; iana_safi_t pkt_safi = IANA_SAFI_UNICAST; - frrtrace(3, frr_bgp, bmp_eor, afi, safi, flags); + frrtrace(4, frr_bgp, bmp_eor, afi, safi, flags, peer_type_flag); s = stream_new(BGP_MAX_PACKET_SIZE); @@ -803,11 +883,22 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) if (!peer->afc_nego[afi][safi]) continue; + uint64_t peer_distinguisher = 0; + /* skip this message if peer distinguisher is not available */ + if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag, + &peer_distinguisher)) { + zlog_warn( + "skipping bmp message for reason: can't get peer distinguisher"); + continue; + } + s2 = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s2, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); - bmp_per_peer_hdr(s2, peer, flags, NULL); + + bmp_per_peer_hdr(s2, bmp->targets->bgp, peer, flags, + peer_type_flag, peer_distinguisher, NULL); stream_putl_at(s2, BMP_LENGTH_POS, stream_get_endp(s) + stream_get_endp(s2)); @@ -822,7 +913,8 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, struct peer *peer, struct attr *attr, - afi_t afi, safi_t safi) + afi_t afi, safi_t safi, mpls_label_t *label, + uint32_t num_labels) { struct bpacket_attr_vec_arr vecarr; struct stream *s; @@ -858,8 +950,8 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, &vecarr, attr); - bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0, - attr); + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, + num_labels, 0, 0, attr); bgp_packet_mpattr_end(s, mpattrlen_pos); total_attr_len += stream_get_endp(s) - p1; } @@ -912,23 +1004,36 @@ static struct stream *bmp_withdraw(const struct prefix *p, } static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, - const struct prefix *p, struct prefix_rd *prd, - struct attr *attr, afi_t afi, safi_t safi, - time_t uptime) + uint8_t peer_type_flag, const struct prefix *p, + struct prefix_rd *prd, struct attr *attr, afi_t afi, + safi_t safi, time_t uptime, mpls_label_t *label, + uint32_t num_labels) { struct stream *hdr, *msg; struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; struct timeval uptime_real; + uint64_t peer_distinguisher = 0; + /* skip this message if peer distinguisher is not available */ + if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag, + &peer_distinguisher)) { + zlog_warn( + "skipping bmp message for reason: can't get peer distinguisher"); + return; + } + monotime_to_realtime(&tv, &uptime_real); if (attr) - msg = bmp_update(p, prd, peer, attr, afi, safi); + msg = bmp_update(p, prd, peer, attr, afi, safi, label, + num_labels); else msg = bmp_withdraw(p, prd, afi, safi); hdr = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); - bmp_per_peer_hdr(hdr, peer, flags, &uptime_real); + bmp_per_peer_hdr(hdr, bmp->targets->bgp, peer, flags, peer_type_flag, + peer_distinguisher, + uptime == (time_t)(-1L) ? NULL : &uptime_real); stream_putl_at(hdr, BMP_LENGTH_POS, stream_get_endp(hdr) + stream_get_endp(msg)); @@ -942,6 +1047,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) { + uint8_t bpi_num_labels; afi_t afi; safi_t safi; @@ -1039,8 +1145,13 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) zlog_info("bmp[%s] %s %s table completed (EoR)", bmp->remote, afi2str(afi), safi2str(safi)); - bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L); - bmp_eor(bmp, afi, safi, 0); + + bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, + BMP_PEER_TYPE_GLOBAL_INSTANCE); + bmp_eor(bmp, afi, safi, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE); + bmp_eor(bmp, afi, safi, 0, + BMP_PEER_TYPE_LOC_RIB_INSTANCE); bmp->afistate[afi][safi] = BMP_AFI_LIVE; bmp->syncafi = AFI_MAX; @@ -1051,10 +1162,16 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn)); } - if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], + BMP_MON_POSTPOLICY) || + CHECK_FLAG(bmp->targets->afimon[afi][safi], + BMP_MON_LOC_RIB)) { for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter; bpiter = bpiter->next) { - if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID)) + if (!CHECK_FLAG(bpiter->flags, + BGP_PATH_VALID) && + !CHECK_FLAG(bpiter->flags, + BGP_PATH_SELECTED)) continue; if (bpiter->peer->qobj_node.nid <= bmp->syncpeerid) @@ -1065,7 +1182,8 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) bpi = bpiter; } } - if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], + BMP_MON_PREPOLICY)) { for (adjiter = bn->adj_in; adjiter; adjiter = adjiter->next) { if (adjiter->peer->qobj_node.nid @@ -1103,12 +1221,31 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) (safi == SAFI_MPLS_VPN)) prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos); - if (bpi) - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd, - bpi->attr, afi, safi, bpi->uptime); + bpi_num_labels = bgp_path_info_num_labels(bpi); + + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) && + CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) { + bmp_monitor(bmp, bpi->peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, + bn_p, prd, bpi->attr, afi, safi, + bpi && bpi->extra ? bpi->extra->bgp_rib_uptime + : (time_t)(-1L), + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); + } + + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) && + CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) + bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, + BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr, + afi, safi, bpi->uptime, + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); + if (adjin) - bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi, - safi, adjin->uptime); + /* TODO: set label here when adjin supports labels */ + bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, + bn_p, prd, adjin->attr, afi, safi, adjin->uptime, + NULL, 0); if (bn) bgp_dest_unlock_node(bn); @@ -1116,30 +1253,136 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) return true; } -static struct bmp_queue_entry *bmp_pull(struct bmp *bmp) +static struct bmp_queue_entry * +bmp_pull_from_queue(struct bmp_qlist_head *list, struct bmp_qhash_head *hash, + struct bmp_queue_entry **queuepos_ptr) { struct bmp_queue_entry *bqe; - bqe = bmp->queuepos; + bqe = *queuepos_ptr; if (!bqe) return NULL; - bmp->queuepos = bmp_qlist_next(&bmp->targets->updlist, bqe); + *queuepos_ptr = bmp_qlist_next(list, bqe); bqe->refcount--; if (!bqe->refcount) { - bmp_qhash_del(&bmp->targets->updhash, bqe); - bmp_qlist_del(&bmp->targets->updlist, bqe); + bmp_qhash_del(hash, bqe); + bmp_qlist_del(list, bqe); } return bqe; } +static inline struct bmp_queue_entry *bmp_pull(struct bmp *bmp) +{ + return bmp_pull_from_queue(&bmp->targets->updlist, + &bmp->targets->updhash, &bmp->queuepos); +} + +static inline struct bmp_queue_entry *bmp_pull_locrib(struct bmp *bmp) +{ + return bmp_pull_from_queue(&bmp->targets->locupdlist, + &bmp->targets->locupdhash, + &bmp->locrib_queuepos); +} + +/* TODO BMP_MON_LOCRIB find a way to merge properly this function with + * bmp_wrqueue or abstract it if possible + */ +static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) +{ + + struct bmp_queue_entry *bqe; + struct peer *peer; + struct bgp_dest *bn = NULL; + bool written = false; + uint8_t bpi_num_labels; + + bqe = bmp_pull_locrib(bmp); + if (!bqe) + return false; + + afi_t afi = bqe->afi; + safi_t safi = bqe->safi; + + if (!CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) + goto out; + + switch (bmp->afistate[afi][safi]) { + case BMP_AFI_INACTIVE: + case BMP_AFI_NEEDSYNC: + goto out; + case BMP_AFI_SYNC: + if (prefix_cmp(&bqe->p, &bmp->syncpos) <= 0) + /* currently syncing but have already passed this + * prefix => send it. + */ + break; + + /* currently syncing & haven't reached this prefix yet + * => it'll be sent as part of the table sync, no need here + */ + goto out; + case BMP_AFI_LIVE: + break; + } + + peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer); + if (!peer) { + /* skipping queued item for deleted peer + */ + goto out; + } + if (peer != bmp->targets->bgp->peer_self && !peer_established(peer->connection)) { + /* peer is neither self, nor established + */ + goto out; + } + + bool is_vpn = (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) || + (bqe->safi == SAFI_MPLS_VPN); + + struct prefix_rd *prd = is_vpn ? &bqe->rd : NULL; + + bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi, + &bqe->p, prd); + + struct bgp_path_info *bpi; + + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { + if (!CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED)) + continue; + if (bpi->peer == peer) + break; + } + + bpi_num_labels = bgp_path_info_num_labels(bpi); + + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd, + bpi ? bpi->attr : NULL, afi, safi, + bpi && bpi->extra ? bpi->extra->bgp_rib_uptime + : (time_t)(-1L), + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); + written = true; + +out: + if (!bqe->refcount) + XFREE(MTYPE_BMP_QUEUE, bqe); + + if (bn) + bgp_dest_unlock_node(bn); + + return written; +} + static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) { struct bmp_queue_entry *bqe; struct peer *peer; struct bgp_dest *bn = NULL; bool written = false; + uint8_t bpi_num_labels; bqe = bmp_pull(bmp); if (!bqe) @@ -1180,11 +1423,10 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi, &bqe->p, prd); - - if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) { struct bgp_path_info *bpi; - for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi; + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) continue; @@ -1192,13 +1434,18 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, + bpi_num_labels = bgp_path_info_num_labels(bpi); + + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, + BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, - bpi ? bpi->uptime : monotime(NULL)); + bpi ? bpi->uptime : monotime(NULL), + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); written = true; } - if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_PREPOLICY)) { struct bgp_adj_in *adjin; for (adjin = bn ? bn->adj_in : NULL; adjin; @@ -1206,9 +1453,10 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) if (adjin->peer == peer) break; } - bmp_monitor(bmp, peer, 0, &bqe->p, prd, - adjin ? adjin->attr : NULL, afi, safi, - adjin ? adjin->uptime : monotime(NULL)); + /* TODO: set label here when adjin supports labels */ + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, + &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, + adjin ? adjin->uptime : monotime(NULL), NULL, 0); written = true; } @@ -1235,6 +1483,8 @@ static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr) break; if (bmp_wrqueue(bmp, pullwr)) break; + if (bmp_wrqueue_locrib(bmp, pullwr)) + break; if (bmp_wrsync(bmp, pullwr)) break; break; @@ -1253,16 +1503,17 @@ static void bmp_wrerr(struct bmp *bmp, struct pullwr *pullwr, bool eof) bmp_free(bmp); } -static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, - safi_t safi, struct bgp_dest *bn, struct peer *peer) +static struct bmp_queue_entry * +bmp_process_one(struct bmp_targets *bt, struct bmp_qhash_head *updhash, + struct bmp_qlist_head *updlist, struct bgp *bgp, afi_t afi, + safi_t safi, struct bgp_dest *bn, struct peer *peer) { - struct bmp *bmp; struct bmp_queue_entry *bqe, bqeref; size_t refcount; refcount = bmp_session_count(&bt->sessions); if (refcount == 0) - return; + return NULL; memset(&bqeref, 0, sizeof(bqeref)); prefix_copy(&bqeref.p, bgp_dest_get_prefix(bn)); @@ -1275,26 +1526,28 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, prefix_copy(&bqeref.rd, (struct prefix_rd *)bgp_dest_get_prefix(bn->pdest)); - bqe = bmp_qhash_find(&bt->updhash, &bqeref); + bqe = bmp_qhash_find(updhash, &bqeref); if (bqe) { if (bqe->refcount >= refcount) /* nothing to do here */ - return; + return NULL; - bmp_qlist_del(&bt->updlist, bqe); + bmp_qlist_del(updlist, bqe); } else { bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe)); memcpy(bqe, &bqeref, sizeof(*bqe)); - bmp_qhash_add(&bt->updhash, bqe); + bmp_qhash_add(updhash, bqe); } bqe->refcount = refcount; - bmp_qlist_add_tail(&bt->updlist, bqe); + bmp_qlist_add_tail(updlist, bqe); - frr_each (bmp_session, &bt->sessions, bmp) - if (!bmp->queuepos) - bmp->queuepos = bqe; + return bqe; + + /* need to update correct queue pos for all sessions of the target after + * a call to this function + */ } static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi, @@ -1316,12 +1569,26 @@ static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi, return 0; frr_each(bmp_targets, &bmpbgp->targets, bt) { - if (!bt->afimon[afi][safi]) + /* check if any monitoring is enabled (ignoring loc-rib since it + * uses another hook & queue + */ + if (!CHECK_FLAG(bt->afimon[afi][safi], ~BMP_MON_LOC_RIB)) continue; - bmp_process_one(bt, bgp, afi, safi, bn, peer); + struct bmp_queue_entry *last_item = + bmp_process_one(bt, &bt->updhash, &bt->updlist, bgp, + afi, safi, bn, peer); + + /* if bmp_process_one returns NULL + * we don't have anything to do next + */ + if (!last_item) + continue; frr_each(bmp_session, &bt->sessions, bmp) { + if (!bmp->queuepos) + bmp->queuepos = last_item; + pullwr_bump(bmp->pullwr); } } @@ -1337,6 +1604,15 @@ static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type, (*cnt)++; } +static void bmp_stat_put_u64(struct stream *s, size_t *cnt, uint16_t type, + uint64_t value) +{ + stream_putw(s, type); + stream_putw(s, 8); + stream_putq(s, value); + (*cnt)++; +} + static void bmp_stats(struct event *thread) { struct bmp_targets *bt = EVENT_ARG(thread); @@ -1360,7 +1636,8 @@ static void bmp_stats(struct event *thread) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT); - bmp_per_peer_hdr(s, peer, 0, &tv); + bmp_per_peer_hdr(s, bt->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); count_pos = stream_get_endp(s); stream_putl(s, 0); @@ -1377,8 +1654,13 @@ static void bmp_stats(struct event *thread) peer->stat_pfx_dup_withdraw); bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW, peer->stat_upd_7606); - bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID, - peer->stat_pfx_nh_invalid); + if (bt->stats_send_experimental) + bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID, + peer->stat_pfx_nh_invalid); + bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_ADJ_RIB_IN, + peer->stat_pfx_adj_rib_in); + bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_LOC_RIB, + peer->stat_pfx_loc_rib); stream_putl_at(s, count_pos, count); @@ -1530,6 +1812,9 @@ static void bmp_close(struct bmp *bmp) while ((bqe = bmp_pull(bmp))) if (!bqe->refcount) XFREE(MTYPE_BMP_QUEUE, bqe); + while ((bqe = bmp_pull_locrib(bmp))) + if (!bqe->refcount) + XFREE(MTYPE_BMP_QUEUE, bqe); EVENT_OFF(bmp->t_read); pullwr_del(bmp->pullwr); @@ -1630,9 +1915,12 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name) bt->name = XSTRDUP(MTYPE_BMP_TARGETSNAME, name); bt->bgp = bgp; bt->bmpbgp = bmp_bgp_get(bgp); + bt->stats_send_experimental = true; bmp_session_init(&bt->sessions); bmp_qhash_init(&bt->updhash); bmp_qlist_init(&bt->updlist); + bmp_qhash_init(&bt->locupdhash); + bmp_qlist_init(&bt->locupdlist); bmp_actives_init(&bt->actives); bmp_listeners_init(&bt->listeners); @@ -1663,6 +1951,8 @@ static void bmp_targets_put(struct bmp_targets *bt) bmp_actives_fini(&bt->actives); bmp_qhash_fini(&bt->updhash); bmp_qlist_fini(&bt->updlist); + bmp_qhash_fini(&bt->locupdhash); + bmp_qlist_fini(&bt->locupdlist); XFREE(MTYPE_BMP_ACLNAME, bt->acl_name); XFREE(MTYPE_BMP_ACLNAME, bt->acl6_name); @@ -2206,21 +2496,32 @@ DEFPY(bmp_stats_cfg, return CMD_SUCCESS; } -DEFPY(bmp_monitor_cfg, - bmp_monitor_cmd, - "[no] bmp monitor $policy", +DEFPY(bmp_stats_send_experimental, + bmp_stats_send_experimental_cmd, + "[no] bmp stats send-experimental", NO_STR BMP_STR - "Send BMP route monitoring messages\n" - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR + "Send BMP statistics messages\n" + "Send experimental BMP stats [65531-65534]\n") +{ + VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt); + + bt->stats_send_experimental = !no; + + return CMD_SUCCESS; +} + +#define BMP_POLICY_IS_LOCRIB(str) ((str)[0] == 'l') /* __l__oc-rib */ +#define BMP_POLICY_IS_PRE(str) ((str)[1] == 'r') /* p__r__e-policy */ + +DEFPY(bmp_monitor_cfg, bmp_monitor_cmd, + "[no] bmp monitor $policy", + NO_STR BMP_STR + "Send BMP route monitoring messages\n" BGP_AF_STR BGP_AF_STR BGP_AF_STR + BGP_AF_STR BGP_AF_STR BGP_AF_STR BGP_AF_STR "Send state before policy and filter processing\n" - "Send state with policy and filters applied\n") + "Send state with policy and filters applied\n" + "Send state after decision process is applied\n") { int index = 0; uint8_t flag, prev; @@ -2233,7 +2534,9 @@ DEFPY(bmp_monitor_cfg, argv_find_and_parse_afi(argv, argc, &index, &afi); argv_find_and_parse_safi(argv, argc, &index, &safi); - if (policy[1] == 'r') + if (BMP_POLICY_IS_LOCRIB(policy)) + flag = BMP_MON_LOC_RIB; + else if (BMP_POLICY_IS_PRE(policy)) flag = BMP_MON_PREPOLICY; else flag = BMP_MON_POSTPOLICY; @@ -2364,23 +2667,31 @@ DEFPY(show_bmp, safi_t safi; FOREACH_AFI_SAFI (afi, safi) { - const char *str = NULL; - - switch (bt->afimon[afi][safi]) { - case BMP_MON_PREPOLICY: - str = "pre-policy"; - break; - case BMP_MON_POSTPOLICY: - str = "post-policy"; - break; - case BMP_MON_PREPOLICY | BMP_MON_POSTPOLICY: - str = "pre-policy and post-policy"; - break; - } - if (!str) + + uint8_t afimon_flag = bt->afimon[afi][safi]; + + if (!afimon_flag) continue; - vty_out(vty, " Route Monitoring %s %s %s\n", - afi2str(afi), safi2str(safi), str); + + const char *pre_str = + CHECK_FLAG(afimon_flag, + BMP_MON_PREPOLICY) + ? "pre-policy " + : ""; + const char *post_str = + CHECK_FLAG(afimon_flag, + BMP_MON_POSTPOLICY) + ? "post-policy " + : ""; + const char *locrib_str = + CHECK_FLAG(afimon_flag, BMP_MON_LOC_RIB) + ? "loc-rib" + : ""; + + vty_out(vty, + " Route Monitoring %s %s %s%s%s\n", + afi2str(afi), safi2str(safi), pre_str, + post_str, locrib_str); } vty_out(vty, " Listeners:\n"); @@ -2492,6 +2803,9 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) if (bt->acl_name) vty_out(vty, " ip access-list %s\n", bt->acl_name); + if (!bt->stats_send_experimental) + vty_out(vty, " no bmp stats send-experimental\n"); + if (bt->stat_msec) vty_out(vty, " bmp stats interval %d\n", bt->stat_msec); @@ -2500,13 +2814,18 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) vty_out(vty, " bmp mirror\n"); FOREACH_AFI_SAFI (afi, safi) { - if (bt->afimon[afi][safi] & BMP_MON_PREPOLICY) + if (CHECK_FLAG(bt->afimon[afi][safi], + BMP_MON_PREPOLICY)) vty_out(vty, " bmp monitor %s %s pre-policy\n", afi2str_lower(afi), safi2str(safi)); - if (bt->afimon[afi][safi] & BMP_MON_POSTPOLICY) + if (CHECK_FLAG(bt->afimon[afi][safi], + BMP_MON_POSTPOLICY)) vty_out(vty, " bmp monitor %s %s post-policy\n", afi2str_lower(afi), safi2str(safi)); + if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) + vty_out(vty, " bmp monitor %s %s loc-rib\n", + afi2str_lower(afi), safi2str(safi)); } frr_each (bmp_listeners, &bt->listeners, bl) vty_out(vty, " \n bmp listener %pSU port %d\n", @@ -2542,6 +2861,7 @@ static int bgp_bmp_init(struct event_loop *tm) install_element(BMP_NODE, &no_bmp_listener_cmd); install_element(BMP_NODE, &bmp_connect_cmd); install_element(BMP_NODE, &bmp_acl_cmd); + install_element(BMP_NODE, &bmp_stats_send_experimental_cmd); install_element(BMP_NODE, &bmp_stats_cmd); install_element(BMP_NODE, &bmp_monitor_cmd); install_element(BMP_NODE, &bmp_mirror_cmd); @@ -2555,6 +2875,82 @@ static int bgp_bmp_init(struct event_loop *tm) return 0; } +static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi, + struct bgp_dest *bn, + struct bgp_path_info *old_route, + struct bgp_path_info *new_route) +{ + bool is_locribmon_enabled = false; + bool is_withdraw = old_route && !new_route; + struct bgp_path_info *updated_route = + is_withdraw ? old_route : new_route; + + + /* this should never happen */ + if (!updated_route) { + zlog_warn("%s: no updated route found!", __func__); + return 0; + } + + struct bmp_bgp *bmpbgp = bmp_bgp_get(bgp); + struct peer *peer = updated_route->peer; + struct bmp_targets *bt; + struct bmp *bmp; + + frr_each (bmp_targets, &bmpbgp->targets, bt) { + if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) { + is_locribmon_enabled = true; + break; + } + } + + if (!is_locribmon_enabled) + return 0; + + /* route is not installed in locrib anymore and rib uptime was saved */ + if (old_route && old_route->extra) + bgp_path_info_extra_get(old_route)->bgp_rib_uptime = + (time_t)(-1L); + + /* route is installed in locrib from now on so + * save rib uptime in bgp_path_info_extra + */ + if (new_route) + bgp_path_info_extra_get(new_route)->bgp_rib_uptime = + monotime(NULL); + + frr_each (bmp_targets, &bmpbgp->targets, bt) { + if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) { + + struct bmp_queue_entry *last_item = bmp_process_one( + bt, &bt->locupdhash, &bt->locupdlist, bgp, afi, + safi, bn, peer); + + /* if bmp_process_one returns NULL + * we don't have anything to do next + */ + if (!last_item) + continue; + + frr_each (bmp_session, &bt->sessions, bmp) { + if (!bmp->locrib_queuepos) + bmp->locrib_queuepos = last_item; + + pullwr_bump(bmp->pullwr); + }; + } + }; + + return 0; +} + +static int bgp_bmp_early_fini(void) +{ + resolver_terminate(); + + return 0; +} + static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); @@ -2565,6 +2961,8 @@ static int bgp_bmp_module_init(void) hook_register(bgp_inst_config_write, bmp_config_write); hook_register(bgp_inst_delete, bmp_bgp_del); hook_register(frr_late_init, bgp_bmp_init); + hook_register(bgp_route_update, bmp_route_update); + hook_register(frr_early_fini, bgp_bmp_early_fini); return 0; } diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index ab7463fadcad..33247c402504 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -124,6 +124,7 @@ struct bmp { * ahead we need to make sure that refcount is decremented. Also, on * disconnects we need to walk the queue and drop our reference. */ + struct bmp_queue_entry *locrib_queuepos; struct bmp_queue_entry *queuepos; struct bmp_mirrorq *mirrorpos; bool mirror_lost; @@ -215,12 +216,14 @@ struct bmp_targets { int stat_msec; /* only supporting: - * - IPv4 / unicast & multicast - * - IPv6 / unicast & multicast + * - IPv4 / unicast & multicast & VPN + * - IPv6 / unicast & multicast & VPN * - L2VPN / EVPN */ #define BMP_MON_PREPOLICY (1 << 0) #define BMP_MON_POSTPOLICY (1 << 1) +#define BMP_MON_LOC_RIB (1 << 2) + uint8_t afimon[AFI_MAX][SAFI_MAX]; bool mirror; @@ -232,8 +235,13 @@ struct bmp_targets { struct bmp_qhash_head updhash; struct bmp_qlist_head updlist; + struct bmp_qhash_head locupdhash; + struct bmp_qlist_head locupdlist; + uint64_t cnt_accept, cnt_aclrefused; + bool stats_send_experimental; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bmp_targets); diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index 8e27d9769f81..1d5034efd258 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -4,6 +4,7 @@ */ #include +#include #include "zebra.h" #include "stream.h" diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 3fd246397fd8..153cbd6e5015 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -128,6 +128,7 @@ static void community_entry_free(struct community_entry *entry) XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) bgp_regex_free(entry->reg); + break; default: break; } @@ -735,6 +736,27 @@ bool community_list_exact_match(struct community *com, return false; } +bool community_list_any_match(struct community *com, struct community_list *list) +{ + struct community_entry *entry; + uint32_t val; + int i; + + for (i = 0; i < com->size; i++) { + val = community_val_get(com, i); + + for (entry = list->head; entry; entry = entry->next) { + if (entry->style == COMMUNITY_LIST_STANDARD && + community_include(entry->u.com, val)) + return entry->direct == COMMUNITY_PERMIT; + if ((entry->style == COMMUNITY_LIST_EXPANDED) && + community_regexp_include(entry->reg, com, i)) + return entry->direct == COMMUNITY_PERMIT; + } + } + return false; +} + /* Delete all permitted communities in the list from com. */ struct community *community_list_match_delete(struct community *com, struct community_list *list) @@ -882,9 +904,9 @@ int community_list_set(struct community_list_handler *ch, const char *name, } /* Unset community-list */ -int community_list_unset(struct community_list_handler *ch, const char *name, - const char *str, const char *seq, int direct, - int style) +void community_list_unset(struct community_list_handler *ch, const char *name, + const char *str, const char *seq, int direct, + int style) { struct community_list_master *cm = NULL; struct community_entry *entry = NULL; @@ -894,14 +916,14 @@ int community_list_unset(struct community_list_handler *ch, const char *name, /* Lookup community list. */ list = community_list_lookup(ch, name, 0, COMMUNITY_LIST_MASTER); if (list == NULL) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; cm = community_list_master_lookup(ch, COMMUNITY_LIST_MASTER); /* Delete all of entry belongs to this community-list. */ if (!str) { community_list_delete(cm, list); route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED); - return 0; + return; } if (style == COMMUNITY_LIST_STANDARD) @@ -914,12 +936,32 @@ int community_list_unset(struct community_list_handler *ch, const char *name, entry = community_list_entry_lookup(list, str, direct); if (!entry) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; community_list_entry_delete(cm, list, entry); route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED); +} - return 0; +bool lcommunity_list_any_match(struct lcommunity *lcom, + struct community_list *list) +{ + struct community_entry *entry; + uint8_t *ptr; + int i; + + for (i = 0; i < lcom->size; i++) { + ptr = lcom->val + (i * LCOMMUNITY_SIZE); + + for (entry = list->head; entry; entry = entry->next) { + if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) && + lcommunity_include(entry->u.lcom, ptr)) + return entry->direct == COMMUNITY_PERMIT; + if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED) && + lcommunity_regexp_include(entry->reg, lcom, i)) + return entry->direct == COMMUNITY_PERMIT; + } + } + return false; } /* Delete all permitted large communities in the list from com. */ @@ -1128,9 +1170,9 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name, /* Unset community-list. When str is NULL, delete all of community-list entry belongs to the specified name. */ -int lcommunity_list_unset(struct community_list_handler *ch, const char *name, - const char *str, const char *seq, int direct, - int style) +void lcommunity_list_unset(struct community_list_handler *ch, const char *name, + const char *str, const char *seq, int direct, + int style) { struct community_list_master *cm = NULL; struct community_entry *entry = NULL; @@ -1141,14 +1183,14 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name, /* Lookup community list. */ list = community_list_lookup(ch, name, 0, LARGE_COMMUNITY_LIST_MASTER); if (list == NULL) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; cm = community_list_master_lookup(ch, LARGE_COMMUNITY_LIST_MASTER); /* Delete all of entry belongs to this community-list. */ if (!str) { community_list_delete(cm, list); route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED); - return 0; + return; } if (style == LARGE_COMMUNITY_LIST_STANDARD) @@ -1157,7 +1199,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name, regex = bgp_regcomp(str); if (!lcom && !regex) - return COMMUNITY_LIST_ERR_MALFORMED_VAL; + return; if (lcom) entry = community_list_entry_lookup(list, lcom, direct); @@ -1170,12 +1212,10 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name, bgp_regex_free(regex); if (!entry) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; community_list_entry_delete(cm, list, entry); route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED); - - return 0; } /* Set extcommunity-list. */ @@ -1255,9 +1295,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name, * When str is NULL, delete all extcommunity-list entries belonging to the * specified name. */ -int extcommunity_list_unset(struct community_list_handler *ch, const char *name, - const char *str, const char *seq, int direct, - int style) +void extcommunity_list_unset(struct community_list_handler *ch, + const char *name, const char *str, const char *seq, + int direct, int style) { struct community_list_master *cm = NULL; struct community_entry *entry = NULL; @@ -1267,14 +1307,14 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name, /* Lookup extcommunity list. */ list = community_list_lookup(ch, name, 0, EXTCOMMUNITY_LIST_MASTER); if (list == NULL) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; cm = community_list_master_lookup(ch, EXTCOMMUNITY_LIST_MASTER); /* Delete all of entry belongs to this extcommunity-list. */ if (!str) { community_list_delete(cm, list); route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED); - return 0; + return; } if (style == EXTCOMMUNITY_LIST_STANDARD) @@ -1287,12 +1327,10 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name, entry = community_list_entry_lookup(list, str, direct); if (!entry) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; community_list_entry_delete(cm, list, entry); route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED); - - return 0; } /* Initializa community-list. Return community-list handler. */ diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 251169876da6..29bd880c937e 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -109,11 +109,9 @@ struct community_list_handler { }; /* Error code of community-list. */ -#define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1 -#define COMMUNITY_LIST_ERR_MALFORMED_VAL -2 -#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3 -#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4 - +#define COMMUNITY_LIST_ERR_MALFORMED_VAL -1 +#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -2 +#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -3 /* Handler. */ extern struct community_list_handler *bgp_clist; @@ -124,22 +122,22 @@ extern void community_list_terminate(struct community_list_handler *ch); extern int community_list_set(struct community_list_handler *ch, const char *name, const char *str, const char *seq, int direct, int style); -extern int community_list_unset(struct community_list_handler *ch, - const char *name, const char *str, - const char *seq, int direct, int style); +extern void community_list_unset(struct community_list_handler *ch, + const char *name, const char *str, + const char *seq, int direct, int style); extern int extcommunity_list_set(struct community_list_handler *ch, const char *name, const char *str, const char *seq, int direct, int style); -extern int extcommunity_list_unset(struct community_list_handler *ch, - const char *name, const char *str, - const char *seq, int direct, int style); +extern void extcommunity_list_unset(struct community_list_handler *ch, + const char *name, const char *str, + const char *seq, int direct, int style); extern int lcommunity_list_set(struct community_list_handler *ch, const char *name, const char *str, const char *seq, int direct, int style); extern bool lcommunity_list_valid(const char *community, int style); -extern int lcommunity_list_unset(struct community_list_handler *ch, - const char *name, const char *str, - const char *seq, int direct, int style); +extern void lcommunity_list_unset(struct community_list_handler *ch, + const char *name, const char *str, + const char *seq, int direct, int style); extern struct community_list_master * community_list_master_lookup(struct community_list_handler *ch, int master); @@ -158,8 +156,12 @@ extern bool community_list_exact_match(struct community *com, struct community_list *list); extern bool lcommunity_list_exact_match(struct lcommunity *lcom, struct community_list *list); +extern bool community_list_any_match(struct community *com, + struct community_list *list); extern struct community * community_list_match_delete(struct community *com, struct community_list *list); +extern bool lcommunity_list_any_match(struct lcommunity *lcom, + struct community_list *list); extern struct lcommunity * lcommunity_list_match_delete(struct lcommunity *lcom, struct community_list *list); diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index b30052d95a73..2d96b444b6c5 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -90,6 +90,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); + SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES); for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { dest_p = bgp_dest_get_prefix(dest); assert(dest_p); @@ -121,8 +122,9 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, if (update_type == UPDATE_TYPE_ADVERTISE && subgroup_announce_check(dest, pi, subgrp, dest_p, &attr, &advmap_attr)) { - bgp_adj_out_set_subgroup(dest, subgrp, &attr, - pi); + if (!bgp_adj_out_set_subgroup(dest, subgrp, + &attr, pi)) + bgp_attr_flush(&attr); } else { /* If default originate is enabled for * the peer, do not send explicit @@ -140,8 +142,9 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, bgp_addpath_id_for_peer( peer, afi, safi, &pi->tx_addpath)); + + bgp_attr_flush(&advmap_attr); } - bgp_attr_flush(&advmap_attr); } } UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 80425ebe7adb..339bfae56d4c 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -22,19 +22,76 @@ #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" -/* Global variable to access damping configuration */ -static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; +static void bgp_reuselist_add(struct reuselist *list, struct bgp_damp_info *info) +{ + assert(info); + SLIST_INSERT_HEAD(list, info, entry); +} + +static void bgp_reuselist_del(struct reuselist *list, struct bgp_damp_info *info) +{ + assert(info); + SLIST_REMOVE(list, info, bgp_damp_info, entry); +} -/* Utility macro to add and delete BGP dampening information to no - used list. */ -#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list) -#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list) +static void bgp_reuselist_switch(struct reuselist *source, + struct bgp_damp_info *info, + struct reuselist *target) +{ + assert(source && target && info); + SLIST_REMOVE(source, info, bgp_damp_info, entry); + SLIST_INSERT_HEAD(target, info, entry); +} + +static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi, + struct reuselist *list) +{ + assert(bdi && bdi->config); + if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) + bgp_reuselist_del(&bdi->config->no_reuse_list, bdi); + else + bgp_reuselist_del(list ? list + : &bdi->config->reuse_list[bdi->index], + bdi); + bdi->config = NULL; +} + +static void bgp_damp_info_claim(struct bgp_damp_info *bdi, + struct bgp_damp_config *bdc) +{ + assert(bdc && bdi); + if (bdi->config == NULL) { + bdi->config = bdc; + return; + } + bgp_damp_info_unclaim(bdi, NULL); + bdi->config = bdc; + bdi->afi = bdc->afi; + bdi->safi = bdc->safi; +} + +struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi, + afi_t afi, safi_t safi) +{ + if (!pi) + return NULL; + if (CHECK_FLAG(pi->peer->af_flags[afi][safi], + PEER_FLAG_CONFIG_DAMPENING)) + return &pi->peer->damp[afi][safi]; + if (peer_group_active(pi->peer)) + if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi], + PEER_FLAG_CONFIG_DAMPENING)) + return &pi->peer->group->conf->damp[afi][safi]; + if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + return &pi->peer->bgp->damp[afi][safi]; + return NULL; +} /* Calculate reuse list index by penalty value. */ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc) { unsigned int i; - int index; + unsigned int index; /* * reuse_limit can't be zero, this is for Coverity @@ -57,27 +114,28 @@ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc) static void bgp_reuse_list_add(struct bgp_damp_info *bdi, struct bgp_damp_config *bdc) { - int index; - - index = bdi->index = bgp_reuse_index(bdi->penalty, bdc); - - bdi->prev = NULL; - bdi->next = bdc->reuse_list[index]; - if (bdc->reuse_list[index]) - bdc->reuse_list[index]->prev = bdi; - bdc->reuse_list[index] = bdi; + bgp_damp_info_claim(bdi, bdc); + bdi->index = bgp_reuse_index(bdi->penalty, bdc); + bgp_reuselist_add(&bdc->reuse_list[bdi->index], bdi); } /* Delete BGP dampening information from reuse list. */ -static void bgp_reuse_list_delete(struct bgp_damp_info *bdi, +static void bgp_reuse_list_delete(struct bgp_damp_info *bdi) +{ + bgp_damp_info_unclaim(bdi, NULL); +} + +static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi, struct bgp_damp_config *bdc) { - if (bdi->next) - bdi->next->prev = bdi->prev; - if (bdi->prev) - bdi->prev->next = bdi->next; - else - bdc->reuse_list[bdi->index] = bdi->next; + bgp_damp_info_claim(bdi, bdc); + bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX; + bgp_reuselist_add(&bdc->no_reuse_list, bdi); +} + +static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi) +{ + bgp_damp_info_unclaim(bdi, NULL); } /* Return decayed penalty value. */ @@ -100,10 +158,10 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc) is evaluated. RFC2439 Section 4.8.7. */ static void bgp_reuse_timer(struct event *t) { - struct bgp_damp_info *bdi; - struct bgp_damp_info *next; + struct bgp_damp_info *bdi, *bdi_next; + struct reuselist plist; + struct bgp *bgp; time_t t_now, t_diff; - struct bgp_damp_config *bdc = EVENT_ARG(t); bdc->t_reuse = NULL; @@ -112,20 +170,20 @@ static void bgp_reuse_timer(struct event *t) t_now = monotime(NULL); - /* 1. save a pointer to the current zeroth queue head and zero the - list head entry. */ - bdi = bdc->reuse_list[bdc->reuse_offset]; - bdc->reuse_list[bdc->reuse_offset] = NULL; + /* 1. save a pointer to the current queue head and zero the list head + * list head entry. */ + assert(bdc->reuse_offset < bdc->reuse_list_size); + plist = bdc->reuse_list[bdc->reuse_offset]; + SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]); /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby rotating the circular queue of list-heads. */ bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size; + assert(bdc->reuse_offset < bdc->reuse_list_size); /* 3. if ( the saved list head pointer is non-empty ) */ - for (; bdi; bdi = next) { - struct bgp *bgp = bdi->path->peer->bgp; - - next = bdi->next; + SLIST_FOREACH_SAFE (bdi, &plist, entry, bdi_next) { + bgp = bdi->path->peer->bgp; /* Set t-diff = t-now - t-updated. */ t_diff = t_now - bdi->t_updated; @@ -150,19 +208,27 @@ static void bgp_reuse_timer(struct event *t) bgp_aggregate_increment( bgp, bgp_dest_get_prefix(bdi->dest), bdi->path, bdi->afi, bdi->safi); - bgp_process(bgp, bdi->dest, bdi->afi, + bgp_process(bgp, bdi->dest, bdi->path, bdi->afi, bdi->safi); } - if (bdi->penalty <= bdc->reuse_limit / 2.0) - bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi); - else - BGP_DAMP_LIST_ADD(bdc, bdi); - } else + if (bdi->penalty <= bdc->reuse_limit / 2.0) { + bgp_damp_info_free(bdi, &plist, 1); + } else { + bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX; + bgp_reuselist_switch(&plist, bdi, + &bdc->no_reuse_list); + } + } else { /* Re-insert into another list (See RFC2439 Section * 4.8.6). */ - bgp_reuse_list_add(bdi, bdc); + bdi->index = bgp_reuse_index(bdi->penalty, bdc); + bgp_reuselist_switch(&plist, bdi, + &bdc->reuse_list[bdi->index]); + } } + + assert(SLIST_EMPTY(&plist)); } /* A route becomes unreachable (RFC2439 Section 4.8.2). */ @@ -172,10 +238,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, time_t t_now; struct bgp_damp_info *bdi = NULL; unsigned int last_penalty = 0; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; - t_now = monotime(NULL); + bdc = get_active_bdc_from_pi(path, afi, safi); + if (!bdc) + return BGP_DAMP_USED; + t_now = monotime(NULL); /* Processing Unreachable Messages. */ if (path->extra) bdi = path->extra->damp_info; @@ -197,12 +266,20 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, bdi->flap = 1; bdi->start_time = t_now; bdi->suppress_time = 0; - bdi->index = -1; + bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX; bdi->afi = afi; bdi->safi = safi; (bgp_path_info_extra_get(path))->damp_info = bdi; - BGP_DAMP_LIST_ADD(bdc, bdi); + bgp_no_reuse_list_add(bdi, bdc); } else { + if (bdi->config != bdc) { + bgp_damp_info_claim(bdi, bdc); + if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) + bgp_reuselist_add(&bdc->no_reuse_list, bdi); + else + bgp_reuselist_add(&bdc->reuse_list[bdi->index], + bdi); + } last_penalty = bdi->penalty; /* 1. Set t-diff = t-now - t-updated. */ @@ -228,8 +305,8 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, /* Remove the route from a reuse list if it is on one. */ if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) { /* If decay rate isn't equal to 0, reinsert brn. */ - if (bdi->penalty != last_penalty && bdi->index >= 0) { - bgp_reuse_list_delete(bdi, bdc); + if (bdi->penalty != last_penalty) { + bgp_reuse_list_delete(bdi); bgp_reuse_list_add(bdi, bdc); } return BGP_DAMP_SUPPRESSED; @@ -240,10 +317,9 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, if (bdi->penalty >= bdc->suppress_value) { bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED); bdi->suppress_time = t_now; - BGP_DAMP_LIST_DEL(bdc, bdi); + bgp_no_reuse_list_delete(bdi); bgp_reuse_list_add(bdi, bdc); } - return BGP_DAMP_USED; } @@ -253,7 +329,10 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, time_t t_now; struct bgp_damp_info *bdi; int status; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; + + bdc = get_active_bdc_from_pi(path, afi, safi); + assert(bdc); if (!path->extra || !((bdi = path->extra->damp_info))) return BGP_DAMP_USED; @@ -271,8 +350,8 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED) && (bdi->penalty < bdc->reuse_limit)) { bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED); - bgp_reuse_list_delete(bdi, bdc); - BGP_DAMP_LIST_ADD(bdc, bdi); + bgp_reuse_list_delete(bdi); + bgp_no_reuse_list_add(bdi, bdc); bdi->suppress_time = 0; status = BGP_DAMP_USED; } else @@ -281,33 +360,32 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, if (bdi->penalty > bdc->reuse_limit / 2.0) bdi->t_updated = t_now; else - bgp_damp_info_free(bdi, 0, afi, safi); + bgp_damp_info_free(bdi, NULL, 0); return status; } -void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi, - safi_t safi) +void bgp_damp_info_free(struct bgp_damp_info *bdi, struct reuselist *list, + int withdraw) { - struct bgp_path_info *path; - struct bgp_damp_config *bdc = &damp[afi][safi]; - - if (!bdi) - return; - - path = bdi->path; - path->extra->damp_info = NULL; - - if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) - bgp_reuse_list_delete(bdi, bdc); - else - BGP_DAMP_LIST_DEL(bdc, bdi); - - bgp_path_info_unset_flag(bdi->dest, path, - BGP_PATH_HISTORY | BGP_PATH_DAMPED); - - if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) - bgp_path_info_delete(bdi->dest, path); + assert(bdi); + + afi_t afi = bdi->afi; + safi_t safi = bdi->safi; + struct bgp_path_info *bpi = bdi->path; + struct bgp_dest *dest = bdi->dest; + struct bgp *bgp = bpi->peer->bgp; + const struct prefix *p = bgp_dest_get_prefix(bdi->dest); + + bgp_damp_info_unclaim(bdi, list); + + bpi->extra->damp_info = NULL; + bgp_path_info_unset_flag(dest, bpi, BGP_PATH_HISTORY | BGP_PATH_DAMPED); + if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) { + bgp_aggregate_decrement(bgp, p, bpi, afi, SAFI_UNICAST); + bgp_path_info_delete(dest, bpi); + bgp_process(bgp, dest, bpi, afi, safi); + } XFREE(MTYPE_BGP_DAMP_INFO, bdi); } @@ -353,8 +431,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse, bdc->reuse_list = XCALLOC(MTYPE_BGP_DAMP_ARRAY, - bdc->reuse_list_size * sizeof(struct bgp_reuse_node *)); - + bdc->reuse_list_size * sizeof(struct reuselist)); /* Reuse-array computations */ bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY, sizeof(int) * bdc->reuse_index_size); @@ -381,7 +458,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse, int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, unsigned int reuse, unsigned int suppress, time_t max) { - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc = &bgp->damp[afi][safi]; if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { if (bdc->half_life == half && bdc->reuse_limit == reuse @@ -393,6 +470,8 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); bgp_damp_parameter_set(half, reuse, suppress, max, bdc); + bdc->afi = afi; + bdc->safi = safi; /* Register reuse timer. */ event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE, @@ -401,8 +480,34 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, return 0; } -static void bgp_damp_config_clean(struct bgp_damp_config *bdc) +/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */ +void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc, + afi_t afi, safi_t safi) { + struct bgp_damp_info *bdi; + struct reuselist *list; + unsigned int i; + + bdc->reuse_offset = 0; + for (i = 0; i < bdc->reuse_list_size; ++i) { + list = &bdc->reuse_list[i]; + while ((bdi = SLIST_FIRST(list)) != NULL) { + if (bdi->lastrecord == BGP_RECORD_UPDATE) { + bgp_aggregate_increment(bgp, + bgp_dest_get_prefix( + bdi->dest), + bdi->path, bdi->afi, + bdi->safi); + bgp_process(bgp, bdi->dest, bdi->path, bdi->afi, + bdi->safi); + } + bgp_damp_info_free(bdi, list, 1); + } + } + + while ((bdi = SLIST_FIRST(&bdc->no_reuse_list)) != NULL) + bgp_damp_info_free(bdi, &bdc->no_reuse_list, 1); + /* Free decay array */ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array); bdc->decay_array_size = 0; @@ -411,41 +516,25 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc) XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index); bdc->reuse_index_size = 0; - /* Free reuse list array. */ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list); bdc->reuse_list_size = 0; -} - -/* Clean all the bgp_damp_info stored in reuse_list. */ -void bgp_damp_info_clean(afi_t afi, safi_t safi) -{ - unsigned int i; - struct bgp_damp_info *bdi, *next; - struct bgp_damp_config *bdc = &damp[afi][safi]; - - bdc->reuse_offset = 0; - for (i = 0; i < bdc->reuse_list_size; i++) { - if (!bdc->reuse_list[i]) - continue; - - for (bdi = bdc->reuse_list[i]; bdi; bdi = next) { - next = bdi->next; - bgp_damp_info_free(bdi, 1, afi, safi); - } - bdc->reuse_list[i] = NULL; - } - - for (bdi = bdc->no_reuse_list; bdi; bdi = next) { - next = bdi->next; - bgp_damp_info_free(bdi, 1, afi, safi); - } - bdc->no_reuse_list = NULL; + EVENT_OFF(bdc->t_reuse); } +/* Disable route flap dampening for a bgp instance. + * + * Please note that this function also gets used to free memory when deleting a + * bgp instance. + */ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi) { - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; + + bdc = &bgp->damp[afi][safi]; + if (!bdc) + return 0; + /* If it wasn't enabled, there's nothing to do. */ if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) return 0; @@ -454,54 +543,51 @@ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bdc->t_reuse); /* Clean BGP dampening information. */ - bgp_damp_info_clean(afi, safi); - - /* Clear configuration */ - bgp_damp_config_clean(bdc); + bgp_damp_info_clean(bgp, bdc, afi, safi); UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); + return 0; } -void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi) +void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { - if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60 - && damp[afi][safi].reuse_limit == DEFAULT_REUSE - && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS - && damp[afi][safi].max_suppress_time - == damp[afi][safi].half_life * 4) + struct bgp_damp_config *bdc; + + bdc = &bgp->damp[afi][safi]; + if (bdc->half_life == DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) vty_out(vty, " bgp dampening\n"); - else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60 - && damp[afi][safi].reuse_limit == DEFAULT_REUSE - && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS - && damp[afi][safi].max_suppress_time - == damp[afi][safi].half_life * 4) - vty_out(vty, " bgp dampening %lld\n", - damp[afi][safi].half_life / 60LL); + else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) + vty_out(vty, " bgp dampening %lld\n", bdc->half_life / 60LL); else vty_out(vty, " bgp dampening %lld %d %d %lld\n", - damp[afi][safi].half_life / 60LL, - damp[afi][safi].reuse_limit, - damp[afi][safi].suppress_value, - damp[afi][safi].max_suppress_time / 60LL); + bdc->half_life / 60LL, bdc->reuse_limit, + bdc->suppress_value, bdc->max_suppress_time / 60LL); } -static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, - size_t len, afi_t afi, safi_t safi, - bool use_json, json_object *json) +static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc, + unsigned int penalty, char *buf, + size_t len, bool use_json, + json_object *json) { time_t reuse_time = 0; struct tm tm; int time_store = 0; - if (penalty > damp[afi][safi].reuse_limit) { - reuse_time = (int)(DELTA_T - * ((log((double)damp[afi][safi].reuse_limit - / penalty)) - / (log(damp[afi][safi].decay_array[1])))); + if (penalty > bdc->reuse_limit) { + reuse_time = (int)(DELTA_T * + ((log((double)bdc->reuse_limit / penalty)) / + (log(bdc->decay_array[1])))); - if (reuse_time > damp[afi][safi].max_suppress_time) - reuse_time = damp[afi][safi].max_suppress_time; + if (reuse_time > bdc->max_suppress_time) + reuse_time = bdc->max_suppress_time; gmtime_r(&reuse_time, &tm); } else @@ -553,14 +639,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, return buf; } -void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, - safi_t safi, json_object *json_path) +void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp, + struct bgp_path_info *path, afi_t afi, safi_t safi, + json_object *json_path) { struct bgp_damp_info *bdi; time_t t_now, t_diff; char timebuf[BGP_UPTIME_LEN] = {}; int penalty; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc = &bgp->damp[afi][safi]; if (!path->extra) return; @@ -588,8 +675,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) - bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, - afi, safi, 1, json_path); + bgp_get_reuse_time(bdc, penalty, timebuf, + BGP_UPTIME_LEN, 1, json_path); } else { vty_out(vty, " Dampinfo: penalty %d, flapped %d times in %s", @@ -600,14 +687,15 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) vty_out(vty, ", reuse in %s", - bgp_get_reuse_time(penalty, timebuf, - BGP_UPTIME_LEN, afi, safi, 0, + bgp_get_reuse_time(bdc, penalty, timebuf, + BGP_UPTIME_LEN, 0, json_path)); vty_out(vty, "\n"); } } + const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, char *timebuf, size_t len, afi_t afi, safi_t safi, bool use_json, @@ -616,7 +704,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, struct bgp_damp_info *bdi; time_t t_now, t_diff; int penalty; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; + + bdc = get_active_bdc_from_pi(path, afi, safi); + if (!bdc) + return NULL; if (!path->extra) return NULL; @@ -636,15 +728,15 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, t_diff = t_now - bdi->t_updated; penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc); - return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json, - json); + return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json); } + static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty, afi_t afi, safi_t safi, bool use_json) { if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc = &bgp->damp[afi][safi]; if (use_json) { json_object *json = json_object_new_object(); @@ -687,7 +779,6 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); bgp = bgp_get_default(); - if (bgp == NULL) { vty_out(vty, "No BGP process is configured\n"); return CMD_WARNING; @@ -729,3 +820,130 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, } return CMD_SUCCESS; } + +void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, time_t half, + unsigned int reuse, unsigned int suppress, time_t max) +{ + struct bgp_damp_config *bdc; + + if (!peer) + return; + bdc = &peer->damp[afi][safi]; + if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) { + if (bdc->half_life == half && bdc->reuse_limit == reuse && + bdc->suppress_value == suppress && + bdc->max_suppress_time == max) + return; + bgp_peer_damp_disable(peer, afi, safi); + } + SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING); + bgp_damp_parameter_set(half, reuse, suppress, max, bdc); + bdc->afi = afi; + bdc->safi = safi; + event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE, + &bdc->t_reuse); +} + +/* Disable route flap dampening for a peer. + * + * Please note that this function also gets used to free memory when deleting a + * peer or peer group. + */ +void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_damp_config *bdc; + + if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) + return; + bdc = &peer->damp[afi][safi]; + if (!bdc) + return; + bgp_damp_info_clean(peer->bgp, bdc, afi, safi); + UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING); +} + +void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi, + safi_t safi) +{ + struct bgp_damp_config *bdc; + + bdc = &peer->damp[afi][safi]; + if (bdc->half_life == DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) + vty_out(vty, " neighbor %s dampening\n", peer->host); + else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) + vty_out(vty, " neighbor %s dampening %lld\n", peer->host, + bdc->half_life / 60LL); + else + vty_out(vty, " neighbor %s dampening %lld %d %d %lld\n", + peer->host, bdc->half_life / 60LL, bdc->reuse_limit, + bdc->suppress_value, bdc->max_suppress_time / 60LL); +} + +static void bgp_print_peer_dampening_parameters(struct vty *vty, + struct peer *peer, afi_t afi, + safi_t safi, bool use_json, + json_object *json) +{ + struct bgp_damp_config *bdc; + + if (!peer) + return; + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) { + bdc = &peer->damp[afi][safi]; + if (!bdc) + return; + if (use_json) { + json_object_int_add(json, "halfLifeSecs", + bdc->half_life); + json_object_int_add(json, "reusePenalty", + bdc->reuse_limit); + json_object_int_add(json, "suppressPenalty", + bdc->suppress_value); + json_object_int_add(json, "maxSuppressTimeSecs", + bdc->max_suppress_time); + json_object_int_add(json, "maxSuppressPenalty", + bdc->ceiling); + } else { + vty_out(vty, "Half-life time: %lld min\n", + (long long)bdc->half_life / 60); + vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit); + vty_out(vty, "Suppress penalty: %d\n", + bdc->suppress_value); + vty_out(vty, "Max suppress time: %lld min\n", + (long long)bdc->max_suppress_time / 60); + vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling); + vty_out(vty, "\n"); + } + } else if (!use_json) + vty_out(vty, "neighbor dampening not enabled for %s\n", + get_afi_safi_str(afi, safi, false)); +} + +void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi, bool use_json) +{ + json_object *json; + + if (use_json) { + json = json_object_new_object(); + json_object_string_add(json, "addressFamily", + get_afi_safi_str(afi, safi, false)); + bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true, + json); + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "\nFor address family: %s\n", + get_afi_safi_str(afi, safi, false)); + bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false, + NULL); + } +} diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h index 5708e6fd55d9..851c6f9e8548 100644 --- a/bgpd/bgp_damp.h +++ b/bgpd/bgp_damp.h @@ -10,11 +10,6 @@ /* Structure maintained on a per-route basis. */ struct bgp_damp_info { - /* Doubly linked list. This information must be linked to - reuse_list or no_reuse_list. */ - struct bgp_damp_info *next; - struct bgp_damp_info *prev; - /* Figure-of-merit. */ unsigned int penalty; @@ -30,6 +25,9 @@ struct bgp_damp_info { /* Time of route start to be suppressed. */ time_t suppress_time; + /* Back reference to associated dampening configuration. */ + struct bgp_damp_config *config; + /* Back reference to bgp_path_info. */ struct bgp_path_info *path; @@ -38,6 +36,8 @@ struct bgp_damp_info { /* Current index in the reuse_list. */ int index; +#define BGP_DAMP_NO_REUSE_LIST_INDEX \ + (-1) /* index for elements on no_reuse_list */ /* Last time message type. */ uint8_t lastrecord; @@ -46,8 +46,12 @@ struct bgp_damp_info { afi_t afi; safi_t safi; + + SLIST_ENTRY(bgp_damp_info) entry; }; +SLIST_HEAD(reuselist, bgp_damp_info); + /* Specified parameter set configuration. */ struct bgp_damp_config { /* Value over which routes suppressed. */ @@ -65,7 +69,6 @@ struct bgp_damp_config { /* Non-configurable parameters but fixed at implementation time. * To change this values, init_bgp_damp() should be modified. */ - time_t tmax; /* Max time previous instability retained */ unsigned int reuse_list_size; /* Number of reuse lists */ unsigned int reuse_index_size; /* Size of reuse index array */ @@ -75,8 +78,8 @@ struct bgp_damp_config { unsigned int ceiling; /* Max value a penalty can attain */ unsigned int decay_rate_per_tick; /* Calculated from half-life */ unsigned int decay_array_size; /* Calculated using config parameters */ - double scale_factor; unsigned int reuse_scale_factor; + double scale_factor; /* Decay array per-set based. */ double *decay_array; @@ -85,17 +88,17 @@ struct bgp_damp_config { int *reuse_index; /* Reuse list array per-set based. */ - struct bgp_damp_info **reuse_list; - int reuse_offset; + struct reuselist *reuse_list; + unsigned int reuse_offset; + safi_t safi; /* All dampening information which is not on reuse list. */ - struct bgp_damp_info *no_reuse_list; + struct reuselist no_reuse_list; /* Reuse timer thread per-set base. */ struct event *t_reuse; afi_t afi; - safi_t safi; }; #define BGP_DAMP_NONE 0 @@ -117,6 +120,8 @@ struct bgp_damp_config { #define REUSE_LIST_SIZE 256 #define REUSE_ARRAY_SIZE 1024 +extern struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi, + afi_t afi, safi_t safi); extern int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, unsigned int reuse, unsigned int suppress, time_t max); @@ -125,14 +130,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, afi_t afi, safi_t safi, int attr_change); extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, afi_t afi, safi_t saff); -extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw, - afi_t afi, safi_t safi); -extern void bgp_damp_info_clean(afi_t afi, safi_t safi); +extern void bgp_damp_info_free(struct bgp_damp_info *bdi, + struct reuselist *list, int withdraw); +extern void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc, + afi_t afi, safi_t safi); +extern void bgp_damp_config_clean(struct bgp_damp_config *bdc); extern int bgp_damp_decay(time_t tdiff, int penalty, - struct bgp_damp_config *damp); -extern void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi); -extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, - afi_t afi, safi_t safi, json_object *json_path); + struct bgp_damp_config *bdc); +extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi); +extern void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp, + struct bgp_path_info *path, afi_t afi, + safi_t safi, json_object *json_path); extern const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, char *timebuf, size_t len, afi_t afi, @@ -140,5 +149,14 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty, json_object *json); extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, uint16_t show_flags); +extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, + time_t half, unsigned int reuse, + unsigned int suppress, time_t max); +extern void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi); +extern void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi); +extern void bgp_show_peer_dampening_parameters(struct vty *vty, + struct peer *peer, afi_t afi, + safi_t safi, bool use_json); #endif /* _QUAGGA_BGP_DAMP_H */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 782245e51214..6228432bd2e8 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -16,6 +16,7 @@ #include "memory.h" #include "queue.h" #include "filter.h" +#include "hook.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" @@ -37,6 +38,9 @@ #include "bgpd/bgp_debug_clippy.c" +DEFINE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running), + (vty, running)); + unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; unsigned long conf_bgp_debug_events; @@ -46,7 +50,6 @@ unsigned long conf_bgp_debug_keepalive; unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_bestpath; unsigned long conf_bgp_debug_zebra; -unsigned long conf_bgp_debug_allow_martians; unsigned long conf_bgp_debug_nht; unsigned long conf_bgp_debug_update_groups; unsigned long conf_bgp_debug_vpn; @@ -67,7 +70,6 @@ unsigned long term_bgp_debug_keepalive; unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_bestpath; unsigned long term_bgp_debug_zebra; -unsigned long term_bgp_debug_allow_martians; unsigned long term_bgp_debug_nht; unsigned long term_bgp_debug_update_groups; unsigned long term_bgp_debug_vpn; @@ -112,6 +114,7 @@ static const struct message bgp_notify_msg[] = { {BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"}, {BGP_NOTIFY_CEASE, "Cease"}, {BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"}, + {BGP_NOTIFY_SEND_HOLD_ERR, "Send Hold Timer Expired"}, {0}}; static const struct message bgp_notify_head_msg[] = { @@ -216,6 +219,7 @@ static void bgp_debug_list_free(struct list *list) listnode_delete(list, filter); prefix_free(&filter->p); XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); } } @@ -233,15 +237,21 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc, vty_out(vty, "%s", desc); if (list && !list_isempty(list)) { - vty_out(vty, " for"); + vty_out(vty, " for:\n"); for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { if (filter->host) - vty_out(vty, " %s", filter->host); + vty_out(vty, " %s", filter->host); + + if (filter->plist_name) + vty_out(vty, " with prefix-list %s", + filter->plist_name); if (filter->p && filter->p->family == AF_EVPN) bgp_debug_print_evpn_prefix(vty, "", filter->p); else if (filter->p) vty_out(vty, " %pFX", filter->p); + + vty_out(vty, "\n"); } } @@ -261,7 +271,11 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, if (list && !list_isempty(list)) { for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { - if (filter->host) { + if (filter->host && filter->plist_name) { + vty_out(vty, "%s %s prefix-list %s\n", desc, + filter->host, filter->plist_name); + write++; + } else if (filter->host) { vty_out(vty, "%s %s\n", desc, filter->host); write++; } @@ -286,7 +300,8 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, } static void bgp_debug_list_add_entry(struct list *list, const char *host, - const struct prefix *p) + const struct prefix *p, + const char *plist_name) { struct bgp_debug_filter *filter; @@ -295,13 +310,27 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host, if (host) { filter->host = XSTRDUP(MTYPE_BGP_DEBUG_STR, host); + filter->plist_name = NULL; + filter->plist_v4 = NULL; + filter->plist_v6 = NULL; filter->p = NULL; } else if (p) { filter->host = NULL; + filter->plist_name = NULL; + filter->plist_v4 = NULL; + filter->plist_v6 = NULL; filter->p = prefix_new(); prefix_copy(filter->p, p); } + if (plist_name) { + filter->plist_name = XSTRDUP(MTYPE_BGP_DEBUG_STR, plist_name); + filter->plist_v4 = prefix_list_lookup(AFI_IP, + filter->plist_name); + filter->plist_v6 = prefix_list_lookup(AFI_IP6, + filter->plist_name); + } + listnode_add(list, filter); } @@ -315,6 +344,7 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host, if (host && strcmp(filter->host, host) == 0) { listnode_delete(list, filter); XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); return true; } else if (p && filter->p->prefixlen == p->prefixlen @@ -330,16 +360,20 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host, } static bool bgp_debug_list_has_entry(struct list *list, const char *host, - const struct prefix *p) + const struct prefix *p, + const char *plist_name) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { - if (host) { - if (strcmp(filter->host, host) == 0) { + if (host && plist_name) { + if (strmatch(filter->host, host) && filter->plist_name && + strmatch(filter->plist_name, plist_name)) + return true; + } else if (host) { + if (strmatch(filter->host, host)) return true; - } } else if (p) { if (filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p)) { @@ -353,7 +387,7 @@ static bool bgp_debug_list_has_entry(struct list *list, const char *host, bool bgp_debug_peer_updout_enabled(char *host) { - return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, + return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, NULL, NULL)); } @@ -480,6 +514,7 @@ const char *bgp_notify_subcode_str(char code, char subcode) return lookup_msg(bgp_notify_update_msg, subcode, "Unrecognized Error Subcode"); case BGP_NOTIFY_HOLD_ERR: + case BGP_NOTIFY_SEND_HOLD_ERR: break; case BGP_NOTIFY_FSM_ERR: return lookup_msg(bgp_notify_fsm_msg, subcode, @@ -498,12 +533,13 @@ const char *bgp_notify_subcode_str(char code, char subcode) const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, size_t datalen) { + memset(buf, 0, bufsz); if (!data || datalen < 1) - return NULL; + return buf; uint8_t len = data[0]; if (!len || len > datalen - 1) - return NULL; + return buf; return zlog_sanitize(buf, bufsz, data + 1, len); } @@ -779,14 +815,15 @@ DEFUN (debug_bgp_neighbor_events_peer, bgp_debug_neighbor_events_peers = list_new(); if (bgp_debug_list_has_entry(bgp_debug_neighbor_events_peers, host, - NULL)) { + NULL, NULL)) { vty_out(vty, "BGP neighbor-events debugging is already enabled for %s\n", host); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL, + NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); @@ -926,14 +963,15 @@ DEFUN (debug_bgp_keepalive_peer, if (!bgp_debug_keepalive_peers) bgp_debug_keepalive_peers = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL)) { + if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL, + NULL)) { vty_out(vty, "BGP keepalive debugging is already enabled for %s\n", host); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL, NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(keepalive, KEEPALIVE); @@ -1014,15 +1052,16 @@ DEFPY (debug_bgp_bestpath_prefix, if (!bgp_debug_bestpath_prefixes) bgp_debug_bestpath_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, - prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP bestpath debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix, + NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(bestpath, BESTPATH); @@ -1115,6 +1154,31 @@ DEFUN (debug_bgp_update, return CMD_SUCCESS; } +DEFPY (debug_bgp_update_detail, + debug_bgp_update_detail_cmd, + "[no] debug bgp updates detail", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Show detailed information about updates\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) + DEBUG_OFF(update, UPDATE_DETAIL); + else + DEBUG_ON(update, UPDATE_DETAIL); + } else { + if (no) + TERM_DEBUG_OFF(update, UPDATE_DETAIL); + else + TERM_DEBUG_ON(update, UPDATE_DETAIL); + vty_out(vty, "BGP updates detail debugging is on\n"); + } + + return CMD_SUCCESS; +} + DEFUN (debug_bgp_update_direct, debug_bgp_update_direct_cmd, "debug bgp updates ", @@ -1149,9 +1213,9 @@ DEFUN (debug_bgp_update_direct, return CMD_SUCCESS; } -DEFUN (debug_bgp_update_direct_peer, +DEFPY (debug_bgp_update_direct_peer, debug_bgp_update_direct_peer_cmd, - "debug bgp updates ", + "debug bgp updates [prefix-list PREFIXLIST_NAME$plist]", DEBUG_STR BGP_STR "BGP updates\n" @@ -1159,7 +1223,9 @@ DEFUN (debug_bgp_update_direct_peer, "Outbound updates\n" "BGP neighbor IP address to debug\n" "BGP IPv6 neighbor to debug\n" - "BGP neighbor on interface to debug\n") + "BGP neighbor on interface to debug\n" + "Use prefix-list to filter prefixes to debug\n" + "Name of prefix-list\n") { int idx_in_out = 3; int idx_peer = 4; @@ -1179,7 +1245,7 @@ DEFUN (debug_bgp_update_direct_peer, if (inbound) { if (bgp_debug_list_has_entry(bgp_debug_update_in_peers, host, - NULL)) { + NULL, plist)) { vty_out(vty, "BGP inbound update debugging is already enabled for %s\n", host); @@ -1189,7 +1255,7 @@ DEFUN (debug_bgp_update_direct_peer, else { if (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, - NULL)) { + NULL, plist)) { vty_out(vty, "BGP outbound update debugging is already enabled for %s\n", host); @@ -1198,14 +1264,15 @@ DEFUN (debug_bgp_update_direct_peer, } if (inbound) - bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL, + plist); else { struct peer *peer; struct peer_af *paf; int afidx; - bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, - NULL); + bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, NULL, + plist); peer = bgp_find_peer(vty, host); if (peer) { @@ -1282,7 +1349,7 @@ DEFUN (no_debug_bgp_update_direct, DEFUN (no_debug_bgp_update_direct_peer, no_debug_bgp_update_direct_peer_cmd, - "no debug bgp updates ", + "no debug bgp updates [prefix-list PREFIXLIST_NAME]", NO_STR DEBUG_STR BGP_STR @@ -1291,7 +1358,9 @@ DEFUN (no_debug_bgp_update_direct_peer, "Outbound updates\n" "BGP neighbor IP address to debug\n" "BGP IPv6 neighbor to debug\n" - "BGP neighbor on interface to debug\n") + "BGP neighbor on interface to debug\n" + "Use prefix-list to filter prefixes to debug\n" + "Name of prefix-list\n") { int idx_in_out = 4; int idx_peer = 5; @@ -1413,15 +1482,15 @@ DEFPY (debug_bgp_update_prefix_afi_safi, if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, - &argv_p)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, &argv_p, + NULL)) { vty_out(vty, "BGP updates debugging is already enabled for %pFX\n", &argv_p); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p, NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); @@ -1509,14 +1578,15 @@ DEFPY (debug_bgp_update_prefix, if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP updates debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix, NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); @@ -1646,13 +1716,14 @@ DEFPY (debug_bgp_zebra_prefix, if (!bgp_debug_zebra_prefixes) bgp_debug_zebra_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP zebra debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix, NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(zebra, ZEBRA); @@ -2092,7 +2163,6 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF(as4, AS4_SEGMENT); TERM_DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS); TERM_DEBUG_OFF(zebra, ZEBRA); - TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS); TERM_DEBUG_OFF(nht, NHT); TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF); TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF); @@ -2168,9 +2238,6 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) vty_out(vty, " BGP graceful-restart debugging is on\n"); - if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) - vty_out(vty, " BGP allow martian next hop debugging is on\n"); - if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) vty_out(vty, " BGP route leak from vrf to vpn debugging is on\n"); @@ -2205,6 +2272,8 @@ DEFUN_NOSH (show_debugging_bgp, cmd_show_lib_debugs(vty); + hook_call(bgp_hook_config_write_debug, vty, false); + return CMD_SUCCESS; } @@ -2264,6 +2333,11 @@ static int bgp_config_write_debug(struct vty *vty) bgp_debug_update_out_peers); } + if (CONF_BGP_DEBUG(update, UPDATE_DETAIL)) { + vty_out(vty, "debug bgp updates detail\n"); + write++; + } + if (CONF_BGP_DEBUG(zebra, ZEBRA)) { if (!bgp_debug_zebra_prefixes || list_isempty(bgp_debug_zebra_prefixes)) { @@ -2276,11 +2350,6 @@ static int bgp_config_write_debug(struct vty *vty) } } - if (CONF_BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { - vty_out(vty, "debug bgp allow-martians\n"); - write++; - } - if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) { vty_out(vty, "debug bgp vpn leak-from-vrf\n"); write++; @@ -2339,6 +2408,9 @@ static int bgp_config_write_debug(struct vty *vty) write++; } + if (hook_call(bgp_hook_config_write_debug, vty, true)) + write++; + return write; } @@ -2369,6 +2441,8 @@ void bgp_debug_init(void) install_element(CONFIG_NODE, &debug_bgp_keepalive_cmd); install_element(ENABLE_NODE, &debug_bgp_update_cmd); install_element(CONFIG_NODE, &debug_bgp_update_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_detail_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_detail_cmd); install_element(ENABLE_NODE, &debug_bgp_zebra_cmd); install_element(CONFIG_NODE, &debug_bgp_zebra_cmd); install_element(ENABLE_NODE, &debug_bgp_update_groups_cmd); @@ -2509,7 +2583,8 @@ static int bgp_debug_per_prefix(const struct prefix *p, /* Return true if this peer is on the per_peer_list of peers to debug * for BGP_DEBUG_TYPE */ -static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, +static bool bgp_debug_per_peer(char *host, const struct prefix *p, + unsigned long term_bgp_debug_type, unsigned int BGP_DEBUG_TYPE, struct list *per_peer_list) { @@ -2521,17 +2596,28 @@ static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, if (!per_peer_list || list_isempty(per_peer_list)) return true; - else { - if (!host) - return false; + if (!host) + return false; - for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, - filter)) - if (strcmp(filter->host, host) == 0) - return true; + for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, filter)) + if (strmatch(filter->host, host) && + filter->plist_name && p) { + struct prefix_list *plist; + afi_t afi = family2afi(p->family); - return false; - } + plist = (afi == AFI_IP) ? filter->plist_v4 + : filter->plist_v6; + + if (!plist) + continue; + + return prefix_list_apply(plist, p) == + PREFIX_PERMIT; + } else if (strmatch(filter->host, host)) { + return true; + } + + return false; } return false; @@ -2544,7 +2630,7 @@ bool bgp_debug_neighbor_events(const struct peer *peer) if (peer) host = peer->host; - return bgp_debug_per_peer(host, term_bgp_debug_neighbor_events, + return bgp_debug_per_peer(host, NULL, term_bgp_debug_neighbor_events, BGP_DEBUG_NEIGHBOR_EVENTS, bgp_debug_neighbor_events_peers); } @@ -2556,7 +2642,7 @@ bool bgp_debug_keepalive(const struct peer *peer) if (peer) host = peer->host; - return bgp_debug_per_peer(host, term_bgp_debug_keepalive, + return bgp_debug_per_peer(host, NULL, term_bgp_debug_keepalive, BGP_DEBUG_KEEPALIVE, bgp_debug_keepalive_peers); } @@ -2570,7 +2656,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p, host = peer->host; if (inbound) { - if (bgp_debug_per_peer(host, term_bgp_debug_update, + if (bgp_debug_per_peer(host, p, term_bgp_debug_update, BGP_DEBUG_UPDATE_IN, bgp_debug_update_in_peers)) return true; @@ -2578,7 +2664,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p, /* outbound */ else { - if (bgp_debug_per_peer(host, term_bgp_debug_update, + if (bgp_debug_per_peer(host, p, term_bgp_debug_update, BGP_DEBUG_UPDATE_OUT, bgp_debug_update_out_peers)) return true; @@ -2627,7 +2713,7 @@ bool bgp_debug_zebra(const struct prefix *p) const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd, union prefixconstptr pu, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, int addpath_valid, uint32_t addpath_id, struct bgp_route_evpn *overlay_index, char *str, int size) diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 118325e0a34e..061d966dc392 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -6,9 +6,15 @@ #ifndef _QUAGGA_BGP_DEBUG_H #define _QUAGGA_BGP_DEBUG_H +#include "hook.h" +#include "vty.h" + #include "bgp_attr.h" #include "bgp_updgrp.h" +DECLARE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running), + (vty, running)); + /* sort of packet direction */ #define DUMP_ON 1 #define DUMP_SEND 2 @@ -55,7 +61,6 @@ extern unsigned long conf_bgp_debug_keepalive; extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_bestpath; extern unsigned long conf_bgp_debug_zebra; -extern unsigned long conf_bgp_debug_allow_martians; extern unsigned long conf_bgp_debug_nht; extern unsigned long conf_bgp_debug_update_groups; extern unsigned long conf_bgp_debug_vpn; @@ -74,7 +79,6 @@ extern unsigned long term_bgp_debug_keepalive; extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_bestpath; extern unsigned long term_bgp_debug_zebra; -extern unsigned long term_bgp_debug_allow_martians; extern unsigned long term_bgp_debug_nht; extern unsigned long term_bgp_debug_update_groups; extern unsigned long term_bgp_debug_vpn; @@ -96,6 +100,9 @@ extern struct list *bgp_debug_zebra_prefixes; struct bgp_debug_filter { char *host; + char *plist_name; + struct prefix_list *plist_v4; + struct prefix_list *plist_v6; struct prefix *p; }; @@ -109,8 +116,8 @@ struct bgp_debug_filter { #define BGP_DEBUG_UPDATE_IN 0x01 #define BGP_DEBUG_UPDATE_OUT 0x02 #define BGP_DEBUG_UPDATE_PREFIX 0x04 +#define BGP_DEBUG_UPDATE_DETAIL 0x08 #define BGP_DEBUG_ZEBRA 0x01 -#define BGP_DEBUG_ALLOW_MARTIANS 0x01 #define BGP_DEBUG_NHT 0x01 #define BGP_DEBUG_UPDATE_GROUPS 0x01 #define BGP_DEBUG_VPN_LEAK_FROM_VRF 0x01 @@ -124,9 +131,6 @@ struct bgp_debug_filter { #define BGP_DEBUG_EVPN_MH_ES 0x01 #define BGP_DEBUG_EVPN_MH_RT 0x02 -#define BGP_DEBUG_PACKET_SEND 0x01 -#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 - #define BGP_DEBUG_GRACEFUL_RESTART 0x01 #define BGP_DEBUG_BFD_LIB 0x01 @@ -149,8 +153,8 @@ struct bgp_debug_filter { TERM_DEBUG_OFF(a, b); \ } while (0) -#define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b) -#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) +#define BGP_DEBUG(a, b) (unlikely(term_bgp_debug_##a & BGP_DEBUG_##b)) +#define CONF_BGP_DEBUG(a, b) (unlikely(conf_bgp_debug_##a & BGP_DEBUG_##b)) extern const char *const bgp_type_str[]; @@ -171,7 +175,7 @@ extern bool bgp_debug_zebra(const struct prefix *p); extern const char *bgp_debug_rdpfxpath2str( afi_t afi, safi_t safi, const struct prefix_rd *prd, - union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels, + union prefixconstptr pu, mpls_label_t *label, uint8_t num_labels, int addpath_valid, uint32_t addpath_id, struct bgp_route_evpn *overlay_index, char *str, int size); const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 529713ee3275..53b52124822e 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -4,6 +4,7 @@ */ #include +#include #include "log.h" #include "stream.h" diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index c408edb16677..1beb0307d20a 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -237,11 +237,10 @@ struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length, disable_ieee_floating); } -struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length, - bool disable_ieee_floating) +struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length) { return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE, - disable_ieee_floating); + false); } /* Duplicate the Extended Communities Attribute structure. */ @@ -263,8 +262,11 @@ struct ecommunity *ecommunity_dup(struct ecommunity *ecom) } /* Return string representation of ecommunities attribute. */ -char *ecommunity_str(struct ecommunity *ecom) +const char *ecommunity_str(struct ecommunity *ecom) { + if (!ecom) + return "(null)"; + if (!ecom->str) ecom->str = ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0); @@ -724,15 +726,21 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr, memset(buf, 0, INET_ADDRSTRLEN + 1); memcpy(buf, str, p - str); - if (dot) { + if (dot == 3) { /* Parsing A.B.C.D in: * A.B.C.D:MN */ ret = inet_aton(buf, &ip); if (ret == 0) goto error; + } else if (dot == 1) { + /* Parsing A.B AS number in: + * A.B:MN + */ + if (!asn_str2asn(buf, &as)) + goto error; } else { - /* ASN */ + /* Parsing A AS number in A:MN */ errno = 0; tmp_as = strtoul(buf, &endptr, 10); /* 'unsigned long' is a uint64 on 64-bit @@ -750,8 +758,11 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr, } else if (*p == '.') { if (separator) goto error; + /* either IP or AS format */ dot++; - if (dot > 4) + if (dot > 1) + ecomm_type = ECOMMUNITY_ENCODE_IP; + if (dot >= 4) goto error; } else { digit = 1; @@ -776,19 +787,18 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr, if (!digit && (!separator || !val_color_set)) goto error; - /* Encode result into extended community. */ - if (dot) - ecomm_type = ECOMMUNITY_ENCODE_IP; - else if (as > BGP_AS_MAX) - ecomm_type = ECOMMUNITY_ENCODE_AS4; - else if (as > 0) - ecomm_type = ECOMMUNITY_ENCODE_AS; - else if (val_color) { - ecomm_type = ECOMMUNITY_ENCODE_OPAQUE; - sub_type = ECOMMUNITY_COLOR; - val = val_color; + if (ecomm_type != ECOMMUNITY_ENCODE_IP) { + /* Encode result into extended community for AS format or color. */ + if (as > BGP_AS_MAX) + ecomm_type = ECOMMUNITY_ENCODE_AS4; + else if (as > 0) + ecomm_type = ECOMMUNITY_ENCODE_AS; + else if (val_color) { + ecomm_type = ECOMMUNITY_ENCODE_OPAQUE; + sub_type = ECOMMUNITY_COLOR; + val = val_color; + } } - if (ecommunity_encode(ecomm_type, sub_type, 1, as, ip, val, eval)) goto error; *token = ecommunity_token_val; @@ -1015,10 +1025,6 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, uint32_t bw_tmp, bw; char bps_buf[20] = {0}; -#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8) -#define ONE_MBPS_BYTES (1000 * 1000 / 8) -#define ONE_KBPS_BYTES (1000 / 8) - as = (*pnt++ << 8); as |= (*pnt++); (void)ptr_get_be32(pnt, &bw_tmp); @@ -1042,6 +1048,66 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, return len; } +static int ipv6_ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, + size_t length) +{ + int len = 0; + as_t as = 0; + uint64_t bw = 0; + char bps_buf[20] = { 0 }; + + if (length < IPV6_ECOMMUNITY_SIZE) + goto done; + + pnt += 2; /* Reserved */ + pnt = ptr_get_be64(pnt, &bw); + (void)ptr_get_be32(pnt, &as); + + if (bw >= ONE_GBPS_BYTES) + snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps", + (float)(bw / ONE_GBPS_BYTES)); + else if (bw >= ONE_MBPS_BYTES) + snprintf(bps_buf, sizeof(bps_buf), "%.3f Mbps", + (float)(bw / ONE_MBPS_BYTES)); + else if (bw >= ONE_KBPS_BYTES) + snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps", + (float)(bw / ONE_KBPS_BYTES)); + else + snprintfrr(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8); + +done: + len = snprintfrr(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf); + return len; +} + +bool ecommunity_has_route_target(struct ecommunity *ecom) +{ + uint32_t i; + uint8_t *pnt; + uint8_t type = 0; + uint8_t sub_type = 0; + + if (!ecom) + return false; + for (i = 0; i < ecom->size; i++) { + /* Retrieve value field */ + pnt = ecom->val + (i * ecom->unit_size); + + /* High-order octet is the type */ + type = *pnt++; + + if (type == ECOMMUNITY_ENCODE_AS || + type == ECOMMUNITY_ENCODE_IP || + type == ECOMMUNITY_ENCODE_AS4) { + /* Low-order octet of type. */ + sub_type = *pnt++; + if (sub_type == ECOMMUNITY_ROUTE_TARGET) + return true; + } + } + return false; +} + /* Convert extended community attribute to string. * Due to historical reason of industry standard implementation, there * are three types of format: @@ -1082,7 +1148,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) char encbuf[128]; for (i = 0; i < ecom->size; i++) { - int unk_ecom = 0; + bool unk_ecom = false; memset(encbuf, 0x00, sizeof(encbuf)); /* Space between each value. */ @@ -1092,6 +1158,18 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) /* Retrieve value field */ pnt = ecom->val + (i * ecom->unit_size); + uint8_t *data = pnt; + uint8_t *end = data + ecom->unit_size; + size_t len = end - data; + + /* Sanity check for extended communities lenght, to avoid + * overrun when dealing with bits, e.g. ptr_get_be64(). + */ + if (len < ecom->unit_size) { + unk_ecom = true; + goto unknown; + } + /* High-order octet is the type */ type = *pnt++; @@ -1114,13 +1192,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) ecommunity_lb_str( encbuf, sizeof(encbuf), pnt, ecom->disable_ieee_floating); + } else if (sub_type == + ECOMMUNITY_EXTENDED_LINK_BANDWIDTH && + type == ECOMMUNITY_ENCODE_AS4) { + ipv6_ecommunity_lb_str(encbuf, + sizeof(encbuf), + pnt, len); } else if (sub_type == ECOMMUNITY_NODE_TARGET && type == ECOMMUNITY_ENCODE_IP) { ecommunity_node_target_str( encbuf, sizeof(encbuf), pnt, format); } else - unk_ecom = 1; + unk_ecom = true; } else { ecommunity_rt_soo_str(encbuf, sizeof(encbuf), pnt, type, sub_type, @@ -1143,7 +1227,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) ecommunity_color_str(encbuf, sizeof(encbuf), pnt); } else { - unk_ecom = 1; + unk_ecom = true; } } else if (type == ECOMMUNITY_ENCODE_EVPN) { if (filter == ECOMMUNITY_ROUTE_TARGET) @@ -1236,14 +1320,14 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) "DF: (alg: %u, pref: %u)", alg, pref); } else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) { snprintf(encbuf, sizeof(encbuf), "FS:redirect IP 0x%x", *(pnt + 5)); } else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP || type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 || type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) { @@ -1290,7 +1374,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) snprintf(encbuf, sizeof(encbuf), "FS:redirect VRF %s", buf); } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP) - unk_ecom = 1; + unk_ecom = true; else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) { char action[64]; @@ -1323,33 +1407,37 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) snprintf(encbuf, sizeof(encbuf), "FS:marking %u", *(pnt + 5)); } else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_LINK_BANDWIDTH) ecommunity_lb_str(encbuf, sizeof(encbuf), pnt, ecom->disable_ieee_floating); + else if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) + ipv6_ecommunity_lb_str(encbuf, sizeof(encbuf), + pnt, len); else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_NODE_TARGET) ecommunity_node_target_str( encbuf, sizeof(encbuf), pnt, format); else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE) ecommunity_origin_validation_state_str( encbuf, sizeof(encbuf), pnt); else - unk_ecom = 1; + unk_ecom = true; } else { sub_type = *pnt++; - unk_ecom = 1; + unk_ecom = true; } +unknown: if (unk_ecom) snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type, sub_type); @@ -1581,8 +1669,8 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, * in the 'Network Address of Next- Hop' * field of the associated MP_REACH_NLRI. */ - struct ecommunity_ip *ip_ecom = (struct ecommunity_ip *) - ecom_eval + 2; + struct ecommunity_ip *ip_ecom = + (struct ecommunity_ip *)&ecom_eval->val[2]; api->u.zr.redirect_ip_v4 = ip_ecom->ip; } else @@ -1766,9 +1854,9 @@ ecommunity_add_origin_validation_state(enum rpki_states rpki_state, * return the BGP link bandwidth extended community, if present; * the actual bandwidth is returned via param */ -const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) +const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw) { - const uint8_t *eval; + const uint8_t *data; uint32_t i; if (bw) @@ -1780,24 +1868,49 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) for (i = 0; i < ecom->size; i++) { const uint8_t *pnt; uint8_t type, sub_type; - uint32_t bwval; - eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + data = pnt = (ecom->val + (i * ecom->unit_size)); type = *pnt++; sub_type = *pnt++; + const uint8_t *end = data + ecom->unit_size; + size_t len = end - data; + + /* Sanity check for extended communities lenght, to avoid + * overrun when dealing with bits, e.g. ptr_get_be64(). + */ + if (len < ecom->unit_size) + return NULL; + if ((type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_AS_NON_TRANS) && sub_type == ECOMMUNITY_LINK_BANDWIDTH) { + uint32_t bwval; + pnt += 2; /* bandwidth is encoded as AS:val */ pnt = ptr_get_be32(pnt, &bwval); (void)pnt; /* consume value */ if (bw) - *bw = ecom->disable_ieee_floating - ? bwval - : ieee_float_uint32_to_uint32( - bwval); - return eval; + *bw = (uint64_t)(ecom->disable_ieee_floating + ? bwval + : ieee_float_uint32_to_uint32( + bwval)); + return data; + } else if (type == ECOMMUNITY_ENCODE_AS4 && + sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) { + uint64_t bwval; + + if (len < IPV6_ECOMMUNITY_SIZE) + return NULL; + + pnt += 2; /* Reserved */ + pnt = ptr_get_be64(pnt, &bwval); + (void)pnt; + + if (bw) + *bw = bwval; + + return data; } } @@ -1807,13 +1920,13 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw, - bool disable_ieee_floating) + bool disable_ieee_floating, + bool extended) { struct ecommunity *new; - struct ecommunity_val lb_eval; const uint8_t *eval; uint8_t type; - uint32_t cur_bw; + uint64_t cur_bw; /* Nothing to replace if link-bandwidth doesn't exist or * is non-transitive - just return existing extcommunity. @@ -1837,10 +1950,21 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, */ if (cum_bw > 0xFFFFFFFF) cum_bw = 0xFFFFFFFF; - encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, false, - &lb_eval, disable_ieee_floating); - new = ecommunity_dup(ecom); - ecommunity_add_val(new, &lb_eval, true, true); + + if (extended) { + struct ecommunity_val_ipv6 lb_eval; + + encode_lb_extended_extcomm(as, cum_bw, false, &lb_eval); + new = ecommunity_dup(ecom); + ecommunity_add_val_ipv6(new, &lb_eval, true, true); + } else { + struct ecommunity_val lb_eval; + + encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, + false, &lb_eval, disable_ieee_floating); + new = ecommunity_dup(ecom); + ecommunity_add_val(new, &lb_eval, true, true); + } return new; } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 7dc04d206af9..929e4e60be0a 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -10,6 +10,10 @@ #include "bgpd/bgp_rpki.h" #include "bgpd/bgpd.h" +#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8) +#define ONE_MBPS_BYTES (1000 * 1000 / 8) +#define ONE_KBPS_BYTES (1000 / 8) + /* Refer to rfc7153 for the IANA registry definitions. These are * updated by other standards like rfc7674. */ @@ -52,10 +56,14 @@ * 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect */ #define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 0x0c -/* from draft-ietf-idr-flow-spec-v6-09 - * 0x0b Flow-spec Redirect to IPv6 +/* RFC 8956 */ +#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d + +/* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01 + * Sub-type is allocated by IANA, just the draft is not yet updated with the + * new value. */ -#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0b +#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0006 /* Low-order octet of the Extended Communities type field for EVPN types */ #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 @@ -117,6 +125,9 @@ struct ecommunity { */ uint8_t unit_size; + /* Disable IEEE floating-point encoding for extended community */ + bool disable_ieee_floating; + /* Size of Extended Communities attribute. */ uint32_t size; @@ -125,9 +136,6 @@ struct ecommunity { /* Human readable format string. */ char *str; - - /* Disable IEEE floating-point encoding for extended community */ - bool disable_ieee_floating; }; struct ecommunity_as { @@ -226,12 +234,13 @@ static uint32_t uint32_to_ieee_float_uint32(uint32_t u) * Encode BGP Link Bandwidth extended community * bandwidth (bw) is in bytes-per-sec */ -static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, +static inline void encode_lb_extcomm(as_t as, uint64_t bw, bool non_trans, struct ecommunity_val *eval, bool disable_ieee_floating) { - uint32_t bandwidth = - disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw); + uint64_t bandwidth = disable_ieee_floating + ? bw + : uint32_to_ieee_float_uint32(bw); memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_AS; @@ -246,6 +255,33 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, eval->val[7] = bandwidth & 0xff; } +/* + * Encode BGP Link Bandwidth inside IPv6 Extended Community, + * bandwidth is in bytes per second. + */ +static inline void encode_lb_extended_extcomm(as_t as, uint64_t bandwidth, + bool non_trans, + struct ecommunity_val_ipv6 *eval) +{ + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_AS4; + if (non_trans) + eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; + eval->val[1] = ECOMMUNITY_EXTENDED_LINK_BANDWIDTH; + eval->val[4] = (bandwidth >> 56) & 0xff; + eval->val[5] = (bandwidth >> 48) & 0xff; + eval->val[6] = (bandwidth >> 40) & 0xff; + eval->val[7] = (bandwidth >> 32) & 0xff; + eval->val[8] = (bandwidth >> 24) & 0xff; + eval->val[9] = (bandwidth >> 16) & 0xff; + eval->val[10] = (bandwidth >> 8) & 0xff; + eval->val[11] = bandwidth & 0xff; + eval->val[12] = (as >> 24) & 0xff; + eval->val[13] = (as >> 16) & 0xff; + eval->val[14] = (as >> 8) & 0xff; + eval->val[15] = as & 0xff; +} + static inline void encode_origin_validation_state(enum rpki_states state, struct ecommunity_val *eval) { @@ -327,8 +363,7 @@ extern void ecommunity_free(struct ecommunity **); extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short, bool disable_ieee_floating); extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, - unsigned short length, - bool disable_ieee_floating); + unsigned short length); extern struct ecommunity *ecommunity_dup(struct ecommunity *); extern struct ecommunity *ecommunity_merge(struct ecommunity *, struct ecommunity *); @@ -341,11 +376,12 @@ extern struct ecommunity *ecommunity_str2com(const char *, int, int); extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type, int keyword_included); extern char *ecommunity_ecom2str(struct ecommunity *, int, int); +extern bool ecommunity_has_route_target(struct ecommunity *ecom); extern void ecommunity_strfree(char **s); extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2); extern bool ecommunity_match(const struct ecommunity *, const struct ecommunity *); -extern char *ecommunity_str(struct ecommunity *ecom); +extern const char *ecommunity_str(struct ecommunity *ecom); extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *, uint8_t, uint8_t); @@ -386,11 +422,10 @@ extern void bgp_remove_ecomm_from_aggregate_hash( struct ecommunity *ecommunity); extern void bgp_aggr_ecommunity_remove(void *arg); extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, - uint32_t *bw); -extern struct ecommunity *ecommunity_replace_linkbw(as_t as, - struct ecommunity *ecom, - uint64_t cum_bw, - bool disable_ieee_floating); + uint64_t *bw); +extern struct ecommunity * +ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw, + bool disable_ieee_floating, bool extended); extern bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ad101f171a7f..3ff6ed9e554d 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -42,6 +42,7 @@ #include "bgpd/bgp_trace.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_packet.h" +#include "bgpd/bgp_rtc.h" /* * Definitions and external declarations. @@ -311,6 +312,49 @@ static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn) return 0; } +/* Flag if the route is injectable into EVPN. + * This would be following category: + * Non-imported route, + * Non-EVPN imported route, + */ +bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi) +{ + struct bgp_path_info *parent_pi; + struct bgp_table *table; + struct bgp_dest *dest; + + if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || + !pi->extra->vrfleak || !pi->extra->vrfleak->parent) + return true; + + parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent; + dest = parent_pi->net; + if (!dest) + return true; + table = bgp_dest_table(dest); + if (table && + table->afi == AFI_L2VPN && + table->safi == SAFI_EVPN) + return false; + + return true; +} + +/* Flag if the route is injectable into EVPN. + * This would be following category: + * Non-imported route, + * Non-EVPN imported route, + * Non Aggregate suppressed route. + */ +bool is_route_injectable_into_evpn(struct bgp_path_info *pi) +{ + /* do not import aggr suppressed routes */ + if (bgp_path_suppressed(pi)) + return false; + + return is_route_injectable_into_evpn_non_supp(pi); +} + /* * Compare Route Targets. */ @@ -504,8 +548,10 @@ static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn, /* Already mapped. */ return; - if (!irt) + if (!irt) { irt = import_rt_new(bgp, &eval_tmp); + bgp_rtc_add_static(bgp, eval, BGP_RTC_MAX_PREFIXLEN); + } /* Add VNI to the hash list for this RT. */ listnode_add(irt->vnis, vpn); @@ -516,11 +562,12 @@ static void map_vni_to_rt(struct bgp *bgp, struct bgpevpn *vpn, * VNIs for this RT, then the RT hash is deleted. */ static void unmap_vni_from_rt(struct bgp *bgp, struct bgpevpn *vpn, - struct irt_node *irt) + struct irt_node *irt, struct ecommunity_val *eval) { /* Delete VNI from hash list for this RT. */ listnode_delete(irt->vnis, vpn); if (!listnode_head(irt->vnis)) { + bgp_rtc_remove_static(bgp, eval, BGP_RTC_MAX_PREFIXLEN); import_rt_free(bgp, irt); } } @@ -849,11 +896,10 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, /* * Add (update) or delete MACIP from zebra. */ -static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - const struct ethaddr *mac, - struct in_addr remote_vtep_ip, int add, - uint8_t flags, uint32_t seq, esi_t *esi) +static enum zclient_send_status bgp_zebra_send_remote_macip( + struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, + const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add, + uint8_t flags, uint32_t seq, esi_t *esi) { struct stream *s; uint16_t ipa_len; @@ -861,8 +907,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, bool esi_valid; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { @@ -870,7 +920,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "%s: No zebra instance to talk to, not installing remote macip", __func__); - return 0; + return ZCLIENT_SEND_SUCCESS; } if (!esi) @@ -881,7 +931,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zclient_create_header( s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, bgp->vrf_id); - stream_putl(s, vpn->vni); + stream_putl(s, vpn ? vpn->vni : 0); if (mac) /* Mac Addr */ stream_put(s, &mac->octet, ETH_ALEN); @@ -927,7 +977,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, snprintf(esi_buf, sizeof(esi_buf), "-"); zlog_debug( "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s", - add ? "ADD" : "DEL", vpn->vni, + add ? "ADD" : "DEL", (vpn ? vpn->vni : 0), (mac ? mac : &p->prefix.macip_addr.mac), &p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip, esi_buf); @@ -936,24 +986,26 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, esi); - if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) - return -1; - - return 0; + return zclient_send_message(zclient); } /* * Add (update) or delete remote VTEP from zebra. */ -static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - int flood_control, int add) +static enum zclient_send_status +bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, int flood_control, + int add) { struct stream *s; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { @@ -961,7 +1013,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "%s: No zebra instance to talk to, not installing remote vtep", __func__); - return 0; + return ZCLIENT_SEND_SUCCESS; } s = zclient->obuf; @@ -970,15 +1022,15 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, zclient_create_header( s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, bgp->vrf_id); - stream_putl(s, vpn->vni); + stream_putl(s, vpn ? vpn->vni : 0); if (is_evpn_prefix_ipaddr_v4(p)) stream_put_in_addr(s, &p->prefix.imet_addr.ip.ipaddr_v4); else if (is_evpn_prefix_ipaddr_v6(p)) { flog_err( EC_BGP_VTEP_INVALID, "Bad remote IP when trying to %s remote VTEP for VNI %u", - add ? "ADD" : "DEL", vpn->vni); - return -1; + add ? "ADD" : "DEL", (vpn ? vpn->vni : 0)); + return ZCLIENT_SEND_FAILURE; } stream_putl(s, flood_control); @@ -986,15 +1038,12 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, if (bgp_debug_zebra(NULL)) zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %pI4", - add ? "ADD" : "DEL", vpn->vni, + add ? "ADD" : "DEL", (vpn ? vpn->vni : 0), &p->prefix.imet_addr.ip.ipaddr_v4); frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p); - if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) - return -1; - - return 0; + return zclient_send_message(zclient); } /* @@ -1114,9 +1163,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add MAC mobility (sticky) if needed. */ - if (attr->sticky) { + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) { seqnum = 0; - memset(&ecom_sticky, 0, sizeof(ecom_sticky)); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; ecom_sticky.unit_size = ECOMMUNITY_SIZE; @@ -1134,8 +1182,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add default gateway, if needed. */ - if (attr->default_gw) { - memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { encode_default_gw_extcomm(&eval_default_gw); ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; @@ -1146,9 +1193,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); - if (attr->router_flag || proxy) { - memset(&ecom_na, 0, sizeof(ecom_na)); - encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) { + encode_na_flag_extcomm(&eval_na, + CHECK_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER), + proxy); ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.val = (uint8_t *)eval_na.val; @@ -1220,25 +1269,28 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) } /* Install EVPN route into zebra. */ -static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *pi) +enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi) { - int ret; uint8_t flags; int flood_control = VXLAN_FLOOD_DISABLED; uint32_t seq; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { flags = 0; if (pi->sub_type == BGP_ROUTE_IMPORTED) { - if (pi->attr->sticky) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_STICKY)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (pi->attr->default_gw) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_DEFAULT_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); if (is_evpn_prefix_ipaddr_v6(p) && - pi->attr->router_flag) + CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); seq = mac_mobility_seqnum(pi->attr); @@ -1305,6 +1357,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, flood_control = VXLAN_FLOOD_DISABLED; break; } + ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1); } @@ -1312,11 +1365,13 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, } /* Uninstall EVPN route from zebra. */ -static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *pi, bool is_sync) +enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi, + bool is_sync) { - int ret; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) ret = bgp_zebra_send_remote_macip( @@ -1331,7 +1386,7 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p); else ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, - VXLAN_FLOOD_DISABLED, 0); + VXLAN_FLOOD_DISABLED, 0); return ret; } @@ -1381,7 +1436,7 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -1395,14 +1450,29 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, * Note: vpn is NULL for local EAD-ES routes. */ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_dest *dest) + struct bgp_dest *dest, struct bgp_path_info *pi) { - struct bgp_path_info *old_select, *new_select; + struct bgp_path_info *old_select, *new_select, *first; struct bgp_path_info_pair old_and_new; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; + first = bgp_dest_get_bgp_path_info(dest); + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); + if (pi != first) { + if (pi->next) + pi->next->prev = pi->prev; + if (pi->prev) + pi->prev->next = pi->next; + + if (first) + first->prev = pi; + pi->next = first; + pi->prev = NULL; + bgp_dest_set_bgp_path_info(dest, pi); + } + /* Compute the best path. */ bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new, afi, safi); @@ -1422,12 +1492,19 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { - if (bgp_zebra_has_route_changed(old_select)) - ret = evpn_zebra_install( - bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix( - dest), - old_select); + if (bgp_zebra_has_route_changed(old_select)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + ret = evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + old_select); + else + bgp_zebra_route_install(dest, old_select, bgp, + true, vpn, false); + } + UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG); bgp_zebra_clear_route_change_flags(dest); @@ -1459,10 +1536,15 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(new_select->attr))) { - ret = evpn_zebra_install( - bgp, vpn, - (struct prefix_evpn *)bgp_dest_get_prefix(dest), - new_select); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + ret = evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + new_select); + else + bgp_zebra_route_install(dest, new_select, bgp, true, + vpn, false); /* If an old best existed and it was a "local" route, the only * reason @@ -1479,13 +1561,20 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, evpn_delete_old_local_route(bgp, vpn, dest, old_select, new_select); } else { - if (old_select && old_select->type == ZEBRA_ROUTE_BGP - && old_select->sub_type == BGP_ROUTE_IMPORTED) - ret = evpn_zebra_uninstall( - bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix( - dest), - old_select, false); + if (old_select && old_select->type == ZEBRA_ROUTE_BGP && + old_select->sub_type == BGP_ROUTE_IMPORTED) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || + CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN)) + ret = evpn_zebra_uninstall(bgp, vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + old_select, false); + else + bgp_zebra_route_install(dest, old_select, bgp, + false, vpn, false); + } } /* Clear any route change flags. */ @@ -1518,11 +1607,12 @@ static struct bgp_path_info *bgp_evpn_route_get_local_path( static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, struct bgp *bgp_vrf, afi_t afi, safi_t safi, struct bgp_dest *dest, - struct attr *attr, int *route_changed) + struct attr *attr, int *route_changed, + struct bgp_path_info **entry) { struct attr *attr_new = NULL; struct bgp_path_info *pi = NULL; - mpls_label_t label = MPLS_INVALID_LABEL; + struct bgp_labels bgp_labels = {}; struct bgp_path_info *local_pi = NULL; struct bgp_path_info *tmp_pi = NULL; @@ -1550,14 +1640,19 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, /* Type-5 routes advertise the L3-VNI */ bgp_path_info_extra_get(pi); - vni2label(bgp_vrf->l3vni, &label); - memcpy(&pi->extra->label, &label, sizeof(label)); - pi->extra->num_labels = 1; + vni2label(bgp_vrf->l3vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&pi->extra->labels); + pi->extra->labels = bgp_labels_intern(&bgp_labels); + } + /* add the route entry to route node*/ bgp_path_info_add(dest, pi); + *entry = pi; } else { - tmp_pi = local_pi; if (!attrhash_cmp(tmp_pi->attr, attr)) { @@ -1579,6 +1674,7 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, tmp_pi->attr = attr_new; tmp_pi->uptime = monotime(NULL); } + *entry = local_pi; } return 0; } @@ -1594,6 +1690,7 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, struct bgp_dest *dest = NULL; struct bgp *bgp_evpn = NULL; int route_changed = 0; + struct bgp_path_info *pi = NULL; bgp_evpn = bgp_get_evpn(); if (!bgp_evpn) @@ -1638,6 +1735,9 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, vrf_id_to_name(bgp_vrf->vrf_id), evp, &attr.rmac, &attr.nexthop); + frrtrace(4, frr_bgp, evpn_advertise_type5, bgp_vrf->vrf_id, evp, + &attr.rmac, attr.nexthop); + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; if (src_afi == AFI_IP6 && @@ -1645,20 +1745,30 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) { if (src_attr && !IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) { - attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + bre->type = OVERLAY_INDEX_GATEWAY_IP; + SET_IPADDR_V6(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v6, &src_attr->mp_nexthop_global, sizeof(struct in6_addr)); + bgp_attr_set_evpn_overlay(&attr, bre); } } else if (src_afi == AFI_IP && CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN], BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) { if (src_attr && src_attr->nexthop.s_addr != 0) { - attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, - &src_attr->nexthop, sizeof(struct in_addr)); + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + bre->type = OVERLAY_INDEX_GATEWAY_IP; + SET_IPADDR_V4(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v4, &src_attr->nexthop, + sizeof(struct in_addr)); + bgp_attr_set_evpn_overlay(&attr, bre); } } @@ -1672,11 +1782,11 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, /* create or update the route entry within the route node */ update_evpn_type5_route_entry(bgp_evpn, bgp_vrf, afi, safi, dest, &attr, - &route_changed); + &route_changed, &pi); /* schedule for processing and unlock node */ if (route_changed) { - bgp_process(bgp_evpn, dest, afi, safi); + bgp_process(bgp_evpn, dest, pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -1747,7 +1857,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, *active_on_peer = true; } - if (second_best_path->attr->router_flag) + if (CHECK_FLAG(second_best_path->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) *peer_router = true; /* we use both proxy and non-proxy imports to @@ -1845,15 +1956,12 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_path_info *local_pi; struct attr *attr_new; struct attr local_attr; - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels = 1; + struct bgp_labels bgp_labels = {}; int route_change = 1; - uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest); - memset(&label, 0, sizeof(label)); /* See if this is an update of an existing route, or a new add. */ local_pi = bgp_evpn_route_get_local_path(bgp, dest); @@ -1881,9 +1989,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, local_attr = *attr; /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = - bgp_attr_mac_mobility_seqnum(&local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr); /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(&local_attr); @@ -1895,7 +2001,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, bgp_path_info_extra_get(tmp_pi); /* The VNI goes into the 'label' field of the route */ - vni2label(vpn->vni, &label[0]); + vni2label(vpn->vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; /* Type-2 routes may carry a second VNI - the L3-VNI. * Only attach second label if we are advertising two labels for @@ -1907,13 +2014,16 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, l3vni = bgpevpn_get_l3vni(vpn); if (l3vni) { - vni2label(l3vni, &label[1]); - num_labels++; + vni2label(l3vni, &bgp_labels.label[1]); + bgp_labels.num_labels++; } } - memcpy(&tmp_pi->extra->label, label, sizeof(label)); - tmp_pi->extra->num_labels = num_labels; + if (!bgp_path_info_labels_same(tmp_pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = bgp_labels_intern(&bgp_labels); + } if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (mac) @@ -1937,7 +2047,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * The attributes have changed, type-2 routes needs to * be advertised with right labels. */ - vni2label(vpn->vni, &label[0]); + vni2label(vpn->vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) { @@ -1945,12 +2056,17 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, l3vni = bgpevpn_get_l3vni(vpn); if (l3vni) { - vni2label(l3vni, &label[1]); - num_labels++; + vni2label(l3vni, &bgp_labels.label[1]); + bgp_labels.num_labels++; } } - memcpy(&tmp_pi->extra->label, label, sizeof(label)); - tmp_pi->extra->num_labels = num_labels; + if (!bgp_path_info_labels_same(tmp_pi, + &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = + bgp_labels_intern(&bgp_labels); + } if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (mac) @@ -1968,9 +2084,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, BGP_PATH_ATTR_CHANGED); /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum( - &local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = + bgp_attr_mac_mobility_seqnum(&local_attr); attr_new = bgp_attr_intern(&local_attr); @@ -2016,9 +2131,19 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp, if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && (curr_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(curr_select->attr))) - evpn_zebra_install(bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix(dest), - curr_select); + if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && + (curr_select->sub_type == BGP_ROUTE_IMPORTED || + bgp_evpn_attr_is_sync(curr_select->attr))) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + curr_select); + else + bgp_zebra_route_install(dest, curr_select, bgp, + true, vpn, false); + } } /* @@ -2093,10 +2218,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; - attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; - attr.router_flag = CHECK_FLAG(flags, - ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) attr.es_flags |= ATTR_ES_PROXY_ADVERT; @@ -2176,7 +2303,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * route would win, and we should evict the defunct local route * and (re)install the remote route into zebra. */ - evpn_route_select_install(bgp, vpn, dest); + evpn_route_select_install(bgp, vpn, dest, pi); /* * If the new local route was not selected evict it and tell zebra * to re-add the best remote dest. BGP doesn't retain non-best local @@ -2199,8 +2326,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * has been removed. */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); - if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, p, pi, true); + if (!new_is_sync && old_is_sync) { + if (CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_uninstall(bgp, vpn, p, pi, + true); + else + bgp_zebra_route_install(dest, pi, bgp, + false, vpn, + true); + } } } bgp_path_info_unlock(pi); @@ -2224,7 +2359,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, global_pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -2280,9 +2415,11 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp) if (!dest) return 0; + frrtrace(2, frr_bgp, evpn_withdraw_type5, bgp_vrf->vrf_id, evp); + delete_evpn_route_entry(bgp_evpn, afi, safi, dest, &pi); if (pi) - bgp_process(bgp_evpn, dest, afi, safi); + bgp_process(bgp_evpn, dest, pi, afi, safi); bgp_dest_unlock_node(dest); return 0; } @@ -2322,7 +2459,7 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -2330,9 +2467,8 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, */ delete_evpn_route_entry(bgp, afi, safi, dest, &pi); if (pi) { - dest = bgp_path_info_reap(dest, pi); - assert(dest); - evpn_route_select_install(bgp, vpn, dest); + bgp_path_info_delete(dest, pi); + evpn_route_select_install(bgp, vpn, dest, pi); } /* dest should still exist due to locking make coverity happy */ @@ -2389,13 +2525,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = (local_pi->attr->sticky) ? 1 : 0; - attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0; + attr.evpn_flags = local_pi->attr->evpn_flags; attr.es_flags = local_pi->attr->es_flags; - if (local_pi->attr->default_gw) { - attr.default_gw = 1; + if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); if (is_evpn_prefix_ipaddr_v6(&evp)) - attr.router_flag = 1; + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, @@ -2446,7 +2581,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * advertised to peers; otherwise, ensure it is evicted and * (re)install the remote route into zebra. */ - evpn_route_select_install(bgp, vpn, dest); + evpn_route_select_install(bgp, vpn, dest, pi); if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { route_change = 0; @@ -2464,8 +2599,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * has been removed. */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); - if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, &evp, pi, true); + if (!new_is_sync && old_is_sync) { + if (CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + (void)evpn_zebra_uninstall(bgp, vpn, + &evp, pi, + true); + else + bgp_zebra_route_install(dest, pi, bgp, + false, vpn, + true); + } } } @@ -2485,7 +2629,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, global_pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -2570,7 +2714,7 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) delete_evpn_route_entry(bgp, afi, safi, dest, &pi); if (pi) - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } /* Unlock RD node. */ @@ -2747,7 +2891,22 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) delete_all_type2_routes(bgp, vpn); build_evpn_type3_prefix(&p, vpn->originator_ip); + + /* + * To handle the following scenario: + * - Say, the new zebra announce fifo list has few vni Evpn prefixes yet + * to be sent to zebra. + * - At this point if we have triggers like "no advertise-all-vni" or + * "networking restart", where a vni is going down. + * + * Perform the below + * 1) send withdraw routes to zebra immediately in case it is installed. + * 2) before we blow up the vni table, we need to walk the list and + * pop all the dest whose za_vpn points to this vni. + */ + SET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN); ret = delete_evpn_route(bgp, vpn, &p); + UNSET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN); if (ret) return ret; @@ -2855,12 +3014,11 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, sizeof(struct bgp_path_info_extra_vrfleak)); pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi); bgp_dest_lock_node((struct bgp_dest *)parent_pi->net); - if (parent_pi->extra) { - memcpy(&pi->extra->label, &parent_pi->extra->label, - sizeof(pi->extra->label)); - pi->extra->num_labels = parent_pi->extra->num_labels; + if (parent_pi->extra) pi->extra->igpmetric = parent_pi->extra->igpmetric; - } + + if (bgp_path_info_num_labels(parent_pi)) + pi->extra->labels = bgp_labels_intern(parent_pi->extra->labels); bgp_path_info_add(dest, pi); @@ -2887,6 +3045,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, bool use_l3nhg = false; bool is_l3nhg_active = false; char buf1[INET6_ADDRSTRLEN]; + struct bgp_route_evpn *bre; memset(pp, 0, sizeof(struct prefix)); ip_prefix_from_evpn_prefix(evp, pp); @@ -2897,6 +3056,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi, parent_pi->flags); + if (bgp_vrf->vrf_id == VRF_UNKNOWN) + return -1; + /* Create (or fetch) route within the VRF. */ /* NOTE: There is no RD here. */ if (is_evpn_prefix_ipaddr_v4(evp)) { @@ -2917,35 +3079,33 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, * make sure to set the flag for next hop attribute. */ attr = *parent_pi->attr; - if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) { - if (afi == AFI_IP6) - evpn_convert_nexthop_to_ipv6(&attr); - else { - attr.nexthop = attr.mp_nexthop_global_in; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); - } - } else { - + bre = bgp_attr_get_evpn_overlay(&attr); + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { /* * If gateway IP overlay index is specified in the NLRI of * EVPN RT-5, this gateway IP should be used as the nexthop * for the prefix in the VRF */ if (bgp_debug_zebra(NULL)) { - zlog_debug( - "Install gateway IP %s as nexthop for prefix %pFX in vrf %s", - inet_ntop(pp->family, &attr.evpn_overlay.gw_ip, - buf1, sizeof(buf1)), pp, - vrf_id_to_name(bgp_vrf->vrf_id)); + zlog_debug("Install gateway IP %s as nexthop for prefix %pFX in vrf %s", + inet_ntop(pp->family, &bre->gw_ip, buf1, + sizeof(buf1)), + pp, vrf_id_to_name(bgp_vrf->vrf_id)); } if (afi == AFI_IP6) { - memcpy(&attr.mp_nexthop_global, - &attr.evpn_overlay.gw_ip.ipaddr_v6, + memcpy(&attr.mp_nexthop_global, &bre->gw_ip.ipaddr_v6, sizeof(struct in6_addr)); attr.mp_nexthop_len = IPV6_MAX_BYTELEN; } else { - attr.nexthop = attr.evpn_overlay.gw_ip.ipaddr_v4; + attr.nexthop = bre->gw_ip.ipaddr_v4; + attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + } + } else { + if (afi == AFI_IP6) + evpn_convert_nexthop_to_ipv6(&attr); + else { + attr.nexthop = attr.mp_nexthop_global_in; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); } } @@ -2997,22 +3157,20 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, } /* Gateway IP nexthop should be resolved */ - if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi, NULL, 0, NULL)) bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID); else { if (BGP_DEBUG(nht, NHT)) { - inet_ntop(pp->family, - &attr.evpn_overlay.gw_ip, - buf1, sizeof(buf1)); + inet_ntop(pp->family, &bre->gw_ip, buf1, + sizeof(buf1)); zlog_debug("%s: gateway IP NH unresolved", buf1); } bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID); } } else { - /* as it is an importation, change nexthop */ bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF); } @@ -3024,16 +3182,27 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, safi); /* Perform route selection and update zebra, if required. */ - bgp_process(bgp_vrf, dest, afi, safi); + bgp_process(bgp_vrf, dest, pi, afi, safi); /* Process for route leaking. */ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); - if (bgp_debug_zebra(NULL)) - zlog_debug("... %s pi dest %p (l %d) pi %p (l %d, f 0x%x)", - new_pi ? "new" : "update", dest, + if (bgp_debug_zebra(NULL)) { + struct ipaddr nhip = {}; + + if (pi->net->rn->p.family == AF_INET6) { + SET_IPADDR_V6(&nhip); + IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global); + } else { + SET_IPADDR_V4(&nhip); + IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop); + } + zlog_debug("... %s pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA", + new_pi ? "new" : "update", + bgp_vrf->name_pretty, dest, bgp_dest_get_lock_count(dest), pi, pi->lock, - pi->flags); + pi->flags, &nhip); + } bgp_dest_unlock_node(dest); @@ -3125,7 +3294,7 @@ static int install_evpn_route_entry_in_vni_common( bgp_evpn_remote_ip_hash_add(vpn, pi); /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install(bgp, vpn, dest); + ret = evpn_route_select_install(bgp, vpn, dest, pi); /* if the best path is a local path with a non-zero ES * sync info against the local path may need to be updated @@ -3167,7 +3336,7 @@ static int uninstall_evpn_route_entry_in_vni_common( bgp_path_info_delete(dest, pi); /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install(bgp, vpn, dest); + ret = evpn_route_select_install(bgp, vpn, dest, pi); /* if the best path is a local path with a non-zero ES * sync info against the local path may need to be updated @@ -3342,10 +3511,22 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, return 0; } - if (bgp_debug_zebra(NULL)) - zlog_debug("... delete dest %p (l %d) pi %p (l %d, f 0x%x)", - dest, bgp_dest_get_lock_count(dest), pi, pi->lock, - pi->flags); + if (bgp_debug_zebra(NULL)) { + struct ipaddr nhip = {}; + + if (pi->net->rn->p.family == AF_INET6) { + SET_IPADDR_V6(&nhip); + IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global); + } else { + SET_IPADDR_V4(&nhip); + IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop); + } + + zlog_debug("... delete pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA", + bgp_vrf->name_pretty, dest, + bgp_dest_get_lock_count(dest), pi, pi->lock, + pi->flags, &nhip); + } /* Process for route leaking. */ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi); @@ -3363,7 +3544,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, bgp_evpn_path_nh_del(bgp_vrf, pi); /* Perform route selection and update zebra, if required. */ - bgp_process(bgp_vrf, dest, afi, safi); + bgp_process(bgp_vrf, dest, pi, afi, safi); /* Unlock route node. */ bgp_dest_unlock_node(dest); @@ -3590,7 +3771,7 @@ static bool bgp_evpn_route_matches_macvrf_soo(struct bgp_path_info *pi, struct ecommunity *macvrf_soo; bool ret = false; - if (!bgp_evpn->evpn_info) + if (!bgp_evpn || !bgp_evpn->evpn_info) return false; /* We only stamp the mac-vrf soo on routes from our local L2VNI. @@ -3728,7 +3909,7 @@ int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf, * Install or uninstall mac-ip routes are appropriate for this * particular VRF. */ -static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) +static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install) { afi_t afi; safi_t safi; @@ -3792,9 +3973,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) * particular VNI. */ static int install_uninstall_routes_for_vni(struct bgp *bgp, - struct bgpevpn *vpn, - bgp_evpn_route_type rtype, - int install) + struct bgpevpn *vpn, bool install) { afi_t afi; safi_t safi; @@ -3825,7 +4004,9 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, (const struct prefix_evpn *)bgp_dest_get_prefix( dest); - if (evp->prefix.route_type != rtype) + if (evp->prefix.route_type != BGP_EVPN_IMET_ROUTE && + evp->prefix.route_type != BGP_EVPN_AD_ROUTE && + evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; for (pi = bgp_dest_get_bgp_path_info(dest); pi; @@ -3852,16 +4033,16 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, bgp, vpn, evp, pi); if (ret) { - flog_err( - EC_BGP_EVPN_FAIL, - "%u: Failed to %s EVPN %s route in VNI %u", - bgp->vrf_id, - install ? "install" - : "uninstall", - rtype == BGP_EVPN_MAC_IP_ROUTE - ? "MACIP" - : "IMET", - vpn->vni); + flog_err(EC_BGP_EVPN_FAIL, + "%u: Failed to %s EVPN %s route in VNI %u", + bgp->vrf_id, + install ? "install" + : "uninstall", + evp->prefix.route_type == + BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + vpn->vni); bgp_dest_unlock_node(rd_dest); bgp_dest_unlock_node(dest); @@ -3879,7 +4060,7 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, */ static int install_routes_for_vrf(struct bgp *bgp_vrf) { - install_uninstall_routes_for_vrf(bgp_vrf, 1); + install_uninstall_routes_for_vrf(bgp_vrf, true); return 0; } @@ -3890,29 +4071,17 @@ static int install_routes_for_vrf(struct bgp *bgp_vrf) */ static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - - /* Install type-3 routes followed by type-2 routes - the ones applicable + /* + * Install type-3 routes followed by type-2 routes - the ones applicable * for this VNI. */ - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE, - 1); - if (ret) - return ret; - - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE, - 1); - if (ret) - return ret; - - return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, - 1); + return install_uninstall_routes_for_vni(bgp, vpn, true); } /* uninstall routes from l3vni vrf. */ static int uninstall_routes_for_vrf(struct bgp *bgp_vrf) { - install_uninstall_routes_for_vrf(bgp_vrf, 0); + install_uninstall_routes_for_vrf(bgp_vrf, false); return 0; } @@ -3922,25 +4091,11 @@ static int uninstall_routes_for_vrf(struct bgp *bgp_vrf) */ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - - /* Uninstall type-2 routes followed by type-3 routes - the ones - * applicable - * for this VNI. + /* + * Uninstall type-2 routes followed by type-3 routes - the ones + * applicable for this VNI. */ - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, - 0); - if (ret) - return ret; - - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE, - 0); - if (ret) - return ret; - - - return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE, - 0); + return install_uninstall_routes_for_vni(bgp, vpn, false); } /* @@ -4360,7 +4515,7 @@ static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn, } /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, global_pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -4410,7 +4565,7 @@ static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -4455,7 +4610,7 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -4546,12 +4701,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, { struct prefix_rd prd; struct prefix_evpn p = {}; - struct bgp_route_evpn evpn = {}; uint8_t ipaddr_len; uint8_t macaddr_len; /* holds the VNI(s) as in packet */ mpls_label_t label[BGP_MAX_LABELS] = {}; - uint32_t num_labels = 0; + uint8_t num_labels = 0; uint32_t eth_tag; int ret = 0; @@ -4648,11 +4802,11 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, if (attr) bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, - &label[0], num_labels, 0, &evpn); + &label[0], num_labels, 0, NULL); else bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label[0], - num_labels, &evpn); + num_labels); goto done; fail: @@ -4742,8 +4896,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, 0, 0, NULL); else bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, - NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); return 0; } @@ -4756,7 +4909,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, { struct prefix_rd prd; struct prefix_evpn p; - struct bgp_route_evpn evpn; + struct bgp_route_evpn *evpn = XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); uint8_t ippfx_len; uint32_t eth_tag; mpls_label_t label; /* holds the VNI as in the packet */ @@ -4786,12 +4940,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, p.prefixlen = EVPN_ROUTE_PREFIXLEN; p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; - /* Additional information outside of prefix - ESI and GW IP */ - memset(&evpn, 0, sizeof(evpn)); - /* Fetch ESI overlay index */ if (attr) - memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t)); + memcpy(&evpn->eth_s_id, pfx, sizeof(esi_t)); pfx += ESI_BYTES; /* Fetch Ethernet Tag. */ @@ -4818,16 +4969,16 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, SET_IPADDR_V4(&p.prefix.prefix_addr.ip); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v4, pfx, 4); pfx += 4; - SET_IPADDR_V4(&evpn.gw_ip); - memcpy(&evpn.gw_ip.ipaddr_v4, pfx, 4); + SET_IPADDR_V4(&evpn->gw_ip); + memcpy(&evpn->gw_ip.ipaddr_v4, pfx, 4); pfx += 4; } else { SET_IPADDR_V6(&p.prefix.prefix_addr.ip); memcpy(&p.prefix.prefix_addr.ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); pfx += IPV6_MAX_BYTELEN; - SET_IPADDR_V6(&evpn.gw_ip); - memcpy(&evpn.gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); + SET_IPADDR_V6(&evpn->gw_ip); + memcpy(&evpn->gw_ip.ipaddr_v6, pfx, IPV6_MAX_BYTELEN); pfx += IPV6_MAX_BYTELEN; } @@ -4845,20 +4996,20 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, * An update containing a non-zero gateway IP and a non-zero ESI * at the same time is should be treated as withdraw */ - if (bgp_evpn_is_esi_valid(&evpn.eth_s_id) && - !ipaddr_is_zero(&evpn.gw_ip)) { + if (bgp_evpn_is_esi_valid(&evpn->eth_s_id) && + !ipaddr_is_zero(&evpn->gw_ip)) { flog_err(EC_BGP_EVPN_ROUTE_INVALID, "%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.", peer->host); is_valid_update = false; - } else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id)) - evpn.type = OVERLAY_INDEX_ESI; - else if (!ipaddr_is_zero(&evpn.gw_ip)) - evpn.type = OVERLAY_INDEX_GATEWAY_IP; + } else if (bgp_evpn_is_esi_valid(&evpn->eth_s_id)) + evpn->type = OVERLAY_INDEX_ESI; + else if (!ipaddr_is_zero(&evpn->gw_ip)) + evpn->type = OVERLAY_INDEX_GATEWAY_IP; if (attr) { if (is_zero_mac(&attr->rmac) && - !bgp_evpn_is_esi_valid(&evpn.eth_s_id) && - ipaddr_is_zero(&evpn.gw_ip) && label == 0) { + !bgp_evpn_is_esi_valid(&evpn->eth_s_id) && + ipaddr_is_zero(&evpn->gw_ip) && label == 0) { flog_err(EC_BGP_EVPN_ROUTE_INVALID, "%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero", peer->host); @@ -4873,7 +5024,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, if (attr && is_valid_update) bgp_update(peer, (struct prefix *)&p, addpath_id, attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, - &label, 1, 0, &evpn); + &label, 1, 0, evpn); else { if (!is_valid_update) { char attr_str[BUFSIZ] = {0}; @@ -4885,8 +5036,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, attr_str); } bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1, - &evpn); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, &label, 1); } return 0; @@ -4894,18 +5044,22 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct attr *attr) { int len; char temp[16]; const struct evpn_addr *p_evpn_p; + struct bgp_route_evpn *bre = NULL; memset(&temp, 0, sizeof(temp)); if (p->family != AF_EVPN) return; p_evpn_p = &(p->u.prefix_evpn); + if (attr) + bre = bgp_attr_get_evpn_overlay(attr); + /* len denites the total len of IP and GW-IP in the route IP and GW-IP have to be both ipv4 or ipv6 */ @@ -4916,7 +5070,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */ stream_putc(s, 8 + 10 + 4 + 1 + len + 3); stream_put(s, prd->val, 8); - if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI) + if (attr && bre && bre->type == OVERLAY_INDEX_ESI) stream_put(s, &attr->esi, sizeof(esi_t)); else stream_put(s, 0, sizeof(esi_t)); @@ -4926,15 +5080,11 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr); else stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16); - if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { - const struct bgp_route_evpn *evpn_overlay = - bgp_attr_get_evpn_overlay(attr); - + if (attr && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) - stream_put_ipv4(s, - evpn_overlay->gw_ip.ipaddr_v4.s_addr); + stream_put_ipv4(s, bre->gw_ip.ipaddr_v4.s_addr); else - stream_put(s, &(evpn_overlay->gw_ip.ipaddr_v6), 16); + stream_put(s, &(bre->gw_ip.ipaddr_v6), 16); } else { if (IS_IPADDR_V4(&p_evpn_p->prefix_addr.ip)) stream_put_ipv4(s, 0); @@ -5684,7 +5834,7 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) /* * TODO: Hardcoded for a maximum of 2 VNIs right now */ -char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf, +char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf, int len) { vni_t vni1, vni2; @@ -5768,7 +5918,7 @@ void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json) */ void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct attr *attr, + uint8_t num_labels, struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id) { struct prefix_evpn *evp = (struct prefix_evpn *)p; @@ -6045,7 +6195,7 @@ void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn) irt = lookup_import_rt(bgp, &eval_tmp); if (irt) - unmap_vni_from_rt(bgp, vpn, irt); + unmap_vni_from_rt(bgp, vpn, irt, eval); } } } @@ -6097,7 +6247,7 @@ void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn) snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, vpn->rd_id); (void)str2prefix_rd(buf, &vpn->prd); if (vpn->prd_pretty) - XFREE(MTYPE_BGP, vpn->prd_pretty); + XFREE(MTYPE_BGP_NAME, vpn->prd_pretty); UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD); } @@ -6191,6 +6341,19 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, */ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) { + struct bgp_dest *dest = NULL; + struct bgp_dest *dest_next = NULL; + + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; + dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); + if (dest->za_vpn == vpn) { + zebra_announce_del(&bm->zebra_announce_head, dest); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_dest_unlock_node(dest); + } + } + bgp_evpn_remote_ip_hash_destroy(vpn); bgp_evpn_vni_es_cleanup(vpn); bgpevpn_unlink_from_l3vni(vpn); @@ -6203,7 +6366,7 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) hash_release(bgp->vni_svi_hash, vpn); hash_release(bgp->vnihash, vpn); if (vpn->prd_pretty) - XFREE(MTYPE_BGP, vpn->prd_pretty); + XFREE(MTYPE_BGP_NAME, vpn->prd_pretty); QOBJ_UNREG(vpn); XFREE(MTYPE_BGP_EVPN, vpn); } @@ -6354,9 +6517,10 @@ void bgp_filter_evpn_routes_upon_martian_change( for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { + struct bgp_path_info *next; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { bool affected = false; const struct prefix *p; @@ -6832,6 +6996,17 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) return 0; } +/* + * When bgp instance goes down also clean up what might have been left over + * from evpn. + */ +void bgp_evpn_instance_down(struct bgp *bgp) +{ + /* If we have a stale local vni, delete it */ + if (bgp->l3vni) + bgp_evpn_local_l3vni_del(bgp->l3vni, bgp->vrf_id); +} + /* * Handle del of a local VNI. */ @@ -7080,7 +7255,7 @@ void bgp_evpn_cleanup(struct bgp *bgp) } if (bgp->vrf_prd_pretty) - XFREE(MTYPE_BGP, bgp->vrf_prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp->vrf_prd_pretty); } /* @@ -7598,7 +7773,7 @@ void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket, * */ mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels, - uint32_t num_labels) + uint8_t num_labels) { if (!labels) return NULL; @@ -7617,8 +7792,10 @@ vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi) if (!pi->extra) return 0; - return label2vni(bgp_evpn_path_info_labels_get_l3vni( - pi->extra->label, pi->extra->num_labels)); + return label2vni( + bgp_evpn_path_info_labels_get_l3vni(pi->extra->labels->label, + pi->extra->labels + ->num_labels)); } /* @@ -7650,3 +7827,64 @@ bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, return false; } + +/* Upon aggregate set trigger unimport suppressed routes + * from EVPN + */ +void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct bgp_dest *agg_dest, *dest, *top; + const struct prefix *aggr_p; + struct bgp_aggregate *bgp_aggregate; + struct bgp_table *table; + struct bgp_path_info *pi; + + if (!bgp_get_evpn() && !advertise_type5_routes(bgp, afi)) + return; + + /* Aggregate-address table walk. */ + table = bgp->rib[afi][safi]; + for (agg_dest = bgp_table_top(bgp->aggregate[afi][safi]); agg_dest; + agg_dest = bgp_route_next(agg_dest)) { + bgp_aggregate = bgp_dest_get_bgp_aggregate_info(agg_dest); + + if (bgp_aggregate == NULL) + continue; + + aggr_p = bgp_dest_get_prefix(agg_dest); + + /* Look all nodes below the aggregate prefix in + * global AFI/SAFI table (IPv4/IPv6). + * Trigger withdrawal (this will be Type-5 routes only) + * from EVPN Global table. + */ + top = bgp_node_get(table, aggr_p); + for (dest = bgp_node_get(table, aggr_p); dest; + dest = bgp_route_next_until(dest, top)) { + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + + if (dest_p->prefixlen <= aggr_p->prefixlen) + continue; + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) { + if (pi->sub_type == BGP_ROUTE_AGGREGATE) + continue; + + /* Only Suppressed route remove from EVPN */ + if (!bgp_path_suppressed(pi)) + continue; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s aggregated %pFX remove suppressed route %pFX", + __func__, aggr_p, dest_p); + + if (!is_route_injectable_into_evpn_non_supp(pi)) + continue; + + bgp_evpn_withdraw_type5_route(bgp, dest_p, afi, + safi); + } + } + } +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 55474464e593..dc82bcfba9e9 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -94,31 +94,6 @@ static inline bool is_pi_family_evpn(struct bgp_path_info *pi) return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN); } -/* Flag if the route is injectable into EVPN. This would be either a - * non-imported route or a non-EVPN imported route. - */ -static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi) -{ - struct bgp_path_info *parent_pi; - struct bgp_table *table; - struct bgp_dest *dest; - - if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || - !pi->extra->vrfleak || !pi->extra->vrfleak->parent) - return true; - - parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent; - dest = parent_pi->net; - if (!dest) - return true; - table = bgp_dest_table(dest); - if (table && - table->afi == AFI_L2VPN && - table->safi == SAFI_EVPN) - return false; - return true; -} - static inline bool evpn_resolve_overlay_index(void) { struct bgp *bgp = NULL; @@ -140,12 +115,12 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf); extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); -extern char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, +extern char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf, int len); extern void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json); extern void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, @@ -178,6 +153,7 @@ extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct in_addr originator_ip, int filter, ifindex_t svi_ifindex, bool is_anycast_mac); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); +extern void bgp_evpn_instance_down(struct bgp *bgp); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip, @@ -202,9 +178,21 @@ extern void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket, void *arg); extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels, - uint32_t num_labels); + uint8_t num_labels); extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi); extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, struct bgp_path_info *mpinfo); - +extern bool is_route_injectable_into_evpn(struct bgp_path_info *pi); +extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi); +extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, + safi_t safi); + +extern enum zclient_send_status evpn_zebra_install(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi); +extern enum zclient_send_status +evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, struct bgp_path_info *pi, + bool is_sync); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index ffb1b17ec7f7..f4528defc295 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -37,7 +37,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_addpath.h" #include "bgpd/bgp_label.h" -#include "bgpd/bgp_nht.h" +#include "bgpd/bgp_nhg.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_trace.h" @@ -45,13 +45,14 @@ static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es); static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp, struct bgp_evpn_es *es); -static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, +static struct bgp_evpn_es_vtep * +bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es, + struct in_addr vtep_ip, bool esr, uint8_t df_alg, + uint16_t df_pref, int *zret); +static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp, struct bgp_evpn_es *es, struct in_addr vtep_ip, - bool esr, uint8_t df_alg, - uint16_t df_pref); -static void bgp_evpn_es_vtep_del(struct bgp *bgp, - struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr); + bool esr); static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es); static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es); static struct bgp_evpn_es_evi * @@ -91,15 +92,19 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info); */ static int bgp_evpn_es_route_select_install(struct bgp *bgp, struct bgp_evpn_es *es, - struct bgp_dest *dest) + struct bgp_dest *dest, + struct bgp_path_info *pi) { int ret = 0; + int zret = 0; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; struct bgp_path_info *old_select; /* old best */ struct bgp_path_info *new_select; /* new best */ struct bgp_path_info_pair old_and_new; + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); + /* Compute the best path. */ bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new, afi, safi); @@ -120,7 +125,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, bgp_evpn_es_vtep_add(bgp, es, old_select->attr->nexthop, true /*esr*/, old_select->attr->df_alg, - old_select->attr->df_pref); + old_select->attr->df_pref, &zret); } UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(dest); @@ -149,7 +154,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, && new_select->sub_type == BGP_ROUTE_IMPORTED) { bgp_evpn_es_vtep_add(bgp, es, new_select->attr->nexthop, true /*esr */, new_select->attr->df_alg, - new_select->attr->df_pref); + new_select->attr->df_pref, &zret); } else { if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_IMPORTED) @@ -231,7 +236,7 @@ static int bgp_evpn_es_route_install(struct bgp *bgp, } /* Perform route selection and update zebra, if required. */ - ret = bgp_evpn_es_route_select_install(bgp, es, dest); + ret = bgp_evpn_es_route_select_install(bgp, es, dest, pi); bgp_dest_unlock_node(dest); @@ -272,7 +277,7 @@ static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es, bgp_path_info_delete(dest, pi); /* Perform route selection and update zebra, if required. */ - ret = bgp_evpn_es_route_select_install(bgp, es, dest); + ret = bgp_evpn_es_route_select_install(bgp, es, dest, pi); /* Unlock route node. */ bgp_dest_unlock_node(dest); @@ -353,6 +358,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, struct bgp_path_info *tmp_pi = NULL; struct bgp_path_info *local_pi = NULL; /* local route entry if any */ struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */ + struct bgp_labels bgp_labels = {}; struct attr *attr_new = NULL; struct prefix_evpn *evp; @@ -399,11 +405,16 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) { bgp_path_info_extra_get(tmp_pi); - tmp_pi->extra->num_labels = 1; + bgp_labels.num_labels = 1; if (vpn) - vni2label(vpn->vni, &tmp_pi->extra->label[0]); - else - tmp_pi->extra->label[0] = 0; + vni2label(vpn->vni, &bgp_labels.label[0]); + if (!bgp_path_info_labels_same(tmp_pi, + &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = + bgp_labels_intern(&bgp_labels); + } } /* add the newly created path to the route-node */ @@ -441,9 +452,13 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, ? "esr" : (vpn ? "ead-evi" : "ead-es"), &attr->mp_nexthop_global_in); + + frrtrace(4, frr_bgp, evpn_mh_local_ead_es_evi_route_upd, + &es->esi, (vpn ? vpn->vni : 0), evp->prefix.route_type, + attr->mp_nexthop_global_in); } - /* Return back the route entry. */ + /* Return back th*e route entry. */ *ri = tmp_pi; return 0; } @@ -491,6 +506,8 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, : (vpn ? "ead-evi" : "ead-es"), &es->originator_ip); + frrtrace(4, frr_bgp, evpn_mh_local_ead_es_evi_route_del, &es->esi, + (vpn ? vpn->vni : 0), p->prefix.route_type, es->originator_ip); /* Next, locate route node in the global EVPN routing table. * Note that this table is a 2-level tree (RD-level + Prefix-level) */ @@ -505,7 +522,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -556,7 +573,7 @@ int delete_global_ead_evi_routes(struct bgp *bgp, struct bgpevpn *vpn) delete_evpn_route_entry(bgp, afi, safi, bd, &pi); if (pi) - bgp_process(bgp, bd, afi, safi); + bgp_process(bgp, bd, pi, afi, safi); } } @@ -662,7 +679,7 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp, * this is just to set the flags correctly * as local route in the ES always wins. */ - bgp_evpn_es_route_select_install(bgp, es, dest); + bgp_evpn_es_route_select_install(bgp, es, dest, pi); bgp_dest_unlock_node(dest); /* If this is a new route or some attribute has changed, export the @@ -680,7 +697,7 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp, attr_new, &global_pi, &route_changed); /* Schedule for processing and unlock node. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, global_pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -753,8 +770,7 @@ int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi, 0, 0, NULL); } else { bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, - NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } return 0; } @@ -1002,7 +1018,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es, * this is just to set the flags correctly as local route in * the ES always wins. */ - evpn_route_select_install(bgp, vpn, dest); + evpn_route_select_install(bgp, vpn, dest, pi); bgp_dest_unlock_node(dest); /* If this is a new route or some attribute has changed, export the @@ -1019,7 +1035,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es, attr_new, &global_pi, &route_changed); /* Schedule for processing and unlock node. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, global_pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -1222,8 +1238,7 @@ int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi, 0, 0, NULL); } else { bgp_withdraw(peer, (struct prefix *)&p, addpath_id, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, - NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); } return 0; } @@ -1365,23 +1380,28 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es, } /* Send the remote ES to zebra for NHG programming */ -static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, bool add) +static enum zclient_send_status +bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, + bool add) { struct bgp_evpn_es *es = es_vtep->es; struct stream *s; uint32_t flags = 0; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("No zebra instance, not installing remote es %s", es->esi_str); - return 0; + return ZCLIENT_SEND_SUCCESS; } if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) @@ -1412,12 +1432,12 @@ static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, return zclient_send_message(zclient); } -static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, - bool param_change) +static enum zclient_send_status bgp_evpn_es_vtep_re_eval_active( + struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, bool param_change) { bool old_active; bool new_active; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; old_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); /* currently we need an active EVI reference to use the VTEP as @@ -1439,7 +1459,7 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, es_vtep->df_alg, es_vtep->df_pref); /* send remote ES to zebra */ - bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); + ret = bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); /* The NHG is updated first for efficient failover handling. * Note the NHG can be de-activated while there are bgp @@ -1451,13 +1471,14 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, /* queue up the es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(es_vtep->es); } + + return ret; } -static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, - struct bgp_evpn_es *es, - struct in_addr vtep_ip, - bool esr, uint8_t df_alg, - uint16_t df_pref) +static struct bgp_evpn_es_vtep * +bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es, + struct in_addr vtep_ip, bool esr, uint8_t df_alg, + uint16_t df_pref, int *zret) { struct bgp_evpn_es_vtep *es_vtep; bool param_change = false; @@ -1484,15 +1505,17 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, ++es_vtep->evi_cnt; } - bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); + *zret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); return es_vtep; } -static void bgp_evpn_es_vtep_do_del(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, bool esr) +static enum zclient_send_status +bgp_evpn_es_vtep_do_del(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, + bool esr) { bool param_change = false; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str, @@ -1509,18 +1532,25 @@ static void bgp_evpn_es_vtep_do_del(struct bgp *bgp, --es_vtep->evi_cnt; } - bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); + ret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); bgp_evpn_es_vtep_free(es_vtep); + + return ret; } -static void bgp_evpn_es_vtep_del(struct bgp *bgp, - struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr) +static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp, + struct bgp_evpn_es *es, + struct in_addr vtep_ip, + bool esr) { struct bgp_evpn_es_vtep *es_vtep; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip); if (es_vtep) - bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); + ret = bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); + + return ret; } /********************** ES MAC-IP paths ************************************* @@ -2429,7 +2459,7 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty, } static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es, - uint8_t vtep_str_size) + size_t vtep_str_size) { char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ]; struct listnode *node; @@ -2999,8 +3029,8 @@ static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es, listnode_add(es->es_vrf_list, &es_vrf->es_listnode); /* setup the L3 NHG id for the ES */ - es_vrf->nhg_id = bgp_l3nhg_id_alloc(); - es_vrf->v6_nhg_id = bgp_l3nhg_id_alloc(); + es_vrf->nhg_id = bgp_nhg_id_alloc(); + es_vrf->v6_nhg_id = bgp_nhg_id_alloc(); if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es->esi_str, @@ -3028,10 +3058,10 @@ static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf) /* Remove the NHG resources */ bgp_evpn_l3nhg_deactivate(es_vrf); if (es_vrf->nhg_id) - bgp_l3nhg_id_free(es_vrf->nhg_id); + bgp_nhg_id_free(es_vrf->nhg_id); es_vrf->nhg_id = 0; if (es_vrf->v6_nhg_id) - bgp_l3nhg_id_free(es_vrf->v6_nhg_id); + bgp_nhg_id_free(es_vrf->v6_nhg_id); es_vrf->v6_nhg_id = 0; /* remove from the ES's VRF list */ @@ -3393,12 +3423,14 @@ static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find( /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and * EAD-per-EVI routes are rxed from it. */ -static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, - struct bgp_evpn_es_evi_vtep *evi_vtep) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, + struct bgp_evpn_es_evi_vtep *evi_vtep) { bool old_active; bool new_active; uint32_t ead_activity_flags; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; old_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); @@ -3419,7 +3451,7 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, new_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); if (old_active == new_active) - return; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s evi %u vtep %pI4 %s", @@ -3428,24 +3460,27 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, new_active ? "active" : "inactive"); /* add VTEP to parent es */ - if (new_active) - evi_vtep->es_vtep = bgp_evpn_es_vtep_add( - bgp, evi_vtep->es_evi->es, evi_vtep->vtep_ip, - false /*esr*/, 0, 0); - else { + if (new_active) { + evi_vtep->es_vtep = + bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es, + evi_vtep->vtep_ip, false /*esr*/, + 0, 0, &ret); + } else { if (evi_vtep->es_vtep) { - bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep, - false /*esr*/); + ret = bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep, + false /*esr*/); evi_vtep->es_vtep = NULL; } } /* queue up the parent es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es); + + return ret; } -static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, - struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip, - bool ead_es) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_add(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi, + struct in_addr vtep_ip, bool ead_es) { struct bgp_evpn_es_evi_vtep *evi_vtep; @@ -3460,23 +3495,28 @@ static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip, ead_es ? "ead_es" : "ead_evi"); + frrtrace(4, frr_bgp, evpn_mh_es_evi_vtep_add, + &evi_vtep->es_evi->es->esi, evi_vtep->es_evi->vpn->vni, + evi_vtep->vtep_ip, ead_es); + if (ead_es) SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES); else SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI); - bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + return bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); } -static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, - struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip, - bool ead_es) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_del(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi, + struct in_addr vtep_ip, bool ead_es) { struct bgp_evpn_es_evi_vtep *evi_vtep; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip); if (!evi_vtep) - return; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("del es %s evi %u vtep %pI4 %s", @@ -3484,13 +3524,19 @@ static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip, ead_es ? "ead_es" : "ead_evi"); + frrtrace(4, frr_bgp, evpn_mh_es_evi_vtep_del, + &evi_vtep->es_evi->es->esi, evi_vtep->es_evi->vpn->vni, + evi_vtep->vtep_ip, ead_es); + if (ead_es) UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES); else UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI); - bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + ret = bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); bgp_evpn_es_evi_vtep_free(evi_vtep); + + return ret; } /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */ @@ -3766,18 +3812,20 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni) /* Add remote ES-EVI entry. This is actually the remote VTEP add and the * ES-EVI is implicity created on first VTEP's reference. */ -int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p) +enum zclient_send_status bgp_evpn_remote_es_evi_add(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; struct bgp_evpn_es_evi *es_evi; bool ead_es; const esi_t *esi = &p->prefix.ead_addr.esi; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (!vpn) /* local EAD-ES need not be sent back to zebra */ - return 0; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("add remote %s es %s evi %u vtep %pI4", @@ -3794,27 +3842,29 @@ int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, es_evi = bgp_evpn_es_evi_new(es, vpn); ead_es = !!p->prefix.ead_addr.eth_tag; - bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4, - ead_es); + ret = bgp_evpn_es_evi_vtep_add(bgp, es_evi, + p->prefix.ead_addr.ip.ipaddr_v4, ead_es); bgp_evpn_es_evi_remote_info_re_eval(es_evi); - return 0; + return ret; } /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the * parent es-evi freed up implicitly in last VTEP's deref. */ -int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p) +enum zclient_send_status bgp_evpn_remote_es_evi_del(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; struct bgp_evpn_es_evi *es_evi; bool ead_es; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (!vpn) /* local EAD-ES need not be sent back to zebra */ - return 0; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug( @@ -3833,7 +3883,7 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)), vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4); - return 0; + return ret; } es_evi = bgp_evpn_es_evi_find(es, vpn); if (!es_evi) { @@ -3846,14 +3896,15 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, sizeof(buf)), vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4); - return 0; + return ret; } ead_es = !!p->prefix.ead_addr.eth_tag; - bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4, - ead_es); + ret = bgp_evpn_es_evi_vtep_del(bgp, es_evi, + p->prefix.ead_addr.ip.ipaddr_v4, ead_es); bgp_evpn_es_evi_remote_info_re_eval(es_evi); - return 0; + + return ret; } /* If a VNI is being deleted we need to force del all remote VTEPs */ @@ -3909,7 +3960,7 @@ void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn) static char *bgp_evpn_es_evi_vteps_str(char *vtep_str, struct bgp_evpn_es_evi *es_evi, - uint8_t vtep_str_size) + size_t vtep_str_size) { char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ]; struct listnode *node; @@ -4443,13 +4494,13 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add) stream_putw_at(s, 0, stream_get_endp(s)); - if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) { + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES) || bgp_debug_zebra(NULL)) { if (add) - zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra", + zlog_debug("evpn %s nh %s rmac %pEA add to zebra", nh->bgp_vrf->name_pretty, nh->nh_str, &nh->rmac); - else if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("evpn vrf %s nh %s del to zebra", + else + zlog_debug("evpn %s nh %s del to zebra", nh->bgp_vrf->name_pretty, nh->nh_str); } @@ -4632,7 +4683,7 @@ static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh *nh) continue; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("evpn vrf %s nh %s ref_pi update", + zlog_debug("evpn %s nh %s ref_pi update", nh->bgp_vrf->name_pretty, nh->nh_str); nh->ref_pi = pi; /* If we have a new pi copy rmac from it and update @@ -4710,11 +4761,12 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info) pi = nh_info->pi; if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %s unlinked from nh %s %s", + zlog_debug("path %s unlinked from %s nh %s pathcount %u", pi->net ? prefix2str(&pi->net->rn->p, prefix_buf, sizeof(prefix_buf)) : "", - nh->bgp_vrf->name_pretty, nh->nh_str); + nh->bgp_vrf->name_pretty, nh->nh_str, + listcount(nh->pi_list)); list_delete_node(nh->pi_list, &nh_info->nh_listnode); @@ -4745,7 +4797,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) if (!bgp_vrf->evpn_nh_table) { if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %pFX linked to vrf %s failed", + zlog_debug("path %pFX linked to %s failed", &pi->net->rn->p, bgp_vrf->name_pretty); return; } @@ -4793,8 +4845,9 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) bgp_evpn_path_nh_unlink(nh_info); if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %pFX linked to nh %s %s", &pi->net->rn->p, - nh->bgp_vrf->name_pretty, nh->nh_str); + zlog_debug("path %pFX linked to %s nh %s pathcount %u", + &pi->net->rn->p, nh->bgp_vrf->name_pretty, + nh->nh_str, listcount(nh->pi_list)); /* link mac-ip path to the new nh */ nh_info->nh = nh; diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index ee1f74989b77..5d393c37a20d 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -388,11 +388,6 @@ static inline bool bgp_evpn_attr_is_local_es(struct attr *attr) return attr ? !!(attr->es_flags & ATTR_ES_IS_LOCAL) : false; } -static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr *attr) -{ - return (attr) ? attr->df_pref : 0; -} - static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es) { return (es->flags & BGP_EVPNES_OPER_UP) @@ -423,10 +418,12 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi); extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni); extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni); -extern int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p); -extern int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p); +extern enum zclient_send_status +bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p); +extern enum zclient_send_status +bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p); extern void bgp_evpn_mh_init(void); extern void bgp_evpn_mh_finish(void); void bgp_evpn_vni_es_init(struct bgpevpn *vpn); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 5af99afa346d..b05df3d82ae7 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, } static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, - uint8_t na_flag, bool proxy) + bool na_flag, bool proxy) { memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_EVPN; @@ -716,7 +716,8 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_path_info **pi); int vni_list_cmp(void *p1, void *p2); extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_dest *dest); + struct bgp_dest *dest, + struct bgp_path_info *pi); extern struct bgp_dest * bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi, const struct prefix_evpn *evp, struct prefix_rd *prd, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index e4c7fdb124f0..c28cdb4a6521 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2294,11 +2294,11 @@ static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd, bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1); if (bgp_vrf->vrf_prd_pretty) - XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp_vrf->vrf_prd_pretty); /* update RD */ memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd)); - bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty); + bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_pretty); SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD); /* We have a new RD for VRF. @@ -2321,7 +2321,7 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf) bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf); UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD); if (bgp_vrf->vrf_prd_pretty) - XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp_vrf->vrf_prd_pretty); /* We have a new RD for VRF. * Advertise all type-5 routes again with the new RD */ @@ -2343,7 +2343,7 @@ static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn, /* update RD */ memcpy(&vpn->prd, rd, sizeof(struct prefix_rd)); - vpn->prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty); + vpn->prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_pretty); SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD); if (is_vni_live(vpn)) @@ -2687,16 +2687,16 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, */ if (is_evpn_prefix_ipaddr_none(evp)) { /* VNI MAC -> Global */ - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, evp, - NULL /* mac */, - evpn_type2_path_info_get_ip(pi)); + evpn_type2_prefix_global_copy(&tmp_p, evp, + NULL /* mac */, + evpn_type2_path_info_get_ip( + pi)); } else { /* VNI IP -> Global */ - evpn_type2_prefix_global_copy( - (struct prefix_evpn *)&tmp_p, evp, - evpn_type2_path_info_get_mac(pi), - NULL /* ip */); + evpn_type2_prefix_global_copy(&tmp_p, evp, + evpn_type2_path_info_get_mac( + pi), + NULL /* ip */); } route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, @@ -4840,7 +4840,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd, char *vrf = NULL; char *neighbor = NULL; as_t as = 0; /* 0 means AS filter not set */ - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; uint16_t show_flags = 0; if (argv_find(argv, argc, "vrf", &idx_vrf)) diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index ad541b67ad44..002f054f5e41 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -16,7 +16,7 @@ #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" -/* List of AS filter list. */ +/* List of AS list. */ struct as_list_list { struct as_list *head; struct as_list *tail; @@ -205,8 +205,9 @@ static struct as_list *as_list_new(void) static void as_list_free(struct as_list *aslist) { - XFREE(MTYPE_AS_STR, aslist->name); - XFREE(MTYPE_AS_LIST, aslist); + + XFREE (MTYPE_AS_STR, aslist->name); + XFREE (MTYPE_AS_LIST, aslist); } /* Insert new AS list to list of as_list. Each as_list is sorted by @@ -415,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; regex_t *regex; char *regstr; int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; @@ -466,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd, else as_list_filter_add(aslist, asfilter); + /* init the exclude rule list*/ + as_list_list_init(&aslist->exclude_rule); + + /* get aspath orphan exclude that are using this acl */ + ase = as_exclude_lookup_orphan(alname); + if (ase) { + as_list_list_add_head(&aslist->exclude_rule, ase); + /* set reverse pointer */ + ase->exclude_aspath_acl = aslist; + /* set list of aspath excludes using that acl */ + while ((ase = as_exclude_lookup_orphan(alname))) { + as_list_list_add_head(&aslist->exclude_rule, ase); + ase->exclude_aspath_acl = aslist; + } + } + return CMD_SUCCESS; } @@ -486,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; char *regstr; regex_t *regex; @@ -540,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, XFREE(MTYPE_TMP, regstr); + /* put aspath exclude list into orphan */ + if (as_list_list_count(&aslist->exclude_rule)) + while ((ase = as_list_list_pop(&aslist->exclude_rule))) + as_exclude_set_orphan(ase); + + as_list_list_fini(&aslist->exclude_rule); as_list_filter_delete(aslist, asfilter); return CMD_SUCCESS; diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 1890fd3d9664..77a3f3c2f727 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -6,11 +6,12 @@ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H +#include + #define ASPATH_SEQ_NUMBER_AUTO -1 enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; - /* Element of AS path filter. */ struct as_filter { struct as_filter *next; @@ -25,6 +26,7 @@ struct as_filter { int64_t seq; }; +PREDECL_DLIST(as_list_list); /* AS path filter list. */ struct as_list { char *name; @@ -34,6 +36,9 @@ struct as_list { struct as_filter *head; struct as_filter *tail; + + /* Changes in AS path */ + struct as_list_list_head exclude_rule; }; diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 6165bf892e72..bd04970fd58c 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -195,7 +195,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, NULL, 0, 0, NULL); } else { bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL); + BGP_ROUTE_NORMAL, NULL, NULL, 0); } XFREE(MTYPE_TMP, temp); diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index a295ec5a14df..d4ccca84bb20 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -547,7 +547,7 @@ static int bgp_fs_local_install_interface(struct bgp *bgp, return CMD_SUCCESS; pbr_if = XCALLOC(MTYPE_TMP, sizeof(struct bgp_pbr_interface)); - strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ); + strlcpy(pbr_if->name, ifname, IFNAMSIZ); RB_INSERT(bgp_pbr_interface_head, head, pbr_if); *bgp_pbr_interface_any = false; } else { diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index eef3b644080a..2f432abb4bfa 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -260,6 +260,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi]; peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi]; peer->llgr[afi][safi] = from_peer->llgr[afi][safi]; + peer->addpath_paths_limit[afi][safi] = + from_peer->addpath_paths_limit[afi][safi]; } if (bgp_getsockname(peer) < 0) { @@ -445,7 +447,7 @@ void bgp_timer_set(struct peer_connection *connection) EVENT_OFF(peer->connection->t_pmax_restart); EVENT_OFF(peer->t_refresh_stalepath); - /* fallthru */ + fallthrough; case Clearing: EVENT_OFF(connection->t_start); EVENT_OFF(connection->t_connect); @@ -562,42 +564,46 @@ void bgp_delayopen_timer(struct event *thread) } /* BGP Peer Down Cause */ -const char *const peer_down_str[] = {"", - "Router ID changed", - "Remote AS changed", - "Local AS change", - "Cluster ID changed", - "Confederation identifier changed", - "Confederation peer changed", - "RR client config change", - "RS client config change", - "Update source change", - "Address family activated", - "Admin. shutdown", - "User reset", - "BGP Notification received", - "BGP Notification send", - "Peer closed the session", - "Neighbor deleted", - "Peer-group add member", - "Peer-group delete member", - "Capability changed", - "Passive config change", - "Multihop config change", - "NSF peer closed the session", - "Intf peering v6only config change", - "BFD down received", - "Interface down", - "Neighbor address lost", - "No path to specified Neighbor", - "Waiting for Peer IPv6 LLA", - "Waiting for VRF to be initialized", - "No AFI/SAFI activated for peer", - "AS Set config change", - "Waiting for peer OPEN", - "Reached received prefix count", - "Socket Error", - "Admin. shutdown (RTT)"}; +const char *const peer_down_str[] = { + "", + "Router ID changed", + "Remote AS changed", + "Local AS change", + "Cluster ID changed", + "Confederation identifier changed", + "Confederation peer changed", + "RR client config change", + "RS client config change", + "Update source change", + "Address family activated", + "Admin. shutdown", + "User reset", + "BGP Notification received", + "BGP Notification send", + "Peer closed the session", + "Neighbor deleted", + "Peer-group add member", + "Peer-group delete member", + "Capability changed", + "Passive config change", + "Multihop config change", + "NSF peer closed the session", + "Intf peering v6only config change", + "BFD down received", + "Interface down", + "Neighbor address lost", + "No path to specified Neighbor", + "Waiting for Peer IPv6 LLA", + "Waiting for VRF to be initialized", + "No AFI/SAFI activated for peer", + "AS Set config change", + "Waiting for peer OPEN", + "Reached received prefix count", + "Socket Error", + "Admin. shutdown (RTT)", + "Suppress Fib Turned On or Off", + "Password config change", +}; static void bgp_graceful_restart_timer_off(struct peer_connection *connection, struct peer *peer) @@ -1236,7 +1242,7 @@ void bgp_fsm_change_status(struct peer_connection *connection, /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ - if (status >= Clearing) { + if (status >= Clearing && (peer->established || peer == bgp->peer_self)) { bgp_clear_route_all(peer); /* If no route was queued for the clear-node processing, @@ -1477,7 +1483,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) EVENT_OFF(connection->t_connect); EVENT_OFF(connection->t_holdtime); EVENT_OFF(connection->t_routeadv); - EVENT_OFF(peer->connection->t_delayopen); + EVENT_OFF(connection->t_delayopen); /* Clear input and output buffer. */ frr_with_mutex (&connection->io_mtx) { @@ -1531,6 +1537,12 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) } } + /* Reset the rtc-plist */ + if (peer->rtc_plist != NULL) { + prefix_list_delete(peer->rtc_plist); + peer->rtc_plist = NULL; + } + /* Reset keepalive and holdtime */ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) { peer->v_keepalive = peer->keepalive; @@ -1584,7 +1596,7 @@ bgp_stop_with_error(struct peer_connection *connection) /* something went wrong, send notify and tear down */ -static enum bgp_fsm_state_progress +enum bgp_fsm_state_progress bgp_stop_with_notify(struct peer_connection *connection, uint8_t code, uint8_t sub_code) { @@ -1774,7 +1786,7 @@ bgp_connect_fail(struct peer_connection *connection) { struct peer *peer = connection->peer; - if (peer_dynamic_neighbor(peer)) { + if (peer_dynamic_neighbor_no_nsf(peer)) { if (bgp_debug_neighbor_events(peer)) zlog_debug("%s (dynamic neighbor) deleted (%s)", peer->host, __func__); @@ -1791,6 +1803,26 @@ bgp_connect_fail(struct peer_connection *connection) return bgp_stop(connection); } +/* after connect is called(), getpeername is able to return + * port and address on non established streams + */ +static void bgp_connect_in_progress_update_connection(struct peer *peer) +{ + if (bgp_getsockname(peer) < 0) { + if (!peer->su_remote && + !BGP_CONNECTION_SU_UNSPEC(peer->connection)) { + /* if connect initiated, then dest port and dest addresses are well known */ + peer->su_remote = sockunion_dup(&peer->connection->su); + if (sockunion_family(peer->su_remote) == AF_INET) + peer->su_remote->sin.sin_port = + htons(peer->port); + else if (sockunion_family(peer->su_remote) == AF_INET6) + peer->su_remote->sin6.sin6_port = + htons(peer->port); + } + } +} + /* This function is the first starting point of all BGP connection. It * try to connect to remote peer with non-blocking IO. */ @@ -1887,6 +1919,8 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) __func__, peer->connection->fd); return BGP_FSM_FAILURE; } + bgp_connect_in_progress_update_connection(peer); + /* * - when the socket becomes ready, poll() will signify POLLOUT * - if it fails to connect, poll() will signify POLLHUP @@ -2019,9 +2053,10 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi, } gr_info->eor_required++; /* Send message to RIB indicating route update pending */ - if (gr_info->af_enabled[afi][safi] == false) { - gr_info->af_enabled[afi][safi] = true; - /* Send message to RIB */ + if (gr_info->af_enabled == false) { + gr_info->af_enabled = true; + gr_info->route_sync = false; + bgp->gr_route_sync_pending = true; bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); } @@ -2055,7 +2090,7 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer)) { /* Check if the forwarding state is preserved */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { + if (bgp_gr_is_forwarding_preserved(bgp)) { gr_info = &(bgp->gr_info[afi][safi]); ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); } @@ -2172,8 +2207,7 @@ bgp_establish(struct peer_connection *connection) } else { if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer) && - CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) + bgp_gr_is_forwarding_preserved(peer->bgp)) peer->bgp->gr_info[afi][safi] .eor_required++; } @@ -2384,6 +2418,7 @@ void bgp_fsm_nht_update(struct peer_connection *connection, struct peer *peer, && (peer->gtsm_hops == BGP_GTSM_HOPS_CONNECTED || peer->bgp->fast_convergence)) BGP_EVENT_ADD(connection, TCP_fatal_error); + break; case Clearing: case Deleted: case BGP_STATUS_MAX: @@ -2667,100 +2702,89 @@ int bgp_event_update(struct peer_connection *connection, } /* BGP GR Code */ -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state) +static inline void +bgp_peer_inherit_global_gr_mode(struct peer *peer, + enum global_mode global_gr_mode) +{ + switch (global_gr_mode) { + case GLOBAL_HELPER: + BGP_PEER_GR_HELPER_ENABLE(peer); + break; + case GLOBAL_GR: + BGP_PEER_GR_ENABLE(peer); + break; + case GLOBAL_DISABLE: + BGP_PEER_GR_DISABLE(peer); + break; + case GLOBAL_INVALID: + default: + zlog_err("Unexpected Global GR mode %d", global_gr_mode); + } +} + +static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, + enum global_mode global_new_state) { struct peer *peer = {0}; struct listnode *node = {0}; struct listnode *nnode = {0}; enum peer_mode peer_old_state = PEER_INVALID; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__, - peer->host); + /* TODO: Need to handle peer-groups. */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { peer_old_state = bgp_peer_gr_mode_get(peer); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; - if (peer_old_state == PEER_GLOBAL_INHERIT) { + bgp_peer_inherit_global_gr_mode(peer, global_new_state); + bgp_peer_gr_flags_update(peer); - /* - *Reset only these peers and send a - *new open message with the change capabilities. - *Considering the mode to be "global_new_state" and - *do all operation accordingly - */ - - switch (global_new_state) { - case GLOBAL_HELPER: - BGP_PEER_GR_HELPER_ENABLE(peer); - break; - case GLOBAL_GR: - BGP_PEER_GR_ENABLE(peer); - break; - case GLOBAL_DISABLE: - BGP_PEER_GR_DISABLE(peer); - break; - case GLOBAL_INVALID: - zlog_debug("%s [BGP_GR] GLOBAL_INVALID", - __func__); - return BGP_ERR_GR_OPERATION_FAILED; - } - } - } + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + peer, peer->peer_gr_new_status_flag, + peer->flags); - bgp->global_gr_present_state = global_new_state; + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - return BGP_GR_SUCCESS; + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. + */ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset_safe(peer, &nnode); + } } -int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd) +int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) { enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__, - print_global_gr_cmd(global_gr_cmd)); - global_old_state = bgp_global_gr_mode_get(bgp); + global_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_old_gr_state :%s:", - print_global_gr_mode(global_old_state)); + zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s", + bgp->name_pretty, print_global_gr_cmd(global_gr_cmd), + print_global_gr_mode(global_old_state), + print_global_gr_mode(global_new_state)); - if (global_old_state != GLOBAL_INVALID) { - global_new_state = - bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_new_gr_state :%s:", - print_global_gr_mode(global_new_state)); - } else { - zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", - __func__); + if (global_old_state == GLOBAL_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - } - - if (global_new_state == GLOBAL_INVALID) { - zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID", - __func__); + if (global_new_state == GLOBAL_INVALID) return BGP_ERR_GR_INVALID_CMD; - } - if (global_new_state == global_old_state) { - /* Trace msg */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] global_new_state == global_old_state :%s", - __func__, - print_global_gr_mode(global_new_state)); + if (global_new_state == global_old_state) return BGP_GR_NO_OPERATION; - } - return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, - global_old_state); + /* Update global GR mode and process all peers in instance. */ + bgp->global_gr_present_state = global_new_state; + bgp_gr_update_mode_of_all_peers(bgp, global_new_state); + + return BGP_GR_SUCCESS; } const char *print_peer_gr_mode(enum peer_mode pr_mode) @@ -2870,181 +2894,107 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer) return peer->peer_gr_present_state; } -int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd) +int bgp_neighbor_graceful_restart(struct peer *peer, + enum peer_gr_command peer_gr_cmd) { enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID; - struct bgp_peer_gr peer_state; + struct bgp_peer_gr gr_fsm; int result = BGP_GR_FAILURE; - /* - * fetch peer_old_state from peer structure also - * fetch global_old_state from bgp structure, - * peer had a back pointer to bgpo struct ; - */ + peer_old_state = bgp_peer_gr_mode_get(peer); + gr_fsm = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; + peer_new_state = gr_fsm.next_state; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:", - __func__, peer->host, - print_peer_gr_cmd(peer_gr_cmd)); - - peer_old_state = bgp_peer_gr_mode_get(peer); + zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s", + peer, print_peer_gr_cmd(peer_gr_cmd), + print_peer_gr_mode(peer_old_state), + print_peer_gr_mode(peer_new_state)); - if (peer_old_state == PEER_INVALID) { - zlog_debug("[BGP_GR] peer_old_state == Invalid state !"); + if (peer_old_state == PEER_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - } - - peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; - peer_new_state = peer_state.next_state; - if (peer_new_state == PEER_INVALID) { - zlog_debug( - "[BGP_GR] Invalid bgp graceful restart command used !"); + if (peer_new_state == PEER_INVALID) return BGP_ERR_GR_INVALID_CMD; - } - if (peer_new_state != peer_old_state) { - result = peer_state.action_fun(peer, peer_old_state, - peer_new_state); - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] peer_old_state == peer_new_state !"); + if (peer_new_state == peer_old_state) return BGP_GR_NO_OPERATION; - } - - if (result == BGP_GR_SUCCESS) { - /* Update the mode i.e peer_new_state into the peer structure */ - peer->peer_gr_present_state = peer_new_state; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Successfully change the state of the peer to : %s : !", - print_peer_gr_mode(peer_new_state)); - - return BGP_GR_SUCCESS; - } + result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state); return result; } -unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state, - int new_peer_state) +static inline bool gr_mode_matches(enum peer_mode peer_gr_mode, + enum global_mode global_gr_mode) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", - __func__, print_peer_gr_mode(old_peer_state), - print_peer_gr_mode(new_peer_state)); + if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) || + (peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) || + (peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE)) + return true; + return false; +} - int bgp_gr_global_mode = GLOBAL_INVALID; - unsigned int ret = BGP_GR_FAILURE; +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, + enum peer_mode new_state) +{ + enum global_mode global_gr_mode; + bool session_reset = true; - if (old_peer_state == new_peer_state) { - /* Nothing to do over here as the present and old state is the - * same */ + if (old_state == new_state) return BGP_GR_NO_OPERATION; - } - if ((old_peer_state == PEER_INVALID) - || (new_peer_state == PEER_INVALID)) { - /* something bad happend , print error message */ + if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID)) return BGP_ERR_GR_INVALID_CMD; - } - bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); - - if ((old_peer_state == PEER_GLOBAL_INHERIT) - && (new_peer_state != PEER_GLOBAL_INHERIT)) { - - /* fetch the Mode running in the Global state machine - *from the bgp structure into a variable called - *bgp_gr_global_mode - */ - - /* Here we are checking if the - *1. peer_new_state == global_mode == helper_mode - *2. peer_new_state == global_mode == GR_mode - *3. peer_new_state == global_mode == disabled_mode - */ + global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + if ((old_state == PEER_GLOBAL_INHERIT) && + (new_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); - if (new_peer_state == bgp_gr_global_mode) { - /*This is incremental updates i.e no tear down - *of the existing session - *as the peer is already working in the same mode. + if (gr_mode_matches(new_state, global_gr_mode)) + /* Peer was inheriting the global state and + * its new state still is the same, so a + * session reset is not needed. */ - ret = BGP_GR_SUCCESS; - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s ", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; - } - } - /* In the case below peer is going into Global inherit mode i.e. - * the peer would work as the mode configured at the global level - */ - else if ((new_peer_state == PEER_GLOBAL_INHERIT) - && (old_peer_state != PEER_GLOBAL_INHERIT)) { - /* Here in this case it would be destructive - * in all the cases except one case when, - * Global GR is configured Disabled - * and present_peer_state is not disable - */ - + session_reset = false; + } else if ((new_state == PEER_GLOBAL_INHERIT) && + (old_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - if (old_peer_state == bgp_gr_global_mode) { - - /* This is incremental updates - *i.e no tear down of the existing session - *as the peer is already working in the same mode. - */ - ret = BGP_GR_SUCCESS; - } else { - /* Destructive always */ - /* Tear down the old session - * and send the new capability - * as per the bgp_gr_global_mode + if (gr_mode_matches(old_state, global_gr_mode)) + /* Peer is inheriting the global state and + * its old state was also the same, so a + * session reset is not needed. */ + session_reset = false; + } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); + /* Ensure we move to the new state and update flags */ + bgp_peer_move_to_gr_mode(peer, new_state); - bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); + if (session_reset) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - ret = BGP_GR_SUCCESS; - } - } else { - /* - *This else case, it include all the cases except --> - *(new_peer_state != Peer_Global) && - *( old_peer_state != Peer_Global ) + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset(peer); } - return ret; + return BGP_GR_SUCCESS; } -inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state) { - int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum peer_mode old_state = bgp_peer_gr_mode_get(peer); switch (new_state) { case PEER_HELPER: @@ -3058,57 +3008,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) break; case PEER_GLOBAL_INHERIT: BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - - if (bgp_global_gr_mode == GLOBAL_HELPER) { - BGP_PEER_GR_HELPER_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_GR) { - BGP_PEER_GR_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { - BGP_PEER_GR_DISABLE(peer); - } else { - zlog_err( - "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!"); - } + bgp_peer_inherit_global_gr_mode(peer, global_gr_mode); break; + case PEER_INVALID: default: zlog_err( "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); break; } + bgp_peer_gr_flags_update(peer); + peer->peer_gr_present_state = new_state; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", - new_state); + zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64, + peer, print_peer_gr_mode(old_state), + print_peer_gr_mode(new_state), + peer->peer_gr_new_status_flag, peer->flags); } void bgp_peer_gr_flags_update(struct peer *peer) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] called !", __func__); if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) SET_FLAG(peer->flags, @@ -3116,28 +3047,28 @@ void bgp_peer_gr_flags_update(struct peer *peer) else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) - ? "Set" - : "UnSet")); - - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { - zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!", - peer->host); + zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64 + ", GR flags 0x%x, GR mode %s", + peer, peer->flags, peer->peer_gr_new_status_flag, + print_peer_gr_mode(bgp_peer_gr_mode_get(peer))); + /* + * If GR has been completely disabled for the peer and we were + * acting as the Helper for the peer (i.e., keeping stale routes + * and running the restart timer or stalepath timer), clear those + * states. + */ + if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { - + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: GR disabled, stopping NSF and clearing stale routes", + peer); peer_nsf_stop(peer); - zlog_debug( - "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!", - peer->host); } } } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index fd46b7994e3a..85c488962fc9 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -122,6 +122,9 @@ extern void bgp_maxmed_update(struct bgp *); extern bool bgp_maxmed_onstartup_configured(struct bgp *); extern bool bgp_maxmed_onstartup_active(struct bgp *); extern int bgp_fsm_error_subcode(int status); +extern enum bgp_fsm_state_progress +bgp_stop_with_notify(struct peer_connection *connection, uint8_t code, + uint8_t sub_code); /** * Start the route advertisement timer (that honors MRAI) for all the @@ -143,11 +146,12 @@ extern void bgp_adjust_routeadv(struct peer *); DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer)); DECLARE_HOOK(peer_established, (struct peer *peer), (peer)); -int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd); -int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd); -unsigned int bgp_peer_gr_action(struct peer *peer, - int old_peer_state, int new_peer_state); -void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); +int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd); +int bgp_neighbor_graceful_restart(struct peer *peer, + enum peer_gr_command peer_gr_cmd); +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, + enum peer_mode new_peer_state); +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state); unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer); unsigned int bgp_peer_gr_global_inherit(struct peer *peer); @@ -156,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer); enum global_mode bgp_global_gr_mode_get(struct bgp *bgp); enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer); unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer); -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state); void bgp_peer_gr_flags_update(struct peer *peer); const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index b8ce1ae467fd..ad40fef62c61 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -15,6 +15,7 @@ #include "memory.h" #include "nexthop.h" #include "mpls.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -27,6 +28,124 @@ extern struct zclient *zclient; + +/* MPLS Labels hash routines. */ +static struct hash *labels_hash; + +static void *bgp_labels_hash_alloc(void *p) +{ + const struct bgp_labels *labels = p; + struct bgp_labels *new; + uint8_t i; + + new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels)); + + new->num_labels = labels->num_labels; + for (i = 0; i < labels->num_labels; i++) + new->label[i] = labels->label[i]; + + return new; +} + +static uint32_t bgp_labels_hash_key_make(const void *p) +{ + const struct bgp_labels *labels = p; + uint32_t key = 0; + + if (labels->num_labels) + key = jhash(&labels->label, + labels->num_labels * sizeof(mpls_label_t), key); + + return key; +} + +static bool bgp_labels_hash_cmp(const void *p1, const void *p2) +{ + return bgp_labels_cmp(p1, p2); +} + +void bgp_labels_init(void) +{ + labels_hash = hash_create(bgp_labels_hash_key_make, bgp_labels_hash_cmp, + "BGP Labels hash"); +} + +/* + * special for hash_clean below + */ +static void bgp_labels_free(void *labels) +{ + XFREE(MTYPE_BGP_LABELS, labels); +} + +void bgp_labels_finish(void) +{ + hash_clean_and_free(&labels_hash, bgp_labels_free); +} + +struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels) +{ + struct bgp_labels *find; + + if (!labels) + return NULL; + + if (!labels->num_labels) + /* do not intern void labels structure */ + return NULL; + + find = (struct bgp_labels *)hash_get(labels_hash, labels, + bgp_labels_hash_alloc); + find->refcnt++; + + return find; +} + +void bgp_labels_unintern(struct bgp_labels **plabels) +{ + struct bgp_labels *labels = *plabels; + struct bgp_labels *ret; + + if (!*plabels) + return; + + /* Decrement labels reference. */ + labels->refcnt--; + + /* If reference becomes zero then free labels object. */ + if (labels->refcnt == 0) { + ret = hash_release(labels_hash, labels); + assert(ret != NULL); + bgp_labels_free(labels); + *plabels = NULL; + } +} + +bool bgp_labels_cmp(const struct bgp_labels *labels1, + const struct bgp_labels *labels2) +{ + uint8_t i; + + if (!labels1 && !labels2) + return true; + + if (!labels1 && labels2) + return false; + + if (labels1 && !labels2) + return false; + + if (labels1->num_labels != labels2->num_labels) + return false; + + for (i = 0; i < labels1->num_labels; i++) { + if (labels1->label[i] != labels2->label[i]) + return false; + } + + return true; +} + int bgp_parse_fec_update(void) { struct stream *s; @@ -74,7 +193,7 @@ int bgp_parse_fec_update(void) bgp_set_valid_label(&dest->local_label); } SET_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, NULL, afi, safi); bgp_dest_unlock_node(dest); return 1; } @@ -89,7 +208,9 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi, if (!dest || !pi || !to) return MPLS_INVALID_LABEL; - remote_label = pi->extra ? pi->extra->label[0] : MPLS_INVALID_LABEL; + remote_label = bgp_path_info_num_labels(pi) + ? pi->extra->labels->label[0] + : MPLS_INVALID_LABEL; from = pi->peer; reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP)); @@ -132,9 +253,8 @@ static void bgp_send_fec_register_label_msg(struct bgp_dest *dest, bool reg, return; if (BGP_DEBUG(labelpool, LABELPOOL)) - zlog_debug("%s: FEC %sregister %pRN label_index=%u label=%u", - __func__, reg ? "" : "un", bgp_dest_to_rnode(dest), - label_index, label); + zlog_debug("%s: FEC %sregister %pBD label_index=%u label=%u", + __func__, reg ? "" : "un", dest, label_index, label); /* If the route node has a local_label assigned or the * path node has an MPLS SR label index allowing zebra to * derive the label, proceed with registration. */ @@ -199,8 +319,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, assert(dest); if (BGP_DEBUG(labelpool, LABELPOOL)) - zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__, - bgp_dest_to_rnode(dest), new_label, allocated); + zlog_debug("%s: FEC %pBD label=%u, allocated=%d", __func__, + dest, new_label, allocated); if (!allocated) { /* @@ -456,7 +576,7 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, } else { bgp_withdraw(peer, &p, addpath_id, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, 1, NULL); + BGP_ROUTE_NORMAL, NULL, &label, 1); } } @@ -472,8 +592,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, return BGP_NLRI_PARSE_OK; } -bool bgp_labels_same(const mpls_label_t *tbl_a, const uint32_t num_labels_a, - const mpls_label_t *tbl_b, const uint32_t num_labels_b) +bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a, + const mpls_label_t *tbl_b, const uint8_t num_labels_b) { uint32_t i; diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index b54403ee89b0..2ffd5b699dc0 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -15,6 +15,26 @@ struct bgp_dest; struct bgp_path_info; struct peer; +/* Maximum number of labels we can process or send with a prefix. We + * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. + */ +#define BGP_MAX_LABELS 2 + +/* MPLS label(s) - VNI(s) for EVPN-VxLAN */ +struct bgp_labels { + mpls_label_t label[BGP_MAX_LABELS]; + uint8_t num_labels; + + unsigned long refcnt; +}; + +extern void bgp_labels_init(void); +extern void bgp_labels_finish(void); +extern struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels); +extern void bgp_labels_unintern(struct bgp_labels **plabels); +extern bool bgp_labels_cmp(const struct bgp_labels *labels1, + const struct bgp_labels *labels2); + extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, bool allocated); extern void bgp_reg_dereg_for_label(struct bgp_dest *dest, @@ -27,9 +47,9 @@ extern mpls_label_t bgp_adv_label(struct bgp_dest *dest, extern int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, struct bgp_nlri *packet); extern bool bgp_labels_same(const mpls_label_t *tbl_a, - const uint32_t num_labels_a, + const uint8_t num_labels_a, const mpls_label_t *tbl_b, - const uint32_t num_labels_b); + const uint8_t num_labels_b); static inline int bgp_labeled_safi(safi_t safi) { diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 883338610c64..23e0c191dcc6 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -36,6 +36,8 @@ static void lptest_init(void); static void lptest_finish(void); #endif +static void bgp_sync_label_manager(struct event *e); + /* * Remember where pool data are kept */ @@ -448,13 +450,16 @@ void bgp_lp_get( if (lp_fifo_count(&lp->requests) > lp->pending_count) { if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, - lp->next_chunksize)) + lp->next_chunksize, true)) return; lp->pending_count += lp->next_chunksize; if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX) lp->next_chunksize <<= 1; } + + event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1, + &bm->t_bgp_sync_label_manager); } void bgp_lp_release( @@ -494,8 +499,18 @@ void bgp_lp_release( bf_release_index(chunk->allocated_map, index); chunk->nfree += 1; deallocated = true; + break; } assert(deallocated); + if (deallocated && + chunk->nfree == chunk->last - chunk->first + 1 && + lp_fifo_count(&lp->requests) == 0) { + bgp_zebra_release_label_range(chunk->first, + chunk->last); + list_delete_node(lp->chunks, node); + lp_chunk_free(chunk); + lp->next_chunksize = LP_CHUNK_SIZE_MIN; + } } } } @@ -547,6 +562,10 @@ static void bgp_sync_label_manager(struct event *e) zlog_debug("%s: out of labels, await more", __func__); } + + lp_fifo_add_tail(&lp->requests, lf); + event_add_timer(bm->master, bgp_sync_label_manager, + NULL, 1, &bm->t_bgp_sync_label_manager); break; } @@ -572,9 +591,6 @@ static void bgp_sync_label_manager(struct event *e) finishedrequest: XFREE(MTYPE_BGP_LABEL_FIFO, lf); } - - event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1, - &bm->t_bgp_sync_label_manager); } void bgp_lp_event_chunk(uint32_t first, uint32_t last) @@ -642,7 +658,7 @@ void bgp_lp_event_zebra_up(void) } /* round up */ - chunks_needed = (labels_needed / lp->next_chunksize) + 1; + chunks_needed = (labels_needed + lp->next_chunksize - 1) / lp->next_chunksize; labels_needed = chunks_needed * lp->next_chunksize; /* @@ -650,10 +666,10 @@ void bgp_lp_event_zebra_up(void) */ list_delete_all_node(lp->chunks); - if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, labels_needed)) + if (labels_needed && !bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, + labels_needed, true)) return; - - lp->pending_count = labels_needed; + lp->pending_count += labels_needed; /* * Invalidate any existing labels and requeue them as requests diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index e629732c78ee..bc44a212cdc9 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -14,6 +14,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_mac.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_label.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_rd.h" @@ -125,6 +126,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, { struct bgp_dest *pdest, *dest; struct bgp_path_info *pi; + uint8_t num_labels; + mpls_label_t *label_pnt; for (pdest = bgp_table_top(table); pdest; pdest = bgp_route_next(pdest)) { @@ -140,9 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, const struct prefix *p = bgp_dest_get_prefix(dest); struct prefix_evpn *pevpn = (struct prefix_evpn *)dest; struct prefix_rd prd; - uint32_t num_labels = 0; - mpls_label_t *label_pnt = NULL; - struct bgp_route_evpn *evpn; if (pevpn->family == AF_EVPN && pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE @@ -169,10 +169,9 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, && !dest_affected) continue; - if (pi->extra) - num_labels = pi->extra->num_labels; - if (num_labels) - label_pnt = &pi->extra->label[0]; + num_labels = bgp_path_info_num_labels(pi); + label_pnt = num_labels ? &pi->extra->labels->label[0] + : NULL; prd.family = AF_UNSPEC; prd.prefixlen = 64; @@ -195,12 +194,10 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, continue; } - memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), - sizeof(evpn)); bgp_update(peer, p, pi->addpath_rx_id, pi->attr, AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, label_pnt, - num_labels, 1, evpn); + BGP_ROUTE_NORMAL, &prd, label_pnt, num_labels, + 1, bgp_attr_get_evpn_overlay(pi->attr)); } } } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 11917c6c4a04..5e6a62c9b929 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -26,6 +26,7 @@ #include "bfd.h" #include "libfrr.h" #include "ns.h" +#include "libagentx.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -47,14 +48,20 @@ #include "bgpd/bgp_errors.h" #include "bgpd/bgp_script.h" #include "bgpd/bgp_evpn_mh.h" -#include "bgpd/bgp_nht.h" +#include "bgpd/bgp_nhg.h" #include "bgpd/bgp_routemap_nb.h" #include "bgpd/bgp_community_alias.h" +DEFINE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf), + (vty, vrf)); + #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #endif +DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), + (vrf, enabled)); + /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' }, @@ -199,7 +206,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) bgp_delete(bgp_default); bgp_evpn_mh_finish(); - bgp_l3nhg_finish(); + bgp_nhg_finish(); + + zebra_announce_fini(&bm->zebra_announce_head); /* reverse bgp_dump_init */ bgp_dump_finish(); @@ -216,6 +225,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) /* reverse bgp_attr_init */ bgp_attr_finish(); + /* reverse bgp_labels_init */ + bgp_labels_finish(); + /* stop pthreads */ bgp_pthreads_finish(); @@ -287,6 +299,7 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp_handle_socket(bgp, vrf, old_vrf_id, true); bgp_instance_up(bgp); + hook_call(bgp_hook_vrf_update, vrf, true); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); @@ -333,15 +346,36 @@ static int bgp_vrf_disable(struct vrf *vrf) * "down". */ bgp_instance_down(bgp); bgp_vrf_unlink(bgp, vrf); + hook_call(bgp_hook_vrf_update, vrf, false); } /* Note: This is a callback, the VRF will be deleted by the caller. */ return 0; } +static int bgp_vrf_config_write(struct vty *vty) +{ + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (vrf->vrf_id == VRF_DEFAULT) { + vty_out(vty, "!\n"); + continue; + } + vty_out(vty, "vrf %s\n", vrf->name); + + hook_call(bgp_hook_config_write_vrf, vty, vrf); + + vty_out(vty, "exit-vrf\n!\n"); + } + + return 0; +} + static void bgp_vrf_init(void) { vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete); + vrf_cmd_init(bgp_vrf_config_write); } static void bgp_vrf_terminate(void) @@ -357,15 +391,20 @@ static const struct frr_yang_module_info *const bgpd_yang_modules[] = { &frr_bgp_route_map_info, }; -FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(bgpd, BGP, + .vty_port = BGP_VTY_PORT, + .proghelp = "Implementation of the BGP routing protocol.", - .proghelp = "Implementation of the BGP routing protocol.", + .signals = bgp_signals, + .n_signals = array_size(bgp_signals), - .signals = bgp_signals, .n_signals = array_size(bgp_signals), + .privs = &bgpd_privs, - .privs = &bgpd_privs, .yang_modules = bgpd_yang_modules, - .n_yang_modules = array_size(bgpd_yang_modules), + .yang_modules = bgpd_yang_modules, + .n_yang_modules = array_size(bgpd_yang_modules), ); +/* clang-format on */ #define DEPRECATED_OPTIONS "" @@ -472,6 +511,7 @@ int main(int argc, char **argv) /* BGP master init. */ bgp_master_init(frr_init(), buffer_size, addresses); + bm->startup_time = monotime(NULL); bm->port = bgp_port; if (bgp_port == 0) bgp_option_set(BGP_OPT_NO_LISTEN); @@ -479,10 +519,15 @@ int main(int argc, char **argv) bgp_option_set(BGP_OPT_NO_FIB); if (no_zebra_flag) bgp_option_set(BGP_OPT_NO_ZEBRA); + if (bgpd_di.graceful_restart) + SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); + bgp_error_init(); /* Initializations. */ + libagentx_init(); bgp_vrf_init(); + #ifdef HAVE_SCRIPTING bgp_script_init(); #endif diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 5c3067f96de4..c2599ade58f1 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -15,6 +15,7 @@ DEFINE_MGROUP(BGPD, "bgpd"); DEFINE_MTYPE(BGPD, BGP, "BGP instance"); +DEFINE_MTYPE(BGPD, BGP_NAME, "BGP Name data"); DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details"); DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer"); DEFINE_MTYPE(BGPD, BGP_PEER_CONNECTION, "BGP peer connection"); @@ -41,6 +42,7 @@ DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_EVPN, "BGP extra info for EVPN"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_FS, "BGP extra info for flowspec"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VRFLEAK, "BGP extra info for vrf leaking"); +DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VNC, "BGP extra info for vnc"); DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected"); DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static"); DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr"); @@ -89,6 +91,7 @@ DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface"); DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface"); DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info"); DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array"); +DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list"); DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp"); DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate"); DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address"); @@ -99,6 +102,8 @@ DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information"); DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information"); DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV"); +DEFINE_MTYPE(BGPD, BGP_LABELS, "BGP LABELS"); + DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options"); DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value"); @@ -130,3 +135,5 @@ DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry"); DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message"); DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version"); + +DEFINE_MTYPE(BGPD, BGP_EVPN_OVERLAY, "BGP EVPN Overlay"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 7acb41eeb51c..1f76945da3e0 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -11,6 +11,7 @@ DECLARE_MGROUP(BGPD); DECLARE_MTYPE(BGP); +DECLARE_MTYPE(BGP_NAME); DECLARE_MTYPE(BGP_LISTENER); DECLARE_MTYPE(BGP_PEER); DECLARE_MTYPE(BGP_PEER_CONNECTION); @@ -37,6 +38,7 @@ DECLARE_MTYPE(BGP_ROUTE_EXTRA); DECLARE_MTYPE(BGP_ROUTE_EXTRA_EVPN); DECLARE_MTYPE(BGP_ROUTE_EXTRA_FS); DECLARE_MTYPE(BGP_ROUTE_EXTRA_VRFLEAK); +DECLARE_MTYPE(BGP_ROUTE_EXTRA_VNC); DECLARE_MTYPE(BGP_CONN); DECLARE_MTYPE(BGP_STATIC); DECLARE_MTYPE(BGP_ADVERTISE_ATTR); @@ -85,6 +87,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE); DECLARE_MTYPE(PEER_CONF_IF); DECLARE_MTYPE(BGP_DAMP_INFO); DECLARE_MTYPE(BGP_DAMP_ARRAY); +DECLARE_MTYPE(BGP_DAMP_REUSELIST); DECLARE_MTYPE(BGP_REGEXP); DECLARE_MTYPE(BGP_AGGREGATE); DECLARE_MTYPE(BGP_ADDR); @@ -95,6 +98,8 @@ DECLARE_MTYPE(BGP_FILTER_NAME); DECLARE_MTYPE(BGP_DUMP_STR); DECLARE_MTYPE(ENCAP_TLV); +DECLARE_MTYPE(BGP_LABELS); + DECLARE_MTYPE(BGP_TEA_OPTIONS); DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE); @@ -129,4 +134,6 @@ DECLARE_MTYPE(BGP_NOTIFICATION); DECLARE_MTYPE(BGP_SOFT_VERSION); +DECLARE_MTYPE(BGP_EVPN_OVERLAY); + #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index f2d1ee0bf319..eadd52b8e0f2 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -129,15 +129,19 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, &bpi2->attr->mp_nexthop_global); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - addr1 = (bpi1->attr->mp_nexthop_prefer_global) + addr1 = (CHECK_FLAG(bpi1->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi1->attr->mp_nexthop_global : bpi1->attr->mp_nexthop_local; - addr2 = (bpi2->attr->mp_nexthop_prefer_global) + addr2 = (CHECK_FLAG(bpi2->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi2->attr->mp_nexthop_global : bpi2->attr->mp_nexthop_local; - if (!bpi1->attr->mp_nexthop_prefer_global - && !bpi2->attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(bpi1->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL) && + !CHECK_FLAG(bpi2->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) compare = !bgp_interface_same( bpi1->peer->ifp, bpi2->peer->ifp); @@ -517,7 +521,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, struct bgp_maxpaths_cfg *mpath_cfg) { uint16_t maxpaths, mpath_count, old_mpath_count; - uint32_t bwval; + uint64_t bwval; uint64_t cum_bw, old_cum_bw; struct listnode *mp_node, *mp_next_node; struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; @@ -554,12 +558,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, } if (debug) - zlog_debug( - "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, - bgp_dest_to_rnode(dest), bgp->name_pretty, - new_best ? new_best->peer->host : "NONE", - mp_list ? listcount(mp_list) : 0, old_mpath_count, - old_cum_bw); + zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, + dest, bgp->name_pretty, + new_best ? new_best->peer->host : "NONE", + mp_list ? listcount(mp_list) : 0, old_mpath_count, + old_cum_bw); /* * We perform an ordered walk through both lists in parallel. @@ -590,11 +593,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, tmp_info = mp_node ? listgetdata(mp_node) : NULL; if (debug) - zlog_debug( - "%pRN(%s): comparing candidate %s with existing mpath %s", - bgp_dest_to_rnode(dest), bgp->name_pretty, - tmp_info ? tmp_info->peer->host : "NONE", - cur_mpath ? cur_mpath->peer->host : "NONE"); + zlog_debug("%pBD(%s): comparing candidate %s with existing mpath %s", + dest, bgp->name_pretty, + tmp_info ? tmp_info->peer->host : "NONE", + cur_mpath ? cur_mpath->peer->host : "NONE"); /* * If equal, the path was a multipath and is still a multipath. @@ -603,42 +605,53 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (mp_node && (listgetdata(mp_node) == cur_mpath)) { list_delete_node(mp_list, mp_node); bgp_path_info_mpath_dequeue(cur_mpath); - if ((mpath_count < maxpaths) - && prev_mpath - && bgp_path_info_nexthop_cmp(prev_mpath, - cur_mpath)) { + if ((mpath_count < maxpaths) && prev_mpath) { + mpath_count++; + if (bgp_path_info_nexthop_cmp(prev_mpath, + cur_mpath)) { + if (ecommunity_linkbw_present( + bgp_attr_get_ecommunity( + cur_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( + cur_mpath->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + cur_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: %s is still multipath, cur count %d", + dest, path_buf, + mpath_count); + } + } else { + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + cur_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); + } + } bgp_path_info_mpath_enqueue(prev_mpath, cur_mpath); prev_mpath = cur_mpath; - mpath_count++; - if (ecommunity_linkbw_present( - bgp_attr_get_ecommunity( - cur_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, - sizeof(path_buf)); - zlog_debug( - "%pRN: %s is still multipath, cur count %d", - bgp_dest_to_rnode(dest), - path_buf, mpath_count); - } } else { mpath_changed = 1; if (debug) { bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf, sizeof(path_buf)); - zlog_debug( - "%pRN: remove mpath %s nexthop %pI4, cur count %d", - bgp_dest_to_rnode(dest), - path_buf, - &cur_mpath->attr->nexthop, - mpath_count); + zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); } } mp_node = mp_next_node; @@ -663,10 +676,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (debug) { bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf, sizeof(path_buf)); - zlog_debug( - "%pRN: remove mpath %s nexthop %pI4, cur count %d", - bgp_dest_to_rnode(dest), path_buf, - &cur_mpath->attr->nexthop, mpath_count); + zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); } cur_mpath = next_mpath; } else { @@ -692,34 +705,50 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, list_delete_node(mp_list, mp_node); assert(new_mpath); assert(prev_mpath); - if ((mpath_count < maxpaths) && (new_mpath != new_best) - && bgp_path_info_nexthop_cmp(prev_mpath, - new_mpath)) { + if ((mpath_count < maxpaths) && (new_mpath != new_best)) { + /* keep duplicate nexthop */ bgp_path_info_mpath_dequeue(new_mpath); bgp_path_info_mpath_enqueue(prev_mpath, new_mpath); - prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; - if (ecommunity_linkbw_present( - bgp_attr_get_ecommunity( - new_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - new_mpath, path_buf, - sizeof(path_buf)); - zlog_debug( - "%pRN: add mpath %s nexthop %pI4, cur count %d", - bgp_dest_to_rnode(dest), - path_buf, - &new_mpath->attr->nexthop, - mpath_count); + if (bgp_path_info_nexthop_cmp(prev_mpath, + new_mpath)) { + if (ecommunity_linkbw_present( + bgp_attr_get_ecommunity( + new_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( + new_mpath->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + new_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr + ->nexthop, + mpath_count); + } + } else { + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + new_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr + ->nexthop, + mpath_count); + } } + prev_mpath = new_mpath; } mp_node = mp_next_node; } @@ -728,8 +757,12 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (new_best) { bgp_path_info_mpath_count_set(new_best, mpath_count - 1); if (mpath_count <= 1 || - !ecommunity_linkbw_present( - bgp_attr_get_ecommunity(new_best->attr), &bwval)) + (!ecommunity_linkbw_present(bgp_attr_get_ecommunity( + new_best->attr), + &bwval) && + !ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity( + new_best->attr), + &bwval))) all_paths_lb = false; else cum_bw += bwval; @@ -737,11 +770,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, all_paths_lb, cum_bw); if (debug) - zlog_debug( - "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, - bgp_dest_to_rnode(dest), bgp->name_pretty, - mpath_count, mpath_changed ? "YES" : "NO", - all_paths_lb, cum_bw); + zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, + dest, bgp->name_pretty, mpath_count, + mpath_changed ? "YES" : "NO", all_paths_lb, + cum_bw); if (mpath_changed || (bgp_path_info_mpath_count(new_best) != old_mpath_count)) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 138b182718e2..9de1c5f4c259 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -245,7 +245,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, } else { bgp_withdraw(peer, &p, addpath_id, packet->afi, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, &prd, &label, 1, NULL); + BGP_ROUTE_NORMAL, &prd, &label, 1); } } /* Packet length consistency check. */ @@ -280,7 +280,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, * * Sending this vrf-label association is qualified by a) whether vrf->vpn * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list - * are set) and b) whether vpn-policy label is set. + * are set), b) whether vpn-policy label is set and c) the vrf loopback + * interface is up. * * If any of these conditions do not hold, then we send MPLS_LABEL_NONE * for this vrf, which zebra interprets to mean "delete this vrf-label @@ -288,6 +289,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, */ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) { + struct interface *ifp; mpls_label_t label = MPLS_LABEL_NONE; int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); @@ -300,8 +302,10 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) return; } - if (vpn_leak_to_vpn_active(bgp, afi, NULL)) { - label = bgp->vpn_policy[afi].tovpn_label; + if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) { + ifp = if_get_vrf_loopback(bgp->vrf_id); + if (ifp && if_is_vrf(ifp) && if_is_up(ifp)) + label = bgp->vpn_policy[afi].tovpn_label; } if (debug) { @@ -388,6 +392,9 @@ void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi) tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); *tovpn_sid_ls = *tovpn_sid; + if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent) + XFREE(MTYPE_BGP_SRV6_SID, + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls; } @@ -435,6 +442,8 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp) tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); *tovpn_sid_ls = *tovpn_sid; + if (bgp->tovpn_zebra_vrf_sid_last_sent) + XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); bgp->tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls; } @@ -482,6 +491,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi) bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); XFREE(MTYPE_BGP_SRV6_SID, bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL; } /* @@ -508,6 +518,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp) bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); + bgp->tovpn_zebra_vrf_sid_last_sent = NULL; } /* @@ -596,6 +607,11 @@ static void sid_register(struct bgp *bgp, const struct in6_addr *sid, listnode_add(bgp->srv6_functions, func); } +void srv6_function_free(struct bgp_srv6_function *func) +{ + XFREE(MTYPE_BGP_SRV6_FUNCTION, func); +} + void sid_unregister(struct bgp *bgp, const struct in6_addr *sid) { struct listnode *node, *nnode; @@ -604,7 +620,7 @@ void sid_unregister(struct bgp *bgp, const struct in6_addr *sid) for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) if (sid_same(&func->sid, sid)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } } @@ -952,50 +968,6 @@ void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, } } -static bool labels_same(struct bgp_path_info *bpi, mpls_label_t *label, - uint32_t n) -{ - if (!bpi->extra) { - if (!n) - return true; - else - return false; - } - - return bgp_labels_same((const mpls_label_t *)bpi->extra->label, - bpi->extra->num_labels, - (const mpls_label_t *)label, n); -} - -/* - * make encoded route labels match specified encoded label set - */ -static void setlabels(struct bgp_path_info *bpi, - mpls_label_t *label, /* array of labels */ - uint32_t num_labels) -{ - if (num_labels) - assert(label); - assert(num_labels <= BGP_MAX_LABELS); - - if (!num_labels) { - if (bpi->extra) - bpi->extra->num_labels = 0; - return; - } - - struct bgp_path_info_extra *extra = bgp_path_info_extra_get(bpi); - uint32_t i; - - for (i = 0; i < num_labels; ++i) { - extra->label[i] = label[i]; - if (!bgp_is_valid_label(&label[i])) { - bgp_set_valid_label(&extra->label[i]); - } - } - extra->num_labels = num_labels; -} - static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, struct attr *new_attr, afi_t afi, safi_t safi, @@ -1006,9 +978,11 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, { struct bgp_path_info *bpi_ultimate; struct bgp *bgp_nexthop; + struct bgp_table *table; bool nh_valid; bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); + table = bgp_dest_table(bpi_ultimate->net); if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig) bgp_nexthop = bpi->extra->vrfleak->bgp_orig; @@ -1024,7 +998,23 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, is_pi_family_evpn(bpi_ultimate) || CHECK_FLAG(bpi_ultimate->flags, BGP_PATH_ACCEPT_OWN)) nh_valid = true; - else + else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP && + bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table && + (table->safi == SAFI_UNICAST || + table->safi == SAFI_LABELED_UNICAST)) { + /* the route is defined with the "network " command */ + + if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK)) + nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, + afi, SAFI_UNICAST, + bpi_ultimate, NULL, + 0, p); + else + /* if "no bgp network import-check" is set, + * then mark the nexthop as valid. + */ + nh_valid = true; + } else /* * TBD do we need to do anything about the * 'connected' parameter? @@ -1056,7 +1046,7 @@ static struct bgp_path_info * leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct attr *new_attr, /* already interned */ afi_t afi, safi_t safi, struct bgp_path_info *source_bpi, - mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig, + mpls_label_t *label, uint8_t num_labels, struct bgp *bgp_orig, struct prefix *nexthop_orig, int nexthop_self_flag, int debug) { const struct prefix *p = bgp_dest_get_prefix(bn); @@ -1064,6 +1054,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *new; struct bgp_path_info_extra *extra; struct bgp_path_info *parent = source_bpi; + struct bgp_labels bgp_labels = {}; + bool labelssame; + uint8_t i; if (debug) zlog_debug( @@ -1098,8 +1091,15 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, break; } + bgp_labels.num_labels = num_labels; + for (i = 0; i < num_labels; i++) { + bgp_labels.label[i] = label[i]; + bgp_set_valid_label(&bgp_labels.label[i]); + } + if (bpi) { - bool labelssame = labels_same(bpi, label, num_labels); + labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label, + bgp_labels.num_labels); if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { @@ -1157,11 +1157,13 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, bpi->uptime = monotime(NULL); /* - * rewrite labels + * update labels */ - if (!labelssame) - setlabels(bpi, label, num_labels); - + if (!labelssame) { + bgp_path_info_extra_get(bpi); + bgp_labels_unintern(&bpi->extra->labels); + bpi->extra->labels = bgp_labels_intern(&bgp_labels); + } if (nexthop_self_flag) bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); @@ -1178,7 +1180,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, /* Process change. */ bgp_aggregate_increment(to_bgp, p, bpi, afi, safi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); if (debug) zlog_debug("%s: ->%s: %pBD Found route, changed attr", @@ -1219,14 +1221,15 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN); - if (num_labels) - setlabels(new, label, num_labels); + if (bgp_labels.num_labels) + new->extra->labels = bgp_labels_intern(&bgp_labels); new->extra->vrfleak->parent = bgp_path_info_lock(parent); bgp_dest_lock_node( (struct bgp_dest *)parent->net); - if (bgp_orig) - new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); + + new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); + if (nexthop_orig) new->extra->vrfleak->nexthop_orig = *nexthop_orig; @@ -1239,7 +1242,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, bgp_aggregate_increment(to_bgp, p, new, afi, safi); bgp_path_info_add(bn, new); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, new, afi, safi); if (debug) zlog_debug("%s: ->%s: %pBD: Added new route", __func__, @@ -1410,6 +1413,16 @@ _vpn_leak_from_vrf_get_per_nexthop_label(struct bgp_path_info *pi, return blnc->label; } +static mpls_label_t bgp_mplsvpn_get_vpn_label(struct vpn_policy *bgp_policy) +{ + if (bgp_policy->tovpn_label == MPLS_LABEL_NONE && + CHECK_FLAG(bgp_policy->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + bgp_lp_get(LP_TYPE_VRF, bgp_policy, vpn_leak_label_callback); + return MPLS_INVALID_LABEL; + } + return bgp_policy->tovpn_label; +} + /* Filter out all the cases where a per nexthop label is not possible: * - return an invalid label when the nexthop is invalid * - return the per VRF label when the per nexthop label is not supported @@ -1438,7 +1451,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to the per VRF label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } if (is_bgp_static_route == false && afi == AFI_IP && @@ -1450,7 +1463,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to the per VRF label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } if (is_bgp_static_route == false && afi == AFI_IP6 && @@ -1464,7 +1477,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to the per VRF label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } /* Check the next-hop reachability. @@ -1486,7 +1499,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * table. Fallback to the per-vrf label */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } if (!nh_valid || !pi->nexthop || pi->nexthop->nexthop_num == 0 || @@ -1509,7 +1522,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to per-vrf label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp, @@ -1532,6 +1545,9 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ struct bgp_dest *bn; const char *debugmsg; int nexthop_self_flag = 0; + struct ecommunity *old_ecom; + struct ecommunity *new_ecom = NULL; + struct ecommunity *rtlist_ecom; if (debug) zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty); @@ -1559,7 +1575,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ if (!is_route_injectable_into_vpn(path_vrf)) return; - if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) { + if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, false)) { if (debug) zlog_debug("%s: %s skipping: %s", __func__, from_bgp->name, debugmsg); @@ -1569,32 +1585,6 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ /* shallow copy */ static_attr = *path_vrf->attr; - /* - * route map handling - */ - if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) { - struct bgp_path_info info; - route_map_result_t ret; - - memset(&info, 0, sizeof(info)); - info.peer = to_bgp->peer_self; - info.attr = &static_attr; - ret = route_map_apply(from_bgp->vpn_policy[afi] - .rmap[BGP_VPN_POLICY_DIR_TOVPN], - p, &info); - if (RMAP_DENYMATCH == ret) { - bgp_attr_flush(&static_attr); /* free any added parts */ - if (debug) - zlog_debug( - "%s: vrf %s route map \"%s\" says DENY, returning", - __func__, from_bgp->name_pretty, - from_bgp->vpn_policy[afi] - .rmap[BGP_VPN_POLICY_DIR_TOVPN] - ->name); - return; - } - } - if (debug && bgp_attr_get_ecommunity(&static_attr)) { char *s = ecommunity_ecom2str( bgp_attr_get_ecommunity(&static_attr), @@ -1608,29 +1598,62 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ /* * Add the vpn-policy rt-list */ - struct ecommunity *old_ecom; - struct ecommunity *new_ecom; /* Export with the 'from' instance's export RTs. */ /* If doing VRF-to-VRF leaking, strip existing RTs first. */ old_ecom = bgp_attr_get_ecommunity(&static_attr); + rtlist_ecom = from_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]; if (old_ecom) { new_ecom = ecommunity_dup(old_ecom); if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST], BGP_CONFIG_VRF_TO_VRF_EXPORT)) ecommunity_strip_rts(new_ecom); - new_ecom = ecommunity_merge( - new_ecom, from_bgp->vpn_policy[afi] - .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); + if (rtlist_ecom) + new_ecom = ecommunity_merge(new_ecom, rtlist_ecom); if (!old_ecom->refcnt) ecommunity_free(&old_ecom); + } else if (rtlist_ecom) { + new_ecom = ecommunity_dup(rtlist_ecom); } else { - new_ecom = ecommunity_dup( - from_bgp->vpn_policy[afi] - .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); + new_ecom = NULL; } + bgp_attr_set_ecommunity(&static_attr, new_ecom); + /* + * route map handling + */ + if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) { + struct bgp_path_info info; + route_map_result_t ret; + + memset(&info, 0, sizeof(info)); + info.peer = to_bgp->peer_self; + info.attr = &static_attr; + ret = route_map_apply(from_bgp->vpn_policy[afi] + .rmap[BGP_VPN_POLICY_DIR_TOVPN], + p, &info); + if (RMAP_DENYMATCH == ret) { + bgp_attr_flush(&static_attr); /* free any added parts */ + if (debug) + zlog_debug("%s: vrf %s route map \"%s\" says DENY, returning", + __func__, from_bgp->name_pretty, + from_bgp->vpn_policy[afi] + .rmap[BGP_VPN_POLICY_DIR_TOVPN] + ->name); + return; + } + } + + new_ecom = bgp_attr_get_ecommunity(&static_attr); + if (!ecommunity_has_route_target(new_ecom)) { + ecommunity_free(&new_ecom); + if (debug) + zlog_debug("%s: %s skipping: waiting for a valid export rt list.", + __func__, from_bgp->name_pretty); + return; + } + if (debug && bgp_attr_get_ecommunity(&static_attr)) { char *s = ecommunity_ecom2str( bgp_attr_get_ecommunity(&static_attr), @@ -1714,12 +1737,10 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ label_val = vpn_leak_from_vrf_get_per_nexthop_label( afi, path_vrf, from_bgp, to_bgp); else - /* per VRF label mode */ - label_val = from_bgp->vpn_policy[afi].tovpn_label; + label_val = + bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); - if (label_val == MPLS_INVALID_LABEL && - CHECK_FLAG(from_bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) { + if (label_val == MPLS_INVALID_LABEL) { /* no valid label for the moment * when the 'bgp_mplsvpn_get_label_per_nexthop_cb' callback gets * a valid label value, it will call the current function again. @@ -1728,6 +1749,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ zlog_debug( "%s: %s skipping: waiting for a valid per-label nexthop.", __func__, from_bgp->name_pretty); + bgp_attr_flush(&static_attr); return; } if (label_val == MPLS_LABEL_NONE) @@ -1883,20 +1905,20 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */ if (!is_route_injectable_into_vpn(path_vrf)) return; - if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) { + if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, true)) { if (debug) zlog_debug("%s: skipping: %s", __func__, debugmsg); return; } - if (debug) - zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf); - - bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, - &(from_bgp->vpn_policy[afi].tovpn_rd)); + bn = bgp_safi_node_lookup(to_bgp->rib[afi][safi], safi, p, + &(from_bgp->vpn_policy[afi].tovpn_rd)); if (!bn) return; + if (debug) + zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf); + /* * vrf -> vpn * match original bpi imported from @@ -1914,7 +1936,7 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); } bgp_dest_unlock_node(bn); } @@ -1934,7 +1956,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, struct bgp_table *table; struct bgp_dest *bn; - struct bgp_path_info *bpi; + struct bgp_path_info *bpi, *next; /* This is the per-RD table of prefixes */ table = bgp_dest_get_bgp_table_info(pdest); @@ -1949,7 +1971,8 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, __func__, bn); } - for (; bpi; bpi = bpi->next) { + for (; (bpi != NULL) && (next = bpi->next, 1); + bpi = next) { if (debug) zlog_debug("%s: type %d, sub_type %d", __func__, bpi->type, @@ -1970,7 +1993,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, to_bgp, bgp_dest_get_prefix(bn), bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); bgp_mplsvpn_path_nh_label_unlink( bpi->extra->vrfleak->parent); } @@ -2051,14 +2074,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ safi_t safi = SAFI_UNICAST; const char *debugmsg; struct prefix nexthop_orig; - mpls_label_t *pLabels = NULL; - uint32_t num_labels = 0; + mpls_label_t *label_pnt = NULL; + uint8_t num_labels = 0; int nexthop_self_flag = 1; struct bgp_path_info *bpi_ultimate = NULL; + struct bgp_path_info *bpi; int origin_local = 0; struct bgp *src_vrf; - struct interface *ifp; + struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; + int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) { @@ -2144,6 +2169,20 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ community_strip_accept_own(&static_attr); + bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); + + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->parent == path_vpn) + break; + } + + if (bpi && leak_update_nexthop_valid(to_bgp, bn, &static_attr, afi, safi, + path_vpn, bpi, src_vrf, p, debug)) + SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID); + else + UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID); + /* * Nexthop: stash and clear * @@ -2159,12 +2198,23 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ /* If the path has accept-own community and the source VRF * is valid, reset next-hop to self, to allow importing own * routes between different VRFs on the same node. - * Set the nh ifindex to VRF's interface, not the real interface. + */ + + if (src_bgp) + subgroup_announce_reset_nhop(nhfamily, &static_attr); + + bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); + + /* The nh ifindex may not be defined (when the route is + * imported from the network statement => BGP_ROUTE_STATIC) + * or to the real interface. + * Rewrite the nh ifindex to VRF's interface. * Let the kernel to decide with double lookup the real next-hop * interface when installing the route. */ - if (src_bgp) { - subgroup_announce_reset_nhop(nhfamily, &static_attr); + if (src_vrf->vrf_id != VRF_DEFAULT && + (src_bgp || bpi_ultimate->sub_type == BGP_ROUTE_STATIC || + bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE)) { ifp = if_get_vrf_loopback(src_vrf->vrf_id); if (ifp) static_attr.nh_ifindex = ifp->ifindex; @@ -2200,6 +2250,15 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ break; } + if (!ifp && static_attr.nh_ifindex) + ifp = if_lookup_by_index(static_attr.nh_ifindex, + src_vrf->vrf_id); + + if (ifp && if_is_operative(ifp)) + SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + /* * route map handling */ @@ -2236,8 +2295,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ new_attr = bgp_attr_intern(&static_attr); bgp_attr_flush(&static_attr); - bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); - /* * ensure labels are copied * @@ -2252,9 +2309,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ */ if (!CHECK_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT)) { - /* work back to original route */ - bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); - /* * if original route was unicast, * then it did not arrive over vpn @@ -2267,21 +2321,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ origin_local = 1; } - /* copy labels */ - if (!origin_local && path_vpn->extra - && path_vpn->extra->num_labels) { - num_labels = path_vpn->extra->num_labels; - if (num_labels > BGP_MAX_LABELS) - num_labels = BGP_MAX_LABELS; - pLabels = path_vpn->extra->label; - } + num_labels = origin_local ? 0 + : bgp_path_info_num_labels(path_vpn); + label_pnt = num_labels ? path_vpn->extra->labels->label : NULL; } if (debug) zlog_debug("%s: pfx %pBD: num_labels %d", __func__, path_vpn->net, num_labels); - if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels, + if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, label_pnt, num_labels, src_vrf, &nexthop_orig, nexthop_self_flag, debug)) bgp_dest_unlock_node(bn); @@ -2434,7 +2483,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn) bpi); bgp_aggregate_decrement(bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, bpi, afi, safi); } bgp_dest_unlock_node(bn); } @@ -2443,7 +2492,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn) void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) { struct bgp_dest *bn; - struct bgp_path_info *bpi; + struct bgp_path_info *bpi, *next; safi_t safi = SAFI_UNICAST; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); @@ -2454,9 +2503,8 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) */ for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn; bn = bgp_route_next(bn)) { - - for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; - bpi = bpi->next) { + for (bpi = bgp_dest_get_bgp_path_info(bn); + (bpi != NULL) && (next = bpi->next, 1); bpi = next) { if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig != to_bgp && bpi->extra->vrfleak->parent && @@ -2466,7 +2514,7 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) bgp_dest_get_prefix(bn), bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); } } } @@ -2495,8 +2543,11 @@ void vpn_leak_no_retain(struct bgp *to_bgp, struct bgp *vpn_from, afi_t afi) continue; for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { - for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; - bpi = bpi->next) { + struct bgp_path_info *next; + + for (bpi = bgp_dest_get_bgp_path_info(bn); + (bpi != NULL) && (next = bpi->next, 1); + bpi = next) { if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig == to_bgp) continue; @@ -2664,7 +2715,7 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, edir = BGP_VPN_POLICY_DIR_TOVPN; for (afi = 0; afi < AFI_MAX; ++afi) { - if (!vpn_leak_to_vpn_active(bgp, afi, NULL)) + if (!vpn_leak_to_vpn_active(bgp, afi, NULL, false)) continue; if (withdraw) { @@ -3683,6 +3734,9 @@ void vpn_leak_postchange_all(void) if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + vpn_leak_postchange( BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, @@ -3702,6 +3756,9 @@ void vpn_leak_postchange_all(void) if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + vpn_leak_postchange( BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP, @@ -3911,7 +3968,7 @@ static void bgp_mplsvpn_nh_label_bind_send_nexthop_label( struct bgp_mplsvpn_nh_label_bind_cache *bmnc, int cmd) { struct prefix pfx_nh, *p = NULL; - uint32_t num_labels = 0, lsp_num_labels; + uint8_t num_labels = 0, lsp_num_labels; mpls_label_t label[MPLS_MAX_LABELS]; struct nexthop *nh; ifindex_t ifindex = IFINDEX_INTERNAL; @@ -4046,7 +4103,7 @@ bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi) /* prefix_sid attribute */ return false; - if (!pi->extra || !bgp_is_valid_label(&pi->extra->label[0])) + if (!bgp_path_info_has_valid_label(pi)) /* invalid MPLS label */ return false; return true; @@ -4117,7 +4174,7 @@ static int bgp_mplsvpn_nh_label_bind_get_local_label_cb(mpls_label_t label, if (!table) continue; SET_FLAG(pi->net->flags, BGP_NODE_LABEL_CHANGED); - bgp_process(table->bgp, pi->net, table->afi, table->safi); + bgp_process(table->bgp, pi->net, pi, table->afi, table->safi); } return 0; @@ -4153,14 +4210,17 @@ void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp, { struct bgp_mplsvpn_nh_label_bind_cache *bmnc; struct bgp_mplsvpn_nh_label_bind_cache_head *tree; + mpls_label_t label; + + label = bgp_path_info_num_labels(pi) + ? decode_label(&pi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; tree = &bgp->mplsvpn_nh_label_bind; - bmnc = bgp_mplsvpn_nh_label_bind_find( - tree, &pi->nexthop->prefix, decode_label(&pi->extra->label[0])); + bmnc = bgp_mplsvpn_nh_label_bind_find(tree, &pi->nexthop->prefix, label); if (!bmnc) { - bmnc = bgp_mplsvpn_nh_label_bind_new( - tree, &pi->nexthop->prefix, - decode_label(&pi->extra->label[0])); + bmnc = bgp_mplsvpn_nh_label_bind_new(tree, &pi->nexthop->prefix, + label); bmnc->bgp_vpn = bgp; bmnc->allocation_in_progress = true; bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 19b6f4eb777e..92a9fba887ae 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -13,6 +13,7 @@ #include "bgpd/bgp_rd.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_label.h" #define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION) #define MPLS_LABEL_IS_NULL(label) \ @@ -112,7 +113,8 @@ static inline bool is_bgp_vrf_mplsvpn(struct bgp *bgp) } static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, - const char **pmsg) + const char **pmsg, + bool ignore_export_rt_list) { if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF && bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { @@ -132,8 +134,21 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, return 0; } - /* Is there an RT list set? */ - if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) { + /* Before performing withdrawal, VPN activation is checked; however, + * when the route-map modifies the export route-target (RT) list, it + * becomes challenging to determine if VPN prefixes were previously + * present, or not. The 'ignore_export_rt_list' parameter will be + * used to force the withdraw operation by not checking the possible + * route-map changes. + * Of the 'ignore_export_rt_list' is set to false, check the following: + * - Is there an RT list set? + * - Is there a route-map that sets RT communities + */ + if (!ignore_export_rt_list && + !bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN] && + (!bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] || + !bgp_route_map_has_extcommunity_rt( + bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]))) { if (pmsg) *pmsg = "rtlist tovpn not defined"; return 0; @@ -155,14 +170,23 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, return 0; } - /* Is there an "auto" export label that isn't allocated yet? */ - if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO) && - (bgp_vrf->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)) { - - if (pmsg) - *pmsg = "auto label not allocated"; - return 0; + /* Is there a "manual" export label that isn't allocated yet? */ + if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO) && + bgp_vrf->vpn_policy[afi].tovpn_label != BGP_PREVENT_VRF_2_VRF_LEAK && + bgp_vrf->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE && + (bgp_vrf->vpn_policy[afi].tovpn_label >= MPLS_LABEL_UNRESERVED_MIN && + !CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG))) { + if (!bgp_zebra_request_label_range(bgp_vrf->vpn_policy[afi] + .tovpn_label, + 1, false)) { + if (pmsg) + *pmsg = "manual label could not be allocated"; + return 0; + } + SET_FLAG(bgp_vrf->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); } return 1; @@ -226,8 +250,7 @@ static inline void vpn_leak_prechange(enum vpn_policy_direction direction, vpn_leak_to_vrf_withdraw_all(bgp_vrf, afi); } if ((direction == BGP_VPN_POLICY_DIR_TOVPN) && - vpn_leak_to_vpn_active(bgp_vrf, afi, NULL)) { - + vpn_leak_to_vpn_active(bgp_vrf, afi, NULL, true)) { vpn_leak_from_vrf_withdraw_all(bgp_vpn, bgp_vrf, afi); } } diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index 0208a6f5a549..93d9f67245e8 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -511,8 +511,8 @@ static int bgp_init_snmp_stats(struct bgp *bgp) { if (is_bgp_vrf_mplsvpn(bgp)) { if (bgp->snmp_stats == NULL) { - bgp->snmp_stats = XCALLOC( - MTYPE_BGP, sizeof(struct bgp_snmp_stats)); + bgp->snmp_stats = XCALLOC(MTYPE_BGP_NAME, + sizeof(struct bgp_snmp_stats)); /* fix up added routes */ if (bgp->snmp_stats) { bgp->snmp_stats->routes_added = @@ -523,7 +523,7 @@ static int bgp_init_snmp_stats(struct bgp *bgp) } } else { if (bgp->snmp_stats) { - XFREE(MTYPE_BGP, bgp->snmp_stats); + XFREE(MTYPE_BGP_NAME, bgp->snmp_stats); bgp->snmp_stats = NULL; } } @@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp) /* add trap in here */ bgp->snmp_stats->active = new_active; + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + bgp_mpls_l3vpn_update_last_changed(bgp); + return 0; + } + /* send relevent trap */ if (bgp->snmp_stats->active) trap = MPLSL3VPNVRFUP; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index f322de76833f..e09dbc22af2d 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -484,10 +484,23 @@ static void bgp_accept(struct event *thread) /* Dynamic neighbor has been created, let it proceed */ connection1->fd = bgp_sock; + if (bgp_set_socket_ttl(connection1) < 0) { + peer1->last_reset = PEER_DOWN_SOCKET_ERROR; + zlog_err("%s: Unable to set min/max TTL on peer %s (dynamic), error received: %s(%d)", + __func__, peer1->host, + safe_strerror(errno), errno); + return; + } + /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS)) sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss); + frr_with_privs (&bgpd_privs) { + vrf_bind(peer1->bgp->vrf_id, bgp_sock, + bgp_get_bound_name(connection1)); + } + bgp_peer_reg_with_nht(peer1); bgp_fsm_change_status(connection1, Active); EVENT_OFF(connection1->t_start); @@ -588,12 +601,6 @@ static void bgp_accept(struct event *thread) peer_delete(peer1->doppelganger); } - if (bgp_set_socket_ttl(peer1->connection) < 0) - if (bgp_debug_neighbor_events(peer1)) - zlog_debug( - "[Event] Unable to set min/max TTL on peer %s, Continuing", - peer1->host); - peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, peer1->as, peer1->as_type, NULL, false, NULL); @@ -617,6 +624,12 @@ static void bgp_accept(struct event *thread) peer->doppelganger = peer1; peer1->doppelganger = peer; connection->fd = bgp_sock; + + if (bgp_set_socket_ttl(connection) < 0) + if (bgp_debug_neighbor_events(peer)) + zlog_debug("[Event] Unable to set min/max TTL on peer %s, Continuing", + peer->host); + frr_with_privs(&bgpd_privs) { vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer->connection)); @@ -693,7 +706,6 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, { struct prefix *p, *sel, d; struct connected *connected; - struct listnode *node; int common; if (!sockunion2hostprefix(dst, &d)) @@ -702,7 +714,7 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, sel = NULL; common = -1; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family != d.family) continue; @@ -805,9 +817,9 @@ int bgp_connect(struct peer_connection *connection) #ifdef IPTOS_PREC_INTERNETCONTROL frr_with_privs(&bgpd_privs) { if (sockunion_family(&connection->su) == AF_INET) - setsockopt_ipv4_tos(connection->fd, bm->tcp_dscp); + setsockopt_ipv4_tos(connection->fd, bm->ip_tos); else if (sockunion_family(&connection->su) == AF_INET6) - setsockopt_ipv6_tclass(connection->fd, bm->tcp_dscp); + setsockopt_ipv6_tclass(connection->fd, bm->ip_tos); } #endif @@ -863,11 +875,7 @@ int bgp_getsockname(struct peer *peer) } peer->su_local = sockunion_getsockname(peer->connection->fd); - if (!peer->su_local) - return -1; peer->su_remote = sockunion_getpeername(peer->connection->fd); - if (!peer->su_remote) - return -1; if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer)) { @@ -897,9 +905,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) - setsockopt_ipv4_tos(sock, bm->tcp_dscp); + setsockopt_ipv4_tos(sock, bm->ip_tos); else if (sa->sa_family == AF_INET6) - setsockopt_ipv6_tclass(sock, bm->tcp_dscp); + setsockopt_ipv6_tclass(sock, bm->ip_tos); #endif sockopt_v6only(sa->sa_family, sock); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index d12dc2233013..98eb9565bf20 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1003,6 +1003,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, if (bnc->is_evpn_gwip_nexthop) json_object_boolean_true_add(json_nexthop, "isEvpnGatewayIp"); + json_object_string_addf(json, "resolvedPrefix", "%pFX", + &bnc->resolved_prefix); } else { vty_out(vty, " %s valid [IGP metric %d], #paths %d", buf, bnc->metric, bnc->path_count); @@ -1010,6 +1012,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, vty_out(vty, ", peer %s", peer->host); if (bnc->is_evpn_gwip_nexthop) vty_out(vty, " EVPN Gateway IP"); + vty_out(vty, "\n Resolved prefix %pFX", + &bnc->resolved_prefix); vty_out(vty, "\n"); } bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 49cbbaf885f4..430c8f17e890 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -26,6 +26,8 @@ PREDECL_RBTREE_UNIQ(bgp_nexthop_cache); /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { + afi_t afi; + /* The ifindex of the outgoing interface *if* it's a v6 LL */ ifindex_t ifindex_ipv6_ll; @@ -37,6 +39,18 @@ struct bgp_nexthop_cache { /* Nexthop number and nexthop linked list.*/ uint8_t nexthop_num; + + /* This flag is set to TRUE for a bnc that is gateway IP overlay index + * nexthop. + */ + bool is_evpn_gwip_nexthop; + + uint16_t change_flags; +#define BGP_NEXTHOP_CHANGED (1 << 0) +#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) +#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) +#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3) + struct nexthop *nexthop; time_t last_update; uint16_t flags; @@ -70,27 +84,17 @@ struct bgp_nexthop_cache { */ #define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7) - uint16_t change_flags; - -#define BGP_NEXTHOP_CHANGED (1 << 0) -#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) -#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) -#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3) + uint32_t srte_color; /* Back pointer to the cache tree this entry belongs to. */ struct bgp_nexthop_cache_head *tree; - uint32_t srte_color; struct prefix prefix; + struct prefix resolved_prefix; void *nht_info; /* In BGP, peer session */ LIST_HEAD(path_list, bgp_path_info) paths; unsigned int path_count; struct bgp *bgp; - - /* This flag is set to TRUE for a bnc that is gateway IP overlay index - * nexthop. - */ - bool is_evpn_gwip_nexthop; }; extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a, diff --git a/bgpd/bgp_nhg.c b/bgpd/bgp_nhg.c new file mode 100644 index 000000000000..bf0ba77444e3 --- /dev/null +++ b/bgpd/bgp_nhg.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Nexthop Group Support + * Copyright (C) 2023 NVIDIA Corporation + * Copyright (C) 2023 6WIND + */ + +#include + +#include +#include +#include + + +/**************************************************************************** + * L3 NHGs are used for fast failover of nexthops in the dplane. These are + * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is + * left to the application using it. + * PS: Currently EVPN host routes is the only app using L3 NHG for fast + * failover of remote ES links. + ***************************************************************************/ +static bitfield_t bgp_nh_id_bitmap; +static uint32_t bgp_nhg_start; + +/* XXX - currently we do nothing on the callbacks */ +static void bgp_nhg_add_cb(const char *name) +{ +} + +static void bgp_nhg_modify_cb(const struct nexthop_group_cmd *nhgc) +{ +} + +static void bgp_nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, + const struct nexthop *nhop) +{ +} + +static void bgp_nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, + const struct nexthop *nhop) +{ +} + +static void bgp_nhg_del_cb(const char *name) +{ +} + +static void bgp_nhg_zebra_init(void) +{ + static bool bgp_nhg_zebra_inited; + + if (bgp_nhg_zebra_inited) + return; + + bgp_nhg_zebra_inited = true; + bgp_nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP); + nexthop_group_init(bgp_nhg_add_cb, bgp_nhg_modify_cb, + bgp_nhg_add_nexthop_cb, bgp_nhg_del_nexthop_cb, + bgp_nhg_del_cb); +} + +void bgp_nhg_init(void) +{ + uint32_t id_max; + + id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); + bf_init(bgp_nh_id_bitmap, id_max); + bf_assign_zero_index(bgp_nh_id_bitmap); + + if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("bgp nhg range %u - %u", bgp_nhg_start + 1, + bgp_nhg_start + id_max); +} + +void bgp_nhg_finish(void) +{ + bf_free(bgp_nh_id_bitmap); +} + +uint32_t bgp_nhg_id_alloc(void) +{ + uint32_t nhg_id = 0; + + bgp_nhg_zebra_init(); + bf_assign_index(bgp_nh_id_bitmap, nhg_id); + if (nhg_id) + nhg_id += bgp_nhg_start; + + return nhg_id; +} + +void bgp_nhg_id_free(uint32_t nhg_id) +{ + if (!nhg_id || (nhg_id <= bgp_nhg_start)) + return; + + nhg_id -= bgp_nhg_start; + + bf_release_index(bgp_nh_id_bitmap, nhg_id); +} diff --git a/bgpd/bgp_nhg.h b/bgpd/bgp_nhg.h new file mode 100644 index 000000000000..370e8ab09164 --- /dev/null +++ b/bgpd/bgp_nhg.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Nexthop Group Support + * Copyright (C) 2023 NVIDIA Corporation + * Copyright (C) 2023 6WIND + */ + +#ifndef _BGP_NHG_H +#define _BGP_NHG_H + +#include "nexthop_group.h" + +/* APIs for setting up and allocating L3 nexthop group ids */ +extern uint32_t bgp_nhg_id_alloc(void); +extern void bgp_nhg_id_free(uint32_t nhg_id); +extern void bgp_nhg_init(void); +void bgp_nhg_finish(void); + +#endif /* _BGP_NHG_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 60d6f74e1478..f75df1e12dc0 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -116,24 +116,36 @@ static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc, static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc, struct bgp_path_info *path) { + return (bnc && (bnc->nexthop_num > 0 && + (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || + bgp_isvalid_nexthop_for_ebgp(bnc, path) || + bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))); +} + +static bool bgp_isvalid_nexthop_for_l3vpn(struct bgp_nexthop_cache *bnc, + struct bgp_path_info *path) +{ + if (bgp_zebra_num_connects() == 0) + return 1; + + if (path->attr->srv6_l3vpn || path->attr->srv6_vpn) { + /* In the case of SRv6-VPN, we need to track the reachability to the + * SID (in other words, IPv6 address). We check that the SID is + * available in the BGP update; then if it is available, we check + * for the nexthop reachability. + */ + if (bnc && (bnc->nexthop_num > 0 && bgp_isvalid_nexthop(bnc))) + return 1; + return 0; + } /* - * - In the case of MPLS-VPN, the label is learned from LDP or other + * In the case of MPLS-VPN, the label is learned from LDP or other * protocols, and nexthop tracking is enabled for the label. * The value is recorded as BGP_NEXTHOP_LABELED_VALID. - * - In the case of SRv6-VPN, we need to track the reachability to the - * SID (in other words, IPv6 address). As in MPLS, we need to record - * the value as BGP_NEXTHOP_SID_VALID. However, this function is - * currently not implemented, and this function assumes that all - * Transit routes for SRv6-VPN are valid. * - Otherwise check for mpls-gre acceptance */ - return (bgp_zebra_num_connects() == 0 || - (bnc && (bnc->nexthop_num > 0 && - (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || - CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || - bnc->bgp->srv6_enabled || - bgp_isvalid_nexthop_for_ebgp(bnc, path) || - bgp_isvalid_nexthop_for_mplsovergre(bnc, path))))); + return bgp_isvalid_nexthop_for_mpls(bnc, path); } static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) @@ -345,9 +357,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, return 0; } - if (CHECK_FLAG(pi->attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - srte_color = bgp_attr_get_color(pi->attr); + srte_color = bgp_attr_get_color(pi->attr); } else if (peer) { /* @@ -386,6 +396,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, bnc = bnc_find(tree, &p, srte_color, ifindex); if (!bnc) { bnc = bnc_new(tree, &p, srte_color, ifindex); + bnc->afi = afi; bnc->bgp = bgp_nexthop; if (BGP_DEBUG(nht, NHT)) zlog_debug("Allocated bnc %pFX(%d)(%u)(%s) peer %p", @@ -405,7 +416,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (pi && is_route_parent_evpn(pi)) bnc->is_evpn_gwip_nexthop = true; - if (is_bgp_static_route) { + if (is_bgp_static_route && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)) { SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); /* If we're toggling the type, re-register */ @@ -493,9 +504,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) return 1; else if (safi == SAFI_UNICAST && pi && - pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra && - pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) - return bgp_isvalid_nexthop_for_mpls(bnc, pi); + pi->sub_type == BGP_ROUTE_IMPORTED && + bgp_path_info_num_labels(pi) && !bnc->is_evpn_gwip_nexthop) + return bgp_isvalid_nexthop_for_l3vpn(bnc, pi); else if (safi == SAFI_MPLS_VPN && pi && pi->sub_type != BGP_ROUTE_IMPORTED) /* avoid not redistributing mpls vpn routes */ @@ -613,6 +624,8 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, } else if (nhr->nexthop_num) { struct peer *peer = bnc->nht_info; + prefix_copy(&bnc->resolved_prefix, &nhr->prefix); + /* notify bgp fsm if nbr ip goes from invalid->valid */ if (!bnc->nexthop_num) UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); @@ -718,6 +731,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, } } } else { + memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix)); bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; bnc->flags &= ~BGP_NEXTHOP_VALID; bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; @@ -897,52 +911,60 @@ void bgp_nht_interface_events(struct peer *peer) bnc->ifindex_ipv6_ll, NULL); } -void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) +void bgp_nexthop_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr) { struct bgp_nexthop_cache_head *tree = NULL; struct bgp_nexthop_cache *bnc_nhc, *bnc_import; - struct bgp *bgp; - struct prefix match; - struct zapi_route nhr; + struct bgp *bgp, *bgp_default; + struct bgp_path_info *pi; + struct bgp_dest *dest; + safi_t safi; afi_t afi; - bgp = bgp_lookup_by_vrf_id(vrf_id); - if (!bgp) { - flog_err( - EC_BGP_NH_UPD, - "parse nexthop update: instance not found for vrf_id %u", - vrf_id); + if (!vrf->info) { + flog_err(EC_BGP_NH_UPD, + "parse nexthop update: instance not found for vrf_id %u", + vrf->vrf_id); return; } - if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) { - zlog_err("%s[%s]: Failure to decode nexthop update", __func__, - bgp->name_pretty); - return; - } - - afi = family2afi(match.family); + bgp = (struct bgp *)vrf->info; + afi = family2afi(match->family); tree = &bgp->nexthop_cache_table[afi]; - bnc_nhc = bnc_find(tree, &match, nhr.srte_color, 0); - if (!bnc_nhc) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug( - "parse nexthop update %pFX(%u)(%s): bnc info not found for nexthop cache", - &nhr.prefix, nhr.srte_color, bgp->name_pretty); - } else - bgp_process_nexthop_update(bnc_nhc, &nhr, false); + bnc_nhc = bnc_find(tree, match, nhr->srte_color, 0); + if (bnc_nhc) + bgp_process_nexthop_update(bnc_nhc, nhr, false); + else if (BGP_DEBUG(nht, NHT)) + zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for nexthop cache", + &nhr->prefix, nhr->srte_color, + bgp->name_pretty); tree = &bgp->import_check_table[afi]; - bnc_import = bnc_find(tree, &match, nhr.srte_color, 0); - if (!bnc_import) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug( - "parse nexthop update %pFX(%u)(%s): bnc info not found for import check", - &nhr.prefix, nhr.srte_color, bgp->name_pretty); - } else - bgp_process_nexthop_update(bnc_import, &nhr, true); + bnc_import = bnc_find(tree, match, nhr->srte_color, 0); + if (bnc_import) { + bgp_process_nexthop_update(bnc_import, nhr, true); + + bgp_default = bgp_get_default(); + safi = nhr->safi; + if (bgp != bgp_default && bgp->rib[afi][safi]) { + dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + match, NULL); + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) + if (pi->peer == bgp->peer_self && + pi->type == ZEBRA_ROUTE_BGP && + pi->sub_type == BGP_ROUTE_STATIC) + vpn_leak_from_vrf_update(bgp_default, + bgp, pi); + } + } else if (BGP_DEBUG(nht, NHT)) + zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for import check", + &nhr->prefix, nhr->srte_color, + bgp->name_pretty); /* * HACK: if any BGP route is dependant on an SR-policy that doesn't @@ -955,17 +977,16 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) * which should provide a better infrastructure to solve this issue in * a more efficient and elegant way. */ - if (nhr.srte_color == 0 && bnc_nhc) { + if (nhr->srte_color == 0) { struct bgp_nexthop_cache *bnc_iter; frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], bnc_iter) { - if (!prefix_same(&bnc_nhc->prefix, &bnc_iter->prefix) || - bnc_iter->srte_color == 0 || - CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID)) + if (!prefix_same(match, &bnc_iter->prefix) || + bnc_iter->srte_color == 0) continue; - bgp_process_nexthop_update(bnc_iter, &nhr, false); + bgp_process_nexthop_update(bnc_iter, nhr, false); } } } @@ -1036,27 +1057,32 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) break; case AFI_IP6: p->family = AF_INET6; - - if (is_bgp_static) { + if (pi->attr->srv6_l3vpn) { + IPV6_ADDR_COPY(&(p->u.prefix6), + &(pi->attr->srv6_l3vpn->sid)); + p->prefixlen = IPV6_MAX_BITLEN; + } else if (is_bgp_static) { p->u.prefix6 = p_orig->u.prefix6; p->prefixlen = p_orig->prefixlen; } else { /* If we receive MP_REACH nexthop with ::(LL) * or LL(LL), use LL address as nexthop cache. */ - if (pi->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL - && (IN6_IS_ADDR_UNSPECIFIED( - &pi->attr->mp_nexthop_global) - || IN6_IS_ADDR_LINKLOCAL( - &pi->attr->mp_nexthop_global))) + if (pi->attr && + pi->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && + (IN6_IS_ADDR_UNSPECIFIED( + &pi->attr->mp_nexthop_global) || + IN6_IS_ADDR_LINKLOCAL(&pi->attr->mp_nexthop_global))) p->u.prefix6 = pi->attr->mp_nexthop_local; /* If we receive MR_REACH with (GA)::(LL) * then check for route-map to choose GA or LL */ - else if (pi->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - if (pi->attr->mp_nexthop_prefer_global) + else if (pi->attr && + pi->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (CHECK_FLAG(pi->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) p->u.prefix6 = pi->attr->mp_nexthop_global; else @@ -1170,6 +1196,11 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc) */ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc) { + struct bgp_nexthop_cache *import; + struct bgp_nexthop_cache *nexthop; + + struct bgp *bgp = bnc->bgp; + /* Check if we have already registered */ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) return; @@ -1179,6 +1210,19 @@ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc) return; } + import = bnc_find(&bgp->import_check_table[bnc->afi], &bnc->prefix, 0, + 0); + nexthop = bnc_find(&bgp->nexthop_cache_table[bnc->afi], &bnc->prefix, 0, + 0); + + /* + * If this entry has both a import and a nexthop entry + * then let's not send the unregister quite as of yet + * wait until we only have 1 left + */ + if (import && nexthop) + return; + sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); } @@ -1261,14 +1305,17 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) bool bnc_is_valid_nexthop = false; bool path_valid = false; + struct bgp_route_evpn *bre = + bgp_attr_get_evpn_overlay(path->attr); - if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED - && path->extra && path->extra->num_labels - && (path->attr->evpn_overlay.type - != OVERLAY_INDEX_GATEWAY_IP)) { + if (safi == SAFI_UNICAST && + path->sub_type == BGP_ROUTE_IMPORTED && + bgp_path_info_num_labels(path) && + !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) { bnc_is_valid_nexthop = - bgp_isvalid_nexthop_for_mpls(bnc, path) ? true - : false; + bgp_isvalid_nexthop_for_l3vpn(bnc, path) + ? true + : false; } else if (safi == SAFI_MPLS_VPN && path->sub_type != BGP_ROUTE_IMPORTED) { /* avoid not redistributing mpls vpn routes */ @@ -1387,7 +1434,7 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) } } - bgp_process(bgp_path, dest, afi, safi); + bgp_process(bgp_path, dest, path, afi, safi); } if (peer) { @@ -1558,90 +1605,3 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) 0); } } - -/**************************************************************************** - * L3 NHGs are used for fast failover of nexthops in the dplane. These are - * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is - * left to the application using it. - * PS: Currently EVPN host routes is the only app using L3 NHG for fast - * failover of remote ES links. - ***************************************************************************/ -static bitfield_t bgp_nh_id_bitmap; -static uint32_t bgp_l3nhg_start; - -/* XXX - currently we do nothing on the callbacks */ -static void bgp_l3nhg_add_cb(const char *name) -{ -} - -static void bgp_l3nhg_modify_cb(const struct nexthop_group_cmd *nhgc) -{ -} - -static void bgp_l3nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, - const struct nexthop *nhop) -{ -} - -static void bgp_l3nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, - const struct nexthop *nhop) -{ -} - -static void bgp_l3nhg_del_cb(const char *name) -{ -} - -static void bgp_l3nhg_zebra_init(void) -{ - static bool bgp_l3nhg_zebra_inited; - if (bgp_l3nhg_zebra_inited) - return; - - bgp_l3nhg_zebra_inited = true; - bgp_l3nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP); - nexthop_group_init(bgp_l3nhg_add_cb, bgp_l3nhg_modify_cb, - bgp_l3nhg_add_nexthop_cb, bgp_l3nhg_del_nexthop_cb, - bgp_l3nhg_del_cb); -} - - -void bgp_l3nhg_init(void) -{ - uint32_t id_max; - - id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); - bf_init(bgp_nh_id_bitmap, id_max); - bf_assign_zero_index(bgp_nh_id_bitmap); - - if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("bgp l3_nhg range %u - %u", bgp_l3nhg_start + 1, - bgp_l3nhg_start + id_max); -} - -void bgp_l3nhg_finish(void) -{ - bf_free(bgp_nh_id_bitmap); -} - -uint32_t bgp_l3nhg_id_alloc(void) -{ - uint32_t nhg_id = 0; - - bgp_l3nhg_zebra_init(); - bf_assign_index(bgp_nh_id_bitmap, nhg_id); - if (nhg_id) - nhg_id += bgp_l3nhg_start; - - return nhg_id; -} - -void bgp_l3nhg_id_free(uint32_t nhg_id) -{ - if (!nhg_id || (nhg_id <= bgp_l3nhg_start)) - return; - - nhg_id -= bgp_l3nhg_start; - - bf_release_index(bgp_nh_id_bitmap, nhg_id); -} diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 0758a0cf08fc..e7c6fdc281b6 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -7,9 +7,10 @@ #define _BGP_NHT_H /** - * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra. + * bgp_nexthop_update() - process a nexthop update message from Zebra. */ -extern void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id); +extern void bgp_nexthop_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr); /** * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc @@ -78,12 +79,6 @@ extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer); extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer); extern void evaluate_paths(struct bgp_nexthop_cache *bnc); -/* APIs for setting up and allocating L3 nexthop group ids */ -extern uint32_t bgp_l3nhg_id_alloc(void); -extern void bgp_l3nhg_id_free(uint32_t nhg_id); -extern void bgp_l3nhg_init(void); -void bgp_l3nhg_finish(void); - extern void bgp_nht_ifp_up(struct interface *ifp); extern void bgp_nht_ifp_down(struct interface *ifp); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 6ee5b5dc5cda..42b4c2cfa4ce 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -42,25 +42,27 @@ const struct message capcode_str[] = { { CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" }, { CAPABILITY_CODE_ROLE, "Role" }, { CAPABILITY_CODE_SOFT_VERSION, "Software Version" }, + { CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" }, { 0 } }; /* Minimum sizes for length field of each cap (so not inc. the header) */ -static const size_t cap_minsizes[] = { - [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, - [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, - [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, - [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, - [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, - [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, - [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, - [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, - [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, - [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, - [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, - [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, - [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, - [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, +const size_t cap_minsizes[] = { + [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, + [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, + [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, + [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, + [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, + [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, + [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, + [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, + [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, + [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, + [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, + [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, + [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, + [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, + [CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN, }; /* value the capability must be a multiple of. @@ -68,21 +70,22 @@ static const size_t cap_minsizes[] = { * Other capabilities whose data doesn't fall on convenient boundaries for this * table should be set to 1. */ -static const size_t cap_modsizes[] = { - [CAPABILITY_CODE_MP] = 4, - [CAPABILITY_CODE_REFRESH] = 1, - [CAPABILITY_CODE_ORF] = 1, - [CAPABILITY_CODE_RESTART] = 1, - [CAPABILITY_CODE_AS4] = 4, - [CAPABILITY_CODE_ADDPATH] = 4, - [CAPABILITY_CODE_DYNAMIC] = 1, - [CAPABILITY_CODE_ENHE] = 6, - [CAPABILITY_CODE_FQDN] = 1, - [CAPABILITY_CODE_ENHANCED_RR] = 1, - [CAPABILITY_CODE_EXT_MESSAGE] = 1, - [CAPABILITY_CODE_LLGR] = 1, - [CAPABILITY_CODE_ROLE] = 1, - [CAPABILITY_CODE_SOFT_VERSION] = 1, +const size_t cap_modsizes[] = { + [CAPABILITY_CODE_MP] = 4, + [CAPABILITY_CODE_REFRESH] = 1, + [CAPABILITY_CODE_ORF] = 1, + [CAPABILITY_CODE_RESTART] = 1, + [CAPABILITY_CODE_AS4] = 4, + [CAPABILITY_CODE_ADDPATH] = 4, + [CAPABILITY_CODE_DYNAMIC] = 1, + [CAPABILITY_CODE_ENHE] = 6, + [CAPABILITY_CODE_FQDN] = 1, + [CAPABILITY_CODE_ENHANCED_RR] = 1, + [CAPABILITY_CODE_EXT_MESSAGE] = 1, + [CAPABILITY_CODE_LLGR] = 1, + [CAPABILITY_CODE_ROLE] = 1, + [CAPABILITY_CODE_SOFT_VERSION] = 1, + [CAPABILITY_CODE_PATHS_LIMIT] = 5, }; /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can @@ -198,6 +201,12 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, "capabilityErrorMultiProtocolSafi", "flowspec"); break; + case SAFI_RTC: + json_object_string_add( + json_cap, + "capabilityErrorMultiProtocolSafi", + "rtc"); + break; case SAFI_UNSPEC: case SAFI_MAX: json_object_int_add( @@ -247,6 +256,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, case SAFI_EVPN: vty_out(vty, "SAFI EVPN"); break; + case SAFI_RTC: + vty_out(vty, "SAFI RTC"); + break; case SAFI_UNSPEC: case SAFI_MAX: vty_out(vty, "SAFI Unknown %d ", @@ -340,15 +352,14 @@ static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi, peer->host, afi, safi, type, mode); } -static const struct message orf_type_str[] = { - {ORF_TYPE_RESERVED, "Reserved"}, - {ORF_TYPE_PREFIX, "Prefixlist"}, - {0}}; +const struct message orf_type_str[] = { { ORF_TYPE_RESERVED, "Reserved" }, + { ORF_TYPE_PREFIX, "Prefixlist" }, + { 0 } }; -static const struct message orf_mode_str[] = {{ORF_MODE_RECEIVE, "Receive"}, - {ORF_MODE_SEND, "Send"}, - {ORF_MODE_BOTH, "Both"}, - {0}}; +const struct message orf_mode_str[] = { { ORF_MODE_RECEIVE, "Receive" }, + { ORF_MODE_SEND, "Send" }, + { ORF_MODE_BOTH, "Both" }, + { 0 } }; static int bgp_capability_orf_entry(struct peer *peer, struct capability_header *hdr) @@ -517,20 +528,17 @@ static int bgp_capability_restart(struct peer *peer, UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; - if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", - peer->host, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) - ? " " - : " not ", - peer->v_gr_restart, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) - ? "yes" - : "no"); - } + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s", + peer, peer->v_gr_restart, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) + ? "SET" + : "NOT-SET"); while (stream_get_getp(s) + 4 <= end) { afi_t afi; @@ -554,14 +562,12 @@ static int bgp_capability_restart(struct peer *peer, iana_safi2str(pkt_safi)); } else { if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Address family %s is%spreserved", - peer->host, get_afi_safi_str(afi, safi, false), - CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV) - ? " " - : " not "); + zlog_debug("%pBP F-bit %s for %s", peer, + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? "SET" + : "NOT-SET", + get_afi_safi_str(afi, safi, false)); SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); @@ -623,17 +629,17 @@ static int bgp_capability_llgr(struct peer *peer, /* Unlike other capability parsing routines, this one returns 0 on error */ static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr) { - SET_FLAG(peer->cap, PEER_CAP_AS4_RCV); - if (hdr->length != CAPABILITY_CODE_AS4_LEN) { flog_err(EC_BGP_PKT_OPEN, "%s AS4 capability has incorrect data length %d", peer->host, hdr->length); - return 0; + return -1; } as_t as4 = stream_getl(BGP_INPUT(peer)); + SET_FLAG(peer->cap, PEER_CAP_AS4_RCV); + if (BGP_DEBUG(as4, AS4)) zlog_debug( "%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", @@ -663,10 +669,8 @@ static int bgp_capability_addpath(struct peer *peer, struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp(s) + hdr->length; - SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); - /* Verify length is a multiple of 4 */ - if (hdr->length % 4) { + if (hdr->length % CAPABILITY_CODE_ADDPATH_LEN) { flog_warn( EC_BGP_CAPABILITY_INVALID_LENGTH, "Add Path: Received invalid length %d, non-multiple of 4", @@ -674,23 +678,38 @@ static int bgp_capability_addpath(struct peer *peer, return -1; } - while (stream_get_getp(s) + 4 <= end) { + SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); + + while (stream_get_getp(s) + CAPABILITY_CODE_ADDPATH_LEN <= end) { afi_t afi; safi_t safi; iana_afi_t pkt_afi = stream_getw(s); iana_safi_t pkt_safi = stream_getc(s); uint8_t send_receive = stream_getc(s); + /* If any other value (other than 1-3) is received, then + * the capability SHOULD be treated as not understood + * and ignored. + */ + if (!send_receive || send_receive > 3) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Add Path: Received invalid send/receive value %u in Add Path capability", + send_receive); + continue; + } + if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s OPEN has %s capability for afi/safi: %s/%s%s%s", - peer->host, - lookup_msg(capcode_str, hdr->code, NULL), - iana_afi2str(pkt_afi), iana_safi2str(pkt_safi), - (send_receive & BGP_ADDPATH_RX) ? ", receive" - : "", - (send_receive & BGP_ADDPATH_TX) ? ", transmit" - : ""); + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s%s%s", + peer->host, + lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + CHECK_FLAG(send_receive, BGP_ADDPATH_RX) + ? ", receive" + : "", + CHECK_FLAG(send_receive, BGP_ADDPATH_TX) + ? ", transmit" + : ""); /* Convert AFI, SAFI to internal values, check. */ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { @@ -709,13 +728,75 @@ static int bgp_capability_addpath(struct peer *peer, continue; } - if (send_receive & BGP_ADDPATH_RX) + if (CHECK_FLAG(send_receive, BGP_ADDPATH_RX)) SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); - if (send_receive & BGP_ADDPATH_TX) + if (CHECK_FLAG(send_receive, BGP_ADDPATH_TX)) SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + } + + return 0; +} + +static int bgp_capability_paths_limit(struct peer *peer, + struct capability_header *hdr) +{ + struct stream *s = BGP_INPUT(peer); + size_t end = stream_get_getp(s) + hdr->length; + + if (hdr->length % CAPABILITY_CODE_PATHS_LIMIT_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Paths-Limit: Received invalid length %d, non-multiple of %d", + hdr->length, CAPABILITY_CODE_PATHS_LIMIT_LEN); + return -1; + } + + if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); + return -1; + } + + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + + while (stream_get_getp(s) + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi = stream_getw(s); + iana_safi_t pkt_safi = stream_getc(s); + uint16_t paths_limit = stream_getw(s); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", + peer->host, + lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), paths_limit); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + continue; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + continue; + } + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_RCV); + peer->addpath_paths_limit[afi][safi].receive = paths_limit; } return 0; @@ -800,8 +881,6 @@ static int bgp_capability_hostname(struct peer *peer, size_t end = stream_get_getp(s) + hdr->length; uint8_t len; - SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); - len = stream_getc(s); if (stream_get_getp(s) + len > end) { flog_warn( @@ -859,6 +938,8 @@ static int bgp_capability_hostname(struct peer *peer, peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); } + SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); + if (bgp_debug_neighbor_events(peer)) { zlog_debug("%s received hostname %s, domainname %s", peer->host, peer->hostname, peer->domainname); @@ -869,14 +950,16 @@ static int bgp_capability_hostname(struct peer *peer, static int bgp_capability_role(struct peer *peer, struct capability_header *hdr) { - SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, "Role: Received invalid length %d", hdr->length); return -1; } + uint8_t role = stream_getc(BGP_INPUT(peer)); + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + peer->remote_role = role; return 0; } @@ -889,8 +972,6 @@ static int bgp_capability_software_version(struct peer *peer, size_t end = stream_get_getp(s) + hdr->length; uint8_t len; - SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); - len = stream_getc(s); if (stream_get_getp(s) + len > end) { flog_warn( @@ -900,6 +981,8 @@ static int bgp_capability_software_version(struct peer *peer, return -1; } + SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + if (len > BGP_MAX_SOFT_VERSION) { flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, "%s: Received Software Version, but the length is too big, truncating, from peer %s", @@ -919,8 +1002,8 @@ static int bgp_capability_software_version(struct peer *peer, peer->soft_version = XSTRDUP(MTYPE_BGP_SOFT_VERSION, str); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s sent Software Version: %s", peer->host, - peer->soft_version); + zlog_debug("%s received Software Version: %s", + peer->host, peer->soft_version); } return 0; @@ -992,6 +1075,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_EXT_MESSAGE: case CAPABILITY_CODE_ROLE: case CAPABILITY_CODE_SOFT_VERSION: + case CAPABILITY_CODE_PATHS_LIMIT: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info( @@ -1020,6 +1104,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } + break; /* we deliberately ignore unknown codes, see below */ default: break; @@ -1092,6 +1177,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_SOFT_VERSION: ret = bgp_capability_software_version(peer, &caphdr); break; + case CAPABILITY_CODE_PATHS_LIMIT: + ret = bgp_capability_paths_limit(peer, &caphdr); + break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor @@ -1368,8 +1456,10 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, /* All OPEN option is parsed. Check capability when strict compare flag is enabled.*/ if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { - /* If Unsupported Capability exists. */ - if (error != error_data) { + /* If Unsupported Capability exists or local capability does + * not negotiated with remote peer + */ + if (error != error_data || !strict_capability_same(peer)) { bgp_notify_send_with_data(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, @@ -1377,14 +1467,6 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, error - error_data); return -1; } - - /* Check local capability does not negotiated with remote - peer. */ - if (!strict_capability_same(peer)) { - bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL); - return -1; - } } /* Extended Message Support */ @@ -1402,34 +1484,29 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, error. */ if (*mp_capability && !CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { - if (!peer->afc_nego[AFI_IP][SAFI_UNICAST] - && !peer->afc_nego[AFI_IP][SAFI_MULTICAST] - && !peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] - && !peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] - && !peer->afc_nego[AFI_IP][SAFI_ENCAP] - && !peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] - && !peer->afc_nego[AFI_IP6][SAFI_UNICAST] - && !peer->afc_nego[AFI_IP6][SAFI_MULTICAST] - && !peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] - && !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] - && !peer->afc_nego[AFI_IP6][SAFI_ENCAP] - && !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] - && !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { + if (!peer->afc_nego[AFI_IP][SAFI_UNICAST] && + !peer->afc_nego[AFI_IP][SAFI_MULTICAST] && + !peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] && + !peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && + !peer->afc_nego[AFI_IP][SAFI_ENCAP] && + !peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] && + !peer->afc_nego[AFI_IP][SAFI_RTC] && + !peer->afc_nego[AFI_IP6][SAFI_UNICAST] && + !peer->afc_nego[AFI_IP6][SAFI_MULTICAST] && + !peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] && + !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && + !peer->afc_nego[AFI_IP6][SAFI_ENCAP] && + !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] && + !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { flog_err(EC_BGP_PKT_OPEN, "%s [Error] Configured AFI/SAFIs do not overlap with received MP capabilities", peer->host); - if (error != error_data) - bgp_notify_send_with_data(peer->connection, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL, - error_data, - error - error_data); - else - bgp_notify_send(peer->connection, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL); - return -1; + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL, + error_data, + error - error_data); } } return 0; @@ -1515,15 +1592,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, uint32_t restart_time; unsigned long capp = 0; unsigned long rcapp = 0; + struct bgp *bgp = peer->bgp; if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) return; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :", - peer->host); - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ @@ -1533,42 +1607,41 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, /* Set Restart Capability Len Pointer */ rcapp = stream_get_endp(s); stream_putc(s, 0); - restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + restart_time = bgp->restart_time; + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending R-Bit for peer: %s", - peer->host); } - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending N-Bit for peer: %s", - peer->host); } stream_putw(s, restart_time); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Sending GR Capability, Restart time %d R-bit %s, N-bit %s", + peer->host, bgp->restart_time, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV) + ? "SET" + : "NOT-SET"); + /* Send address-family specific graceful-restart capability * only when GR config is present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] F bit Set"); - FOREACH_AFI_SAFI (afi, safi) { + bool f_bit = false; + if (!peer->afc[afi][safi]) continue; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:", - afi, safi); - /* Convert AFI, SAFI to values for * packet. */ @@ -1576,11 +1649,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, &pkt_safi); stream_putw(s, pkt_afi); stream_putc(s, pkt_safi); - if (CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) - stream_putc(s, GRACEFUL_RESTART_F_BIT); - else - stream_putc(s, 0); + + f_bit = bgp_gr_is_forwarding_preserved(bgp); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("... F-bit %s for %s", + f_bit ? "SET" : "NOT-SET", + get_afi_safi_str(afi, safi, false)); + + stream_putc(s, f_bit ? GRACEFUL_RESTART_F_BIT : 0); } } @@ -1853,6 +1930,31 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, } } + /* Paths-Limit capability */ + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV); + stream_putc(s, BGP_OPEN_OPT_CAP); + ext_opt_params ? stream_putw(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * + afi_safi_count) + + 2) + : stream_putc(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * + afi_safi_count) + + 2); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putw(s, peer->addpath_paths_limit[afi][safi].send); + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_ADV); + } + /* ORF capability. */ FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG(peer->af_flags[afi][safi], @@ -1866,7 +1968,7 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, } /* Dynamic capability. */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) { + if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) { SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); ext_opt_params @@ -1876,8 +1978,9 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); } - /* Hostname capability */ - if (cmd_hostname_get()) { + /* FQDN capability */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN) + && cmd_hostname_get()) { SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); rcapp = stream_get_endp(s); /* Ptr to length placeholder */ @@ -1929,8 +2032,7 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, * or disable its use, and that switch MUST be off by default. */ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION) || - CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY) || - peer->sort == BGP_PEER_IBGP) { + peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) { SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); rcapp = stream_get_endp(s); diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index a92c56d1b508..3a8cba9b7d33 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -53,6 +53,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */ #define CAPABILITY_CODE_ROLE 9 /* Role Capability */ +#define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */ /* Capability Length */ #define CAPABILITY_CODE_MP_LEN 4 @@ -61,6 +62,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ #define CAPABILITY_CODE_AS4_LEN 4 #define CAPABILITY_CODE_ADDPATH_LEN 4 +#define CAPABILITY_CODE_PATHS_LIMIT_LEN 5 #define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */ #define CAPABILITY_CODE_MIN_FQDN_LEN 2 #define CAPABILITY_CODE_ENHANCED_LEN 0 @@ -108,5 +110,9 @@ extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, json_object *json_neigh); extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length); extern const struct message capcode_str[]; +extern const struct message orf_type_str[]; +extern const struct message orf_mode_str[]; +extern const size_t cap_minsizes[]; +extern const size_t cap_modsizes[]; #endif /* _QUAGGA_BGP_OPEN_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index abbc298e47a0..4ed289dbaf50 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -24,6 +24,7 @@ #include "lib_errors.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_addpath.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_bmp.h" @@ -49,6 +50,7 @@ #include "bgpd/bgp_keepalives.h" #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_trace.h" +#include "bgpd/bgp_rtc.h" DEFINE_HOOK(bgp_packet_dump, (struct peer *peer, uint8_t type, bgp_size_t size, @@ -147,7 +149,8 @@ static void bgp_packet_add(struct peer_connection *connection, EC_BGP_SENDQ_STUCK_PROPER, "%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session", peer, sendholdtime); - BGP_EVENT_ADD(connection, TCP_fatal_error); + bgp_stop_with_notify(connection, + BGP_NOTIFY_SEND_HOLD_ERR, 0); } else if (delta > (intmax_t)holdtime && monotime(NULL) - peer->last_sendq_warn > 5) { flog_warn( @@ -349,6 +352,8 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr, return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw); case SAFI_FLOWSPEC: return bgp_nlri_parse_flowspec(peer, attr, packet, mp_withdraw); + case SAFI_RTC: + return bgp_nlri_parse_rtc(peer, attr, packet, mp_withdraw); } return BGP_NLRI_PARSE_ERROR; } @@ -558,40 +563,37 @@ void bgp_generate_updgrp_packets(struct event *thread) } } - if (CHECK_FLAG(peer->cap, - PEER_CAP_RESTART_RCV)) { - if (!(PAF_SUBGRP(paf))->t_coalesce - && peer->afc_nego[afi][safi] - && peer->synctime - && !CHECK_FLAG( - peer->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND)) { - /* If EOR is disabled, - * the message is not sent - */ - if (BGP_SEND_EOR(peer->bgp, afi, - safi)) { - SET_FLAG( - peer->af_sflags - [afi] - [safi], - PEER_STATUS_EOR_SEND); - - /* Update EOR - * send time - */ - peer->eor_stime[afi] - [safi] = - monotime(NULL); - - BGP_UPDATE_EOR_PKT( - peer, afi, safi, - s); - bgp_process_pending_refresh( - peer, afi, - safi); - } - } + /* rfc4724 says: + * Although the End-of-RIB marker is + * specified for the purpose of BGP + * graceful restart, it is noted that + * the generation of such a marker upon + * completion of the initial update would + * be useful for routing convergence in + * general, and thus the practice is + * recommended. + */ + if (!(PAF_SUBGRP(paf))->t_coalesce && + peer->afc_nego[afi][safi] && + peer->synctime && + !CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND)) { + /* If EOR is disabled, the message is + * not sent. + */ + if (!BGP_SEND_EOR(peer->bgp, afi, safi)) + continue; + + SET_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND); + + /* Update EOR send time */ + peer->eor_stime[afi][safi] = + monotime(NULL); + + BGP_UPDATE_EOR_PKT(peer, afi, safi, s); + bgp_process_pending_refresh(peer, afi, + safi); } continue; } @@ -652,6 +654,7 @@ void bgp_open_send(struct peer_connection *connection) uint16_t send_holdtime; as_t local_as; struct peer *peer = connection->peer; + bool ext_opt_params = false; if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) send_holdtime = peer->holdtime; @@ -678,15 +681,17 @@ void bgp_open_send(struct peer_connection *connection) /* Set capabilities */ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { struct stream *tmp = stream_new(STREAM_SIZE(s)); stream_copy(tmp, s); - if (bgp_open_capability(tmp, peer, false) - > BGP_OPEN_NON_EXT_OPT_LEN) { + if (bgp_open_capability(tmp, peer, ext_opt_params) > + BGP_OPEN_NON_EXT_OPT_LEN) { stream_free(tmp); - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { stream_copy(s, tmp); stream_free(tmp); @@ -697,10 +702,10 @@ void bgp_open_send(struct peer_connection *connection) bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", - peer->host, BGP_VERSION_4, local_as, send_holdtime, - &peer->local_id); + zlog_debug("%pBP fd %d sending OPEN%s, version %d, my as %u, holdtime %d, id %pI4", + peer, peer->connection->fd, + ext_opt_params ? " (Extended)" : "", BGP_VERSION_4, + local_as, send_holdtime, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ @@ -983,6 +988,7 @@ static void bgp_notify_send_internal(struct peer_connection *connection, peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; peer->notify.length = bgp_notify.length; + peer->notify.hard_reset = hard_reset; if (bgp_notify.length && data) { bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION, @@ -1211,13 +1217,19 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, unsigned long cap_len; uint16_t len; uint32_t gr_restart_time; + uint8_t addpath_afi_safi_count = 0; + bool adv_addpath_tx = false; + unsigned long number_of_orfs_p; + uint8_t number_of_orfs = 0; const char *capability = lookup_msg(capcode_str, capability_code, "Unknown"); + const char *hostname = cmd_hostname_get(); + const char *domainname = cmd_domainname_get(); if (!peer_established(peer->connection)) return; - if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) || !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) return; @@ -1232,7 +1244,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, /* Encode MP_EXT capability. */ switch (capability_code) { case CAPABILITY_CODE_SOFT_VERSION: - SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV); stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_SOFT_VERSION); cap_len = stream_get_endp(s); @@ -1263,6 +1274,9 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, : "Removing", capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV, + action == CAPABILITY_ACTION_SET); break; case CAPABILITY_CODE_MP: stream_putc(s, action); @@ -1282,18 +1296,13 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, iana_safi2str(pkt_safi)); break; case CAPABILITY_CODE_RESTART: - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && - !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) - return; - - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_RESTART); cap_len = stream_get_endp(s); stream_putc(s, 0); gr_restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); } @@ -1335,13 +1344,10 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + COND_FLAG(peer->cap, PEER_CAP_RESTART_ADV, + action == CAPABILITY_ACTION_SET); break; case CAPABILITY_CODE_LLGR: - if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)) - return; - - SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV); - stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_LLGR); cap_len = stream_get_endp(s); @@ -1373,25 +1379,257 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, : "Removing", capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_LLGR_ADV, + action == CAPABILITY_ACTION_SET); + break; + case CAPABILITY_CODE_ADDPATH: + FOREACH_AFI_SAFI (afi, safi) { + if (peer->afc[afi][safi]) { + addpath_afi_safi_count++; + + /* Only advertise addpath TX if a feature that + * will use it is + * configured */ + if (peer->addpath_type[afi][safi] != + BGP_ADDPATH_NONE) + adv_addpath_tx = true; + + /* If we have enabled labeled unicast, we MUST check + * against unicast SAFI because addpath IDs are + * allocated under unicast SAFI, the same as the RIB + * is managed in unicast SAFI. + */ + if (safi == SAFI_LABELED_UNICAST) + if (peer->addpath_type[afi][SAFI_UNICAST] != + BGP_ADDPATH_NONE) + adv_addpath_tx = true; + } + } + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ADDPATH); + stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN * + addpath_afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (peer->afc[afi][safi]) { + bool adv_addpath_rx = + !CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_DISABLE_ADDPATH_RX); + uint8_t flags = 0; + + /* Convert AFI, SAFI to values for packet. */ + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + + if (adv_addpath_rx) { + SET_FLAG(flags, BGP_ADDPATH_RX); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV); + } else { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV); + } + + if (adv_addpath_tx) { + SET_FLAG(flags, BGP_ADDPATH_TX); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG(peer->af_cap[afi] + [SAFI_UNICAST], + PEER_CAP_ADDPATH_AF_TX_ADV); + } else { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV); + } + + stream_putc(s, flags); + } + } + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV, + action == CAPABILITY_ACTION_SET); + break; + case CAPABILITY_CODE_PATHS_LIMIT: + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + addpath_afi_safi_count++; + } + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * + addpath_afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putw(s, + peer->addpath_paths_limit[afi][safi].send); + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s, limit: %u", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + peer->addpath_paths_limit[afi][safi] + .send); + } + + COND_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV, + action == CAPABILITY_ACTION_SET); break; - case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_ORF: + /* Convert AFI, SAFI to values for packet. */ + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ORF); + cap_len = stream_get_endp(s); + stream_putc(s, 0); + + stream_putw(s, pkt_afi); /* Address Family Identifier */ + stream_putc(s, 0); /* Reserved */ + stream_putc(s, + pkt_safi); /* Subsequent Address Family Identifier */ + + number_of_orfs_p = + stream_get_endp(s); /* Number of ORFs pointer */ + stream_putc(s, 0); /* Number of ORFs */ + + /* Address Prefix ORF */ + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_SM) || + CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_RM)) { + stream_putc(s, ORF_TYPE_PREFIX); + + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_SM) && + CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_RM)) { + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + stream_putc(s, ORF_MODE_BOTH); + } else if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_SM)) { + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + stream_putc(s, ORF_MODE_SEND); + } else { + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + stream_putc(s, ORF_MODE_RECEIVE); + } + number_of_orfs++; + } else { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + } + + /* Total Number of ORFs. */ + stream_putc_at(s, number_of_orfs_p, number_of_orfs); + + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + break; + case CAPABILITY_CODE_FQDN: + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_FQDN); + cap_len = stream_get_endp(s); + stream_putc(s, 0); /* Capability Length */ + + len = strlen(hostname); + if (len > BGP_MAX_HOSTNAME) + len = BGP_MAX_HOSTNAME; + + stream_putc(s, len); + stream_put(s, hostname, len); + + if (domainname) { + len = strlen(domainname); + if (len > BGP_MAX_HOSTNAME) + len = BGP_MAX_HOSTNAME; + + stream_putc(s, len); + stream_put(s, domainname, len); + } else + stream_putc(s, 0); + + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV, + action == CAPABILITY_ACTION_SET); + break; + case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: - case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ENHANCED_RR: - case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: break; case CAPABILITY_CODE_ROLE: - if (peer->local_role != ROLE_UNDEFINED) { - SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV); - stream_putc(s, action); - stream_putc(s, CAPABILITY_CODE_ROLE); - stream_putc(s, CAPABILITY_CODE_ROLE_LEN); - stream_putc(s, peer->local_role); - } + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ROLE); + stream_putc(s, CAPABILITY_CODE_ROLE_LEN); + stream_putc(s, peer->local_role); + COND_FLAG(peer->cap, PEER_CAP_ROLE_ADV, + action == CAPABILITY_ACTION_SET); break; default: break; @@ -1569,6 +1807,23 @@ static int bgp_open_receive(struct peer_connection *connection, mp_capability = 0; optlen = stream_getc(peer->curr); + /* If we previously had some more capabilities e.g.: + * FQDN, SOFT_VERSION, we MUST clear the values we used + * before, to avoid using stale data. + * Checking peer->cap is enough before checking for the real + * data, but we don't have this check everywhere in the code, + * thus let's clear the data here too before parsing the + * capabilities. + */ + if (peer->hostname) + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + + if (peer->domainname) + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + if (peer->soft_version) + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + /* Extended Optional Parameters Length for BGP OPEN Message */ if (optlen == BGP_OPEN_NON_EXT_OPT_LEN || CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { @@ -1746,6 +2001,14 @@ static int bgp_open_receive(struct peer_connection *connection, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; + } else if (peer->as_type == AS_AUTO) { + if (remote_as == peer->bgp->as) { + peer->as = peer->local_as; + SET_FLAG(peer->as_type, AS_INTERNAL); + } else { + peer->as = remote_as; + SET_FLAG(peer->as_type, AS_EXTERNAL); + } } else if (peer->as_type == AS_INTERNAL) { if (remote_as != peer->bgp->as) { if (bgp_debug_neighbor_events(peer)) @@ -1886,6 +2149,7 @@ static int bgp_open_receive(struct peer_connection *connection, peer->afc[AFI_IP][SAFI_LABELED_UNICAST]; peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] = peer->afc[AFI_IP][SAFI_FLOWSPEC]; + peer->afc_nego[AFI_IP][SAFI_RTC] = peer->afc[AFI_IP][SAFI_RTC]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = @@ -2147,15 +2411,16 @@ static int bgp_update_receive(struct peer_connection *connection, ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, sizeof(peer->rcvd_attr_str)); - peer->stat_upd_7606++; - - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) { + peer->stat_upd_7606++; flog_err( EC_BGP_UPDATE_RCV, "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer); + } - if (ret && bgp_debug_update(peer, NULL, NULL, 1)) { + if (ret && bgp_debug_update(peer, NULL, NULL, 1) && + BGP_DEBUG(update, UPDATE_DETAIL)) { zlog_debug("%pBP rcvd UPDATE w/ attr: %s", peer, peer->rcvd_attr_str); peer->rcvd_attr_printed = 1; @@ -2165,7 +2430,12 @@ static int bgp_update_receive(struct peer_connection *connection, /* Network Layer Reachability Information. */ update_len = end - stream_pnt(s); - if (update_len && attribute_len) { + /* If we received MP_UNREACH_NLRI attribute, but also NLRIs, then + * NLRIs should be handled as a new data. Though, if we received + * NLRIs without mandatory attributes, they should be ignored. + */ + if (update_len && attribute_len && + attr_parse_ret != BGP_ATTR_PARSE_MISSING_MANDATORY) { /* Set NLRI portion to structure. */ nlris[NLRI_UPDATE].afi = AFI_IP; nlris[NLRI_UPDATE].safi = SAFI_UNICAST; @@ -2185,7 +2455,7 @@ static int bgp_update_receive(struct peer_connection *connection, } } - if (BGP_DEBUG(update, UPDATE_IN)) + if (BGP_DEBUG(update, UPDATE_IN) && BGP_DEBUG(update, UPDATE_DETAIL)) zlog_debug("%pBP rcvd UPDATE wlen %d attrlen %d alen %d", peer, withdraw_len, attribute_len, update_len); @@ -2242,8 +2512,7 @@ static int bgp_update_receive(struct peer_connection *connection, * Non-MP IPv4/Unicast EoR is a completely empty UPDATE * and MP EoR should have only an empty MP_UNREACH */ - if ((!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) - || (attr_parse_ret == BGP_ATTR_PARSE_EOR)) { + if (!update_len && !withdraw_len && nlris[NLRI_MP_UPDATE].length == 0) { afi_t afi = 0; safi_t safi; struct graceful_restart_info *gr_info; @@ -2264,9 +2533,6 @@ static int bgp_update_receive(struct peer_connection *connection, && nlris[NLRI_MP_WITHDRAW].length == 0) { afi = nlris[NLRI_MP_WITHDRAW].afi; safi = nlris[NLRI_MP_WITHDRAW].safi; - } else if (attr_parse_ret == BGP_ATTR_PARSE_EOR) { - afi = nlris[NLRI_MP_UPDATE].afi; - safi = nlris[NLRI_MP_UPDATE].safi; } if (afi && peer->afc[afi][safi]) { @@ -2871,6 +3137,400 @@ static int bgp_route_refresh_receive(struct peer_connection *connection, return BGP_PACKET_NOOP; } +static void bgp_dynamic_capability_addpath(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + size_t len = end - data; + afi_t afi; + safi_t safi; + + if (action == CAPABILITY_ACTION_SET) { + if (len % CAPABILITY_CODE_ADDPATH_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Add Path: Received invalid length %zu, non-multiple of 4", + len); + return; + } + + SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); + + while (data + CAPABILITY_CODE_ADDPATH_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + struct bgp_addpath_capability bac; + + memcpy(&bac, data, sizeof(bac)); + pkt_afi = ntohs(bac.afi); + pkt_safi = safi_int2iana(bac.safi); + + /* If any other value (other than 1-3) is received, + * then the capability SHOULD be treated as not + * understood and ignored. + */ + if (!bac.flags || bac.flags > 3) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Add Path: Received invalid send/receive value %u in Add Path capability", + bac.flags); + goto ignore; + } + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s%s%s", + peer->host, + lookup_msg(capcode_str, hdr->code, + NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + (bac.flags & BGP_ADDPATH_RX) + ? ", receive" + : "", + (bac.flags & BGP_ADDPATH_TX) + ? ", transmit" + : ""); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, + &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Addpath Attribute for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the AddPath capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } + + if (CHECK_FLAG(bac.flags, BGP_ADDPATH_RX)) + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); + + if (CHECK_FLAG(bac.flags, BGP_ADDPATH_TX)) + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + +ignore: + data += CAPABILITY_CODE_ADDPATH_LEN; + } + } else { + FOREACH_AFI_SAFI (afi, safi) { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + } + + UNSET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); + } +} + +static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + size_t len = end - data; + afi_t afi; + safi_t safi; + + if (action == CAPABILITY_ACTION_SET) { + if (len % CAPABILITY_CODE_PATHS_LIMIT_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Paths-Limit: Received invalid length %zu, non-multiple of %d", + len, CAPABILITY_CODE_PATHS_LIMIT_LEN); + return; + } + + if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); + goto ignore; + } + + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + + while (data + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + uint16_t paths_limit = 0; + struct bgp_paths_limit_capability bpl = {}; + + memcpy(&bpl, data, sizeof(bpl)); + pkt_afi = ntohs(bpl.afi); + pkt_safi = safi_int2iana(bpl.safi); + paths_limit = ntohs(bpl.paths_limit); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", + peer->host, + lookup_msg(capcode_str, hdr->code, + NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), paths_limit); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, + &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV); + peer->addpath_paths_limit[afi][safi].receive = + paths_limit; +ignore: + data += CAPABILITY_CODE_PATHS_LIMIT_LEN; + } + } else { + FOREACH_AFI_SAFI (afi, safi) + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV); + + UNSET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + } +} + +static void bgp_dynamic_capability_orf(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + size_t len = end - data; + + struct capability_mp_data mpc; + uint8_t num; + iana_afi_t pkt_afi; + afi_t afi; + iana_safi_t pkt_safi; + safi_t safi; + uint8_t type; + uint8_t mode; + uint16_t sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; + uint16_t rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; + int i; + + if (data + CAPABILITY_CODE_ORF_LEN > end) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "ORF: Received invalid length %zu, less than %d", len, + CAPABILITY_CODE_ORF_LEN); + return; + } + + /* ORF Entry header */ + memcpy(&mpc, data, sizeof(mpc)); + data += sizeof(mpc); + num = *data++; + pkt_afi = ntohs(mpc.afi); + pkt_safi = mpc.safi; + + /* Convert AFI, SAFI to internal values, check. */ + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { + zlog_info("%pBP Addr-family %d/%d not supported. Ignoring the ORF capability", + peer, pkt_afi, pkt_safi); + return; + } + + /* validate number field */ + if (CAPABILITY_CODE_ORF_LEN + (num * 2) > hdr->length) { + zlog_info("%pBP ORF Capability entry length error, Cap length %u, num %u", + peer, hdr->length, num); + return; + } + + if (action == CAPABILITY_ACTION_UNSET) { + UNSET_FLAG(peer->af_cap[afi][safi], sm_cap); + UNSET_FLAG(peer->af_cap[afi][safi], rm_cap); + return; + } + + for (i = 0; i < num; i++) { + if (data + 1 > end) { + flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH, + "%pBP ORF Capability entry length (type) error, Cap length %u, num %u", + peer, hdr->length, num); + return; + } + type = *data++; + + if (data + 1 > end) { + flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH, + "%pBP ORF Capability entry length (mode) error, Cap length %u, num %u", + peer, hdr->length, num); + return; + } + mode = *data++; + + /* ORF Mode error check */ + switch (mode) { + case ORF_MODE_BOTH: + case ORF_MODE_SEND: + case ORF_MODE_RECEIVE: + break; + default: + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP Addr-family %d/%d has ORF type/mode %d/%d not supported", + peer, afi, safi, type, mode); + continue; + } + + if (!((afi == AFI_IP && safi == SAFI_UNICAST) || + (afi == AFI_IP && safi == SAFI_MULTICAST) || + (afi == AFI_IP6 && safi == SAFI_UNICAST))) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP Addr-family %d/%d unsupported AFI/SAFI received", + peer, afi, safi); + continue; + } + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has %s ORF capability as %s for afi/safi: %s/%s", + peer, lookup_msg(orf_type_str, type, NULL), + lookup_msg(orf_mode_str, mode, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + switch (mode) { + case ORF_MODE_BOTH: + SET_FLAG(peer->af_cap[afi][safi], sm_cap); + SET_FLAG(peer->af_cap[afi][safi], rm_cap); + break; + case ORF_MODE_SEND: + SET_FLAG(peer->af_cap[afi][safi], sm_cap); + UNSET_FLAG(peer->af_cap[afi][safi], rm_cap); + break; + case ORF_MODE_RECEIVE: + SET_FLAG(peer->af_cap[afi][safi], rm_cap); + UNSET_FLAG(peer->af_cap[afi][safi], sm_cap); + break; + } + } +} + +static void bgp_dynamic_capability_role(uint8_t *pnt, int action, + struct peer *peer) +{ + uint8_t role; + + if (action == CAPABILITY_ACTION_SET) { + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + memcpy(&role, pnt + 3, sizeof(role)); + + peer->remote_role = role; + } else { + UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + peer->remote_role = ROLE_UNDEFINED; + } +} + +static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + char str[BGP_MAX_HOSTNAME + 1] = {}; + uint8_t len; + + if (action == CAPABILITY_ACTION_SET) { + /* hostname */ + if (data + 1 >= end) { + zlog_err("%pBP: Received invalid FQDN capability (host name length)", + peer); + return; + } + + len = *data; + if (data + len + 1 > end) { + zlog_err("%pBP: Received invalid FQDN capability length (host name) %d", + peer, hdr->length); + return; + } + data++; + + if (len > BGP_MAX_HOSTNAME) { + memcpy(&str, data, BGP_MAX_HOSTNAME); + str[BGP_MAX_HOSTNAME] = '\0'; + } else if (len) { + memcpy(&str, data, len); + str[len] = '\0'; + } + data += len; + + if (len) { + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); + } + + if (data + 1 >= end) { + zlog_err("%pBP: Received invalid FQDN capability (domain name length)", + peer); + return; + } + + /* domainname */ + len = *data; + if (data + len + 1 > end) { + zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d", + peer, len); + return; + } + data++; + + if (len > BGP_MAX_HOSTNAME) { + memcpy(&str, data, BGP_MAX_HOSTNAME); + str[BGP_MAX_HOSTNAME] = '\0'; + } else if (len) { + memcpy(&str, data, len); + str[len] = '\0'; + } + /* data += len; In case new code is ever added */ + + if (len) { + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); + } + + SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); + } else { + UNSET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + } +} + static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action, struct capability_header *hdr, struct peer *peer) @@ -3057,6 +3717,40 @@ static void bgp_dynamic_capability_graceful_restart(uint8_t *pnt, int action, } } +static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + uint8_t len = *data; + char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; + + if (action == CAPABILITY_ACTION_SET) { + if (data + len + 1 > end) { + zlog_err("%pBP: Received invalid Software Version capability length %d", + peer, len); + return; + } + data++; + + if (len > BGP_MAX_SOFT_VERSION) + len = BGP_MAX_SOFT_VERSION; + + memcpy(&soft_version, data, len); + soft_version[len] = '\0'; + + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + peer->soft_version = XSTRDUP(MTYPE_BGP_SOFT_VERSION, + soft_version); + + SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + } else { + UNSET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + } +} + /** * Parse BGP CAPABILITY message for peer. * @@ -3075,7 +3769,6 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, afi_t afi; iana_safi_t pkt_safi; safi_t safi; - char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; const char *capability; end = pnt + length; @@ -3087,6 +3780,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, zlog_err("%pBP: Capability length error", peer); bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); + /* + * If we did not return then + * pnt += length; + */ return BGP_Stop; } action = *pnt; @@ -3099,7 +3796,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, action); bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); - return BGP_Stop; + goto done; } if (bgp_debug_neighbor_events(peer)) @@ -3111,33 +3808,63 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, zlog_err("%pBP: Capability length error", peer); bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); + /* + * If we did not return then + * pnt += length; + */ return BGP_Stop; } /* Ignore capability when override-capability is set. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) - continue; + goto done; capability = lookup_msg(capcode_str, hdr->code, "Unknown"); + /* Length sanity check, type-specific, for known capabilities */ switch (hdr->code) { + case CAPABILITY_CODE_MP: + case CAPABILITY_CODE_REFRESH: + case CAPABILITY_CODE_ORF: + case CAPABILITY_CODE_RESTART: + case CAPABILITY_CODE_AS4: + case CAPABILITY_CODE_ADDPATH: + case CAPABILITY_CODE_DYNAMIC: + case CAPABILITY_CODE_ENHE: + case CAPABILITY_CODE_FQDN: + case CAPABILITY_CODE_ENHANCED_RR: + case CAPABILITY_CODE_EXT_MESSAGE: + case CAPABILITY_CODE_ROLE: case CAPABILITY_CODE_SOFT_VERSION: - if (action == CAPABILITY_ACTION_SET) { - SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); - - memcpy(&soft_version, pnt + 3, hdr->length); - soft_version[hdr->length] = '\0'; - - XFREE(MTYPE_BGP_SOFT_VERSION, - peer->soft_version); - peer->soft_version = - XSTRDUP(MTYPE_BGP_SOFT_VERSION, - soft_version); - } else { - UNSET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); - XFREE(MTYPE_BGP_SOFT_VERSION, - peer->soft_version); + case CAPABILITY_CODE_PATHS_LIMIT: + if (hdr->length < cap_minsizes[hdr->code]) { + zlog_info("%pBP: %s Capability length error: got %u, expected at least %u", + peer, capability, hdr->length, + (unsigned int)cap_minsizes[hdr->code]); + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_MALFORMED_ATTR); + goto done; } + if (hdr->length && + hdr->length % cap_modsizes[hdr->code] != 0) { + zlog_info("%pBP %s Capability length error: got %u, expected a multiple of %u", + peer, capability, hdr->length, + (unsigned int)cap_modsizes[hdr->code]); + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_MALFORMED_ATTR); + goto done; + } + break; + default: + break; + } + + switch (hdr->code) { + case CAPABILITY_CODE_SOFT_VERSION: + bgp_dynamic_capability_software_version(pnt, action, + hdr, peer); break; case CAPABILITY_CODE_MP: if (hdr->length < sizeof(struct capability_mp_data)) { @@ -3145,7 +3872,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, peer, capability, sizeof(struct capability_mp_data), hdr->length); - return BGP_Stop; + goto done; } memcpy(&mpc, pnt + 3, sizeof(struct capability_mp_data)); @@ -3160,7 +3887,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, peer, capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); - continue; + goto done; } /* Address family check. */ @@ -3187,56 +3914,38 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, if (peer_active_nego(peer)) bgp_clear_route(peer, afi, safi); else - return BGP_Stop; + goto done; } break; case CAPABILITY_CODE_RESTART: - if ((hdr->length - 2) % 4) { - zlog_err("%pBP: Received invalid Graceful-Restart capability length %d", - peer, hdr->length); - bgp_notify_send(peer->connection, - BGP_NOTIFY_CEASE, - BGP_NOTIFY_SUBCODE_UNSPECIFIC); - return BGP_Stop; - } - bgp_dynamic_capability_graceful_restart(pnt, action, hdr, peer); break; case CAPABILITY_CODE_LLGR: bgp_dynamic_capability_llgr(pnt, action, hdr, peer); break; - case CAPABILITY_CODE_REFRESH: + case CAPABILITY_CODE_ADDPATH: + bgp_dynamic_capability_addpath(pnt, action, hdr, peer); + break; + case CAPABILITY_CODE_PATHS_LIMIT: + bgp_dynamic_capability_paths_limit(pnt, action, hdr, + peer); + break; case CAPABILITY_CODE_ORF: + bgp_dynamic_capability_orf(pnt, action, hdr, peer); + break; + case CAPABILITY_CODE_FQDN: + bgp_dynamic_capability_fqdn(pnt, action, hdr, peer); + break; + case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: - case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ENHANCED_RR: - case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: break; case CAPABILITY_CODE_ROLE: - if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { - zlog_err("%pBP: Capability (%s) length error", - peer, capability); - bgp_notify_send(peer->connection, - BGP_NOTIFY_CEASE, - BGP_NOTIFY_SUBCODE_UNSPECIFIC); - return BGP_Stop; - } - - uint8_t role; - - if (action == CAPABILITY_ACTION_SET) { - SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); - memcpy(&role, pnt + 3, sizeof(role)); - - peer->remote_role = role; - } else { - UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); - peer->remote_role = ROLE_UNDEFINED; - } + bgp_dynamic_capability_role(pnt, action, peer); break; default: flog_warn(EC_BGP_UNRECOGNIZED_CAPABILITY, @@ -3245,6 +3954,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, break; } +done: pnt += hdr->length + 3; } @@ -3272,8 +3982,8 @@ int bgp_capability_receive(struct peer_connection *connection, if (bgp_debug_neighbor_events(peer)) zlog_debug("%s rcv CAPABILITY", peer->host); - /* If peer does not have the capability, send notification. */ - if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) { + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV) || + !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { flog_err(EC_BGP_NO_CAP, "%s [Error] BGP dynamic capability is not enabled", peer->host); diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index ed143d9af707..cb16c4dc2e80 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -134,7 +134,7 @@ struct bgp_pbr_entry_main { struct bgp_pbr_interface { RB_ENTRY(bgp_pbr_interface) id_entry; - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; }; RB_HEAD(bgp_pbr_interface_head, bgp_pbr_interface); diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h index e38c2fad3baf..93dda17236f6 100644 --- a/bgpd/bgp_rd.h +++ b/bgpd/bgp_rd.h @@ -41,8 +41,8 @@ struct rd_as { struct rd_ip { uint16_t type; - struct in_addr ip; uint16_t val; + struct in_addr ip; }; #ifdef ENABLE_BGP_VNC diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3a850a486dce..73148f19caa7 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0-or-later /* BGP routing information * Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro * Copyright (C) 2016 Job Snijders @@ -28,6 +27,8 @@ #include "lib/json.h" #include "lib_errors.h" #include "zclient.h" +#include "frrdistance.h" + #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" @@ -73,6 +74,7 @@ #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_pbr.h" +#include "bgpd/bgp_rtc.h" #include "bgpd/bgp_route_clippy.c" @@ -85,6 +87,11 @@ DEFINE_HOOK(bgp_rpki_prefix_status, const struct prefix *prefix), (peer, attr, prefix)); +DEFINE_HOOK(bgp_route_update, + (struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + struct bgp_path_info *old_route, struct bgp_path_info *new_route), + (bgp, afi, safi, bn, old_route, new_route)); + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; @@ -107,13 +114,53 @@ static const struct message bgp_pmsi_tnltype_str[] = { #define VRFID_NONE_STR "-" #define SOFT_RECONFIG_TASK_MAX_PREFIX 25000 +static inline char *bgp_route_dump_path_info_flags(struct bgp_path_info *pi, + char *buf, size_t len) +{ + uint32_t flags = pi->flags; + + if (flags == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED) ? "IGP Changed " : "", + CHECK_FLAG(flags, BGP_PATH_DAMPED) ? "Damped" : "", + CHECK_FLAG(flags, BGP_PATH_HISTORY) ? "History " : "", + CHECK_FLAG(flags, BGP_PATH_SELECTED) ? "Selected " : "", + CHECK_FLAG(flags, BGP_PATH_VALID) ? "Valid " : "", + CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED) ? "Attr Changed " + : "", + CHECK_FLAG(flags, BGP_PATH_DMED_CHECK) ? "Dmed Check " : "", + CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED) ? "Dmed Selected " + : "", + CHECK_FLAG(flags, BGP_PATH_STALE) ? "Stale " : "", + CHECK_FLAG(flags, BGP_PATH_REMOVED) ? "Removed " : "", + CHECK_FLAG(flags, BGP_PATH_COUNTED) ? "Counted " : "", + CHECK_FLAG(flags, BGP_PATH_MULTIPATH) ? "Mpath " : "", + CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG) ? "Mpath Chg " : "", + CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG) ? "Rib Chg " : "", + CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF) ? "NH Self " : "", + CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG) ? "LinkBW Chg " : "", + CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN) ? "Accept Own " : "", + CHECK_FLAG(flags, BGP_PATH_MPLSVPN_LABEL_NH) ? "MPLS Label " + : "", + CHECK_FLAG(flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND) + ? "MPLS Label Bind " + : "", + CHECK_FLAG(flags, BGP_PATH_UNSORTED) ? "Unsorted " : ""); + + return buf; +} + DEFINE_HOOK(bgp_process, (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, struct peer *peer, bool withdraw), (bgp, afi, safi, bn, peer, withdraw)); /** Test if path is suppressed. */ -static bool bgp_path_suppressed(struct bgp_path_info *pi) +bool bgp_path_suppressed(struct bgp_path_info *pi) { if (pi->extra == NULL || pi->extra->aggr_suppressors == NULL) return false; @@ -188,8 +235,6 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void) struct bgp_path_info_extra *new; new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_path_info_extra)); - new->label[0] = MPLS_INVALID_LABEL; - new->num_labels = 0; new->flowspec = NULL; return new; } @@ -202,10 +247,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) return; e = *extra; - if (e->damp_info) - bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi, - e->damp_info->safi); + if (e->damp_info) + bgp_damp_info_free(e->damp_info, NULL, 0); e->damp_info = NULL; if (e->vrfleak && e->vrfleak->parent) { struct bgp_path_info *bpi = @@ -256,6 +300,13 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) XFREE(MTYPE_BGP_ROUTE_EXTRA_FS, e->flowspec); if (e->vrfleak) XFREE(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, e->vrfleak); +#ifdef ENABLE_BGP_VNC + if (e->vnc) + XFREE(MTYPE_BGP_ROUTE_EXTRA_VNC, e->vnc); +#endif + + if (e->labels) + bgp_labels_unintern(&e->labels); XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); } @@ -274,6 +325,41 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) return pi->extra; } +bool bgp_path_info_has_valid_label(const struct bgp_path_info *path) +{ + if (!bgp_path_info_num_labels(path)) + return false; + + return bgp_is_valid_label(&path->extra->labels->label[0]); +} + +bool bgp_path_info_labels_same(const struct bgp_path_info *bpi, + const mpls_label_t *label, uint32_t n) +{ + uint8_t bpi_num_labels; + const mpls_label_t *bpi_label; + + bpi_num_labels = bgp_path_info_num_labels(bpi); + bpi_label = bpi_num_labels ? bpi->extra->labels->label : NULL; + + return bgp_labels_same(bpi_label, bpi_num_labels, + (const mpls_label_t *)label, n); +} + +uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi) +{ + if (!pi) + return 0; + + if (!pi->extra) + return 0; + + if (!pi->extra->labels) + return 0; + + return pi->extra->labels->num_labels; +} + /* Free bgp route information. */ void bgp_path_info_free_with_caller(const char *name, struct bgp_path_info *path) @@ -431,10 +517,13 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest, top->prev = pi; bgp_dest_set_bgp_path_info(dest, pi); + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); bgp_path_info_lock(pi); bgp_dest_lock_node(dest); peer_lock(pi->peer); /* bgp_path_info peer reference */ bgp_dest_set_defer_flag(dest, false); + if (pi->peer) + pi->peer->stat_pfx_loc_rib++; hook_call(bgp_snmp_update_stats, dest, pi, true); } @@ -451,8 +540,30 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest, bgp_dest_set_bgp_path_info(dest, pi->next); bgp_path_info_mpath_dequeue(pi); + + pi->next = NULL; + pi->prev = NULL; + + if (pi->peer) + pi->peer->stat_pfx_loc_rib--; + hook_call(bgp_snmp_update_stats, dest, pi, false); + bgp_path_info_unlock(pi); + return bgp_dest_unlock_node(dest); +} + +static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest, + struct bgp_path_info *pi) +{ + bgp_path_info_mpath_dequeue(pi); + + pi->next = NULL; + pi->prev = NULL; + + if (pi->peer) + pi->peer->stat_pfx_loc_rib--; hook_call(bgp_snmp_update_stats, dest, pi, false); + bgp_path_info_unlock(pi); return bgp_dest_unlock_node(dest); } @@ -542,6 +653,15 @@ void bgp_path_info_unset_flag(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_pcount_adjust(dest, pi); } +static bool use_bgp_med_value(struct attr *attr, struct bgp *bgp) +{ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC) || + CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) + return true; + + return false; +} + /* Get MED value. If MED value is missing and "bgp bestpath missing-as-worst" is specified, treat it as the worst value. */ static uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp) @@ -561,6 +681,11 @@ void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, { struct peer *peer; + if (!pi) { + snprintf(buf, buf_len, "NONE"); + return; + } + if (pi->sub_type == BGP_ROUTE_IMPORTED && bgp_get_imported_bpi_ultimate(pi)) peer = bgp_get_imported_bpi_ultimate(pi)->peer; @@ -606,6 +731,8 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, struct attr *newattr, *existattr; enum bgp_peer_sort new_sort; enum bgp_peer_sort exist_sort; + enum bgp_peer_sub_sort new_sub_sort; + enum bgp_peer_sub_sort exist_sub_sort; uint32_t new_pref; uint32_t exist_pref; uint32_t new_med; @@ -661,12 +788,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (debug) { + char buf1[256], buf2[256]; + bpi_ultimate = bgp_get_imported_bpi_ultimate(exist); bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, exist_buf, sizeof(exist_buf)); - zlog_debug("%s(%s): Comparing %s flags 0x%x with %s flags 0x%x", - pfx_buf, bgp->name_pretty, new_buf, new->flags, - exist_buf, exist->flags); + zlog_debug("%s(%s): Comparing %s flags %s with %s flags %s", + pfx_buf, bgp->name_pretty, new_buf, + bgp_route_dump_path_info_flags(new, buf1, + sizeof(buf1)), + exist_buf, + bgp_route_dump_path_info_flags(exist, buf2, + sizeof(buf2))); } newattr = new->attr; @@ -718,8 +851,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * with the * sticky flag. */ - if (newattr->sticky != existattr->sticky) { - if (newattr->sticky && !existattr->sticky) { + bool new_sticky = CHECK_FLAG(newattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + bool exist_sticky = CHECK_FLAG(existattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + + if (new_sticky != exist_sticky) { + if (new_sticky && !exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -728,7 +866,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } - if (!newattr->sticky && existattr->sticky) { + if (!new_sticky && exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -1140,26 +1278,34 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* 7. Peer type check. */ new_sort = peer_new->sort; exist_sort = peer_exist->sort; + new_sub_sort = peer_new->sub_sort; + exist_sub_sort = peer_exist->sub_sort; - if (new_sort == BGP_PEER_EBGP - && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) { + if (new_sort == BGP_PEER_EBGP && + (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED || + exist_sub_sort == BGP_PEER_EBGP_OAD)) { *reason = bgp_path_selection_peer; if (debug) - zlog_debug( - "%s: %s wins over %s due to eBGP peer > iBGP peer", - pfx_buf, new_buf, exist_buf); + zlog_debug("%s: %s wins over %s due to eBGP peer > %s peer", + pfx_buf, new_buf, exist_buf, + (exist_sub_sort == BGP_PEER_EBGP_OAD) + ? "eBGP-OAD" + : "iBGP"); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) return 1; peer_sort_ret = 1; } - if (exist_sort == BGP_PEER_EBGP - && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) { + if (exist_sort == BGP_PEER_EBGP && + (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED || + new_sub_sort == BGP_PEER_EBGP_OAD)) { *reason = bgp_path_selection_peer; if (debug) - zlog_debug( - "%s: %s loses to %s due to iBGP peer < eBGP peer", - pfx_buf, new_buf, exist_buf); + zlog_debug("%s: %s loses to %s due to %s peer < eBGP peer", + pfx_buf, new_buf, exist_buf, + (exist_sub_sort == BGP_PEER_EBGP_OAD) + ? "eBGP-OAD" + : "iBGP"); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) return 0; peer_sort_ret = 0; @@ -1254,25 +1400,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* If one path has a label but the other does not, do not treat * them as equals for multipath */ - int newl, existl; - - newl = existl = 0; - - if (new->extra) - newl = new->extra->num_labels; - if (exist->extra) - existl = exist->extra->num_labels; - if (((new->extra &&bgp_is_valid_label(&new->extra->label[0])) != - (exist->extra && - bgp_is_valid_label(&exist->extra->label[0]))) || - (newl != existl)) { + bool new_label_valid, exist_label_valid; + + new_label_valid = bgp_path_info_has_valid_label(new); + exist_label_valid = bgp_path_info_has_valid_label(exist); + + if (new_label_valid != exist_label_valid) { if (debug) zlog_debug( "%s: %s and %s cannot be multipath, one has a label while the other does not", pfx_buf, new_buf, exist_buf); } else if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { - /* * For the two paths, all comparison steps till IGP * metric @@ -1468,18 +1607,16 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (ret == 1) { *reason = bgp_path_selection_neighbor_ip; if (debug) - zlog_debug( - "%s: %s loses to %s due to Neighor IP comparison", - pfx_buf, new_buf, exist_buf); + zlog_debug("%s: %s loses to %s due to Neighbor IP comparison", + pfx_buf, new_buf, exist_buf); return 0; } if (ret == -1) { *reason = bgp_path_selection_neighbor_ip; if (debug) - zlog_debug( - "%s: %s wins over %s due to Neighor IP comparison", - pfx_buf, new_buf, exist_buf); + zlog_debug("%s: %s wins over %s due to Neighbor IP comparison", + pfx_buf, new_buf, exist_buf); return 1; } @@ -1738,11 +1875,12 @@ static bool bgp_check_role_applicability(afi_t afi, safi_t safi) static int bgp_input_modifier(struct peer *peer, const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, - uint32_t num_labels, struct bgp_dest *dest) + uint8_t num_labels, struct bgp_dest *dest) { struct bgp_filter *filter; struct bgp_path_info rmap_path = { 0 }; struct bgp_path_info_extra extra = { 0 }; + struct bgp_labels bgp_labels = {}; route_map_result_t ret; struct route_map *rmap = NULL; @@ -1774,11 +1912,12 @@ static int bgp_input_modifier(struct peer *peer, const struct prefix *p, rmap_path.attr = attr; rmap_path.extra = &extra; rmap_path.net = dest; + extra.labels = &bgp_labels; - extra.num_labels = num_labels; + bgp_labels.num_labels = num_labels; if (label && num_labels && num_labels <= BGP_MAX_LABELS) - memcpy(extra.label, label, - num_labels * sizeof(mpls_label_t)); + memcpy(bgp_labels.label, label, + num_labels * sizeof(mpls_label_t)); SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN); @@ -2113,8 +2252,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * off box as that the RT and RD created are localy * significant and globaly useless. */ - if (safi == SAFI_MPLS_VPN && pi->extra && pi->extra->num_labels - && pi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + if (safi == SAFI_MPLS_VPN && bgp_path_info_num_labels(pi) && + pi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) return false; /* If it's labeled safi, make sure the route has a valid label. */ @@ -2162,9 +2301,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * configured for default-originate */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) { - if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) - return false; - else if (p->family == AF_INET6 && p->prefixlen == 0) + if ((p->family == AF_INET || p->family == AF_INET6) && p->prefixlen == 0) return false; } @@ -2218,7 +2355,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } /* AS path loop check. */ - if (peer->as_path_loop_detection && + if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION) && aspath_loop_check(piattr->aspath, peer->as)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( @@ -2299,8 +2436,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ - if (peer->sort == BGP_PEER_EBGP - && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD && + attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { if (from != bgp->peer_self && !transparent && !CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) @@ -2378,6 +2515,14 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_otc_egress(peer, attr)) return false; + /* RTC-Filtering */ + if (peer->afc[AFI_IP][SAFI_RTC]) { + /* The update group should only have one peer */ + onlypeer = SUBGRP_PFIRST(subgrp)->peer; + if (bgp_rtc_filter(onlypeer, attr, p)) + return false; + } + if (filter->advmap.update_type == UPDATE_TYPE_WITHDRAW && filter->advmap.aname && route_map_lookup_by_name(filter->advmap.aname)) { @@ -2514,8 +2659,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, return false; if (bgp_in_graceful_shutdown(bgp)) { - if (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED) { + if (peer->sort == BGP_PEER_IBGP || + peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD) { attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); attr->local_pref = BGP_GSHUT_LOCAL_PREF; } else { @@ -2645,17 +2791,25 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If this is an iBGP, send Origin Validation State (OVS) * extended community (rfc8097). + * draft-uttaro-idr-bgp-oad states: + * For example, the Origin Validation State Extended Community, + * defined as non-transitive in [RFC8097], can be advertised to + * peers in the same OAD. */ - if (peer->sort == BGP_PEER_IBGP) { + if ((peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) && + peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI)) { enum rpki_states rpki_state = RPKI_NOT_BEING_USED; rpki_state = hook_call(bgp_rpki_prefix_status, peer, attr, p); if (rpki_state != RPKI_NOT_BEING_USED) - bgp_attr_set_ecommunity( - attr, ecommunity_add_origin_validation_state( - rpki_state, - bgp_attr_get_ecommunity(attr))); + bgp_attr_set_ecommunity(attr, + ecommunity_add_origin_validation_state( + rpki_state, + bgp_attr_get_ecommunity( + attr))); } /* @@ -2664,17 +2818,26 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * the most sense. However, don't modify if the link-bandwidth has * been explicitly set by user policy. */ - if (nh_reset && - bgp_path_info_mpath_chkwtd(bgp, pi) && + if (nh_reset && bgp_path_info_mpath_chkwtd(bgp, pi) && (cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 && - !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) - bgp_attr_set_ecommunity( - attr, - ecommunity_replace_linkbw( - bgp->as, bgp_attr_get_ecommunity(attr), cum_bw, - CHECK_FLAG( - peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE))); + !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) { + if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) + bgp_attr_set_ipv6_ecommunity( + attr, + ecommunity_replace_linkbw(bgp->as, + bgp_attr_get_ipv6_ecommunity( + attr), + cum_bw, false, true)); + else + bgp_attr_set_ecommunity( + attr, + ecommunity_replace_linkbw( + bgp->as, bgp_attr_get_ecommunity(attr), + cum_bw, + CHECK_FLAG(peer->flags, + PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE), + false)); + } return true; } @@ -2703,17 +2866,18 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info_pair *result, afi_t afi, safi_t safi) { - struct bgp_path_info *new_select; - struct bgp_path_info *old_select; + struct bgp_path_info *new_select, *look_thru; + struct bgp_path_info *old_select, *worse, *first; struct bgp_path_info *pi; struct bgp_path_info *pi1; struct bgp_path_info *pi2; - struct bgp_path_info *nextpi = NULL; int paths_eq, do_mpath; - bool debug; + bool debug, any_comparisons; struct list mp_list; char pfx_buf[PREFIX2STR_BUFFER] = {}; char path_buf[PATH_ADDPATH_STR_BUFFER]; + enum bgp_path_selection_reason reason = bgp_path_selection_none; + bool unsorted_items = true; bgp_mp_list_init(&mp_list); do_mpath = @@ -2724,16 +2888,16 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (debug) prefix2str(bgp_dest_get_prefix(dest), pfx_buf, sizeof(pfx_buf)); - dest->reason = bgp_path_selection_none; /* bgp deterministic-med */ new_select = NULL; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)) { - /* Clear BGP_PATH_DMED_SELECTED for all paths */ for (pi1 = bgp_dest_get_bgp_path_info(dest); pi1; - pi1 = pi1->next) + pi1 = pi1->next) { bgp_path_info_unset_flag(dest, pi1, BGP_PATH_DMED_SELECTED); + UNSET_FLAG(pi1->flags, BGP_PATH_DMED_CHECK); + } for (pi1 = bgp_dest_get_bgp_path_info(dest); pi1; pi1 = pi1->next) { @@ -2749,41 +2913,35 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } new_select = pi1; - if (pi1->next) { - for (pi2 = pi1->next; pi2; pi2 = pi2->next) { - if (CHECK_FLAG(pi2->flags, - BGP_PATH_DMED_CHECK)) - continue; - if (BGP_PATH_HOLDDOWN(pi2)) - continue; - if (pi2->peer != bgp->peer_self && - !CHECK_FLAG(pi2->peer->sflags, - PEER_STATUS_NSF_WAIT) && - !peer_established( - pi2->peer->connection)) - continue; - - if (!aspath_cmp_left(pi1->attr->aspath, - pi2->attr->aspath) - && !aspath_cmp_left_confed( - pi1->attr->aspath, - pi2->attr->aspath)) - continue; + for (pi2 = pi1->next; pi2; pi2 = pi2->next) { + if (CHECK_FLAG(pi2->flags, BGP_PATH_DMED_CHECK)) + continue; + if (BGP_PATH_HOLDDOWN(pi2)) + continue; + if (pi2->peer != bgp->peer_self && + !CHECK_FLAG(pi2->peer->sflags, + PEER_STATUS_NSF_WAIT) && + !peer_established(pi2->peer->connection)) + continue; - if (bgp_path_info_cmp( - bgp, pi2, new_select, - &paths_eq, mpath_cfg, debug, - pfx_buf, afi, safi, - &dest->reason)) { - bgp_path_info_unset_flag( - dest, new_select, - BGP_PATH_DMED_SELECTED); - new_select = pi2; - } + if (!aspath_cmp_left(pi1->attr->aspath, + pi2->attr->aspath) && + !aspath_cmp_left_confed(pi1->attr->aspath, + pi2->attr->aspath)) + continue; - bgp_path_info_set_flag( - dest, pi2, BGP_PATH_DMED_CHECK); + if (bgp_path_info_cmp(bgp, pi2, new_select, + &paths_eq, mpath_cfg, + debug, pfx_buf, afi, safi, + &dest->reason)) { + bgp_path_info_unset_flag(dest, + new_select, + BGP_PATH_DMED_SELECTED); + new_select = pi2; } + + bgp_path_info_set_flag(dest, pi2, + BGP_PATH_DMED_CHECK); } bgp_path_info_set_flag(dest, new_select, BGP_PATH_DMED_CHECK); @@ -2802,69 +2960,273 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } } - /* Check old selected route and new selected route. */ + /* + * Let's grab the unsorted items from the list + */ + struct bgp_path_info *unsorted_list = NULL; + struct bgp_path_info *unsorted_list_spot = NULL; + struct bgp_path_info *unsorted_holddown = NULL; + old_select = NULL; - new_select = NULL; - for (pi = bgp_dest_get_bgp_path_info(dest); - (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { - enum bgp_path_selection_reason reason; + pi = bgp_dest_get_bgp_path_info(dest); + while (pi && CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED)) { + struct bgp_path_info *next = pi->next; if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) old_select = pi; - if (BGP_PATH_HOLDDOWN(pi)) { - /* reap REMOVED routes, if needs be + /* + * Pull off pi off the list + */ + if (pi->next) + pi->next->prev = NULL; + + bgp_dest_set_bgp_path_info(dest, pi->next); + pi->next = NULL; + pi->prev = NULL; + + /* + * Place it on the unsorted list + */ + if (unsorted_list_spot) { + unsorted_list_spot->next = pi; + pi->prev = unsorted_list_spot; + pi->next = NULL; + } else { + unsorted_list = pi; + + pi->next = NULL; + pi->prev = NULL; + } + + unsorted_list_spot = pi; + pi = next; + } + + if (!old_select) { + old_select = bgp_dest_get_bgp_path_info(dest); + if (old_select && + !CHECK_FLAG(old_select->flags, BGP_PATH_SELECTED)) + old_select = NULL; + } + + if (!unsorted_list) + unsorted_items = true; + else + unsorted_items = false; + + any_comparisons = false; + worse = NULL; + while (unsorted_list) { + first = unsorted_list; + unsorted_list = unsorted_list->next; + + if (unsorted_list) + unsorted_list->prev = NULL; + first->next = NULL; + first->prev = NULL; + + /* + * It's not likely that the just received unsorted entry + * is in holddown and scheduled for removal but we should + * check + */ + if (BGP_PATH_HOLDDOWN(first)) { + /* + * reap REMOVED routes, if needs be * selected route must stay for a while longer though */ - if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && - (pi != old_select)) { - dest = bgp_path_info_reap(dest, pi); - assert(dest); - } - if (debug) - zlog_debug( - "%s: %pBD(%s) pi from %s in holddown", - __func__, dest, bgp->name_pretty, - pi->peer->host); + zlog_debug("%s: %pBD(%s) pi %p from %s in holddown", + __func__, dest, bgp->name_pretty, + first, first->peer->host); + + if (old_select != first && + CHECK_FLAG(first->flags, BGP_PATH_REMOVED)) { + dest = bgp_path_info_reap_unsorted(dest, first); + assert(dest); + } else { + /* + * We are in hold down, so we cannot sort this + * item yet. Let's wait, so hold the unsorted + * to the side + */ + if (unsorted_holddown) { + first->next = unsorted_holddown; + unsorted_holddown->prev = first; + unsorted_holddown = first; + } else + unsorted_holddown = first; + UNSET_FLAG(first->flags, BGP_PATH_UNSORTED); + } continue; } - if (pi->peer && pi->peer != bgp->peer_self - && !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT)) - if (!peer_established(pi->peer->connection)) { + bgp_path_info_unset_flag(dest, first, BGP_PATH_DMED_CHECK); + + worse = NULL; + + struct bgp_path_info *look_thru_next; + + for (look_thru = bgp_dest_get_bgp_path_info(dest); look_thru; + look_thru = look_thru_next) { + /* look thru can be reaped save the next pointer */ + look_thru_next = look_thru->next; + + /* + * Now we have the first unsorted and the best selected + * Let's do best path comparison + */ + if (BGP_PATH_HOLDDOWN(look_thru)) { + /* reap REMOVED routes, if needs be + * selected route must stay for a while longer though + */ if (debug) - zlog_debug( - "%s: %pBD(%s) non self peer %s not estab state", - __func__, dest, - bgp->name_pretty, - pi->peer->host); + zlog_debug("%s: %pBD(%s) pi from %s %p in holddown", + __func__, dest, + bgp->name_pretty, + look_thru->peer->host, + look_thru); + + if (CHECK_FLAG(look_thru->flags, + BGP_PATH_REMOVED) && + (look_thru != old_select)) { + dest = bgp_path_info_reap(dest, + look_thru); + assert(dest); + } continue; } - if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED) - && (!CHECK_FLAG(pi->flags, BGP_PATH_DMED_SELECTED))) { - bgp_path_info_unset_flag(dest, pi, BGP_PATH_DMED_CHECK); - if (debug) - zlog_debug("%s: %pBD(%s) pi %s dmed", __func__, - dest, bgp->name_pretty, - pi->peer->host); - continue; + if (look_thru->peer && + look_thru->peer != bgp->peer_self && + !CHECK_FLAG(look_thru->peer->sflags, + PEER_STATUS_NSF_WAIT)) + if (!peer_established( + look_thru->peer->connection)) { + if (debug) + zlog_debug("%s: %pBD(%s) non self peer %s not estab state", + __func__, dest, + bgp->name_pretty, + look_thru->peer->host); + + continue; + } + + bgp_path_info_unset_flag(dest, look_thru, + BGP_PATH_DMED_CHECK); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED) && + (!CHECK_FLAG(look_thru->flags, + BGP_PATH_DMED_SELECTED))) { + bgp_path_info_unset_flag(dest, look_thru, + BGP_PATH_DMED_CHECK); + if (debug) + zlog_debug("%s: %pBD(%s) pi %s dmed", + __func__, dest, + bgp->name_pretty, + look_thru->peer->host); + + worse = look_thru; + continue; + } + + reason = dest->reason; + any_comparisons = true; + if (bgp_path_info_cmp(bgp, first, look_thru, &paths_eq, + mpath_cfg, debug, pfx_buf, afi, + safi, &reason)) { + first->reason = reason; + worse = look_thru; + /* + * We can stop looking + */ + break; + } + + look_thru->reason = reason; } - bgp_path_info_unset_flag(dest, pi, BGP_PATH_DMED_CHECK); + if (!any_comparisons) + first->reason = bgp_path_selection_first; + + /* + * At this point worse if NON-NULL is where the first + * pointer should be before. if worse is NULL then + * first is bestpath too. Let's remove first from the + * list and place it in the right spot + */ + + if (!worse) { + struct bgp_path_info *end = + bgp_dest_get_bgp_path_info(dest); - reason = dest->reason; - if (bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, - debug, pfx_buf, afi, safi, - &dest->reason)) { - if (new_select == NULL && - reason != bgp_path_selection_none) - dest->reason = reason; - new_select = pi; + for (; end && end->next != NULL; end = end->next) + ; + + if (end) + end->next = first; + else + bgp_dest_set_bgp_path_info(dest, first); + first->prev = end; + first->next = NULL; + + dest->reason = first->reason; + } else { + if (worse->prev) + worse->prev->next = first; + first->next = worse; + if (worse) { + first->prev = worse->prev; + worse->prev = first; + } else + first->prev = NULL; + + if (dest->info == worse) { + bgp_dest_set_bgp_path_info(dest, first); + dest->reason = first->reason; + } } + UNSET_FLAG(first->flags, BGP_PATH_UNSORTED); + } + + if (!unsorted_items) { + new_select = bgp_dest_get_bgp_path_info(dest); + while (new_select && BGP_PATH_HOLDDOWN(new_select)) + new_select = new_select->next; + + if (new_select) { + if (new_select->reason == bgp_path_selection_none) + new_select->reason = bgp_path_selection_first; + else if (new_select == bgp_dest_get_bgp_path_info(dest) && + new_select->next == NULL) + new_select->reason = bgp_path_selection_first; + dest->reason = new_select->reason; + } else + dest->reason = bgp_path_selection_none; + } else + new_select = old_select; + + + /* + * Reinsert all the unsorted_holddown items for future processing + * at the end of the list. + */ + if (unsorted_holddown) { + struct bgp_path_info *top = bgp_dest_get_bgp_path_info(dest); + struct bgp_path_info *prev = NULL; + + while (top != NULL) { + prev = top; + top = top->next; + } + + if (prev) { + prev->next = unsorted_holddown; + unsorted_holddown->prev = prev; + } else + bgp_dest_set_bgp_path_info(dest, unsorted_holddown); } /* Now that we know which path is the bestpath see if any of the other @@ -2872,11 +3234,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, * qualify as multipaths */ if (debug) { - if (new_select) - bgp_path_info_path_with_addpath_rx_str( - new_select, path_buf, sizeof(path_buf)); - else - snprintf(path_buf, sizeof(path_buf), "NONE"); + bgp_path_info_path_with_addpath_rx_str(new_select, path_buf, + sizeof(path_buf)); zlog_debug( "%pBD(%s): After path selection, newbest is %s oldbest was %s", dest, bgp->name_pretty, path_buf, @@ -2884,9 +3243,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } if (do_mpath && new_select) { - for (pi = bgp_dest_get_bgp_path_info(dest); - (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { - + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (debug) bgp_path_info_path_with_addpath_rx_str( pi, path_buf, sizeof(path_buf)); @@ -2910,15 +3267,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (!peer_established(pi->peer->connection)) continue; - if (!bgp_path_info_nexthop_cmp(pi, new_select)) { - if (debug) - zlog_debug( - "%pBD(%s): %s has the same nexthop as the bestpath, skip it", - dest, bgp->name_pretty, - path_buf); - continue; - } - bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, debug, pfx_buf, afi, safi, &dest->reason); @@ -2958,7 +3306,7 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, { const struct prefix *p; struct peer *onlypeer; - struct attr attr; + struct attr attr = { 0 }, *pattr = &attr; struct bgp *bgp; bool advertise; @@ -2986,26 +3334,30 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, advertise = bgp_check_advertise(bgp, dest, safi); if (selected) { - if (subgroup_announce_check(dest, selected, subgrp, p, &attr, + if (subgroup_announce_check(dest, selected, subgrp, p, pattr, NULL)) { /* Route is selected, if the route is already installed * in FIB, then it is advertised */ if (advertise) { if (!bgp_check_withdrawal(bgp, dest, safi)) { - struct attr *adv_attr = - bgp_attr_intern(&attr); - - bgp_adj_out_set_subgroup(dest, subgrp, - adv_attr, - selected); - } else + if (!bgp_adj_out_set_subgroup(dest, + subgrp, + pattr, + selected)) + bgp_attr_flush(pattr); + } else { bgp_adj_out_unset_subgroup( dest, subgrp, 1, addpath_tx_id); - } - } else + bgp_attr_flush(pattr); + } + } else + bgp_attr_flush(pattr); + } else { bgp_adj_out_unset_subgroup(dest, subgrp, 1, addpath_tx_id); + bgp_attr_flush(pattr); + } } /* If selected is NULL we must withdraw the path using addpath_tx_id */ @@ -3136,8 +3488,7 @@ static bool bgp_lu_need_null_label(struct bgp *bgp, || new_select->sub_type == BGP_ROUTE_AGGREGATE || new_select->sub_type == BGP_ROUTE_REDISTRIBUTE) goto need_null_label; - else if (new_select->extra && - bgp_is_valid_label(&new_select->extra->label[0])) + else if (bgp_path_info_has_valid_label(new_select)) return false; need_null_label: if (label == NULL) @@ -3206,6 +3557,7 @@ static void bgp_lu_handle_label_allocation(struct bgp *bgp, CHECK_FLAG(dest->flags, BGP_NODE_LABEL_REQUESTED)) { bgp_unregister_for_label(dest); } + } static struct interface * @@ -3314,7 +3666,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, return; } +#ifdef ENABLE_BGP_VNC const struct prefix *p = bgp_dest_get_prefix(dest); +#endif debug = bgp_debug_bestpath(dest); if (debug) @@ -3377,9 +3731,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_IMPORTED)) - - bgp_zebra_announce(dest, p, old_select, - bgp, afi, safi); + bgp_zebra_route_install(dest, old_select, + bgp, true, NULL, + false); } } @@ -3434,11 +3788,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, &bgp->t_rmap_def_originate_eval); } + /* TODO BMP insert rib update hook */ if (old_select) bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED); if (new_select) { if (debug) - zlog_debug("%s: setting SELECTED flag", __func__); + zlog_debug("%s: %pBD setting SELECTED flag", __func__, + dest); bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED); bgp_path_info_unset_flag(dest, new_select, BGP_PATH_ATTR_CHANGED); @@ -3446,6 +3802,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG); } + /* call bmp hook for loc-rib route update / withdraw after flags were + * set + */ + if (old_select || new_select) { + hook_call(bgp_route_update, bgp, afi, safi, dest, old_select, + new_select); + } + + #ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (old_select != new_select) { @@ -3463,14 +3828,6 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, } #endif - group_announce_route(bgp, afi, safi, dest, new_select); - - /* unicast routes must also be annouced to labeled-unicast update-groups - */ - if (safi == SAFI_UNICAST) - group_announce_route(bgp, afi, SAFI_LABELED_UNICAST, dest, - new_select); - /* FIB update. */ if (bgp_fibupd_safi(safi) && (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) && !bgp_option_check(BGP_OPT_NO_FIB)) { @@ -3486,9 +3843,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, */ if (old_select && is_route_parent_evpn(old_select)) - bgp_zebra_withdraw(p, old_select, bgp, safi); + bgp_zebra_withdraw_actual(dest, old_select, bgp); - bgp_zebra_announce(dest, p, new_select, bgp, afi, safi); + bgp_zebra_route_install(dest, new_select, bgp, true, + NULL, false); } else { /* Withdraw the route from the kernel. */ if (old_select && old_select->type == ZEBRA_ROUTE_BGP @@ -3496,10 +3854,20 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, || old_select->sub_type == BGP_ROUTE_AGGREGATE || old_select->sub_type == BGP_ROUTE_IMPORTED)) - bgp_zebra_withdraw(p, old_select, bgp, safi); + bgp_zebra_route_install(dest, old_select, bgp, + false, NULL, false); } } + group_announce_route(bgp, afi, safi, dest, new_select); + + /* unicast routes must also be annouced to labeled-unicast update-groups + */ + if (safi == SAFI_UNICAST) + group_announce_route(bgp, afi, SAFI_LABELED_UNICAST, dest, + new_select); + + bgp_process_evpn_route_injection(bgp, afi, safi, dest, new_select, old_select); @@ -3521,6 +3889,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) struct bgp_dest *dest; int cnt = 0; struct afi_safi_info *thread_info; + bool route_sync_pending = false; if (bgp->gr_info[afi][safi].t_route_select) { struct event *t = bgp->gr_info[afi][safi].t_route_select; @@ -3530,7 +3899,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bgp->gr_info[afi][safi].t_route_select); } - if (BGP_DEBUG(update, UPDATE_OUT)) { + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { zlog_debug("%s: processing route for %s : cnt %d", __func__, get_afi_safi_str(afi, safi, false), bgp->gr_info[afi][safi].gr_deferred); @@ -3563,6 +3932,21 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) /* Send route processing complete message to RIB */ bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); + bgp->gr_info[afi][safi].route_sync = true; + + /* If this instance is all done, check for GR completion overall */ + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (bgp->gr_info[afi][safi].af_enabled && + !bgp->gr_info[afi][safi].route_sync) { + route_sync_pending = true; + break; + } + } + + if (!route_sync_pending) { + bgp->gr_route_sync_pending = false; + bgp_update_gr_completion(); + } return; } @@ -3650,13 +4034,38 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp) return pqnode; } -void bgp_process(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi) +void bgp_process(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi) { #define ARBITRARY_PROCESS_QLEN 10000 struct work_queue *wq = bgp->process_queue; struct bgp_process_queue *pqnode; int pqnode_reuse = 0; + /* + * Indicate that *this* pi is in an unsorted + * situation, even if the node is already + * scheduled. + */ + if (pi) { + struct bgp_path_info *first = bgp_dest_get_bgp_path_info(dest); + + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); + + if (pi != first) { + if (pi->next) + pi->next->prev = pi->prev; + if (pi->prev) + pi->prev->next = pi->next; + + if (first) + first->prev = pi; + pi->next = first; + pi->prev = NULL; + bgp_dest_set_bgp_path_info(dest, pi); + } + } + /* already scheduled for processing? */ if (CHECK_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED)) return; @@ -3905,7 +4314,7 @@ void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi, } hook_call(bgp_process, peer->bgp, afi, safi, dest, peer, true); - bgp_process(peer->bgp, dest, afi, safi); + bgp_process(peer->bgp, dest, pi, afi, safi); } static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi, @@ -3917,14 +4326,16 @@ static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi, /* apply dampening, if result is suppressed, we'll be retaining * the bgp_path_info in the RIB for historical reference. */ - if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) - if ((bgp_damp_withdraw(pi, dest, afi, safi, 0)) - == BGP_DAMP_SUPPRESSED) { - bgp_aggregate_decrement(peer->bgp, p, pi, afi, - safi); - return; + if (peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi)) { + if (bgp_damp_withdraw(pi, dest, afi, safi, 0) == + BGP_DAMP_SUPPRESSED) { + bgp_aggregate_decrement(peer->bgp, p, pi, afi, + safi); + return; + } } + } #ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { @@ -4144,27 +4555,27 @@ static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi, void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, int soft_reconfig, + uint8_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn) { int ret; int aspath_loop_count = 0; struct bgp_dest *dest; struct bgp *bgp; - struct attr new_attr; + struct attr new_attr = {}; struct attr *attr_new; struct bgp_path_info *pi; struct bgp_path_info *new = NULL; - struct bgp_path_info_extra *extra; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; int connected = 0; int do_loop_check = 1; - int has_valid_label = 0; afi_t nh_afi; bool force_evpn_import = false; safi_t orig_safi = safi; int allowas_in = 0; + struct bgp_labels bgp_labels = {}; + uint8_t i; if (frrtrace_enabled(frr_bgp, process_update)) { char pfxprint[PREFIX2STR_BUFFER]; @@ -4184,21 +4595,14 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (orig_safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; - memset(&new_attr, 0, sizeof(new_attr)); - new_attr.label_index = BGP_INVALID_LABEL_INDEX; - new_attr.label = MPLS_INVALID_LABEL; - bgp = peer->bgp; dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); - /* TODO: Check to see if we can get rid of "is_valid_label" */ - if (afi == AFI_L2VPN && safi == SAFI_EVPN) - has_valid_label = (num_labels > 0) ? 1 : 0; - else - has_valid_label = bgp_is_valid_label(label); - - if (has_valid_label) - assert(label != NULL); + if ((afi == AFI_L2VPN && safi == SAFI_EVPN) || + bgp_is_valid_label(&label[0])) + bgp_labels.num_labels = num_labels; + for (i = 0; i < bgp_labels.num_labels; i++) + bgp_labels.label[i] = label[i]; /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -4211,11 +4615,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * will not be interned. In which case, it is ok to update the * attr->evpn_overlay, so that, this can be stored in adj_in. */ - if ((afi == AFI_L2VPN) && evpn) { - memcpy(&attr->evpn_overlay, evpn, - sizeof(struct bgp_route_evpn)); - } - bgp_adj_in_set(dest, peer, attr, addpath_id); + if ((afi == AFI_L2VPN) && evpn) + bgp_attr_set_evpn_overlay(attr, evpn); + bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels); } /* Update permitted loop count */ @@ -4376,8 +4778,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * evpn to new_atr.evpn_overlay before it is interned. */ if (soft_reconfig && (afi == AFI_L2VPN) && evpn) - memcpy(&new_attr.evpn_overlay, evpn, - sizeof(struct bgp_route_evpn)); + bgp_attr_set_evpn_overlay(&new_attr, evpn); /* Apply incoming route-map. * NB: new_attr may now contain newly allocated values from route-map @@ -4397,7 +4798,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) /* remove from RIB previous entry */ - bgp_zebra_withdraw(p, pi, bgp, safi); + bgp_zebra_route_install(dest, pi, bgp, false, NULL, + false); } if (peer->sort == BGP_PEER_EBGP) { @@ -4490,16 +4892,13 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, hook_call(bgp_process, bgp, afi, safi, dest, peer, true); /* Same attribute comes in. */ - if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) - && same_attr - && (!has_valid_label - || memcmp(&(bgp_path_info_extra_get(pi))->label, label, - num_labels * sizeof(mpls_label_t)) - == 0)) { - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP - && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { + if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && same_attr && + (!bgp_labels.num_labels || + bgp_path_info_labels_same(pi, bgp_labels.label, + bgp_labels.num_labels))) { + if (get_active_bdc_from_pi(pi, afi, safi) && + peer->sort == BGP_PEER_EBGP && + CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( afi, safi, prd, p, label, @@ -4514,7 +4913,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, != BGP_DAMP_SUPPRESSED) { bgp_aggregate_increment(bgp, p, pi, afi, safi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } else /* Duplicate - odd */ { @@ -4542,7 +4941,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_path_info_unset_flag( dest, pi, BGP_PATH_STALE); bgp_dest_set_defer_flag(dest, false); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } @@ -4600,11 +4999,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); /* Update bgp route dampening information. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi) && + peer->sort == BGP_PEER_EBGP) { /* This is implicit withdraw so we should update - dampening - information. */ + * dampening information. + */ if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) bgp_damp_withdraw(pi, dest, afi, safi, 1); } @@ -4678,15 +5077,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, pi->attr = attr_new; /* Update MPLS label */ - if (has_valid_label) { - extra = bgp_path_info_extra_get(pi); - if (extra->label != label) { - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; - } - if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) - bgp_set_valid_label(&extra->label[0]); + if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_path_info_extra_get(pi); + bgp_labels_unintern(&pi->extra->labels); + pi->extra->labels = bgp_labels_intern(&bgp_labels); } #ifdef ENABLE_BGP_VNC @@ -4713,8 +5108,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, #endif /* Update bgp route dampening information. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi) && + peer->sort == BGP_PEER_EBGP) { /* Now we do normal update dampening. */ ret = bgp_damp_update(pi, dest, afi, safi); if (ret == BGP_DAMP_SUPPRESSED) { @@ -4761,9 +5156,10 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, BGP_PATH_VALID); } else { if (BGP_DEBUG(nht, NHT)) { - zlog_debug("%s(%pI4): NH unresolved", + zlog_debug("%s(%pI4): NH unresolved for existing %pFX pi %p flags 0x%x", __func__, - (in_addr_t *)&attr_new->nexthop); + (in_addr_t *)&attr_new->nexthop, + p, pi, pi->flags); } bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID); @@ -4808,15 +5204,28 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * updating * the attributes for the route in the VNI(s). */ - if (safi == SAFI_EVPN && - (!same_attr || force_evpn_import) && - CHECK_FLAG(pi->flags, BGP_PATH_VALID)) - bgp_evpn_import_route(bgp, afi, safi, p, pi); + if (safi == SAFI_EVPN) { + if ((!same_attr || force_evpn_import) && + CHECK_FLAG(pi->flags, BGP_PATH_VALID)) + bgp_evpn_import_route(bgp, afi, safi, p, pi); + + /* If existing path is marked invalid then unimport the + * path from EVPN prefix. This will ensure EVPN route + * has only valid paths and path refcount maintained in + * EVPN nexthop is decremented appropriately. + */ + else if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) { + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s unimport EVPN %pFX as pi %p is not VALID", + __func__, p, pi); + bgp_evpn_unimport_route(bgp, afi, safi, p, pi); + } + } /* Process change. */ bgp_aggregate_increment(bgp, p, pi, afi, safi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); bgp_dest_unlock_node(dest); if (SAFI_UNICAST == safi @@ -4863,16 +5272,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, new = info_make(type, sub_type, 0, peer, attr_new, dest); /* Update MPLS label */ - if (has_valid_label) { - extra = bgp_path_info_extra_get(new); - if (extra->label != label) { - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; - } - if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) - bgp_set_valid_label(&extra->label[0]); - } + bgp_path_info_extra_get(new); + new->extra->labels = bgp_labels_intern(&bgp_labels); /* Nexthop reachability check. */ if (((afi == AFI_IP || afi == AFI_IP6) && @@ -4960,7 +5361,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, hook_call(bgp_process, bgp, afi, safi, dest, peer, false); /* Process change. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, new, afi, safi); if (SAFI_UNICAST == safi && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF @@ -5053,7 +5454,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct bgp_route_evpn *evpn) + uint8_t num_labels) { struct bgp *bgp; char pfx_buf[BGP_PRD_PATH_STRLEN]; @@ -5146,7 +5547,7 @@ void bgp_withdraw(struct peer *peer, const struct prefix *p, } void bgp_default_originate(struct peer *peer, afi_t afi, safi_t safi, - int withdraw) + bool withdraw) { struct update_subgroup *subgrp; subgrp = peer_subgroup(peer, afi, safi); @@ -5280,27 +5681,23 @@ static void bgp_soft_reconfig_table_update(struct peer *peer, safi_t safi, struct prefix_rd *prd) { struct bgp_path_info *pi; - uint32_t num_labels = 0; - mpls_label_t *label_pnt = NULL; - struct bgp_route_evpn evpn; + uint8_t num_labels; + mpls_label_t *label_pnt; + struct bgp_route_evpn *bre = NULL; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->peer == peer) break; - if (pi && pi->extra) - num_labels = pi->extra->num_labels; - if (num_labels) - label_pnt = &pi->extra->label[0]; + num_labels = ain->labels ? ain->labels->num_labels : 0; + label_pnt = num_labels ? &ain->labels->label[0] : NULL; + if (pi) - memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), - sizeof(evpn)); - else - memset(&evpn, 0, sizeof(evpn)); + bre = bgp_attr_get_evpn_overlay(pi->attr); bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, - label_pnt, num_labels, 1, &evpn); + label_pnt, num_labels, 1, bre); } static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi, @@ -5531,7 +5928,7 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) struct bgp_clear_node_queue *cnq = data; struct bgp_dest *dest = cnq->dest; struct peer *peer = wq->spec.data; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp *bgp; afi_t afi = bgp_dest_table(dest)->afi; safi_t safi = bgp_dest_table(dest)->safi; @@ -5542,7 +5939,8 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) /* It is possible that we have multiple paths for a prefix from a peer * if that peer is using AddPath. */ - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; @@ -5804,7 +6202,7 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi) void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) { struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp_table *table; if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { @@ -5819,8 +6217,9 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) - for (pi = bgp_dest_get_bgp_path_info(rm); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(rm); + (pi != NULL) && (next = pi->next, 1); + pi = next) { if (pi->peer != peer) continue; if (CHECK_FLAG( @@ -5853,8 +6252,8 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) } else { for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; if (CHECK_FLAG(peer->af_sflags[afi][safi], @@ -5957,20 +6356,22 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi) bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; - if (peer->sort == BGP_PEER_EBGP - && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) - || FILTER_LIST_OUT_NAME(filter) - || DISTRIBUTE_OUT_NAME(filter))) + if (peer->sort == BGP_PEER_EBGP && + (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) || + FILTER_LIST_OUT_NAME(filter) || DISTRIBUTE_OUT_NAME(filter) || + UNSUPPRESS_MAP_NAME(filter))) return true; return false; } bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP @@ -5982,7 +6383,7 @@ bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) } static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, - safi_t safi) + afi_t afi, safi_t safi) { struct bgp_dest *dest; struct bgp_path_info *pi; @@ -6006,7 +6407,7 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, || pi->sub_type == BGP_ROUTE_IMPORTED)) { if (bgp_fibupd_safi(safi)) - bgp_zebra_withdraw(p, pi, bgp, safi); + bgp_zebra_withdraw_actual(dest, pi, bgp); } dest = bgp_path_info_reap(dest, pi); @@ -6024,7 +6425,7 @@ void bgp_cleanup_routes(struct bgp *bgp) for (afi = AFI_IP; afi < AFI_MAX; ++afi) { if (afi == AFI_L2VPN) continue; - bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST], + bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST); /* * VPN and ENCAP and EVPN tables are two-level (RD is top level) @@ -6036,7 +6437,7 @@ void bgp_cleanup_routes(struct bgp *bgp) dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); if (table != NULL) { - bgp_cleanup_table(bgp, table, safi); + bgp_cleanup_table(bgp, table, afi, safi); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); dest = bgp_dest_unlock_node(dest); @@ -6049,7 +6450,7 @@ void bgp_cleanup_routes(struct bgp *bgp) dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); if (table != NULL) { - bgp_cleanup_table(bgp, table, safi); + bgp_cleanup_table(bgp, table, afi, safi); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); dest = bgp_dest_unlock_node(dest); @@ -6063,7 +6464,7 @@ void bgp_cleanup_routes(struct bgp *bgp) dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); if (table != NULL) { - bgp_cleanup_table(bgp, table, SAFI_EVPN); + bgp_cleanup_table(bgp, table, afi, SAFI_EVPN); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); dest = bgp_dest_unlock_node(dest); @@ -6215,7 +6616,7 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr, else bgp_withdraw(peer, &p, addpath_id, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, - NULL, 0, NULL); + NULL, 0); /* Do not send BGP notification twice when maximum-prefix count * overflow. */ @@ -6239,13 +6640,19 @@ static void bgp_nexthop_reachability_check(afi_t afi, safi_t safi, struct bgp_path_info *bpi, const struct prefix *p, struct bgp_dest *dest, - struct bgp *bgp) + struct bgp *bgp, + struct bgp *bgp_nexthop) { + if (safi == SAFI_RTC) { + bgp_unlink_nexthop(bpi); + + bgp_path_info_set_flag(dest, bpi, BGP_PATH_VALID); + } /* Nexthop reachability check. */ if (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)) { - if (bgp_find_or_add_nexthop(bgp, bgp, afi, safi, bpi, - NULL, 0, p)) + if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi, + bpi, NULL, 0, p)) bgp_path_info_set_flag(dest, bpi, BGP_PATH_VALID); else { @@ -6272,18 +6679,18 @@ static void bgp_nexthop_reachability_check(afi_t afi, safi_t safi, } } -static struct bgp_static *bgp_static_new(void) +struct bgp_static *bgp_static_new(void) { return XCALLOC(MTYPE_BGP_STATIC, sizeof(struct bgp_static)); } -static void bgp_static_free(struct bgp_static *bgp_static) +void bgp_static_free(struct bgp_static *bgp_static) { XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); route_map_counter_decrement(bgp_static->rmap.map); if (bgp_static->prd_pretty) - XFREE(MTYPE_BGP, bgp_static->prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp_static->prd_pretty); XFREE(MTYPE_ATTR, bgp_static->eth_s_id); XFREE(MTYPE_BGP_STATIC, bgp_static); } @@ -6300,9 +6707,11 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, route_map_result_t ret; #ifdef ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; - mpls_label_t label = 0; + mpls_label_t label = MPLS_INVALID_LABEL; #endif - uint32_t num_labels = 0; + uint8_t num_labels = 0; + struct bgp *bgp_nexthop = bgp; + struct bgp_labels labels = {}; assert(bgp_static); @@ -6343,15 +6752,25 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, if (afi == AFI_L2VPN) { if (bgp_static->gatewayIp.family == AF_INET) { - SET_IPADDR_V4(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v4, + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + SET_IPADDR_V4(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v4, &bgp_static->gatewayIp.u.prefix4, IPV4_MAX_BYTELEN); + bgp_attr_set_evpn_overlay(&attr, bre); } else if (bgp_static->gatewayIp.family == AF_INET6) { - SET_IPADDR_V6(&attr.evpn_overlay.gw_ip); - memcpy(&attr.evpn_overlay.gw_ip.ipaddr_v6, + struct bgp_route_evpn *bre = + XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); + + SET_IPADDR_V6(&bre->gw_ip); + memcpy(&bre->gw_ip.ipaddr_v6, &bgp_static->gatewayIp.u.prefix6, IPV6_MAX_BYTELEN); + bgp_attr_set_evpn_overlay(&attr, bre); } memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t)); if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) { @@ -6452,18 +6871,20 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp, p, pi); } } else { - if (pi->extra) + if (bgp_path_info_num_labels(pi)) label = decode_label( - &pi->extra->label[0]); + &pi->extra->labels->label[0]); } #endif + if (pi->extra && pi->extra->vrfleak->bgp_orig) + bgp_nexthop = pi->extra->vrfleak->bgp_orig; bgp_nexthop_reachability_check(afi, safi, pi, p, dest, - bgp); + bgp, bgp_nexthop); /* Process change. */ bgp_aggregate_increment(bgp, p, pi, afi, safi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); if (SAFI_MPLS_VPN == safi && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { @@ -6501,15 +6922,16 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_extra_get(new); if (num_labels) { - new->extra->label[0] = bgp_static->label; - new->extra->num_labels = num_labels; + labels.num_labels = num_labels; + labels.label[0] = bgp_static->label; + new->extra->labels = bgp_labels_intern(&labels); } #ifdef ENABLE_BGP_VNC label = decode_label(&bgp_static->label); #endif } - bgp_nexthop_reachability_check(afi, safi, new, p, dest, bgp); + bgp_nexthop_reachability_check(afi, safi, new, p, dest, bgp, bgp); /* Aggregate address increment. */ bgp_aggregate_increment(bgp, p, new, afi, safi); @@ -6521,7 +6943,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp_dest_unlock_node(dest); /* Process change. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, new, afi, safi); if (SAFI_UNICAST == safi && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF || @@ -6560,6 +6982,7 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi, /* Withdraw static BGP route from routing table. */ if (pi) { + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); #ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) rfapiProcessWithdraw(pi->peer, NULL, p, prd, pi->attr, @@ -6578,7 +7001,7 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi, bgp_aggregate_decrement(bgp, p, pi, afi, safi); bgp_unlink_nexthop(pi); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } /* Unlock bgp_node_lookup. */ @@ -6770,6 +7193,10 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, bgp_static->label = label; bgp_static->prd = prd; + if (rd_str) + bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP_NAME, + rd_str); + if (rmap) { XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); @@ -6979,7 +7406,7 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, safi); bgp_unlink_nexthop(pi); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } } @@ -7322,8 +7749,9 @@ static void bgp_aggregate_install( * If the aggregate information has not changed * no need to re-install it again. */ - if (pi && bgp_aggregate_info_same(pi, origin, aspath, community, - ecommunity, lcommunity)) { + if (pi && (!aggregate->rmap.changed && + bgp_aggregate_info_same(pi, origin, aspath, community, + ecommunity, lcommunity))) { bgp_dest_unlock_node(dest); if (aspath) @@ -7341,8 +7769,10 @@ static void bgp_aggregate_install( /* * Mark the old as unusable */ - if (pi) + if (pi) { bgp_path_info_delete(dest, pi); + bgp_process(bgp, dest, pi, afi, safi); + } attr = bgp_attr_aggregate_intern( bgp, origin, aspath, community, ecommunity, lcommunity, @@ -7367,7 +7797,7 @@ static void bgp_aggregate_install( SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_add(dest, new); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, new, afi, safi); } else { uninstall_aggregate_route: for (pi = orig; pi; pi = pi->next) @@ -7379,7 +7809,7 @@ static void bgp_aggregate_install( /* Withdraw static BGP route from routing table. */ if (pi) { bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } @@ -7465,7 +7895,6 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, const struct prefix *dest_p; struct bgp_dest *dest, *top; struct bgp_path_info *pi; - bool toggle_suppression; /* We've found a different MED we must revert any suppressed routes. */ top = bgp_node_get(table, p); @@ -7475,7 +7904,6 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (dest_p->prefixlen <= p->prefixlen) continue; - toggle_suppression = false; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -7486,17 +7914,14 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (suppress) { /* Suppress route if not suppressed already. */ if (aggr_suppress_path(aggregate, pi)) - toggle_suppression = true; + bgp_process(bgp, dest, pi, afi, safi); continue; } /* Install route if there is no more suppression. */ if (aggr_unsuppress_path(aggregate, pi)) - toggle_suppression = true; + bgp_process(bgp, dest, pi, afi, safi); } - - if (toggle_suppression) - bgp_process(bgp, dest, afi, safi); } bgp_dest_unlock_node(top); } @@ -7555,7 +7980,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; struct bgp_path_info *pi; - unsigned long match = 0; uint8_t atomic_aggregate = 0; /* If the bgp instance is being deleted or self peer is deleted @@ -7577,7 +8001,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, */ aggregate->count = 0; aggregate->incomplete_origin_count = 0; - aggregate->incomplete_origin_count = 0; aggregate->egp_origin_count = 0; /* ORIGIN attribute: If at least one route among routes that are @@ -7606,8 +8029,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (!bgp_check_advertise(bgp, dest, safi)) continue; - match = 0; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -7631,7 +8052,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate)) { if (aggr_suppress_path(aggregate, pi)) - match++; + bgp_process(bgp, dest, pi, afi, safi); } /* @@ -7647,7 +8068,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, && AGGREGATE_MED_VALID(aggregate) && aggr_suppress_map_test(bgp, aggregate, pi)) { if (aggr_suppress_path(aggregate, pi)) - match++; + bgp_process(bgp, dest, pi, afi, safi); } aggregate->count++; @@ -7708,8 +8129,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, aggregate, bgp_attr_get_lcommunity(pi->attr)); } - if (match) - bgp_process(bgp, dest, afi, safi); } if (aggregate->as_set) { bgp_compute_aggregate_aspath_val(aggregate); @@ -7752,6 +8171,9 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, lcommunity = lcommunity_dup(aggregate->lcommunity); } + /* Unimport suppressed routes from EVPN */ + bgp_aggr_supp_withdraw_from_evpn(bgp, afi, safi); + bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, ecommunity, lcommunity, atomic_aggregate, aggregate); @@ -7766,7 +8188,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, struct bgp_dest *top; struct bgp_dest *dest; struct bgp_path_info *pi; - unsigned long match; table = bgp->rib[afi][safi]; @@ -7778,7 +8199,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (dest_p->prefixlen <= p->prefixlen) continue; - match = 0; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (BGP_PATH_HOLDDOWN(pi)) @@ -7796,10 +8216,11 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (pi->extra && pi->extra->aggr_suppressors && listcount(pi->extra->aggr_suppressors)) { if (aggr_unsuppress_path(aggregate, pi)) - match++; + bgp_process(bgp, dest, pi, afi, safi); } - aggregate->count--; + if (aggregate->count > 0) + aggregate->count--; if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) aggregate->incomplete_origin_count--; @@ -7838,10 +8259,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, pi->attr)); } } - - /* If this node was suppressed, process the change. */ - if (match) - bgp_process(bgp, dest, afi, safi); } if (aggregate->as_set) { aspath_free(aggregate->aspath); @@ -7990,7 +8407,6 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, struct community *community = NULL; struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; - unsigned long match = 0; /* If the bgp instance is being deleted or self peer is deleted * then do not create aggregate route @@ -8007,12 +8423,12 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate)) if (aggr_unsuppress_path(aggregate, pi)) - match++; + bgp_process(bgp, pi->net, pi, afi, safi); if (aggregate->suppress_map_name && AGGREGATE_MED_VALID(aggregate) && aggr_suppress_map_test(bgp, aggregate, pi)) if (aggr_unsuppress_path(aggregate, pi)) - match++; + bgp_process(bgp, pi->net, pi, afi, safi); /* * This must be called after `summary`, `suppress-map` check to avoid @@ -8054,10 +8470,6 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, aggregate, bgp_attr_get_lcommunity(pi->attr)); } - /* If this node was suppressed, process the change. */ - if (match) - bgp_process(bgp, pi->net, afi, safi); - origin = BGP_ORIGIN_IGP; if (aggregate->incomplete_origin_count > 0) origin = BGP_ORIGIN_INCOMPLETE; @@ -8331,6 +8743,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, aggregate->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); aggregate->rmap.map = route_map_lookup_by_name(rmap); + aggregate->rmap.changed = true; route_map_counter_increment(aggregate->rmap.map); } @@ -8514,6 +8927,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, afi_t afi; route_map_result_t ret; struct bgp_redist *red; + struct interface *ifp; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || bgp->peer_self == NULL) @@ -8573,6 +8987,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, } attr.nh_type = nhtype; attr.nh_ifindex = ifindex; + ifp = if_lookup_by_index(ifindex, bgp->vrf_id); + if (ifp && if_is_operative(ifp)) + SET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); attr.med = metric; attr.distance = distance; @@ -8660,7 +9079,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, /* Process change. */ bgp_aggregate_increment(bgp, p, bpi, afi, SAFI_UNICAST); - bgp_process(bgp, bn, afi, SAFI_UNICAST); + bgp_process(bgp, bn, bpi, afi, SAFI_UNICAST); bgp_dest_unlock_node(bn); aspath_unintern(&attr.aspath); @@ -8683,7 +9102,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, bgp_path_info_add(bn, new); bgp_dest_unlock_node(bn); SET_FLAG(bn->flags, BGP_NODE_FIB_INSTALLED); - bgp_process(bgp, bn, afi, SAFI_UNICAST); + bgp_process(bgp, bn, new, afi, SAFI_UNICAST); if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF) || (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) { @@ -8724,7 +9143,7 @@ void bgp_redistribute_delete(struct bgp *bgp, struct prefix *p, uint8_t type, } bgp_aggregate_decrement(bgp, p, pi, afi, SAFI_UNICAST); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, SAFI_UNICAST); + bgp_process(bgp, dest, pi, afi, SAFI_UNICAST); } bgp_dest_unlock_node(dest); } @@ -8758,7 +9177,7 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, bgp_path_info_delete(dest, pi); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) - bgp_process(bgp, dest, afi, SAFI_UNICAST); + bgp_process(bgp, dest, pi, afi, SAFI_UNICAST); else { dest = bgp_path_info_reap(dest, pi); assert(dest); @@ -8904,6 +9323,9 @@ static void route_vty_short_status_out(struct vty *vty, if (path->extra && bgp_path_suppressed(path)) json_object_boolean_true_add(json_path, "suppressed"); + if (CHECK_FLAG(path->flags, BGP_PATH_UNSORTED)) + json_object_boolean_true_add(json_path, "unsorted"); + if (CHECK_FLAG(path->flags, BGP_PATH_VALID) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) json_object_boolean_true_add(json_path, "valid"); @@ -8966,6 +9388,8 @@ static void route_vty_short_status_out(struct vty *vty, /* Selected */ if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) vty_out(vty, "h"); + else if (CHECK_FLAG(path->flags, BGP_PATH_UNSORTED)) + vty_out(vty, "u"); else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) vty_out(vty, "d"); else if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) @@ -8981,6 +9405,9 @@ static void route_vty_short_status_out(struct vty *vty, vty_out(vty, "i"); else vty_out(vty, " "); + + /* adding space between next column */ + vty_out(vty, " "); } static char *bgp_nexthop_hostname(struct peer *peer, @@ -9262,9 +9689,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, "link-local"); if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, - &attr->mp_nexthop_local) - != 0) - && !attr->mp_nexthop_prefer_global) + &attr->mp_nexthop_local) != + 0) && + !CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add( json_nexthop_ll, "used"); else @@ -9276,10 +9704,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } else { /* Display LL if LL/Global both in table unless * prefer-global is set */ - if (((attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - && !attr->mp_nexthop_prefer_global) - || (path->peer->conf_if)) { + if (((attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) && + !CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) || + (path->peer->conf_if)) { if (path->peer->conf_if) { len = vty_out(vty, "%s", path->peer->conf_if); @@ -9333,14 +9762,16 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } /* MED/Metric */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) + if (use_bgp_med_value(attr, path->peer->bgp)) { + uint32_t value = bgp_med_value(attr, path->peer->bgp); + if (json_paths) - json_object_int_add(json_path, "metric", attr->med); + json_object_int_add(json_path, "metric", value); else if (wide) - vty_out(vty, "%7u", attr->med); + vty_out(vty, "%7u", value); else - vty_out(vty, "%10u", attr->med); - else if (!json_paths) { + vty_out(vty, "%10u", value); + } else if (!json_paths) { if (wide) vty_out(vty, "%*s", 7, " "); else @@ -9461,18 +9892,16 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } /* called from terminal list command */ -void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, +void route_vty_out_tmp(struct vty *vty, struct bgp *bgp, struct bgp_dest *dest, const struct prefix *p, struct attr *attr, safi_t safi, bool use_json, json_object *json_ar, bool wide) { - json_object *json_status = NULL; json_object *json_net = NULL; int len; char buff[BUFSIZ]; /* Route status display. */ if (use_json) { - json_status = json_object_new_object(); json_net = json_object_new_object(); } else { vty_out(vty, " *"); @@ -9522,10 +9951,11 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, &attr->mp_nexthop_global_in); } - if (attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) - json_object_int_add(json_net, "metric", - attr->med); + if (use_bgp_med_value(attr, bgp)) { + uint32_t value = bgp_med_value(attr, bgp); + + json_object_int_add(json_net, "metric", value); + } if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) json_object_int_add(json_net, "locPrf", @@ -9539,11 +9969,6 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, attr->aspath->str); /* Print origin */ -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") -#endif - json_object_string_add(json_net, "bgpOriginCode", - bgp_origin_str[attr->origin]); json_object_string_add( json_net, "origin", bgp_origin_long_str[attr->origin]); @@ -9570,13 +9995,15 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") else vty_out(vty, "%*s", len, " "); } - if (attr->flag - & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) + + if (use_bgp_med_value(attr, bgp)) { + uint32_t value = bgp_med_value(attr, bgp); + if (wide) - vty_out(vty, "%7u", attr->med); + vty_out(vty, "%7u", value); else - vty_out(vty, "%10u", attr->med); - else if (wide) + vty_out(vty, "%10u", value); + } else if (wide) vty_out(vty, " "); else vty_out(vty, " "); @@ -9599,20 +10026,11 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") if (use_json) { struct bgp_path_info *bpi = bgp_dest_get_bgp_path_info(dest); -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpStatusCodes` from JSON outputs") -#endif - json_object_boolean_true_add(json_status, "*"); - json_object_boolean_true_add(json_status, ">"); json_object_boolean_true_add(json_net, "valid"); json_object_boolean_true_add(json_net, "best"); - if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_MULTIPATH)) { - json_object_boolean_true_add(json_status, "="); + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_MULTIPATH)) json_object_boolean_true_add(json_net, "multipath"); - } - json_object_object_add(json_net, "appliedStatusSymbols", - json_status); json_object_object_addf(json_ar, json_net, "%pFX", p); } else vty_out(vty, "\n"); @@ -9695,8 +10113,8 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, } } - if (bgp_is_valid_label(&path->extra->label[0])) { - label = decode_label(&path->extra->label[0]); + if (bgp_path_info_has_valid_label(path)) { + label = decode_label(&path->extra->labels->label[0]); if (json) { json_object_int_add(json_out, "notag", label); json_object_array_add(json, json_out); @@ -9716,6 +10134,7 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, json_object *json_path = NULL; json_object *json_nexthop = NULL; json_object *json_overlay = NULL; + struct bgp_route_evpn *bre = NULL; if (!path->extra) return; @@ -9781,12 +10200,14 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p, } } - const struct bgp_route_evpn *eo = bgp_attr_get_evpn_overlay(attr); - - if (!json_path) - vty_out(vty, "/%pIA", &eo->gw_ip); - else - json_object_string_addf(json_overlay, "gw", "%pIA", &eo->gw_ip); + bre = bgp_attr_get_evpn_overlay(attr); + if (bre) { + if (!json_path) + vty_out(vty, "/%pIA", &bre->gw_ip); + else + json_object_string_addf(json_overlay, "gw", "%pIA", + &bre->gw_ip); + } if (bgp_attr_get_ecommunity(attr)) { char *mac = NULL; @@ -10086,7 +10507,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; - char tag_buf[30]; + char vni_buf[30] = {}; struct attr *attr = path->attr; time_t tbuf; char timebuf[32]; @@ -10094,6 +10515,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_cluster_list = NULL; json_object *json_cluster_list_list = NULL; json_object *json_ext_community = NULL; + json_object *json_ext_ipv6_community = NULL; json_object *json_last_update = NULL; json_object *json_pmsi = NULL; json_object *json_nexthop_global = NULL; @@ -10118,9 +10540,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, uint32_t bos = 0; uint32_t exp = 0; mpls_label_t label = MPLS_INVALID_LABEL; - tag_buf[0] = '\0'; struct bgp_path_info *bpi_ultimate = bgp_get_imported_bpi_ultimate(path); + struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr); if (json_paths) { json_path = json_object_new_object(); @@ -10128,35 +10550,29 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_nexthop_global = json_object_new_object(); } + if (bgp_path_info_num_labels(path)) { + bgp_evpn_label2str(path->extra->labels->label, + path->extra->labels->num_labels, vni_buf, + sizeof(vni_buf)); + } + if (safi == SAFI_EVPN) { if (!json_paths) vty_out(vty, " Route %pFX", p); - } - if (path->extra) { - if (path->extra && path->extra->num_labels) { - bgp_evpn_label2str(path->extra->label, - path->extra->num_labels, tag_buf, - sizeof(tag_buf)); - } - if (safi == SAFI_EVPN) { - if (!json_paths) { - if (tag_buf[0] != '\0') - vty_out(vty, " VNI %s", tag_buf); - } else { - if (tag_buf[0]) - json_object_string_add(json_path, "vni", - tag_buf); - } + if (vni_buf[0]) { + if (json_paths) + json_object_string_add(json_path, "vni", + vni_buf); + else + vty_out(vty, " VNI %s", vni_buf); } } - if (safi == SAFI_EVPN - && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) { + if (safi == SAFI_EVPN && bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) { char gwip_buf[INET6_ADDRSTRLEN]; - ipaddr2str(&attr->evpn_overlay.gw_ip, gwip_buf, - sizeof(gwip_buf)); + ipaddr2str(&bre->gw_ip, gwip_buf, sizeof(gwip_buf)); if (json_paths) json_object_string_add(json_path, "gatewayIP", @@ -10187,7 +10603,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ":%pFX, VNI %s", (struct prefix_evpn *) bgp_dest_get_prefix(dest), - tag_buf); + vni_buf); if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG)) vty_out(vty, ", L3NHG %s", CHECK_FLAG( @@ -10543,7 +10959,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object_boolean_true_add(json_nexthop_ll, "accessible"); - if (!attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add(json_nexthop_ll, "used"); else @@ -10553,7 +10970,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " (%s) %s\n", inet_ntop(AF_INET6, &attr->mp_nexthop_local, buf, INET6_ADDRSTRLEN), - attr->mp_nexthop_prefer_global + CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL) ? "(prefer-global)" : "(used)"); } @@ -10580,11 +10998,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " Origin %s", bgp_origin_long_str[attr->origin]); - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { + if (use_bgp_med_value(attr, bgp)) { + uint32_t value = bgp_med_value(attr, bgp); + if (json_paths) - json_object_int_add(json_path, "metric", attr->med); + json_object_int_add(json_path, "metric", value); else - vty_out(vty, ", metric %u", attr->med); + vty_out(vty, ", metric %u", value); } if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) { @@ -10661,9 +11081,17 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } else { if (json_paths) json_object_string_add( - json_peer, "type", "external"); + json_peer, "type", + (path->peer->sub_sort == + BGP_PEER_EBGP_OAD) + ? "external (oad)" + : "external"); else - vty_out(vty, ", external"); + vty_out(vty, ", %s", + (path->peer->sub_sort == + BGP_PEER_EBGP_OAD) + ? "external (oad)" + : "external"); } } } else if (path->sub_type == BGP_ROUTE_AGGREGATE) { @@ -10790,6 +11218,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)) { + if (json_paths) { + json_ext_ipv6_community = json_object_new_object(); + json_object_string_add(json_ext_ipv6_community, "string", + bgp_attr_get_ipv6_ecommunity(attr) + ->str); + json_object_object_add(json_path, + "extendedIpv6Community", + json_ext_ipv6_community); + } else { + vty_out(vty, " Extended IPv6 Community: %s\n", + bgp_attr_get_ipv6_ecommunity(attr)->str); + } + } + /* Line 6 display Large community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { if (json_paths) { @@ -10869,13 +11312,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } if (path->extra && path->extra->damp_info) - bgp_damp_info_vty(vty, path, afi, safi, json_path); + bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path); /* Remote Label */ - if (path->extra && bgp_is_valid_label(&path->extra->label[0]) - && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { - mpls_lse_decode(path->extra->label[0], &label, &ttl, &exp, - &bos); + if (bgp_path_info_has_valid_label(path) && + (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { + mpls_lse_decode(path->extra->labels->label[0], &label, &ttl, + &exp, &bos); if (json_paths) json_object_int_add(json_path, "remoteLabel", label); @@ -11599,7 +12042,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa total_count); } else vty_out(vty, - "\nDisplayed %ld routes and %ld total paths\n", + "\nDisplayed %ld routes and %ld total paths\n", output_count, total_count); } } @@ -11607,6 +12050,69 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa return CMD_SUCCESS; } +int bgp_show_table_rtc(struct vty *vty, struct bgp *bgp, safi_t safi, + struct bgp_table *table, enum bgp_show_type type, + void *output_arg, uint16_t show_flags); +int bgp_show_table_rtc(struct vty *vty, struct bgp *bgp, safi_t safi, + struct bgp_table *table, enum bgp_show_type type, + void *output_arg, uint16_t show_flags) +{ + struct bgp_dest *dest, *next; + unsigned long output_cum = 0; + unsigned long total_cum = 0; + struct bgp_table *itable; + bool show_msg; + bool use_json = !!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); + + show_msg = (!use_json && type == bgp_show_type_normal); + + for (dest = bgp_table_top(table); dest; dest = next) { + struct prefix local_p = {}; + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + local_p = *dest_p; + + next = bgp_route_next(dest); + + itable = bgp_dest_get_bgp_table_info(dest); + if (itable != NULL) { + + struct bgp_path_info *pi = + bgp_dest_get_bgp_path_info(dest); + struct ecommunity *ecom = ecommunity_parse( + local_p.u.prefix_rtc.route_target, 8, true); + char *ecomstr = ecommunity_ecom2str( + ecom, ECOMMUNITY_FORMAT_DISPLAY, 0); + vty_out(vty, + "Prefix: \n\tRoute Target: %s/%u\n\tOrigin-as: %u\n", + ecomstr, local_p.prefixlen, + local_p.u.prefix_rtc.origin_as); + XFREE(MTYPE_ECOMMUNITY_STR, ecomstr); + ecommunity_unintern(&ecom); + route_vty_out_detail_header(vty, bgp, dest, &local_p, + NULL, AFI_IP, safi, NULL, + false); + route_vty_out_detail(vty, bgp, dest, &local_p, pi, + AFI_IP, safi, RPKI_NOT_BEING_USED, + NULL); + if (next == NULL) + show_msg = false; + } + } + if (show_msg) { + if (output_cum == 0) + vty_out(vty, "No BGP prefixes displayed, %ld exist\n", + total_cum); + else + vty_out(vty, + "\nDisplayed %ld routes and %ld total paths\n", + output_cum, total_cum); + } else { + if (use_json && output_cum == 0) + vty_out(vty, "{}\n"); + } + return CMD_SUCCESS; +} + int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd_match, enum bgp_show_type type, void *output_arg, @@ -11650,7 +12156,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, total_cum); else vty_out(vty, - "\nDisplayed %ld routes and %ld total paths\n", + "\nDisplayed %ld routes and %ld total paths\n", output_cum, total_cum); } else { if (use_json && output_cum == 0 && json_header_depth == 0) @@ -11816,7 +12322,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } else { if (incremental_print) { vty_out(vty, "\"prefix\": \"%pFX\",\n", p); - vty_out(vty, "\"version\": \"%" PRIu64 "\",\n", + vty_out(vty, "\"version\": \"%" PRIu64 "\",", dest->version); } else { json_object_string_addf(json, "prefix", "%pFX", @@ -12052,6 +12558,7 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_LABELED_UNICAST: + case SAFI_RTC: case SAFI_FLOWSPEC: case SAFI_MAX: return NULL; @@ -13607,21 +14114,23 @@ enum bgp_pcounts { PCOUNT_COUNTED, PCOUNT_BPATH_SELECTED, PCOUNT_PFCNT, /* the figure we display to users */ + PCOUNT_UNSORTED, PCOUNT_MAX, }; static const char *const pcount_strs[] = { - [PCOUNT_ADJ_IN] = "Adj-in", - [PCOUNT_DAMPED] = "Damped", - [PCOUNT_REMOVED] = "Removed", - [PCOUNT_HISTORY] = "History", - [PCOUNT_STALE] = "Stale", - [PCOUNT_VALID] = "Valid", - [PCOUNT_ALL] = "All RIB", - [PCOUNT_COUNTED] = "PfxCt counted", - [PCOUNT_BPATH_SELECTED] = "PfxCt Best Selected", - [PCOUNT_PFCNT] = "Useable", - [PCOUNT_MAX] = NULL, + [PCOUNT_ADJ_IN] = "Adj-in", + [PCOUNT_DAMPED] = "Damped", + [PCOUNT_REMOVED] = "Removed", + [PCOUNT_HISTORY] = "History", + [PCOUNT_STALE] = "Stale", + [PCOUNT_VALID] = "Valid", + [PCOUNT_ALL] = "All RIB", + [PCOUNT_COUNTED] = "PfxCt counted", + [PCOUNT_BPATH_SELECTED] = "PfxCt Best Selected", + [PCOUNT_PFCNT] = "Useable", + [PCOUNT_UNSORTED] = "Unsorted", + [PCOUNT_MAX] = NULL, }; struct peer_pcounts { @@ -13662,6 +14171,8 @@ static void bgp_peer_count_proc(struct bgp_dest *rn, struct peer_pcounts *pc) pc->count[PCOUNT_PFCNT]++; if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) pc->count[PCOUNT_BPATH_SELECTED]++; + if (CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED)) + pc->count[PCOUNT_UNSORTED]++; if (CHECK_FLAG(pi->flags, BGP_PATH_COUNTED)) { pc->count[PCOUNT_COUNTED]++; @@ -13925,9 +14436,7 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, static void show_adj_route_header(struct vty *vty, struct peer *peer, struct bgp_table *table, int *header1, - int *header2, json_object *json, - json_object *json_scode, - json_object *json_ocode, bool wide, + int *header2, json_object *json, bool wide, bool detail) { uint64_t version = table ? table->version : 0; @@ -13943,10 +14452,6 @@ static void show_adj_route_header(struct vty *vty, struct peer *peer, peer->change_local_as ? peer->change_local_as : peer->local_as); - json_object_object_add(json, "bgpStatusCodes", - json_scode); - json_object_object_add(json, "bgpOriginCodes", - json_ocode); } else { vty_out(vty, "BGP table version is %" PRIu64 @@ -13983,7 +14488,6 @@ static void show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, afi_t afi, safi_t safi, enum bgp_show_adj_route_type type, const char *rmap_name, json_object *json, json_object *json_ar, - json_object *json_scode, json_object *json_ocode, uint16_t show_flags, int *header1, int *header2, char *rd_str, const struct prefix *match, unsigned long *output_count, unsigned long *filtered_count) @@ -14078,8 +14582,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (ret != RMAP_DENY) { show_adj_route_header(vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + header2, json, wide, detail); if (use_json) json_net = json_object_new_object(); @@ -14116,10 +14619,6 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, peer->change_local_as ? peer->change_local_as : peer->local_as); - json_object_object_add(json, "bgpStatusCodes", - json_scode); - json_object_object_add(json, "bgpOriginCodes", - json_ocode); json_object_string_add( json, "bgpOriginatingDefaultNetwork", (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); @@ -14159,8 +14658,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (ain->peer != peer) continue; show_adj_route_header(vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + header2, json, wide, + detail); if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) @@ -14232,7 +14731,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, json_ar, json_net, "%pFX", rn_p); } else - route_vty_out_tmp(vty, dest, rn_p, + route_vty_out_tmp(vty, bgp, dest, rn_p, &attr, safi, use_json, json_ar, wide); bgp_attr_flush(&attr); @@ -14244,10 +14743,10 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (paf->peer != peer || !adj->attr) continue; - show_adj_route_header( - vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + show_adj_route_header(vty, peer, table, + header1, header2, + json, wide, + detail); const struct prefix *rn_p = bgp_dest_get_prefix(dest); @@ -14295,11 +14794,15 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, "%pFX", rn_p); } else - route_vty_out_tmp( - vty, dest, rn_p, - &attr, safi, - use_json, - json_ar, wide); + route_vty_out_tmp(vty, + bgp, + dest, + rn_p, + &attr, + safi, + use_json, + json_ar, + wide); (*output_count)++; } else { (*filtered_count)++; @@ -14311,8 +14814,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, struct bgp_path_info *pi; show_adj_route_header(vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + header2, json, wide, detail); const struct prefix *rn_p = bgp_dest_get_prefix(dest); @@ -14338,9 +14840,10 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, json_ar, json_net, "%pFX", rn_p); } else - route_vty_out_tmp( - vty, dest, rn_p, pi->attr, safi, - use_json, json_ar, wide); + route_vty_out_tmp(vty, bgp, dest, rn_p, + pi->attr, safi, + use_json, json_ar, + wide); (*output_count)++; } } @@ -14355,8 +14858,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, struct bgp *bgp; struct bgp_table *table; json_object *json = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; json_object *json_ar = NULL; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); @@ -14385,28 +14886,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, if (use_json) { json = json_object_new_object(); json_ar = json_object_new_object(); - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpStatusCodes` from JSON outputs") -#endif - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "multipath", "="); - json_object_string_add(json_scode, "internal", "i"); - json_object_string_add(json_scode, "ribFailure", "r"); - json_object_string_add(json_scode, "stale", "S"); - json_object_string_add(json_scode, "removed", "R"); - -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") -#endif - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); } if (!peer || !peer->afc[afi][safi]) { @@ -14417,8 +14896,6 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); json_object_free(json_ar); - json_object_free(json_scode); - json_object_free(json_ocode); } else vty_out(vty, "%% No such neighbor or address family\n"); @@ -14436,8 +14913,6 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); json_object_free(json_ar); - json_object_free(json_scode); - json_object_free(json_ocode); } else vty_out(vty, "%% Inbound soft reconfiguration not enabled\n"); @@ -14477,11 +14952,11 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") prefix_rd2str(prd, rd_str, sizeof(rd_str), bgp->asnotation); - show_adj_route( - vty, peer, table, afi, safi, type, rmap_name, - json, json_routes, json_scode, json_ocode, - show_flags, &header1, &header2, rd_str, match, - &output_count_per_rd, &filtered_count_per_rd); + show_adj_route(vty, peer, table, afi, safi, type, + rmap_name, json, json_routes, show_flags, + &header1, &header2, rd_str, match, + &output_count_per_rd, + &filtered_count_per_rd); /* Don't include an empty RD in the output! */ if (json_routes && (output_count_per_rd > 0)) @@ -14493,9 +14968,8 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") } } else show_adj_route(vty, peer, table, afi, safi, type, rmap_name, - json, json_ar, json_scode, json_ocode, - show_flags, &header1, &header2, rd_str, match, - &output_count, &filtered_count); + json, json_ar, show_flags, &header1, &header2, + rd_str, match, &output_count, &filtered_count); if (use_json) { if (type == bgp_show_adj_route_advertised) @@ -14507,16 +14981,6 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") json_object_int_add(json, "filteredPrefixCounter", filtered_count); - /* - * These fields only give up ownership to `json` when `header1` - * is used (set to zero). See code in `show_adj_route` and - * `show_adj_route_header`. - */ - if (header1 == 1) { - json_object_free(json_scode); - json_object_free(json_ocode); - } - /* * This is an extremely expensive operation at scale * and non-pretty reduces memory footprint significantly. @@ -15464,9 +15928,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, while (pi) { if (pi->extra && pi->extra->damp_info) { pi_temp = pi->next; - bgp_damp_info_free( - pi->extra->damp_info, - 1, afi, safi); + bgp_damp_info_free(pi->extra->damp_info, + NULL, 1); pi = pi_temp; } else pi = pi->next; @@ -15477,26 +15940,38 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, } } else { dest = bgp_node_match(bgp->rib[afi][safi], &match); - if (dest != NULL) { - const struct prefix *dest_p = bgp_dest_get_prefix(dest); + if (!dest) + return CMD_SUCCESS; - if (!prefix_check - || dest_p->prefixlen == match.prefixlen) { - pi = bgp_dest_get_bgp_path_info(dest); - while (pi) { - if (pi->extra && pi->extra->damp_info) { - pi_temp = pi->next; - bgp_damp_info_free( - pi->extra->damp_info, - 1, afi, safi); - pi = pi_temp; - } else - pi = pi->next; - } + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + + if (prefix_check || dest_p->prefixlen != match.prefixlen) + return CMD_SUCCESS; + + pi = bgp_dest_get_bgp_path_info(dest); + while (pi) { + if (!(pi->extra && pi->extra->damp_info)) { + pi = pi->next; + continue; } - bgp_dest_unlock_node(dest); + pi_temp = pi->next; + struct bgp_damp_info *bdi = pi->extra->damp_info; + + if (bdi->lastrecord != BGP_RECORD_UPDATE) + continue; + + bgp_aggregate_increment(bgp, + bgp_dest_get_prefix(bdi->dest), + bdi->path, bdi->afi, bdi->safi); + bgp_process(bgp, bdi->dest, bdi->path, bdi->afi, + bdi->safi); + + bgp_damp_info_free(pi->extra->damp_info, NULL, 1); + pi = pi_temp; } + + bgp_dest_unlock_node(dest); } return CMD_SUCCESS; @@ -15510,7 +15985,9 @@ DEFUN (clear_ip_bgp_dampening, BGP_STR "Clear route flap dampening information\n") { - bgp_damp_info_clean(AFI_IP, SAFI_UNICAST); + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp_damp_info_clean(bgp, &bgp->damp[AFI_IP][SAFI_UNICAST], AFI_IP, + SAFI_UNICAST); return CMD_SUCCESS; } @@ -15754,7 +16231,28 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, p = bgp_dest_get_prefix(dest); - vty_out(vty, " network %pFX", p); + if (safi == SAFI_RTC) { + /* Only prefixes with a length of more than 48 have the + * type and subtype field set. If those aren't set + * ecommunity_ecom2str returns just UNK: */ + if (p->prefixlen >= 48) { + struct ecommunity *ecom = ecommunity_parse( + (unsigned char *)&p->u.prefix_rtc + .route_target, + 8, false); + char *b = ecommunity_ecom2str( + ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); + vty_out(vty, " rt %s", b); + ecommunity_unintern(&ecom); + XFREE(MTYPE_ECOMMUNITY_STR, b); + } else { + vty_out(vty, " rt 0:0"); + } + vty_out(vty, "/%d", p->prefixlen); + } else { + vty_out(vty, " network %pFX", p); + } if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) vty_out(vty, " label-index %u", diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e9f48ea64778..639f74543898 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -59,20 +59,15 @@ enum bgp_show_adj_route_type { #define BGP_SHOW_SCODE_HEADER \ "Status codes: s suppressed, d damped, " \ - "h history, * valid, > best, = multipath,\n" \ + "h history, u unsorted, * valid, > best, = multipath,\n" \ " i internal, r RIB-failure, S Stale, R Removed\n" #define BGP_SHOW_OCODE_HEADER \ "Origin codes: i - IGP, e - EGP, ? - incomplete\n" #define BGP_SHOW_NCODE_HEADER "Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self\n" #define BGP_SHOW_RPKI_HEADER \ "RPKI validation codes: V valid, I invalid, N Not found\n\n" -#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" -#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n" - -/* Maximum number of labels we can process or send with a prefix. We - * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. - */ -#define BGP_MAX_LABELS 2 +#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" +#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n" /* Maximum number of sids we can process or send with a prefix. */ #define BGP_MAX_SIDS 6 @@ -193,30 +188,9 @@ struct bgp_path_info_extra_vrfleak { struct prefix nexthop_orig; }; -/* Ancillary information to struct bgp_path_info, - * used for uncommonly used data (aggregation, MPLS, etc.) - * and lazily allocated to save memory. - */ -struct bgp_path_info_extra { - /* Pointer to dampening structure. */ - struct bgp_damp_info *damp_info; - - /** List of aggregations that suppress this path. */ - struct list *aggr_suppressors; - - /* Nexthop reachability check. */ - uint32_t igpmetric; - - /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels; - - /*For EVPN*/ - struct bgp_path_info_extra_evpn *evpn; - #ifdef ENABLE_BGP_VNC +struct bgp_path_info_extra_vnc { union { - struct { void *rfapi_handle; /* export: NVE advertising this route */ @@ -239,8 +213,35 @@ struct bgp_path_info_extra { struct prefix aux_prefix; /* AFI_L2VPN: the IP addr, if family set */ } import; - } vnc; +}; +#endif + +/* Ancillary information to struct bgp_path_info, + * used for uncommonly used data (aggregation, MPLS, etc.) + * and lazily allocated to save memory. + */ +struct bgp_path_info_extra { + /* Pointer to dampening structure. */ + struct bgp_damp_info *damp_info; + + /** List of aggregations that suppress this path. */ + struct list *aggr_suppressors; + + /* Nexthop reachability check. */ + uint32_t igpmetric; + + /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ + struct bgp_labels *labels; + + /* timestamp of the rib installation */ + time_t bgp_rib_uptime; + + /*For EVPN*/ + struct bgp_path_info_extra_evpn *evpn; + +#ifdef ENABLE_BGP_VNC + struct bgp_path_info_extra_vnc *vnc; #endif /* For flowspec*/ @@ -320,6 +321,7 @@ struct bgp_path_info { #define BGP_PATH_ACCEPT_OWN (1 << 16) #define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17) #define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18) +#define BGP_PATH_UNSORTED (1 << 19) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ uint8_t type; @@ -338,6 +340,8 @@ struct bgp_path_info { unsigned short instance; + enum bgp_path_selection_reason reason; + /* Addpath identifiers */ uint32_t addpath_rx_id; struct bgp_addpath_info_data tx_addpath; @@ -366,6 +370,8 @@ struct bgp_static { /* Import check status. */ uint8_t valid; + uint16_t encap_tunneltype; + /* IGP metric. */ uint32_t igpmetric; @@ -391,7 +397,6 @@ struct bgp_static { /* EVPN */ esi_t *eth_s_id; struct ethaddr *router_mac; - uint16_t encap_tunneltype; struct prefix gatewayIp; }; @@ -412,10 +417,22 @@ struct bgp_aggregate { /* AS set generation. */ uint8_t as_set; + /* Optional modify flag to override ORIGIN */ + uint8_t origin; + + /** Are there MED mismatches? */ + bool med_mismatched; + /* MED matching state. */ + /** Did we get the first MED value? */ + bool med_initialized; + /** Match only equal MED. */ + bool match_med; + /* Route-map for aggregated route. */ struct { char *name; struct route_map *map; + bool changed; } rmap; /* Suppress-count. */ @@ -427,9 +444,6 @@ struct bgp_aggregate { /* Count of routes of origin type egp under this aggregate. */ unsigned long egp_origin_count; - /* Optional modify flag to override ORIGIN */ - uint8_t origin; - /* Hash containing the communities of all the * routes under this aggregate. */ @@ -465,13 +479,6 @@ struct bgp_aggregate { /* SAFI configuration. */ safi_t safi; - /** Match only equal MED. */ - bool match_med; - /* MED matching state. */ - /** Did we get the first MED value? */ - bool med_initialized; - /** Are there MED mismatches? */ - bool med_mismatched; /** MED value found in current group. */ uint32_t med_matched_value; @@ -674,6 +681,12 @@ DECLARE_HOOK(bgp_process, struct peer *peer, bool withdraw), (bgp, afi, safi, bn, peer, withdraw)); +/* called when a route is updated in the rib */ +DECLARE_HOOK(bgp_route_update, + (struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + struct bgp_path_info *old_route, struct bgp_path_info *new_route), + (bgp, afi, safi, bn, old_route, new_route)); + /* BGP show options */ #define BGP_SHOW_OPT_JSON (1 << 0) #define BGP_SHOW_OPT_WIDE (1 << 1) @@ -698,7 +711,8 @@ extern void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi, bool force); extern void bgp_stop_announce_route_timer(struct peer_af *paf); extern void bgp_announce_route_all(struct peer *); -extern void bgp_default_originate(struct peer *, afi_t, safi_t, int); +extern void bgp_default_originate(struct peer *peer, afi_t afi, safi_t safi, + bool withdraw); extern void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp, const struct bgp_table *table, const struct peer *peer); @@ -733,12 +747,16 @@ extern void bgp_path_info_delete(struct bgp_dest *dest, struct bgp_path_info *pi); extern struct bgp_path_info_extra * bgp_path_info_extra_get(struct bgp_path_info *path); +extern bool bgp_path_info_has_valid_label(const struct bgp_path_info *path); +extern uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi); extern void bgp_path_info_set_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_unset_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, size_t buf_len); +extern bool bgp_path_info_labels_same(const struct bgp_path_info *bpi, + const mpls_label_t *label, uint32_t n); extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *); @@ -769,22 +787,30 @@ extern int bgp_static_set(struct vty *vty, bool negate, const char *ip_str, uint32_t label_index, int evpn_type, const char *esi, const char *gwip, const char *ethtag, const char *routermac); +extern struct bgp_static *bgp_static_new(void); +extern void bgp_static_free(struct bgp_static *bgp_static); /* this is primarily for MPLS-VPN */ extern void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, int soft_reconfig, + uint8_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn); extern void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, - struct bgp_route_evpn *evpn); + mpls_label_t *label, uint8_t num_labels); + +extern void bgp_static_update(struct bgp *bgp, const struct prefix *p, + struct bgp_static *bgp_static, afi_t afi, + safi_t safi); +extern void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, + afi_t afi, safi_t safi, struct prefix_rd *prd); /* for bgp_nexthop and bgp_damp */ -extern void bgp_process(struct bgp *, struct bgp_dest *, afi_t, safi_t); +extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi); /* * Add an end-of-initial-update marker to the process queue. This is just a @@ -828,10 +854,10 @@ extern void route_vty_out(struct vty *vty, const struct prefix *p, extern void route_vty_out_tag(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, safi_t safi, json_object *json); -extern void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, - const struct prefix *p, struct attr *attr, - safi_t safi, bool use_json, json_object *json_ar, - bool wide); +extern void route_vty_out_tmp(struct vty *vty, struct bgp *bgp, + struct bgp_dest *dest, const struct prefix *p, + struct attr *attr, safi_t safi, bool use_json, + json_object *json_ar, bool wide); extern void route_vty_out_overlay(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, json_object *json); @@ -905,6 +931,7 @@ extern void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, extern void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr); const char * bgp_path_selection_reason2str(enum bgp_path_selection_reason reason); +extern bool bgp_path_suppressed(struct bgp_path_info *pi); extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi); extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, safi_t safi); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 274df5197e2c..79c61e2ee293 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -680,9 +680,8 @@ route_match_address_prefix_list(void *rule, afi_t afi, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } @@ -1056,7 +1055,7 @@ static enum route_map_cmd_result_t route_match_vni(void *rule, const struct prefix *prefix, void *object) { vni_t vni = 0; - unsigned int label_cnt = 0; + unsigned int label_cnt; struct bgp_path_info *path = NULL; struct prefix_evpn *evp = (struct prefix_evpn *) prefix; @@ -1081,13 +1080,10 @@ route_match_vni(void *rule, const struct prefix *prefix, void *object) && evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)) return RMAP_NOOP; - if (path->extra == NULL) - return RMAP_NOMATCH; - - for (; - label_cnt < BGP_MAX_LABELS && label_cnt < path->extra->num_labels; + for (label_cnt = 0; label_cnt < BGP_MAX_LABELS && + label_cnt < bgp_path_info_num_labels(path); label_cnt++) { - if (vni == label2vni(&path->extra->label[label_cnt])) + if (vni == label2vni(&path->extra->labels->label[label_cnt])) return RMAP_MATCH; } @@ -1240,6 +1236,8 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object) struct ipaddr *gw_ip = rule; struct bgp_path_info *path; struct prefix_evpn *evp; + struct bgp_route_evpn *bre = XCALLOC(MTYPE_BGP_EVPN_OVERLAY, + sizeof(struct bgp_route_evpn)); if (prefix->family != AF_EVPN) return RMAP_OKAY; @@ -1255,9 +1253,9 @@ route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object) path = object; /* Set gateway-ip value. */ - path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP; - memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr, - IPADDRSZ(gw_ip)); + bre->type = OVERLAY_INDEX_GATEWAY_IP; + memcpy(&bre->gw_ip, &gw_ip->ip.addr, IPADDRSZ(gw_ip)); + bgp_attr_set_evpn_overlay(path->attr, bre); return RMAP_OKAY; } @@ -1528,7 +1526,8 @@ static const struct route_map_rule_cmd route_match_aspath_cmd = { struct rmap_community { char *name; uint32_t name_hash; - int exact; + bool exact; + bool any; }; /* Match function for community match. */ @@ -1551,6 +1550,12 @@ route_match_community(void *rule, const struct prefix *prefix, void *object) if (community_list_exact_match( bgp_attr_get_community(path->attr), list)) return RMAP_MATCH; + } else if (rcom->any) { + if (!bgp_attr_get_community(path->attr)) + return RMAP_OKAY; + if (community_list_any_match(bgp_attr_get_community(path->attr), + list)) + return RMAP_MATCH; } else { if (community_list_match(bgp_attr_get_community(path->attr), list)) @@ -1574,10 +1579,15 @@ static void *route_match_community_compile(const char *arg) len = p - arg; rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy(rcom->name, arg, len); - rcom->exact = 1; + p++; + if (*p == 'e') + rcom->exact = true; + else + rcom->any = true; } else { rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); - rcom->exact = 0; + rcom->exact = false; + rcom->any = false; } rcom->name_hash = bgp_clist_hash_key(rcom->name); @@ -1637,6 +1647,12 @@ route_match_lcommunity(void *rule, const struct prefix *prefix, void *object) if (lcommunity_list_exact_match( bgp_attr_get_lcommunity(path->attr), list)) return RMAP_MATCH; + } else if (rcom->any) { + if (!bgp_attr_get_lcommunity(path->attr)) + return RMAP_OKAY; + if (lcommunity_list_any_match(bgp_attr_get_lcommunity(path->attr), + list)) + return RMAP_MATCH; } else { if (lcommunity_list_match(bgp_attr_get_lcommunity(path->attr), list)) @@ -1660,10 +1676,15 @@ static void *route_match_lcommunity_compile(const char *arg) len = p - arg; rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy(rcom->name, arg, len); - rcom->exact = 1; + p++; + if (*p == 'e') + rcom->exact = true; + else + rcom->any = true; } else { rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); - rcom->exact = 0; + rcom->exact = false; + rcom->any = false; } rcom->name_hash = bgp_clist_hash_key(rcom->name); @@ -1921,7 +1942,6 @@ route_set_srte_color(void *rule, const struct prefix *prefix, void *object) path = object; path->attr->srte_color = *srte_color; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR); return RMAP_OKAY; } @@ -2300,17 +2320,10 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { route_set_aspath_prepend_free, }; -/* `set as-path exclude ASn' */ -struct aspath_exclude { - struct aspath *aspath; - bool exclude_all; - char *exclude_aspath_acl_name; - struct as_list *exclude_aspath_acl; -}; - static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; + struct as_list *aux_aslist; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2322,15 +2335,33 @@ static void *route_aspath_exclude_compile(const char *arg) while (*str == ' ') str++; ase->exclude_aspath_acl_name = XSTRDUP(MTYPE_TMP, str); - ase->exclude_aspath_acl = as_list_lookup(str); + aux_aslist = as_list_lookup(str); + if (!aux_aslist) + /* new orphan filter */ + as_exclude_set_orphan(ase); + else + as_list_list_add_head(&aux_aslist->exclude_rule, ase); + + ase->exclude_aspath_acl = aux_aslist; } else ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL)); + return ase; } static void route_aspath_exclude_free(void *rule) { struct aspath_exclude *ase = rule; + struct as_list *acl; + + /* manage references to that rule*/ + if (ase->exclude_aspath_acl) { + acl = ase->exclude_aspath_acl; + as_list_list_del(&acl->exclude_rule, ase); + } else { + /* no ref to acl, this aspath exclude is orphan */ + as_exclude_remove_orphan(ase); + } aspath_free(ase->aspath); if (ase->exclude_aspath_acl_name) @@ -2369,16 +2400,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object) else if (ase->exclude_all) path->attr->aspath = aspath_filter_exclude_all(new_path); - else if (ase->exclude_aspath_acl_name) { - if (!ase->exclude_aspath_acl) - ase->exclude_aspath_acl = - as_list_lookup(ase->exclude_aspath_acl_name); - if (ase->exclude_aspath_acl) - path->attr->aspath = - aspath_filter_exclude_acl(new_path, - ase->exclude_aspath_acl); - } - + else if (ase->exclude_aspath_acl) + path->attr->aspath = + aspath_filter_exclude_acl(new_path, + ase->exclude_aspath_acl); return RMAP_OKAY; } @@ -3155,7 +3180,7 @@ struct rmap_ecomm_lb_set { #define RMAP_ECOMM_LB_SET_CUMUL 2 #define RMAP_ECOMM_LB_SET_NUM_MPATH 3 bool non_trans; - uint32_t bw; + uint64_t bw; }; static enum route_map_cmd_result_t @@ -3165,8 +3190,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) struct bgp_path_info *path; struct peer *peer; struct ecommunity ecom_lb = {0}; - struct ecommunity_val lb_eval; - uint32_t bw_bytes = 0; + uint64_t bw_bytes = 0; uint16_t mpath_count = 0; struct ecommunity *new_ecom; struct ecommunity *old_ecom; @@ -3180,13 +3204,13 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) /* Build link bandwidth extended community */ as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as; if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) { - bw_bytes = ((uint64_t)rels->bw * 1000 * 1000) / 8; + bw_bytes = (rels->bw * 1000 * 1000) / 8; } else if (rels->lb_type == RMAP_ECOMM_LB_SET_CUMUL) { /* process this only for the best path. */ if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) return RMAP_OKAY; - bw_bytes = (uint32_t)bgp_path_info_mpath_cumbw(path); + bw_bytes = bgp_path_info_mpath_cumbw(path); if (!bw_bytes) return RMAP_OKAY; @@ -3196,31 +3220,53 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) return RMAP_OKAY; - bw_bytes = ((uint64_t)peer->bgp->lb_ref_bw * 1000 * 1000) / 8; + bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8; mpath_count = bgp_path_info_mpath_count(path) + 1; bw_bytes *= mpath_count; } - encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval, - CHECK_FLAG(peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) { + struct ecommunity_val_ipv6 lb_eval; - /* add to route or merge with existing */ - old_ecom = bgp_attr_get_ecommunity(path->attr); - if (old_ecom) { - new_ecom = ecommunity_dup(old_ecom); - ecommunity_add_val(new_ecom, &lb_eval, true, true); - if (!old_ecom->refcnt) - ecommunity_free(&old_ecom); + encode_lb_extended_extcomm(as, bw_bytes, rels->non_trans, + &lb_eval); + + old_ecom = bgp_attr_get_ipv6_ecommunity(path->attr); + if (old_ecom) { + new_ecom = ecommunity_dup(old_ecom); + ecommunity_add_val_ipv6(new_ecom, &lb_eval, true, true); + if (!old_ecom->refcnt) + ecommunity_free(&old_ecom); + } else { + ecom_lb.size = 1; + ecom_lb.unit_size = IPV6_ECOMMUNITY_SIZE; + ecom_lb.val = (uint8_t *)lb_eval.val; + new_ecom = ecommunity_dup(&ecom_lb); + } + + bgp_attr_set_ipv6_ecommunity(path->attr, new_ecom); } else { - ecom_lb.size = 1; - ecom_lb.unit_size = ECOMMUNITY_SIZE; - ecom_lb.val = (uint8_t *)lb_eval.val; - new_ecom = ecommunity_dup(&ecom_lb); - } + struct ecommunity_val lb_eval; + + encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval, + CHECK_FLAG(peer->flags, + PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + + old_ecom = bgp_attr_get_ecommunity(path->attr); + if (old_ecom) { + new_ecom = ecommunity_dup(old_ecom); + ecommunity_add_val(new_ecom, &lb_eval, true, true); + if (!old_ecom->refcnt) + ecommunity_free(&old_ecom); + } else { + ecom_lb.size = 1; + ecom_lb.unit_size = ECOMMUNITY_SIZE; + ecom_lb.val = (uint8_t *)lb_eval.val; + new_ecom = ecommunity_dup(&ecom_lb); + } - /* new_ecom will be intern()'d or attr_flush()'d in call stack */ - bgp_attr_set_ecommunity(path->attr, new_ecom); + bgp_attr_set_ecommunity(path->attr, new_ecom); + } /* Mark that route-map has set link bandwidth; used in attribute * setting decisions. @@ -3234,7 +3280,7 @@ static void *route_set_ecommunity_lb_compile(const char *arg) { struct rmap_ecomm_lb_set *rels; uint8_t lb_type; - uint32_t bw = 0; + uint64_t bw = 0; char bw_str[40] = {0}; char *p, *str; bool non_trans = false; @@ -3276,13 +3322,8 @@ static enum route_map_cmd_result_t route_set_ecommunity_color(void *rule, const struct prefix *prefix, void *object) { - struct bgp_path_info *path; - - path = object; - route_set_ecommunity(rule, prefix, object); - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR); return RMAP_OKAY; } @@ -3912,11 +3953,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) { /* Set next hop preference to global */ - path->attr->mp_nexthop_prefer_global = true; + SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } else { - path->attr->mp_nexthop_prefer_global = false; + UNSET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } @@ -4419,6 +4460,13 @@ static void bgp_route_map_update_peer_group(const char *rmap_name, filter->map[direct].name) == 0)) filter->map[direct].map = map; + + if (group->conf->default_rmap[afi][safi].name && + strmatch(group->conf->default_rmap[afi][safi] + .name, + rmap_name)) + group->conf->default_rmap[afi][safi].map = + map; } if (filter->usmap.name @@ -4573,6 +4621,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, route_map_counter_increment(map); aggregate->rmap.map = map; + aggregate->rmap.changed = true; matched = true; } @@ -4720,6 +4769,24 @@ static void bgp_route_map_delete(const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); } +bool bgp_route_map_has_extcommunity_rt(const struct route_map *map) +{ + struct route_map_index *index = NULL; + struct route_map_rule *set = NULL; + + assert(map); + + for (index = map->head; index; index = index->next) { + for (set = index->set_list.head; set; set = set->next) { + if (set->cmd && set->cmd->str && + (strmatch(set->cmd->str, "extcommunity rt") || + strmatch(set->cmd->str, "extended-comm-list"))) + return true; + } + } + return false; +} + static void bgp_route_map_event(const char *rmap_name) { if (route_map_mark_updated(rmap_name) == 0) @@ -5152,27 +5219,23 @@ DEFPY_YANG (match_peer, nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - if (addrv4_str) { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - addrv4_str); - } else if (addrv6_str) { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-bgp-route-map:peer-ipv6-address", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - addrv6_str); - } else { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-bgp-route-map:peer-interface", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, intf); - } + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, + addrv4_str ? NB_OP_MODIFY : NB_OP_DESTROY, + addrv4_str); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-ipv6-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, + addrv6_str ? NB_OP_MODIFY : NB_OP_DESTROY, + addrv6_str); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-interface", + xpath); + nb_cli_enqueue_change(vty, xpath_value, + intf ? NB_OP_MODIFY : NB_OP_DESTROY, intf); return nb_cli_apply_changes(vty, NULL); } @@ -5493,15 +5556,15 @@ DEFUN_YANG(no_match_alias, no_match_alias_cmd, "no match alias [ALIAS_NAME]", return nb_cli_apply_changes(vty, NULL); } -DEFPY_YANG (match_community, - match_community_cmd, - "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]", - MATCH_STR - "Match BGP community list\n" - "Community-list number (standard)\n" - "Community-list number (expanded)\n" - "Community-list name\n" - "Do exact matching of communities\n") +DEFPY_YANG( + match_community, match_community_cmd, + "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> []", + MATCH_STR "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-community']"; @@ -5517,35 +5580,35 @@ DEFPY_YANG (match_community, xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg); - if (argc == 4) { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + if (exact) nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); - } else { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); - nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, - "false"); - } + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); + + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + xpath); + if (any) + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); return nb_cli_apply_changes(vty, NULL); } -DEFUN_YANG (no_match_community, - no_match_community_cmd, - "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]]", - NO_STR - MATCH_STR - "Match BGP community list\n" - "Community-list number (standard)\n" - "Community-list number (expanded)\n" - "Community-list name\n" - "Do exact matching of communities\n") +DEFUN_YANG( + no_match_community, no_match_community_cmd, + "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> []]", + NO_STR MATCH_STR "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-community']"; @@ -5554,15 +5617,15 @@ DEFUN_YANG (no_match_community, return nb_cli_apply_changes(vty, NULL); } -DEFPY_YANG (match_lcommunity, - match_lcommunity_cmd, - "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]", - MATCH_STR - "Match BGP large community list\n" - "Large Community-list number (standard)\n" - "Large Community-list number (expanded)\n" - "Large Community-list name\n" - "Do exact matching of communities\n") +DEFPY_YANG( + match_lcommunity, match_lcommunity_cmd, + "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> []", + MATCH_STR "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-large-community']"; @@ -5578,35 +5641,35 @@ DEFPY_YANG (match_lcommunity, xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_lcomm_list]->arg); - if (argc == 4) { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + if (exact) nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); - } else { - snprintf( - xpath_match, sizeof(xpath_match), - "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", - xpath); - nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, - "false"); - } + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); + + snprintf(xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + xpath); + if (any) + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false"); return nb_cli_apply_changes(vty, NULL); } -DEFUN_YANG (no_match_lcommunity, - no_match_lcommunity_cmd, - "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]]", - NO_STR - MATCH_STR - "Match BGP large community list\n" - "Large Community-list number (standard)\n" - "Large Community-list number (expanded)\n" - "Large Community-list name\n" - "Do exact matching of communities\n") +DEFUN_YANG( + no_match_lcommunity, no_match_lcommunity_cmd, + "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> []]", + NO_STR MATCH_STR "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n" + "Do exact matching of communities\n" + "Do matching of any community\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-large-community']"; @@ -5815,10 +5878,11 @@ DEFUN_YANG (set_table_id, DEFUN_YANG (no_set_table_id, no_set_table_id_cmd, - "no set table", + "no set table [(1-4294967295)]", NO_STR SET_STR - "export route to non-main kernel table\n") + "export route to non-main kernel table\n" + "Kernel routing table id\n") { const char *xpath = "./set-action[action='frr-bgp-route-map:table']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -6206,13 +6270,12 @@ DEFPY_YANG( } DEFUN_YANG (no_set_aspath_prepend, - no_set_aspath_prepend_cmd, - "no set as-path prepend [ASNUM] [last-as [(1-10)]]", + no_set_aspath_prepend_last_as_cmd, + "no set as-path prepend [last-as [(1-10)]]", NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" - AS_STR "Use the peers AS-number\n" "Number of times to insert\n") { @@ -6223,6 +6286,15 @@ DEFUN_YANG (no_set_aspath_prepend, return nb_cli_apply_changes(vty, NULL); } +ALIAS_YANG (no_set_aspath_prepend, + no_set_aspath_prepend_as_cmd, + "no set as-path prepend ASNUM...", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + AS_STR) + DEFUN_YANG (set_aspath_exclude, set_aspath_exclude_cmd, "set as-path exclude ASNUM...", @@ -6808,7 +6880,7 @@ DEFUN_YANG(no_set_ecommunity_none, no_set_ecommunity_none_cmd, DEFUN_YANG (set_ecommunity_lb, set_ecommunity_lb_cmd, - "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", + "set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]", SET_STR "BGP extended community attribute\n" "Link bandwidth extended community\n" @@ -6862,7 +6934,7 @@ DEFUN_YANG (set_ecommunity_lb, DEFUN_YANG (no_set_ecommunity_lb, no_set_ecommunity_lb_cmd, - "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", + "no set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]", NO_STR SET_STR "BGP extended community attribute\n" @@ -7899,7 +7971,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_aspath_exclude_access_list_cmd); install_element(RMAP_NODE, &set_aspath_replace_asn_cmd); install_element(RMAP_NODE, &set_aspath_replace_access_list_cmd); - install_element(RMAP_NODE, &no_set_aspath_prepend_cmd); + install_element(RMAP_NODE, &no_set_aspath_prepend_last_as_cmd); + install_element(RMAP_NODE, &no_set_aspath_prepend_as_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_access_list_cmd); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index ae695a6f80a1..096502aaa904 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -147,6 +147,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list", .cbs = { + .create = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy, .apply_finish = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish, } }, @@ -154,7 +156,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", .cbs = { .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify, - .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy, } }, { @@ -164,6 +165,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy, } }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy, + } + }, { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv4-address", .cbs = { @@ -349,6 +357,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator", .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_aggregator_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy, .apply_finish = lib_route_map_entry_set_action_rmap_set_action_aggregator_finish, } }, @@ -356,14 +366,12 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy, } }, { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy, } }, { @@ -383,6 +391,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb", .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy, .apply_finish = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish, } }, @@ -390,7 +400,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy, } }, { @@ -411,7 +420,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy, } }, { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index 3ff58f71a733..d7f0cea30ea0 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -60,11 +60,18 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy( + struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify(struct nb_cb_modify_args *args); @@ -123,24 +130,28 @@ int lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify(s int lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify( struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy( diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 9ef9031e54a5..15c32eaa2856 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -522,6 +522,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy( case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: return lib_route_map_entry_match_destroy(args); } @@ -1120,6 +1121,27 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des /* * XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list */ +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( struct nb_cb_apply_finish_args *args) @@ -1127,6 +1149,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( struct routemap_hook_context *rhc; const char *value; bool exact_match = false; + bool any = false; char *argstr; const char *condition; route_map_event_t event; @@ -1134,18 +1157,27 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( /* Add configuration. */ rhc = nb_running_get_entry(args->dnode, NULL, true); - value = yang_dnode_get_string(args->dnode, "./comm-list-name"); + value = yang_dnode_get_string(args->dnode, "comm-list-name"); - if (yang_dnode_exists(args->dnode, "./comm-list-name-exact-match")) + if (yang_dnode_exists(args->dnode, "comm-list-name-exact-match")) exact_match = yang_dnode_get_bool( args->dnode, "./comm-list-name-exact-match"); + if (yang_dnode_exists(args->dnode, "comm-list-name-any")) + any = yang_dnode_get_bool(args->dnode, "comm-list-name-any"); + if (exact_match) { argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, strlen(value) + strlen("exact-match") + 2); snprintf(argstr, (strlen(value) + strlen("exact-match") + 2), "%s exact-match", value); + } else if (any) { + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(value) + strlen("any") + 2); + + snprintf(argstr, (strlen(value) + strlen("any") + 2), "%s any", + value); } else argstr = (char *)value; @@ -1200,21 +1232,36 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam return NB_OK; } -int -lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy( - struct nb_cb_destroy_args *args) +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any + */ +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( + struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + break; } return NB_OK; +} +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; } /* @@ -1243,9 +1290,8 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + break; } return NB_OK; @@ -1407,7 +1453,7 @@ int lib_route_map_entry_set_action_rmap_set_action_distance_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1461,7 +1507,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1513,7 +1559,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_nt_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1568,7 +1614,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1704,7 +1750,7 @@ int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify( || IN6_IS_ADDR_LINKLOCAL(&i6a)) return NB_ERR_VALIDATION; } - /* FALLTHROUGH */ + return NB_OK; case NB_EV_PREPARE: case NB_EV_ABORT: return NB_OK; @@ -2691,6 +2737,27 @@ lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy( * xpath = * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator */ +int lib_route_map_entry_set_action_rmap_set_action_aggregator_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish( struct nb_cb_apply_finish_args *args) { @@ -2702,8 +2769,8 @@ void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish( /* Add configuration. */ rhc = nb_running_get_entry(args->dnode, NULL, true); - asn = yang_dnode_get_string(args->dnode, "./aggregator-asn"); - addr = yang_dnode_get_string(args->dnode, "./aggregator-address"); + asn = yang_dnode_get_string(args->dnode, "aggregator-asn"); + addr = yang_dnode_get_string(args->dnode, "aggregator-address"); argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, strlen(asn) + strlen(addr) + 2); @@ -2755,22 +2822,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify( return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_set_destroy(args); - } - - return NB_OK; -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address @@ -2790,22 +2841,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_mod return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_set_destroy(args); - } - - return NB_OK; -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name @@ -2874,6 +2909,27 @@ lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy( * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb */ +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( struct nb_cb_apply_finish_args *args) @@ -2881,12 +2937,12 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( struct routemap_hook_context *rhc; enum ecommunity_lb_type lb_type; char str[VTY_BUFSIZ]; - uint16_t bandwidth; + uint32_t bandwidth; int ret; /* Add configuration. */ rhc = nb_running_get_entry(args->dnode, NULL, true); - lb_type = yang_dnode_get_enum(args->dnode, "./lb-type"); + lb_type = yang_dnode_get_enum(args->dnode, "lb-type"); /* Set destroy information. */ rhc->rhc_shook = generic_set_delete; @@ -2895,8 +2951,8 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( switch (lb_type) { case EXPLICIT_BANDWIDTH: - bandwidth = yang_dnode_get_uint16(args->dnode, "./bandwidth"); - snprintf(str, sizeof(str), "%d", bandwidth); + bandwidth = yang_dnode_get_uint32(args->dnode, "bandwidth"); + snprintf(str, sizeof(str), "%u", bandwidth); break; case CUMULATIVE_BANDWIDTH: snprintf(str, sizeof(str), "%s", "cumulative"); @@ -2905,7 +2961,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( snprintf(str, sizeof(str), "%s", "num-multipaths"); } - if (yang_dnode_get_bool(args->dnode, "./two-octet-as-specific")) + if (yang_dnode_get_bool(args->dnode, "two-octet-as-specific")) strlcat(str, " non-transitive", sizeof(str)); ret = generic_set_add(rhc->rhc_rmi, "extcommunity bandwidth", str, @@ -2929,13 +2985,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify( return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth @@ -2951,7 +3000,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy( struct nb_cb_destroy_args *args) { - return lib_route_map_entry_set_destroy(args); + return NB_OK; } /* @@ -3000,7 +3049,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -3017,13 +3066,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index f0b2ffdee522..9db7b1529614 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -25,14 +25,17 @@ #include "memory.h" #include "frrevent.h" #include "filter.h" +#include "lib_errors.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgp_advertise.h" +#include "bgp_label.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_rpki.h" +#include "bgpd/bgp_debug.h" #include "northbound_cli.h" #include "lib/network.h" @@ -43,27 +46,33 @@ #include "bgpd/bgp_rpki_clippy.c" +DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_TEMP, "BGP RPKI Intermediate Buffer"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_REVALIDATE, "BGP RPKI Revalidation"); +#define STR_SEPARATOR 10 + #define POLLING_PERIOD_DEFAULT 3600 #define EXPIRE_INTERVAL_DEFAULT 7200 #define RETRY_INTERVAL_DEFAULT 600 #define BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT 3 -static struct event *t_rpki_sync; - #define RPKI_DEBUG(...) \ - if (rpki_debug) { \ + if (rpki_debug_conf || rpki_debug_term) { \ zlog_debug("RPKI: " __VA_ARGS__); \ } #define RPKI_OUTPUT_STRING "Control rpki specific settings\n" struct cache { - enum { TCP, SSH } type; + enum { + TCP, +#if defined(FOUND_SSH) + SSH +#endif + } type; struct tr_socket *tr_socket; union { struct tr_tcp_config *tcp_config; @@ -71,6 +80,7 @@ struct cache { } tr_config; struct rtr_socket *rtr_socket; uint8_t preference; + struct rpki_vrf *rpki_vrf; }; enum return_values { SUCCESS = 0, ERROR = -1 }; @@ -83,32 +93,61 @@ struct rpki_for_each_record_arg { enum asnotation_mode asnotation; }; -static int start(void); -static void stop(void); -static int reset(bool force); -static struct rtr_mgr_group *get_connected_group(void); -static void print_prefix_table(struct vty *vty, json_object *json); +struct rpki_vrf { + struct rtr_mgr_config *rtr_config; + struct list *cache_list; + bool rtr_is_running; + bool rtr_is_stopping; + bool rtr_is_synced; + _Atomic int rtr_update_overflow; + unsigned int polling_period; + unsigned int expire_interval; + unsigned int retry_interval; + int rpki_sync_socket_rtr; + int rpki_sync_socket_bgpd; + char *vrfname; + struct event *t_rpki_sync; + + QOBJ_FIELDS; +}; + +static pthread_key_t rpki_pthread; + +static struct rpki_vrf *find_rpki_vrf(const char *vrfname); +static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled); +static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf); +static int bgp_rpki_hook_write_vrf(struct vty *vty, struct vrf *vrf); +static int bgp_rpki_write_debug(struct vty *vty, bool running); +static int start(struct rpki_vrf *rpki_vrf); +static void stop(struct rpki_vrf *rpki_vrf); +static int reset(bool force, struct rpki_vrf *rpki_vrf); +static struct rtr_mgr_group *get_connected_group(struct rpki_vrf *rpki_vrf); +static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf, + json_object *json, bool count_only); static void install_cli_commands(void); static int config_write(struct vty *vty); static int config_on_exit(struct vty *vty); static void free_cache(struct cache *cache); -static struct rtr_mgr_group *get_groups(void); +static struct rtr_mgr_group *get_groups(struct list *cache_list); #if defined(FOUND_SSH) -static int add_ssh_cache(const char *host, const unsigned int port, - const char *username, const char *client_privkey_path, +static int add_ssh_cache(struct rpki_vrf *rpki_vrf, const char *host, + const unsigned int port, const char *username, + const char *client_privkey_path, const char *server_pubkey_path, const uint8_t preference, const char *bindaddr); #endif static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket); -static struct cache *find_cache(const uint8_t preference); -static void rpki_delete_all_cache_nodes(void); -static int add_tcp_cache(const char *host, const char *port, - const uint8_t preference, const char *bindaddr); +static struct cache *find_cache(const uint8_t preference, + struct list *cache_list); +static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf); +static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, + const char *port, const uint8_t preference, + const char *bindaddr); static void print_record(const struct pfx_record *record, struct vty *vty, json_object *json, enum asnotation_mode asnotation); -static bool is_synchronized(void); -static bool is_running(void); -static bool is_stopping(void); +static bool is_synchronized(struct rpki_vrf *rpki_vrf); +static bool is_running(struct rpki_vrf *rpki_vrf); +static bool is_stopping(struct rpki_vrf *rpki_vrf); static void route_match_free(void *rule); static enum route_map_cmd_result_t route_match(void *rule, const struct prefix *prefix, @@ -116,20 +155,14 @@ static enum route_map_cmd_result_t route_match(void *rule, void *object); static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi); -static void revalidate_all_routes(void); - -static struct rtr_mgr_config *rtr_config; -static struct list *cache_list; -static bool rtr_is_running; -static bool rtr_is_stopping; -static bool rtr_is_synced; -static _Atomic int rtr_update_overflow; -static bool rpki_debug; -static unsigned int polling_period; -static unsigned int expire_interval; -static unsigned int retry_interval; -static int rpki_sync_socket_rtr; -static int rpki_sync_socket_bgpd; +static void revalidate_all_routes(struct rpki_vrf *rpki_vrf); + +static bool rpki_debug_conf, rpki_debug_term; + +DECLARE_QOBJ_TYPE(rpki_vrf); +DEFINE_QOBJ_TYPE(rpki_vrf); + +struct list *rpki_vrf_list; static struct cmd_node rpki_node = { .name = "rpki", @@ -139,6 +172,16 @@ static struct cmd_node rpki_node = { .config_write = config_write, .node_exit = config_on_exit, }; + +static struct cmd_node rpki_vrf_node = { + .name = "rpki", + .node = RPKI_VRF_NODE, + .parent_node = VRF_NODE, + .prompt = "%s(config-vrf-rpki)# ", + .config_write = NULL, + .node_exit = config_on_exit, +}; + static const struct route_map_rule_cmd route_match_rpki_cmd = { "rpki", route_match, route_match_compile, route_match_free}; @@ -246,10 +289,141 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket) return rtr_socket; } -static struct cache *find_cache(const uint8_t preference) +static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled) +{ + struct rpki_vrf *rpki; + + if (vrf->vrf_id == VRF_DEFAULT) + rpki = find_rpki_vrf(NULL); + else + rpki = find_rpki_vrf(vrf->name); + if (!rpki) + return 0; + + if (enabled) + start(rpki); + else + stop(rpki); + return 1; +} + +/* tcp identifier : : + * ssh identifier : @: + */ +static struct rpki_vrf *find_rpki_vrf_from_ident(const char *ident) { +#if defined(FOUND_SSH) + struct tr_ssh_config *ssh_config; +#endif + struct tr_tcp_config *tcp_config; + struct listnode *rpki_vrf_nnode; + unsigned int cache_port, port; struct listnode *cache_node; + struct rpki_vrf *rpki_vrf; struct cache *cache; + bool is_tcp = true; + size_t host_len; + char *endptr; + char *host; + char *ptr; + char *buf; + + /* extract the */ + ptr = strrchr(ident, ':'); + if (!ptr) + return NULL; + + ptr++; + /* extract port */ + port = atoi(ptr); + if (port == 0) + /* not ours */ + return NULL; + + /* extract host */ + ptr--; + host_len = (size_t)(ptr - ident); + buf = XCALLOC(MTYPE_BGP_RPKI_TEMP, host_len + 1); + memcpy(buf, ident, host_len); + buf[host_len] = '\0'; + endptr = strrchr(buf, '@'); + + /* ssh session */ + if (endptr) { + host = XCALLOC(MTYPE_BGP_RPKI_TEMP, + (size_t)(buf + host_len - endptr) + 1); + memcpy(host, endptr + 1, (size_t)(buf + host_len - endptr) + 1); + is_tcp = false; + } else { + host = buf; + buf = NULL; + } + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) { + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + cache)) { + if ((cache->type == TCP && !is_tcp) +#if defined(FOUND_SSH) + || (cache->type == SSH && is_tcp) +#endif + ) + continue; + + if (is_tcp) { + tcp_config = cache->tr_config.tcp_config; + cache_port = atoi(tcp_config->port); + if (cache_port != port) + continue; + if (strlen(tcp_config->host) != strlen(host)) + continue; + if (memcmp(tcp_config->host, host, host_len) == + 0) + break; + } +#if defined(FOUND_SSH) + else { + ssh_config = cache->tr_config.ssh_config; + if (port != ssh_config->port) + continue; + if (strmatch(ssh_config->host, host)) + break; + } +#endif + } + if (cache) + break; + } + if (host) + XFREE(MTYPE_BGP_RPKI_TEMP, host); + if (buf) + XFREE(MTYPE_BGP_RPKI_TEMP, buf); + return rpki_vrf; +} + +static struct rpki_vrf *find_rpki_vrf(const char *vrfname) +{ + struct listnode *rpki_vrf_nnode; + struct rpki_vrf *rpki_vrf; + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) { + if (!vrfname && !rpki_vrf->vrfname) + /* rpki_vrf struct of the default VRF */ + return rpki_vrf; + if (vrfname && rpki_vrf->vrfname && + strmatch(vrfname, rpki_vrf->vrfname)) + return rpki_vrf; + } + return NULL; +} + +static struct cache *find_cache(const uint8_t preference, + struct list *cache_list) +{ + struct listnode *cache_node; + struct cache *cache; + + if (!cache_list) + return NULL; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { if (cache->preference == preference) @@ -258,14 +432,17 @@ static struct cache *find_cache(const uint8_t preference) return NULL; } -static void rpki_delete_all_cache_nodes(void) +static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf) { struct listnode *cache_node, *cache_next; struct cache *cache; - for (ALL_LIST_ELEMENTS(cache_list, cache_node, cache_next, cache)) { - rtr_mgr_remove_group(rtr_config, cache->preference); - listnode_delete(cache_list, cache); + for (ALL_LIST_ELEMENTS(rpki_vrf->cache_list, cache_node, cache_next, + cache)) { + if (is_running(rpki_vrf)) + rtr_mgr_remove_group(rpki_vrf->rtr_config, + cache->preference); + listnode_delete(rpki_vrf->cache_list, cache); } } @@ -315,7 +492,14 @@ static void print_record_cb(const struct pfx_record *record, void *data) print_record(record, vty, arg->json, arg->asnotation); } -static struct rtr_mgr_group *get_groups(void) +static void count_record_cb(const struct pfx_record *record, void *data) +{ + struct rpki_for_each_record_arg *arg = data; + + (*arg->prefix_amount)++; +} + +static struct rtr_mgr_group *get_groups(struct list *cache_list) { struct listnode *cache_node; struct rtr_mgr_group *rtr_mgr_groups; @@ -344,19 +528,19 @@ static struct rtr_mgr_group *get_groups(void) return rtr_mgr_groups; } -inline bool is_synchronized(void) +inline bool is_synchronized(struct rpki_vrf *rpki_vrf) { - return rtr_is_synced; + return rpki_vrf->rtr_is_synced; } -inline bool is_running(void) +inline bool is_running(struct rpki_vrf *rpki_vrf) { - return rtr_is_running; + return rpki_vrf->rtr_is_running; } -inline bool is_stopping(void) +inline bool is_stopping(struct rpki_vrf *rpki_vrf) { - return rtr_is_stopping; + return rpki_vrf->rtr_is_stopping; } static void pfx_record_to_prefix(struct pfx_record *record, @@ -408,23 +592,26 @@ static void bgpd_sync_callback(struct event *thread) struct listnode *node; struct prefix prefix; struct pfx_record rec; + struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); + struct vrf *vrf = NULL; - event_add_read(bm->master, bgpd_sync_callback, NULL, - rpki_sync_socket_bgpd, NULL); + event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, + rpki_vrf->rpki_sync_socket_bgpd, NULL); - if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) { - while (read(rpki_sync_socket_bgpd, &rec, + if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, + memory_order_seq_cst)) { + while (read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)) != -1) ; - atomic_store_explicit(&rtr_update_overflow, 0, + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst); - revalidate_all_routes(); + revalidate_all_routes(rpki_vrf); return; } - int retval = - read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + int retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, + sizeof(struct pfx_record)); if (retval != sizeof(struct pfx_record)) { RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); return; @@ -433,9 +620,23 @@ static void bgpd_sync_callback(struct event *thread) afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + if (rpki_vrf->vrfname) { + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) { + zlog_err("%s(): vrf for rpki %s not found", __func__, + rpki_vrf->vrfname); + return; + } + } + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { safi_t safi; + if (!vrf && bgp->vrf_id != VRF_DEFAULT) + continue; + if (vrf && bgp->vrf_id != vrf->vrf_id) + continue; + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { struct bgp_table *table = bgp->rib[afi][safi]; struct rpki_revalidate_prefix *rrp; @@ -458,17 +659,16 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, safi_t safi) { struct bgp_adj_in *ain; + mpls_label_t *label; + uint8_t num_labels; for (ain = bgp_dest->adj_in; ain; ain = ain->next) { struct bgp_path_info *path = bgp_dest_get_bgp_path_info(bgp_dest); - mpls_label_t *label = NULL; - uint32_t num_labels = 0; - if (path && path->extra) { - label = path->extra->label; - num_labels = path->extra->num_labels; - } + num_labels = bgp_path_info_num_labels(path); + label = num_labels ? path->extra->labels->label : NULL; + (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, @@ -501,15 +701,30 @@ static void bgp_rpki_revalidate_peer(struct event *thread) XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp); } -static void revalidate_all_routes(void) +static void revalidate_all_routes(struct rpki_vrf *rpki_vrf) { struct bgp *bgp; struct listnode *node; + struct vrf *vrf = NULL; + + if (rpki_vrf->vrfname) { + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) { + zlog_err("%s(): vrf for rpki %s not found", __func__, + rpki_vrf->vrfname); + return; + } + } for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { struct peer *peer; struct listnode *peer_listnode; + if (!vrf && bgp->vrf_id != VRF_DEFAULT) + continue; + if (vrf && bgp->vrf_id != vrf->vrf_id) + continue; + for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { afi_t afi; safi_t safi; @@ -542,21 +757,49 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), const struct pfx_record rec, const bool added __attribute__((unused))) { - if (is_stopping() || - atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) + struct rpki_vrf *rpki_vrf; + const char *msg; + const struct rtr_socket *rtr = rec.socket; + const char *ident; + + if (!rtr) { + msg = "could not find rtr_socket from cb_sync_rtr"; + goto err; + } + if (!rtr->tr_socket) { + msg = "could not find tr_socket from cb_sync_rtr"; + goto err; + } + ident = rtr->tr_socket->ident_fp(rtr->tr_socket->socket); + if (!ident) { + msg = "could not find ident from cb_sync_rtr"; + goto err; + } + rpki_vrf = find_rpki_vrf_from_ident(ident); + if (!rpki_vrf) { + msg = "could not find rpki_vrf"; + goto err; + } + + if (is_stopping(rpki_vrf) || + atomic_load_explicit(&rpki_vrf->rtr_update_overflow, + memory_order_seq_cst)) return; - int retval = - write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record)); + int retval = write(rpki_vrf->rpki_sync_socket_rtr, &rec, + sizeof(struct pfx_record)); if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) - atomic_store_explicit(&rtr_update_overflow, 1, + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 1, memory_order_seq_cst); else if (retval != sizeof(struct pfx_record)) RPKI_DEBUG("Could not write to rpki_sync_socket_rtr"); + return; +err: + zlog_err("RPKI: %s", msg); } -static void rpki_init_sync_socket(void) +static void rpki_init_sync_socket(struct rpki_vrf *rpki_vrf) { int fds[2]; const char *msg; @@ -566,22 +809,22 @@ static void rpki_init_sync_socket(void) msg = "could not open rpki sync socketpair"; goto err; } - rpki_sync_socket_rtr = fds[0]; - rpki_sync_socket_bgpd = fds[1]; + rpki_vrf->rpki_sync_socket_rtr = fds[0]; + rpki_vrf->rpki_sync_socket_bgpd = fds[1]; - if (set_nonblocking(rpki_sync_socket_rtr) != 0) { + if (set_nonblocking(rpki_vrf->rpki_sync_socket_rtr) != 0) { msg = "could not set rpki_sync_socket_rtr to non blocking"; goto err; } - if (set_nonblocking(rpki_sync_socket_bgpd) != 0) { + if (set_nonblocking(rpki_vrf->rpki_sync_socket_bgpd) != 0) { msg = "could not set rpki_sync_socket_bgpd to non blocking"; goto err; } - event_add_read(bm->master, bgpd_sync_callback, NULL, - rpki_sync_socket_bgpd, NULL); + event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, + rpki_vrf->rpki_sync_socket_bgpd, NULL); return; @@ -591,139 +834,195 @@ static void rpki_init_sync_socket(void) } +static struct rpki_vrf *bgp_rpki_allocate(const char *vrfname) +{ + struct rpki_vrf *rpki_vrf; + + /* initialise default vrf cache list */ + rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct rpki_vrf)); + + rpki_vrf->cache_list = list_new(); + rpki_vrf->cache_list->del = (void (*)(void *)) & free_cache; + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; + rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; + + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) + rpki_vrf->vrfname = XSTRDUP(MTYPE_BGP_RPKI_CACHE, vrfname); + QOBJ_REG(rpki_vrf, rpki_vrf); + listnode_add(rpki_vrf_list, rpki_vrf); + + return rpki_vrf; +} + static int bgp_rpki_init(struct event_loop *master) { - rpki_debug = false; - rtr_is_running = false; - rtr_is_stopping = false; - rtr_is_synced = false; + rpki_debug_conf = false; + rpki_debug_term = false; - cache_list = list_new(); - cache_list->del = (void (*)(void *)) & free_cache; + rpki_vrf_list = list_new(); - polling_period = POLLING_PERIOD_DEFAULT; - expire_interval = EXPIRE_INTERVAL_DEFAULT; - retry_interval = RETRY_INTERVAL_DEFAULT; install_cli_commands(); - rpki_init_sync_socket(); + return 0; } static int bgp_rpki_fini(void) { - stop(); - list_delete(&cache_list); + struct listnode *node, *nnode; + struct rpki_vrf *rpki_vrf; + + for (ALL_LIST_ELEMENTS(rpki_vrf_list, node, nnode, rpki_vrf)) { + stop(rpki_vrf); + list_delete(&rpki_vrf->cache_list); - close(rpki_sync_socket_rtr); - close(rpki_sync_socket_bgpd); + close(rpki_vrf->rpki_sync_socket_rtr); + close(rpki_vrf->rpki_sync_socket_bgpd); + + listnode_delete(rpki_vrf_list, rpki_vrf); + QOBJ_UNREG(rpki_vrf); + if (rpki_vrf->vrfname) + XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf->vrfname); + XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf); + } return 0; } static int bgp_rpki_module_init(void) { + pthread_key_create(&rpki_pthread, NULL); + lrtr_set_alloc_functions(malloc_wrapper, realloc_wrapper, free_wrapper); hook_register(bgp_rpki_prefix_status, rpki_validate_prefix); hook_register(frr_late_init, bgp_rpki_init); hook_register(frr_early_fini, bgp_rpki_fini); + hook_register(bgp_hook_config_write_debug, &bgp_rpki_write_debug); + hook_register(bgp_hook_vrf_update, &bgp_rpki_vrf_update); + hook_register(bgp_hook_config_write_vrf, &bgp_rpki_hook_write_vrf); return 0; } static void sync_expired(struct event *thread) { - if (!rtr_mgr_conf_in_sync(rtr_config)) { + struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); + + if (!rtr_mgr_conf_in_sync(rpki_vrf->rtr_config)) { RPKI_DEBUG("rtr_mgr is not synced, retrying."); - event_add_timer(bm->master, sync_expired, NULL, + event_add_timer(bm->master, sync_expired, rpki_vrf, BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT, - &t_rpki_sync); + &rpki_vrf->t_rpki_sync); return; } RPKI_DEBUG("rtr_mgr sync is done."); - rtr_is_synced = true; + rpki_vrf->rtr_is_synced = true; } -static int start(void) +static int start(struct rpki_vrf *rpki_vrf) { + struct list *cache_list = NULL; + struct vrf *vrf; int ret; - rtr_is_stopping = false; - rtr_is_synced = false; - rtr_update_overflow = 0; + rpki_vrf->rtr_is_stopping = false; + rpki_vrf->rtr_is_synced = false; + rpki_vrf->rtr_update_overflow = 0; + cache_list = rpki_vrf->cache_list; + rpki_vrf->rtr_update_overflow = 0; - if (list_isempty(cache_list)) { + if (!cache_list || list_isempty(cache_list)) { RPKI_DEBUG( "No caches were found in config. Prefix validation is off."); return ERROR; } - RPKI_DEBUG("Init rtr_mgr."); + + if (rpki_vrf->vrfname) + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { + RPKI_DEBUG("VRF %s not present or disabled", rpki_vrf->vrfname); + return ERROR; + } + + RPKI_DEBUG("Init rtr_mgr (%s).", vrf->name); int groups_len = listcount(cache_list); - struct rtr_mgr_group *groups = get_groups(); + struct rtr_mgr_group *groups = get_groups(rpki_vrf->cache_list); - RPKI_DEBUG("Polling period: %d", polling_period); - ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period, - expire_interval, retry_interval, - rpki_update_cb_sync_rtr, NULL, NULL, NULL); + RPKI_DEBUG("Polling period: %d", rpki_vrf->polling_period); + ret = rtr_mgr_init(&rpki_vrf->rtr_config, groups, groups_len, + rpki_vrf->polling_period, rpki_vrf->expire_interval, + rpki_vrf->retry_interval, rpki_update_cb_sync_rtr, + NULL, NULL, NULL); if (ret == RTR_ERROR) { - RPKI_DEBUG("Init rtr_mgr failed."); + RPKI_DEBUG("Init rtr_mgr failed (%s).", vrf->name); return ERROR; } - RPKI_DEBUG("Starting rtr_mgr."); - ret = rtr_mgr_start(rtr_config); + RPKI_DEBUG("Starting rtr_mgr (%s).", vrf->name); + ret = rtr_mgr_start(rpki_vrf->rtr_config); if (ret == RTR_ERROR) { - RPKI_DEBUG("Starting rtr_mgr failed."); - rtr_mgr_free(rtr_config); + RPKI_DEBUG("Starting rtr_mgr failed (%s).", vrf->name); + rtr_mgr_free(rpki_vrf->rtr_config); return ERROR; } - event_add_timer(bm->master, sync_expired, NULL, 0, &t_rpki_sync); + event_add_timer(bm->master, sync_expired, rpki_vrf, 0, + &rpki_vrf->t_rpki_sync); XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups); - rtr_is_running = true; + rpki_vrf->rtr_is_running = true; return SUCCESS; } -static void stop(void) +static void stop(struct rpki_vrf *rpki_vrf) { - rtr_is_stopping = true; - if (is_running()) { - EVENT_OFF(t_rpki_sync); - rtr_mgr_stop(rtr_config); - rtr_mgr_free(rtr_config); - rtr_is_running = false; + rpki_vrf->rtr_is_stopping = true; + if (is_running(rpki_vrf)) { + EVENT_OFF(rpki_vrf->t_rpki_sync); + rtr_mgr_stop(rpki_vrf->rtr_config); + rtr_mgr_free(rpki_vrf->rtr_config); + rpki_vrf->rtr_is_running = false; } } -static int reset(bool force) +static int reset(bool force, struct rpki_vrf *rpki_vrf) { - if (is_running() && !force) + if (is_running(rpki_vrf) && !force) return SUCCESS; RPKI_DEBUG("Resetting RPKI Session"); - stop(); - return start(); + stop(rpki_vrf); + return start(rpki_vrf); } -static struct rtr_mgr_group *get_connected_group(void) +static struct rtr_mgr_group *get_connected_group(struct rpki_vrf *rpki_vrf) { + struct list *cache_list; + + if (!rpki_vrf) + return NULL; + + cache_list = rpki_vrf->cache_list; if (!cache_list || list_isempty(cache_list)) return NULL; - return rtr_mgr_get_first_group(rtr_config); + return rtr_mgr_get_first_group(rpki_vrf->rtr_config); } static void print_prefix_table_by_asn(struct vty *vty, as_t as, + struct rpki_vrf *rpki_vrf, json_object *json) { unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0; - struct rtr_mgr_group *group = get_connected_group(); + struct rtr_mgr_group *group = get_connected_group(rpki_vrf); struct rpki_for_each_record_arg arg; json_object *json_records = NULL; @@ -732,8 +1031,14 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as, arg.json = NULL; arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT)); + if (!rpki_vrf) + return; + if (!group) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Cannot find a connected group."); + vty_json(vty, json); + } else vty_out(vty, "Cannot find a connected group.\n"); return; } @@ -772,42 +1077,58 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as, vty_json(vty, json); } -static void print_prefix_table(struct vty *vty, json_object *json) +static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf, + json_object *json, bool count_only) { struct rpki_for_each_record_arg arg; unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0; - struct rtr_mgr_group *group = get_connected_group(); + struct rtr_mgr_group *group; json_object *json_records = NULL; + if (!rpki_vrf) + return; + + group = get_connected_group(rpki_vrf); arg.vty = vty; arg.json = NULL; arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT)); if (!group) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Cannot find a connected group."); + vty_json(vty, json); + } else vty_out(vty, "Cannot find a connected group.\n"); return; } struct pfx_table *pfx_table = group->sockets[0]->pfx_table; - if (!json) { - vty_out(vty, "RPKI/RTR prefix table\n"); - vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", - "Origin-AS"); - } else { - json_records = json_object_new_array(); - json_object_object_add(json, "prefixes", json_records); - arg.json = json_records; + if (!count_only) { + if (!json) { + vty_out(vty, "RPKI/RTR prefix table\n"); + vty_out(vty, "%-40s %s %s\n", "Prefix", + "Prefix Length", "Origin-AS"); + } else { + json_records = json_object_new_array(); + json_object_object_add(json, "prefixes", json_records); + arg.json = json_records; + } } arg.prefix_amount = &number_of_ipv4_prefixes; - pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); + if (count_only) + pfx_table_for_each_ipv4_record(pfx_table, count_record_cb, &arg); + else + pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); arg.prefix_amount = &number_of_ipv6_prefixes; - pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); + if (count_only) + pfx_table_for_each_ipv6_record(pfx_table, count_record_cb, &arg); + else + pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); if (!json) { vty_out(vty, "Number of IPv4 Prefixes: %u\n", @@ -832,8 +1153,25 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, as_t as_number = 0; struct lrtr_ip_addr ip_addr_prefix; enum pfxv_state result; + struct bgp *bgp = peer->bgp; + struct vrf *vrf; + struct rpki_vrf *rpki_vrf; + + if (!bgp) + return 0; + + vrf = vrf_lookup_by_id(bgp->vrf_id); + if (!vrf) + return 0; + + if (vrf->vrf_id == VRF_DEFAULT) + rpki_vrf = find_rpki_vrf(NULL); + else + rpki_vrf = find_rpki_vrf(vrf->name); + if (!rpki_vrf || !is_synchronized(rpki_vrf)) + return 0; - if (!is_synchronized()) + if (!is_synchronized(rpki_vrf)) return RPKI_NOT_BEING_USED; // No aspath means route comes from iBGP @@ -878,7 +1216,7 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, } // Do the actual validation - rtr_mgr_validate(rtr_config, as_number, &ip_addr_prefix, + rtr_mgr_validate(rpki_vrf->rtr_config, as_number, &ip_addr_prefix, prefix->prefixlen, &result); // Print Debug output @@ -911,15 +1249,26 @@ static int add_cache(struct cache *cache) { uint8_t preference = cache->preference; struct rtr_mgr_group group; + struct list *cache_list; + struct rpki_vrf *rpki_vrf; + + rpki_vrf = cache->rpki_vrf; + if (!rpki_vrf) + return ERROR; group.preference = preference; group.sockets_len = 1; group.sockets = &cache->rtr_socket; - if (is_running()) { + cache_list = rpki_vrf->cache_list; + if (!cache_list) + return ERROR; + + if (is_running(rpki_vrf)) { init_tr_socket(cache); - if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) { + if (rtr_mgr_add_group(rpki_vrf->rtr_config, &group) != + RTR_SUCCESS) { free_tr_socket(cache); return ERROR; } @@ -930,8 +1279,165 @@ static int add_cache(struct cache *cache) return SUCCESS; } -static int add_tcp_cache(const char *host, const char *port, - const uint8_t preference, const char *bindaddr) +static int rpki_create_socket(void *_cache) +{ + struct timeval prev_snd_tmout, prev_rcv_tmout, timeout; + struct cache *cache = (struct cache *)_cache; + struct rpki_vrf *rpki_vrf; + struct tr_tcp_config *tcp_config; + struct addrinfo *res = NULL; + struct addrinfo hints = {}; + socklen_t optlen; + char *host, *port; + struct vrf *vrf; + int cancel_state; + int socket; + int ret; +#if defined(FOUND_SSH) + struct tr_ssh_config *ssh_config; + char s_port[10]; +#endif + + if (!cache) + return -1; + + rpki_vrf = cache->rpki_vrf; + + /* + * the rpki infrastructure can call this function + * multiple times per pthread. Why? I have absolutely + * no idea, and I am not sure I care a whole bunch. + * Why does this matter? Well when we attempt to + * hook this pthread into the rcu structure multiple + * times the rcu code asserts on shutdown. Clearly + * upset that you have rcu data associated with a pthread + * that has not been cleaned up. And frankly this is rightly so. + * + * At this point we know that this function is not + * called a million bajillion times so let's just + * add a bit of insurance by looking to see if + * some thread specific code has been set for this + * pthread. If not, hook into the rcu code and + * make things happy. + * + * IF YOU PUT A ZLOG_XXXX prior to the call into + * frr_pthread_non_controlled_startup in this function + * BGP WILL CRASH. You have been warned. + */ + if (!pthread_getspecific(rpki_pthread) && + frr_pthread_non_controlled_startup(cache->rtr_socket->thread_id, + "RPKI RTRLIB socket", + "rpki_create_socket") < 0) + return -1; + + pthread_setspecific(rpki_pthread, &rpki_pthread); + + if (rpki_vrf->vrfname == NULL) + vrf = vrf_lookup_by_id(VRF_DEFAULT); + else + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) + return -1; + + if (!CHECK_FLAG(vrf->status, VRF_ACTIVE) || vrf->vrf_id == VRF_UNKNOWN) + return -1; + + if (cache->type == TCP) { + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + + tcp_config = cache->tr_config.tcp_config; + host = tcp_config->host; + port = tcp_config->port; + } +#if defined(FOUND_SSH) + else { + ssh_config = cache->tr_config.ssh_config; + host = ssh_config->host; + snprintf(s_port, sizeof(s_port), "%u", ssh_config->port); + port = s_port; + + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + } +#endif + + frr_with_privs (&bgpd_privs) { + ret = vrf_getaddrinfo(host, port, &hints, &res, vrf->vrf_id); + } + if (ret != 0) { + flog_err_sys(EC_LIB_SOCKET, "getaddrinfo: %s", + gai_strerror(ret)); + return -1; + } + + frr_with_privs (&bgpd_privs) { + socket = vrf_socket(res->ai_family, res->ai_socktype, + res->ai_protocol, vrf->vrf_id, NULL); + } + if (socket < 0) { + freeaddrinfo(res); + return -1; + } + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancel_state); + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + optlen = sizeof(prev_rcv_tmout); + ret = getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout, + &optlen); + if (ret < 0) + zlog_warn("%s: failed to getsockopt SO_RCVTIMEO for socket %d", + __func__, socket); + ret = getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout, + &optlen); + if (ret < 0) + zlog_warn("%s: failed to getsockopt SO_SNDTIMEO for socket %d", + __func__, socket); + ret = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof(timeout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_RCVTIMEO for socket %d", + __func__, socket); + + ret = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, + sizeof(timeout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_SNDTIMEO for socket %d", + __func__, socket); + + if (connect(socket, res->ai_addr, res->ai_addrlen) == -1) { + freeaddrinfo(res); + close(socket); + pthread_setcancelstate(cancel_state, NULL); + return -1; + } + + freeaddrinfo(res); + pthread_setcancelstate(cancel_state, NULL); + + ret = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout, + sizeof(prev_rcv_tmout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_RCVTIMEO for socket %d", + __func__, socket); + + ret = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout, + sizeof(prev_snd_tmout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_SNDTIMEO for socket %d", + __func__, socket); + + return socket; +} + +static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, + const char *port, const uint8_t preference, + const char *bindaddr) { struct rtr_socket *rtr_socket; struct tr_tcp_config *tcp_config = @@ -948,8 +1454,11 @@ static int add_tcp_cache(const char *host, const char *port, else tcp_config->bindaddr = NULL; + tcp_config->data = cache; + tcp_config->new_socket = rpki_create_socket; rtr_socket = create_rtr_socket(tr_socket); + cache->rpki_vrf = rpki_vrf; cache->type = TCP; cache->tr_socket = tr_socket; cache->tr_config.tcp_config = tcp_config; @@ -958,15 +1467,16 @@ static int add_tcp_cache(const char *host, const char *port, int ret = add_cache(cache); if (ret != SUCCESS) { + tcp_config->data = NULL; free_cache(cache); } - return ret; } #if defined(FOUND_SSH) -static int add_ssh_cache(const char *host, const unsigned int port, - const char *username, const char *client_privkey_path, +static int add_ssh_cache(struct rpki_vrf *rpki_vrf, const char *host, + const unsigned int port, const char *username, + const char *client_privkey_path, const char *server_pubkey_path, const uint8_t preference, const char *bindaddr) { @@ -984,6 +1494,8 @@ static int add_ssh_cache(const char *host, const unsigned int port, ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr); else ssh_config->bindaddr = NULL; + ssh_config->data = cache; + ssh_config->new_socket = rpki_create_socket; ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username); ssh_config->client_privkey_path = @@ -993,6 +1505,7 @@ static int add_ssh_cache(const char *host, const unsigned int port, rtr_socket = create_rtr_socket(tr_socket); + cache->rpki_vrf = rpki_vrf; cache->type = SSH; cache->tr_socket = tr_socket; cache->tr_config.ssh_config = ssh_config; @@ -1001,6 +1514,7 @@ static int add_ssh_cache(const char *host, const unsigned int port, int ret = add_cache(cache); if (ret != SUCCESS) { + ssh_config->data = NULL; free_cache(cache); } @@ -1036,25 +1550,72 @@ static void free_cache(struct cache *cache) XFREE(MTYPE_BGP_RPKI_CACHE, cache); } -static int config_write(struct vty *vty) +static int bgp_rpki_write_debug(struct vty *vty, bool running) { - struct listnode *cache_node; - struct cache *cache; - - if (rpki_debug) + if (rpki_debug_conf && running) { vty_out(vty, "debug rpki\n"); + return 1; + } + if ((rpki_debug_conf || rpki_debug_term) && !running) { + vty_out(vty, " BGP RPKI debugging is on\n"); + return 1; + } + return 0; +} - vty_out(vty, "!\n"); - vty_out(vty, "rpki\n"); +static int bgp_rpki_hook_write_vrf(struct vty *vty, struct vrf *vrf) +{ + int ret; - if (polling_period != POLLING_PERIOD_DEFAULT) - vty_out(vty, " rpki polling_period %d\n", polling_period); - if (retry_interval != RETRY_INTERVAL_DEFAULT) - vty_out(vty, " rpki retry_interval %d\n", retry_interval); - if (expire_interval != EXPIRE_INTERVAL_DEFAULT) - vty_out(vty, " rpki expire_interval %d\n", expire_interval); + ret = bgp_rpki_write_vrf(vty, vrf); + if (ret == ERROR) + return 0; + return ret; +} - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { +static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) +{ + struct listnode *cache_node; + struct cache *cache; + struct rpki_vrf *rpki_vrf = NULL; + char sep[STR_SEPARATOR]; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (!vrf) { + rpki_vrf = find_rpki_vrf(NULL); + snprintf(sep, sizeof(sep), "%s", ""); + } else if (vrf->vrf_id != VRF_DEFAULT) { + rpki_vrf = find_rpki_vrf(vrf->name); + snprintf(sep, sizeof(sep), "%s", " "); + vrf_id = vrf->vrf_id; + } else + return ERROR; + + if (!rpki_vrf) + return ERROR; + + if (rpki_vrf->cache_list && list_isempty(rpki_vrf->cache_list) && + rpki_vrf->polling_period == POLLING_PERIOD_DEFAULT && + rpki_vrf->retry_interval == RETRY_INTERVAL_DEFAULT && + rpki_vrf->expire_interval == EXPIRE_INTERVAL_DEFAULT) + /* do not display the default config values */ + return 0; + + if (vrf_id == VRF_DEFAULT) + vty_out(vty, "%s!\n", sep); + vty_out(vty, "%srpki\n", sep); + + if (rpki_vrf->polling_period != POLLING_PERIOD_DEFAULT) + vty_out(vty, "%s rpki polling_period %d\n", sep, + rpki_vrf->polling_period); + if (rpki_vrf->retry_interval != RETRY_INTERVAL_DEFAULT) + vty_out(vty, "%s rpki retry_interval %d\n", sep, + rpki_vrf->retry_interval); + if (rpki_vrf->expire_interval != EXPIRE_INTERVAL_DEFAULT) + vty_out(vty, "%s rpki expire_interval %d\n", sep, + rpki_vrf->expire_interval); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; #if defined(FOUND_SSH) @@ -1062,8 +1623,8 @@ static int config_write(struct vty *vty) #endif case TCP: tcp_config = cache->tr_config.tcp_config; - vty_out(vty, " rpki cache %s %s ", tcp_config->host, - tcp_config->port); + vty_out(vty, "%s rpki cache tcp %s %s ", sep, + tcp_config->host, tcp_config->port); if (tcp_config->bindaddr) vty_out(vty, "source %s ", tcp_config->bindaddr); @@ -1071,13 +1632,13 @@ static int config_write(struct vty *vty) #if defined(FOUND_SSH) case SSH: ssh_config = cache->tr_config.ssh_config; - vty_out(vty, " rpki cache %s %u %s %s %s ", + vty_out(vty, "%s rpki cache ssh %s %u %s %s %s ", sep, ssh_config->host, ssh_config->port, ssh_config->username, ssh_config->client_privkey_path, ssh_config->server_hostkey_path != NULL ? ssh_config->server_hostkey_path - : " "); + : ""); if (ssh_config->bindaddr) vty_out(vty, "source %s ", ssh_config->bindaddr); @@ -1089,17 +1650,66 @@ static int config_write(struct vty *vty) vty_out(vty, "preference %hhu\n", cache->preference); } - vty_out(vty, "exit\n"); + + vty_out(vty, "%sexit\n%s", sep, vrf_id == VRF_DEFAULT ? "!\n" : ""); return 1; } +static int config_write(struct vty *vty) +{ + return bgp_rpki_write_vrf(vty, NULL); +} + +static struct rpki_vrf *get_rpki_vrf(const char *vrfname) +{ + struct rpki_vrf *rpki_vrf = NULL; + struct vrf *vrf = NULL; + + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) { + vrf = vrf_lookup_by_name(vrfname); + if (!vrf) + return NULL; + rpki_vrf = find_rpki_vrf(vrf->name); + } else + /* default VRF */ + rpki_vrf = find_rpki_vrf(NULL); + + return rpki_vrf; +} + DEFUN_NOSH (rpki, rpki_cmd, "rpki", "Enable rpki and enter rpki configuration mode\n") { - vty->node = RPKI_NODE; + struct rpki_vrf *rpki_vrf; + char *vrfname = NULL; + struct vrf *vrf; + + if (vty->node == CONFIG_NODE) + vty->node = RPKI_NODE; + else { + vrf = VTY_GET_CONTEXT(vrf); + + if (!vrf) + return CMD_WARNING; + + vty->node = RPKI_VRF_NODE; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) { + rpki_vrf = bgp_rpki_allocate(vrfname); + + rpki_init_sync_socket(rpki_vrf); + } + if (vty->node == RPKI_VRF_NODE) + VTY_PUSH_CONTEXT_SUB(vty->node, rpki_vrf); + else + VTY_PUSH_CONTEXT(vty->node, rpki_vrf); return CMD_SUCCESS; } @@ -1109,23 +1719,49 @@ DEFPY (no_rpki, NO_STR "Enable rpki and enter rpki configuration mode\n") { - rpki_delete_all_cache_nodes(); - stop(); + struct rpki_vrf *rpki_vrf; + char *vrfname = NULL; + + if (vty->node == VRF_NODE) { + VTY_DECLVAR_CONTEXT(vrf, vrf); + + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); + + rpki_delete_all_cache_nodes(rpki_vrf); + stop(rpki_vrf); + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; + rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; + return CMD_SUCCESS; } -DEFUN (bgp_rpki_start, +DEFPY (bgp_rpki_start, bgp_rpki_start_cmd, - "rpki start", + "rpki start [vrf NAME$vrfname]", RPKI_OUTPUT_STRING - "start rpki support\n") + "start rpki support\n" + VRF_CMD_HELP_STR) { - if (listcount(cache_list) == 0) + struct list *cache_list = NULL; + struct rpki_vrf *rpki_vrf; + + rpki_vrf = get_rpki_vrf(vrfname); + + if (!rpki_vrf) + return CMD_WARNING; + + cache_list = rpki_vrf->cache_list; + if (!cache_list || listcount(cache_list) == 0) vty_out(vty, "Could not start rpki because no caches are configured\n"); - if (!is_running()) { - if (start() == ERROR) { + if (!is_running(rpki_vrf)) { + if (start(rpki_vrf) == ERROR) { RPKI_DEBUG("RPKI failed to start"); return CMD_WARNING; } @@ -1133,14 +1769,19 @@ DEFUN (bgp_rpki_start, return CMD_SUCCESS; } -DEFUN (bgp_rpki_stop, +DEFPY (bgp_rpki_stop, bgp_rpki_stop_cmd, - "rpki stop", + "rpki stop [vrf NAME$vrfname]", RPKI_OUTPUT_STRING - "start rpki support\n") + "start rpki support\n" + VRF_CMD_HELP_STR) { - if (is_running()) - stop(); + struct rpki_vrf *rpki_vrf; + + rpki_vrf = get_rpki_vrf(vrfname); + + if (rpki_vrf && is_running(rpki_vrf)) + stop(rpki_vrf); return CMD_SUCCESS; } @@ -1152,7 +1793,17 @@ DEFPY (rpki_polling_period, "Set polling period\n" "Polling period value\n") { - polling_period = pp; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + rpki_vrf->polling_period = pp; return CMD_SUCCESS; } @@ -1164,7 +1815,17 @@ DEFUN (no_rpki_polling_period, "Set polling period back to default\n" "Polling period value\n") { - polling_period = POLLING_PERIOD_DEFAULT; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; return CMD_SUCCESS; } @@ -1175,8 +1836,18 @@ DEFPY (rpki_expire_interval, "Set expire interval\n" "Expire interval value\n") { - if ((unsigned int)tmp >= polling_period) { - expire_interval = tmp; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if ((unsigned int)tmp >= rpki_vrf->polling_period) { + rpki_vrf->expire_interval = tmp; return CMD_SUCCESS; } @@ -1192,7 +1863,17 @@ DEFUN (no_rpki_expire_interval, "Set expire interval back to default\n" "Expire interval value\n") { - expire_interval = polling_period * 2; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + rpki_vrf->expire_interval = rpki_vrf->polling_period * 2; return CMD_SUCCESS; } @@ -1203,7 +1884,17 @@ DEFPY (rpki_retry_interval, "Set retry interval\n" "retry interval value\n") { - retry_interval = tmp; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + rpki_vrf->retry_interval = tmp; return CMD_SUCCESS; } @@ -1215,12 +1906,25 @@ DEFUN (no_rpki_retry_interval, "Set retry interval back to default\n" "retry interval value\n") { - retry_interval = RETRY_INTERVAL_DEFAULT; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; return CMD_SUCCESS; } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove rpki_cache_cmd") +#endif DEFPY(rpki_cache, rpki_cache_cmd, - "rpki cache [source $bindaddr] preference (1-255)", + "rpki cache [source $bindaddr] preference (1-255)", RPKI_OUTPUT_STRING "Install a cache server to current group\n" "IP address of cache server\n" @@ -1229,7 +1933,7 @@ DEFPY(rpki_cache, rpki_cache_cmd, "SSH port number\n" "SSH user name\n" "Path to own SSH private key\n" - "Path to Public key of cache server\n" + "Path to the known hosts file\n" "Configure source IP address of RPKI connection\n" "Define a Source IP Address\n" "Preference of the cache server\n" @@ -1238,8 +1942,24 @@ DEFPY(rpki_cache, rpki_cache_cmd, int return_value; struct listnode *cache_node; struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) { + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { if (current_cache->preference == preference) { vty_out(vty, "Cache with preference %ld is already configured\n", @@ -1248,21 +1968,20 @@ DEFPY(rpki_cache, rpki_cache_cmd, } } - // use ssh connection if (ssh_uname) { #if defined(FOUND_SSH) - return_value = - add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey, - server_pubkey, preference, bindaddr_str); + return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, + ssh_privkey, known_hosts_path, + preference, bindaddr_str); #else return_value = SUCCESS; vty_out(vty, "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n"); #endif } else { // use tcp connection - return_value = - add_tcp_cache(cache, tcpport, preference, bindaddr_str); + return_value = add_tcp_cache(rpki_vrf, cache, tcpport, + preference, bindaddr_str); } if (return_value == ERROR) { @@ -1270,39 +1989,179 @@ DEFPY(rpki_cache, rpki_cache_cmd, return CMD_WARNING; } + if (init) + start(rpki_vrf); + + return CMD_SUCCESS; +} + +DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd, + "rpki cache tcp $cache TCPPORT [source $bindaddr] preference (1-255)", + RPKI_OUTPUT_STRING + "Install a cache server to current group\n" + "Use TCP\n" + "IP address of cache server\n" + "Hostname of cache server\n" + "TCP port number\n" + "Configure source IP address of RPKI connection\n" + "Define a Source IP Address\n" + "Preference of the cache server\n" + "Preference value\n") +{ + int return_value; + struct listnode *cache_node; + struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { + if (current_cache->preference == preference) { + vty_out(vty, + "Cache with preference %ld is already configured\n", + preference); + return CMD_WARNING; + } + } + + return_value = add_tcp_cache(rpki_vrf, cache, tcpport, preference, + bindaddr_str); + + if (return_value == ERROR) { + vty_out(vty, "Could not create new rpki cache\n"); + return CMD_WARNING; + } + + if (init) + start(rpki_vrf); + + return CMD_SUCCESS; +} + +DEFPY(rpki_cache_ssh, rpki_cache_ssh_cmd, + "rpki cache ssh $cache (1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH] [source $bindaddr] preference (1-255)", + RPKI_OUTPUT_STRING + "Install a cache server to current group\n" + "Use SSH\n" + "IP address of cache server\n" + "Hostname of cache server\n" + "SSH port number\n" + "SSH user name\n" + "Path to own SSH private key\n" + "Path to the known hosts file\n" + "Configure source IP address of RPKI connection\n" + "Define a Source IP Address\n" + "Preference of the cache server\n" + "Preference value\n") +{ + int return_value; + struct listnode *cache_node; + struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { + if (current_cache->preference == preference) { + vty_out(vty, + "Cache with preference %ld is already configured\n", + preference); + return CMD_WARNING; + } + } + +#if defined(FOUND_SSH) + return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, + ssh_privkey, known_hosts_path, preference, + bindaddr_str); +#else + return_value = SUCCESS; + vty_out(vty, + "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n"); +#endif + + if (return_value == ERROR) { + vty_out(vty, "Could not create new rpki cache\n"); + return CMD_WARNING; + } + + if (init) + start(rpki_vrf); + return CMD_SUCCESS; } DEFPY (no_rpki_cache, no_rpki_cache_cmd, - "no rpki cache [source $bindaddr] preference (1-255)", + "no rpki cache [source $bindaddr] preference (1-255)", NO_STR RPKI_OUTPUT_STRING "Install a cache server to current group\n" + "Use TCP\n" + "Use SSH\n" "IP address of cache server\n" "Hostname of cache server\n" "TCP port number\n" "SSH port number\n" "SSH user name\n" "Path to own SSH private key\n" - "Path to Public key of cache server\n" + "Path to the known hosts file\n" "Configure source IP address of RPKI connection\n" "Define a Source IP Address\n" "Preference of the cache server\n" "Preference value\n") { - struct cache *cache_p = find_cache(preference); + struct cache *cache_p; + struct list *cache_list = NULL; + struct rpki_vrf *rpki_vrf; - if (!cache_p) { + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + cache_list = rpki_vrf->cache_list; + cache_p = find_cache(preference, cache_list); + if (!rpki_vrf || !cache_p) { vty_out(vty, "Could not find cache with preference %ld\n", preference); return CMD_WARNING; } - if (is_running() && listcount(cache_list) == 1) { - stop(); - } else if (is_running()) { - if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) { + if (is_running(rpki_vrf) && listcount(cache_list) == 1) { + stop(rpki_vrf); + } else if (is_running(rpki_vrf)) { + if (rtr_mgr_remove_group(rpki_vrf->rtr_config, preference) == + RTR_ERROR) { vty_out(vty, "Could not remove cache with preference %ld\n", preference); @@ -1318,72 +2177,125 @@ DEFPY (no_rpki_cache, DEFPY (show_rpki_prefix_table, show_rpki_prefix_table_cmd, - "show rpki prefix-table [json$uj]", + "show rpki $prefixkind [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Show validated prefixes which were received from RPKI Cache\n" + "Show prefixes count which were received from RPKI Cache\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; + struct rpki_vrf *rpki_vrf; + + if (uj) + json = json_object_new_object(); - if (!is_synchronized()) { - if (!uj) + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; + } + + if (is_synchronized(rpki_vrf)) { + if (strmatch(prefixkind, "prefix-count")) + print_prefix_table(vty, rpki_vrf, json, true); + else + print_prefix_table(vty, rpki_vrf, json, false); + } else { + if (json) { + json_object_string_add(json, "error", "No Connection to RPKI cache server."); + vty_json(vty, json); + } else vty_out(vty, "No connection to RPKI cache server.\n"); return CMD_WARNING; } - if (uj) - json = json_object_new_object(); - - print_prefix_table(vty, json); return CMD_SUCCESS; } DEFPY (show_rpki_as_number, show_rpki_as_number_cmd, - "show rpki as-number ASNUM$by_asn [json$uj]", + "show rpki as-number <0$zero|ASNUM$by_asn> [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Lookup by ASN in prefix table\n" + "AS Number of 0, see RFC-7607\n" "AS Number\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; + struct rpki_vrf *rpki_vrf; + as_t as; + + if (uj) + json = json_object_new_object(); - if (!is_synchronized()) { - if (!uj) + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; + } + + if (!is_synchronized(rpki_vrf)) { + if (json) { + json_object_string_add(json, "error", "No Connection to RPKI cache server."); + vty_json(vty, json); + } else vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } - if (uj) - json = json_object_new_object(); + if (zero) + as = 0; + else + as = by_asn; - print_prefix_table_by_asn(vty, by_asn, json); + print_prefix_table_by_asn(vty, as, rpki_vrf, json); return CMD_SUCCESS; } DEFPY (show_rpki_prefix, show_rpki_prefix_cmd, - "show rpki prefix [ASNUM$asn] [json$uj]", + "show rpki prefix [0$zero|ASNUM$asn] [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Lookup IP prefix and optionally ASN in prefix table\n" "IPv4 prefix\n" "IPv6 prefix\n" + "AS Number of 0, see RFC-7607\n" "AS Number\n" + VRF_CMD_HELP_STR JSON_STR) { json_object *json = NULL; json_object *json_records = NULL; enum asnotation_mode asnotation; + struct rpki_vrf *rpki_vrf; + as_t as; + + if (uj) + json = json_object_new_object(); - if (!is_synchronized()) { - if (!uj) + rpki_vrf = get_rpki_vrf(vrfname); + + if (!rpki_vrf || !is_synchronized(rpki_vrf)) { + if (json) { + json_object_string_add(json, "error", "No Connection to RPKI cache server."); + vty_json(vty, json); + } else vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } + if (zero) + as = 0; + else + as = asn; + struct lrtr_ip_addr addr; char addr_str[INET6_ADDRSTRLEN]; size_t addr_len = strchr(prefix_str, '/') - prefix_str; @@ -1392,7 +2304,10 @@ DEFPY (show_rpki_prefix, memcpy(addr_str, prefix_str, addr_len); if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Invalid IP prefix."); + vty_json(vty, json); + } else vty_out(vty, "Invalid IP prefix\n"); return CMD_WARNING; } @@ -1401,16 +2316,17 @@ DEFPY (show_rpki_prefix, unsigned int match_count = 0; enum pfxv_state result; - if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, - asn, &addr, prefix->prefixlen, + if (pfx_table_validate_r(rpki_vrf->rtr_config->pfx_table, &matches, + &match_count, as, &addr, prefix->prefixlen, &result) != PFX_SUCCESS) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Prefix lookup failed."); + vty_json(vty, json); + } else vty_out(vty, "Prefix lookup failed\n"); return CMD_WARNING; } - if (uj) - json = json_object_new_object(); if (!json) { vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", @@ -1425,7 +2341,7 @@ DEFPY (show_rpki_prefix, const struct pfx_record *record = &matches[i]; if (record->max_len >= prefix->prefixlen && - ((asn != 0 && (uint32_t)asn == record->asn) || asn == 0)) { + ((as != 0 && (uint32_t)as == record->asn) || asn == 0)) { print_record(&matches[i], vty, json_records, asnotation); } @@ -1439,10 +2355,11 @@ DEFPY (show_rpki_prefix, DEFPY (show_rpki_cache_server, show_rpki_cache_server_cmd, - "show rpki cache-server [json$uj]", + "show rpki cache-server [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Show configured cache server\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; @@ -1450,6 +2367,7 @@ DEFPY (show_rpki_cache_server, struct json_object *json_servers = NULL; struct listnode *cache_node; struct cache *cache; + struct rpki_vrf *rpki_vrf; if (uj) { json = json_object_new_object(); @@ -1457,14 +2375,27 @@ DEFPY (show_rpki_cache_server, json_object_object_add(json, "servers", json_servers); } - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (json) + vty_json(vty, json); + return CMD_SUCCESS; + } + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { if (cache->type == TCP) { if (!json) { vty_out(vty, - "host: %s port: %s, preference: %hhu\n", + "host: %s port: %s, preference: %hhu, protocol: tcp", cache->tr_config.tcp_config->host, cache->tr_config.tcp_config->port, cache->preference); + if (cache->tr_config.tcp_config->bindaddr) + vty_out(vty, ", source: %s\n", + cache->tr_config.tcp_config + ->bindaddr); + else + vty_out(vty, "\n"); } else { json_server = json_object_new_object(); json_object_string_add(json_server, "mode", @@ -1477,6 +2408,12 @@ DEFPY (show_rpki_cache_server, cache->tr_config.tcp_config->port); json_object_int_add(json_server, "preference", cache->preference); + if (cache->tr_config.tcp_config->bindaddr) + json_object_string_add(json_server, + "source", + cache->tr_config + .tcp_config + ->bindaddr); json_object_array_add(json_servers, json_server); } @@ -1485,7 +2422,7 @@ DEFPY (show_rpki_cache_server, } else if (cache->type == SSH) { if (!json) { vty_out(vty, - "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s, preference: %hhu\n", + "host: %s, port: %d, username: %s, server_hostkey_path: %s, client_privkey_path: %s, preference: %hhu, protocol: ssh", cache->tr_config.ssh_config->host, cache->tr_config.ssh_config->port, cache->tr_config.ssh_config->username, @@ -1494,6 +2431,12 @@ DEFPY (show_rpki_cache_server, cache->tr_config.ssh_config ->client_privkey_path, cache->preference); + if (cache->tr_config.ssh_config->bindaddr) + vty_out(vty, ", source: %s\n", + cache->tr_config.ssh_config + ->bindaddr); + else + vty_out(vty, "\n"); } else { json_server = json_object_new_object(); json_object_string_add(json_server, "mode", @@ -1517,6 +2460,12 @@ DEFPY (show_rpki_cache_server, ->client_privkey_path); json_object_int_add(json_server, "preference", cache->preference); + if (cache->tr_config.ssh_config->bindaddr) + json_object_string_add(json_server, + "source", + cache->tr_config + .ssh_config + ->bindaddr); json_object_array_add(json_servers, json_server); } @@ -1532,10 +2481,11 @@ DEFPY (show_rpki_cache_server, DEFPY (show_rpki_cache_connection, show_rpki_cache_connection_cmd, - "show rpki cache-connection [json$uj]", + "show rpki cache-connection [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Show to which RPKI Cache Servers we have a connection\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; @@ -1544,25 +2494,35 @@ DEFPY (show_rpki_cache_connection, struct listnode *cache_node; struct cache *cache; struct rtr_mgr_group *group; + struct rpki_vrf *rpki_vrf; if (uj) json = json_object_new_object(); - if (!is_synchronized()) { - if (!json) - vty_out(vty, "No connection to RPKI cache server.\n"); - else + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (json) vty_json(vty, json); + return CMD_SUCCESS; + } + + if (!is_synchronized(rpki_vrf)) { + if (json) { + json_object_string_add(json, "error", "No connection to RPKI cache server."); + vty_json(vty, json); + } else + vty_out(vty, "No connection to RPKI cache server.\n"); return CMD_SUCCESS; } - group = get_connected_group(); + group = get_connected_group(rpki_vrf); if (!group) { - if (!json) - vty_out(vty, "Cannot find a connected group.\n"); - else + if (json) { + json_object_string_add(json, "error", "Cannot find a connected group."); vty_json(vty, json); + } else + vty_out(vty, "Cannot find a connected group.\n"); return CMD_SUCCESS; } @@ -1575,7 +2535,7 @@ DEFPY (show_rpki_cache_connection, json_object_object_add(json, "connections", json_conns); } - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { struct tr_tcp_config *tcp_config; #if defined(FOUND_SSH) struct tr_ssh_config *ssh_config; @@ -1656,19 +2616,110 @@ DEFPY (show_rpki_cache_connection, return CMD_SUCCESS; } +DEFPY(show_rpki_configuration, show_rpki_configuration_cmd, + "show rpki configuration [vrf NAME$vrfname] [json$uj]", + SHOW_STR RPKI_OUTPUT_STRING + "Show RPKI configuration\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + struct json_object *json = NULL; + struct rpki_vrf *rpki_vrf; + + if (uj) + json = json_object_new_object(); + + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; + } + + if (uj) { + json_object_boolean_add(json, "enabled", + !!listcount(rpki_vrf->cache_list)); + json_object_int_add(json, "serversCount", + listcount(rpki_vrf->cache_list)); + json_object_int_add(json, "pollingPeriodSeconds", + rpki_vrf->polling_period); + json_object_int_add(json, "retryIntervalSeconds", + rpki_vrf->retry_interval); + json_object_int_add(json, "expireIntervalSeconds", + rpki_vrf->expire_interval); + + vty_json(vty, json); + + return CMD_SUCCESS; + } + + vty_out(vty, "rpki is %s", + listcount(rpki_vrf->cache_list) ? "Enabled" : "Disabled"); + + if (list_isempty(rpki_vrf->cache_list)) { + vty_out(vty, "\n"); + return CMD_SUCCESS; + } + + vty_out(vty, " (%d cache servers configured)", + listcount(rpki_vrf->cache_list)); + vty_out(vty, "\n"); + vty_out(vty, "\tpolling period %d\n", rpki_vrf->polling_period); + vty_out(vty, "\tretry interval %d\n", rpki_vrf->retry_interval); + vty_out(vty, "\texpire interval %d\n", rpki_vrf->expire_interval); + + return CMD_SUCCESS; +} + static int config_on_exit(struct vty *vty) { - reset(false); + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + reset(false, rpki_vrf); return 1; } -DEFUN (rpki_reset, +DEFPY(rpki_reset, rpki_reset_cmd, + "rpki reset [vrf NAME$vrfname]", + RPKI_OUTPUT_STRING + "reset rpki\n" + VRF_CMD_HELP_STR) +{ + struct rpki_vrf *rpki_vrf; + + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) + return CMD_WARNING; + + return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; +} + +DEFPY (rpki_reset_config_mode, + rpki_reset_config_mode_cmd, "rpki reset", RPKI_OUTPUT_STRING "reset rpki\n") { - return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; } DEFUN (debug_rpki, @@ -1677,7 +2728,10 @@ DEFUN (debug_rpki, DEBUG_STR "Enable debugging for rpki\n") { - rpki_debug = true; + if (vty->node == CONFIG_NODE) + rpki_debug_conf = true; + else + rpki_debug_term = true; return CMD_SUCCESS; } @@ -1688,7 +2742,10 @@ DEFUN (no_debug_rpki, DEBUG_STR "Disable debugging for rpki\n") { - rpki_debug = false; + if (vty->node == CONFIG_NODE) + rpki_debug_conf = false; + else + rpki_debug_term = false; return CMD_SUCCESS; } @@ -1735,8 +2792,9 @@ static void install_cli_commands(void) // TODO: make config write work install_node(&rpki_node); install_default(RPKI_NODE); + install_node(&rpki_vrf_node); + install_default(RPKI_VRF_NODE); install_element(CONFIG_NODE, &rpki_cmd); - install_element(ENABLE_NODE, &rpki_cmd); install_element(CONFIG_NODE, &no_rpki_cmd); @@ -1745,7 +2803,7 @@ static void install_cli_commands(void) /* Install rpki reset command */ install_element(ENABLE_NODE, &rpki_reset_cmd); - install_element(RPKI_NODE, &rpki_reset_cmd); + install_element(RPKI_NODE, &rpki_reset_config_mode_cmd); /* Install rpki polling period commands */ install_element(RPKI_NODE, &rpki_polling_period_cmd); @@ -1760,15 +2818,42 @@ static void install_cli_commands(void) install_element(RPKI_NODE, &no_rpki_retry_interval_cmd); /* Install rpki cache commands */ + install_element(RPKI_NODE, &rpki_cache_tcp_cmd); + install_element(RPKI_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_NODE, &rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd); + /* RPKI_VRF_NODE commands */ + install_element(VRF_NODE, &rpki_cmd); + install_element(VRF_NODE, &no_rpki_cmd); + /* Install rpki reset command */ + install_element(RPKI_VRF_NODE, &rpki_reset_config_mode_cmd); + + /* Install rpki polling period commands */ + install_element(RPKI_VRF_NODE, &rpki_polling_period_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_polling_period_cmd); + + /* Install rpki expire interval commands */ + install_element(RPKI_VRF_NODE, &rpki_expire_interval_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_expire_interval_cmd); + + /* Install rpki retry interval commands */ + install_element(RPKI_VRF_NODE, &rpki_retry_interval_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_retry_interval_cmd); + + /* Install rpki cache commands */ + install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd); + install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd); + install_element(RPKI_VRF_NODE, &rpki_cache_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); + /* Install show commands */ install_element(VIEW_NODE, &show_rpki_prefix_table_cmd); install_element(VIEW_NODE, &show_rpki_cache_connection_cmd); install_element(VIEW_NODE, &show_rpki_cache_server_cmd); install_element(VIEW_NODE, &show_rpki_prefix_cmd); install_element(VIEW_NODE, &show_rpki_as_number_cmd); + install_element(VIEW_NODE, &show_rpki_configuration_cmd); /* Install debug commands */ install_element(CONFIG_NODE, &debug_rpki_cmd); diff --git a/bgpd/bgp_rpki.h b/bgpd/bgp_rpki.h index de28715d1b16..4f2f87d2efb2 100644 --- a/bgpd/bgp_rpki.h +++ b/bgpd/bgp_rpki.h @@ -8,6 +8,8 @@ #ifndef __BGP_RPKI_H__ #define __BGP_RPKI_H__ +extern struct zebra_privs_t bgpd_privs; + enum rpki_states { RPKI_NOT_BEING_USED, RPKI_VALID, diff --git a/bgpd/bgp_rtc.c b/bgpd/bgp_rtc.c new file mode 100644 index 000000000000..96c8f6de4399 --- /dev/null +++ b/bgpd/bgp_rtc.c @@ -0,0 +1,205 @@ +#include "bgpd/bgp_rtc.h" +#include "bgpd/bgp_debug.h" +#include "bgp_route.h" + +int bgp_nlri_parse_rtc(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, bool withdraw) +{ + uint8_t *pnt = packet->nlri; + uint8_t *lim = packet->nlri + packet->length; + int psize = 0; + /* Iterate over all received prefixes */ + for (; pnt < lim; pnt += psize) { + struct prefix p = {0}; + p.prefixlen = *pnt++; + if (p.prefixlen > BGP_RTC_MAX_PREFIXLEN || p.prefixlen < 32) { + zlog_err("SAFI_RTC parse error. Invalid prefixlen: %u", + p.prefixlen); + return BGP_NLRI_PARSE_ERROR; + } + p.family = AF_RTC; + psize = PSIZE(p.prefixlen); + if (pnt + psize > lim) { + zlog_err("SAFI_RTC parse error."); + return BGP_NLRI_PARSE_ERROR; + } + + /* Mask the value according to the prefixlen */ + for (int j = p.prefixlen; j < psize * 8; j++) { + pnt[j / 8] &= ~(1 << (j % 8)); + } + + p.u.prefix_rtc.origin_as = ntohl(*(uint32_t *)pnt); + + memcpy(&p.u.prefix_rtc.route_target, pnt + 4, psize - 4); + + if (withdraw) { + if (prefix_bgp_rtc_set(peer->host, &p, PREFIX_PERMIT, 0)) { + zlog_info("Withdrawn prefix %pFX is not in RTC prefix-list", + &p); + } + peer->rtc_plist = + prefix_list_get(AFI_IP, 0, 1, peer->host); + bgp_withdraw(peer, &p, 0, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + NULL, 0); + } else { + prefix_bgp_rtc_set(peer->host, &p, PREFIX_PERMIT, 1); + peer->rtc_plist = + prefix_list_get(AFI_IP, 0, 1, peer->host); + bgp_update(peer, &p, 0, attr, packet->afi, packet->safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + NULL, 0, 0, NULL); + } + } + bgp_announce_route(peer, AFI_L2VPN, SAFI_EVPN, false); + return BGP_NLRI_PARSE_OK; +} + +int bgp_rtc_filter(struct peer *peer, struct attr *attr, const struct prefix *p) +{ + struct ecommunity *ecom = bgp_attr_get_ecommunity(attr); + if (ecom == NULL) { + return false; + } + + /* Build prefix to compare with */ + struct prefix cmp; + cmp.family = AF_RTC; + cmp.prefixlen = BGP_RTC_MAX_PREFIXLEN; + cmp.u.prefix_rtc.origin_as = peer->as; + + uint8_t *pnt; + uint8_t sub_type = 0; + for (uint32_t i = 0; i < ecom->size; i++) { + /* Retrieve value field */ + pnt = ecom->val + (i * ecom->unit_size); + + sub_type = *++pnt; + + if (sub_type == ECOMMUNITY_ROUTE_TARGET) { + if (peer->rtc_plist == NULL) { + if (BGP_DEBUG(update, UPDATE_OUT)) { + zlog_debug( + "Filtered prefix %pFX because RTC prefix-list does not exist", p); + } + return true; + } + memcpy(&cmp.u.prefix_rtc.route_target, + ecom->val + (i * ecom->unit_size), + ECOMMUNITY_SIZE); + if (prefix_list_apply_ext(peer->rtc_plist, NULL, &cmp, + true) == PREFIX_DENY) { + if (BGP_DEBUG(update, UPDATE_OUT)) { + zlog_debug( + "Filtered prefix %pFX because of RTC prefix-list", p); + } + return true; + } + } + } + return false; +} + +int bgp_rtc_static_from_str(struct vty *vty, struct bgp *bgp, const char *str, + bool add) +{ + struct ecommunity *ecom = NULL; + int plen = BGP_RTC_MAX_PREFIXLEN; + char *pnt; + char *cp; + + /* Find slash inside string. */ + pnt = strchr(str, '/'); + + /* String doesn't contain slash. */ + if (pnt == NULL) { + ecom = ecommunity_str2com(str, ECOMMUNITY_ROUTE_TARGET, 0); + if (ecom == NULL) { + vty_out(vty, "%% Can't parse ecommunity %s\n", str); + return CMD_WARNING_CONFIG_FAILED; + } + } else { + cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1); + memcpy(cp, str, pnt - str); + *(cp + (pnt - str)) = '\0'; + ecom = ecommunity_str2com(cp, ECOMMUNITY_ROUTE_TARGET, 0); + + XFREE(MTYPE_TMP, cp); + if (ecom == NULL) { + vty_out(vty, "%% Can't parse ecommunity %s\n", str); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get prefix length. */ + plen = (uint8_t)atoi(++pnt); + if (plen > BGP_RTC_MAX_PREFIXLEN) { + ecommunity_free(&ecom); + vty_out(vty, "%% Invalid prefix length %d\n", plen); + return CMD_WARNING_CONFIG_FAILED; + } + } + if (add) + bgp_rtc_add_static(bgp, (struct ecommunity_val *)ecom->val, + plen); + else + bgp_rtc_remove_static(bgp, (struct ecommunity_val *)ecom->val, + plen); + + ecommunity_free(&ecom); + return CMD_SUCCESS; +} + +void bgp_rtc_add_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen) +{ + struct prefix prefix = {0}; + struct bgp_dest *dest; + struct bgp_static *bgp_static; + prefix.family = AF_RTC; + prefix.prefixlen = prefixlen; + prefix.u.prefix_rtc.origin_as = bgp->as; + memcpy(prefix.u.prefix_rtc.route_target, eval, PSIZE(prefixlen) - 4); + dest = bgp_node_get(bgp->route[AFI_IP][SAFI_RTC], &prefix); + + if (bgp_dest_has_bgp_path_info_data(dest)) { + bgp_dest_unlock_node(dest); + } else { + bgp_static = bgp_static_new(); + bgp_static->backdoor = 0; + bgp_static->valid = 0; + bgp_static->igpmetric = 0; + bgp_static->igpnexthop.s_addr = INADDR_ANY; + bgp_static->label = MPLS_INVALID_LABEL; + bgp_static->label_index = BGP_INVALID_LABEL_INDEX; + + bgp_dest_set_bgp_static_info(dest, bgp_static); + + bgp_static->valid = 1; + bgp_static_update(bgp, &prefix, bgp_static, AFI_IP, SAFI_RTC); + } +} + +void bgp_rtc_remove_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen) +{ + struct prefix prefix = {0}; + struct bgp_dest *dest; + struct bgp_static *bgp_static; + prefix.family = AF_RTC; + prefix.prefixlen = prefixlen; + prefix.u.prefix_rtc.origin_as = bgp->as; + memcpy(prefix.u.prefix_rtc.route_target, eval, PSIZE(prefixlen) - 4); + dest = bgp_node_get(bgp->route[AFI_IP][SAFI_RTC], &prefix); + + if (dest) { + bgp_static_withdraw(bgp, &prefix, AFI_IP, SAFI_RTC, NULL); + + bgp_static = bgp_dest_get_bgp_static_info(dest); + if (bgp_static != NULL) + bgp_static_free(bgp_static); + bgp_dest_set_bgp_static_info(dest, NULL); + bgp_dest_unlock_node(dest); + bgp_dest_unlock_node(dest); + } +} \ No newline at end of file diff --git a/bgpd/bgp_rtc.h b/bgpd/bgp_rtc.h new file mode 100644 index 000000000000..3fa0b786e0f7 --- /dev/null +++ b/bgpd/bgp_rtc.h @@ -0,0 +1,23 @@ +#ifndef BGP_RTC_H +#define BGP_RTC_H +#include +#include +#include +#include "bgpd.h" +#include "bgp_attr.h" +#include "bgp_ecommunity.h" +#include "vty.h" +#include "lib/prefix.h" + +#define BGP_RTC_MAX_PREFIXLEN 96 + +extern int bgp_nlri_parse_rtc(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, bool withdraw); +extern int bgp_rtc_filter(struct peer *peer, struct attr *attr, const struct prefix *p); +extern void bgp_rtc_add_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen); +extern void bgp_rtc_remove_static(struct bgp *bgp, struct ecommunity_val *eval, + uint32_t prefixlen); +int bgp_rtc_static_from_str(struct vty *vty, struct bgp *bgp, const char *str, + bool add); +#endif /* BGP_RTC_H */ \ No newline at end of file diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index ce9442c1e020..eff7c5e0f653 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -29,10 +29,115 @@ #include "bgpd/bgp_snmp_bgp4.h" #include "bgpd/bgp_snmp_bgp4v2.h" #include "bgpd/bgp_mplsvpn_snmp.h" +#include "bgpd/bgp_snmp_clippy.c" + + + +static int bgp_cli_snmp_traps_config_write(struct vty *vty); + +DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd, + "[no$no] bgp snmp traps rfc4273", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of rfc4273 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); + return CMD_SUCCESS; +} + +DEFPY(bgp_snmp_traps_rfc4382, bgp_snmp_traps_rfc4382_cmd, + "[no$no] bgp snmp traps rfc4382", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of rfc4382 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; +} + +DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd, + "[no$no] bgp snmp traps bgp4-mibv2", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of BGP4-MIBv2 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2); + return CMD_SUCCESS; +} + +static void bgp_snmp_traps_init(void) +{ + install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd); + install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd); + install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4382_cmd); + + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); + /* BGP4MIBv2 traps are disabled by default */ + + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); +} + +int bgp_cli_snmp_traps_config_write(struct vty *vty) +{ + int write = 0; + + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) { + vty_out(vty, "no bgp snmp traps rfc4273\n"); + write++; + } + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) { + vty_out(vty, "bgp snmp traps bgp4-mibv2\n"); + write++; + } + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + vty_out(vty, "no bgp snmp traps rfc4382\n"); + write++; + } + + return write; +} + +int bgpTrapEstablished(struct peer *peer) +{ + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) + bgp4TrapEstablished(peer); + + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + bgpv2TrapEstablished(peer); + + return 0; +} + +int bgpTrapBackwardTransition(struct peer *peer) +{ + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) + bgp4TrapBackwardTransition(peer); + + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + bgpv2TrapBackwardTransition(peer); + + return 0; +} static int bgp_snmp_init(struct event_loop *tm) { smux_init(tm); + bgp_snmp_traps_init(); bgp_snmp_bgp4_init(tm); bgp_snmp_bgp4v2_init(tm); bgp_mpls_l3vpn_module_init(); @@ -44,6 +149,8 @@ static int bgp_snmp_module_init(void) hook_register(peer_status_changed, bgpTrapEstablished); hook_register(peer_backward_transition, bgpTrapBackwardTransition); hook_register(frr_late_init, bgp_snmp_init); + hook_register(bgp_snmp_traps_config_write, + bgp_cli_snmp_traps_config_write); return 0; } diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h index d324782ae33b..12ec652f8d29 100644 --- a/bgpd/bgp_snmp.h +++ b/bgpd/bgp_snmp.h @@ -15,4 +15,7 @@ #define IPADDRESS ASN_IPADDRESS #define GAUGE32 ASN_UNSIGNED +extern int bgpTrapEstablished(struct peer *peer); +extern int bgpTrapBackwardTransition(struct peer *peer); + #endif /* _FRR_BGP_SNMP_H_ */ diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c index 692e232a83c2..755777c16789 100644 --- a/bgpd/bgp_snmp_bgp4.c +++ b/bgpd/bgp_snmp_bgp4.c @@ -401,7 +401,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], /* Set OID offset for prefix. */ offset = name + v->namelen; oid2in_addr(offset, IN_ADDR_SIZE, &addr->prefix); - offset++; + offset += IN_ADDR_SIZE; /* Prefix length. */ addr->prefixlen = *offset; @@ -497,7 +497,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], offset = name + v->namelen; oid_copy_in_addr(offset, &rn_p->u.prefix4); - offset++; + offset += IN_ADDR_SIZE; *offset = rn_p->prefixlen; offset++; oid_copy_in_addr(offset, @@ -757,7 +757,7 @@ static struct variable bgp_variables[] = { {6, 1, 14}}, }; -int bgpTrapEstablished(struct peer *peer) +int bgp4TrapEstablished(struct peer *peer) { int ret; struct in_addr addr; @@ -782,7 +782,7 @@ int bgpTrapEstablished(struct peer *peer) return 0; } -int bgpTrapBackwardTransition(struct peer *peer) +int bgp4TrapBackwardTransition(struct peer *peer) { int ret; struct in_addr addr; diff --git a/bgpd/bgp_snmp_bgp4.h b/bgpd/bgp_snmp_bgp4.h index ccf00d6b7c7e..67f7cc640bda 100644 --- a/bgpd/bgp_snmp_bgp4.h +++ b/bgpd/bgp_snmp_bgp4.h @@ -69,8 +69,8 @@ #define BGP4PATHATTRBEST 13 #define BGP4PATHATTRUNKNOWN 14 -extern int bgpTrapEstablished(struct peer *peer); -extern int bgpTrapBackwardTransition(struct peer *peer); +extern int bgp4TrapEstablished(struct peer *peer); +extern int bgp4TrapBackwardTransition(struct peer *peer); extern int bgp_snmp_bgp4_init(struct event_loop *tm); #endif /* _FRR_BGP_SNMP_BGP4_H_ */ diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index fb6f13a6ca21..e8c3e6513df1 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -32,6 +32,7 @@ SNMP_LOCAL_VARIABLES static oid bgpv2_oid[] = {BGP4V2MIB}; +static oid bgpv2_trap_oid[] = { BGP4V2MIB, 0 }; static struct in_addr bgp_empty_addr = {}; static struct peer *peer_lookup_all_vrf(struct ipaddr *addr) @@ -339,7 +340,8 @@ static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[], } return SNMP_STRING(""); case BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA: - if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) + if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED && + peer->notify.data) return SNMP_STRING(peer->notify.data); else return SNMP_STRING(""); @@ -435,54 +437,103 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, struct bgp_path_info *path, *min; struct bgp_dest *dest; union sockunion su; - unsigned int len; struct ipaddr paddr = {}; size_t namelen = v ? v->namelen : BGP4V2_NLRI_ENTRY_OFFSET; - sa_family_t family = name[namelen - 1] == 1 ? AF_INET : AF_INET6; - afi_t afi = AFI_IP; - size_t afi_len = IN_ADDR_SIZE; + sa_family_t family; + sa_family_t min_family = 0; /* family of the selected min path */ + afi_t afi; + safi_t safi; + size_t afi_len; + long prefix_type = 0; + long peer_addr_type = 0; + long nrli_index = 1; + long cur_index = 0; + + /* Bgp4V2AddressFamilyIdentifierTC limited to IPv6 */ + if (name[namelen - 1] > IANA_AFI_IPV6) + return NULL; + afi = afi_iana2int(name[namelen - 1]); + afi_len = afi == AFI_IP ? IN_ADDR_SIZE : IN6_ADDR_SIZE; + assert(IS_VALID_AFI(afi)); - if (family == AF_INET6) { - afi = AFI_IP6; - afi_len = IN6_ADDR_SIZE; - } +#define BGP_NLRI_ENTRY_OFFSET namelen +#define BGP4V2_NLRI_V4_V4_OFFSET IN_ADDR_SIZE + IN_ADDR_SIZE + 5 +#define BGP4V2_NLRI_V4_V6_OFFSET IN_ADDR_SIZE + IN6_ADDR_SIZE + 5 +#define BGP4V2_NLRI_V6_V6_OFFSET IN6_ADDR_SIZE + IN6_ADDR_SIZE + 5 -#define BGP_NLRI_ENTRY_OFFSET (afi_len + 1 + afi_len) sockunion_init(&su); if (exact) { - if (*length - namelen != BGP_NLRI_ENTRY_OFFSET) + if (*length - namelen != BGP4V2_NLRI_V4_V4_OFFSET && + *length - namelen != BGP4V2_NLRI_V4_V6_OFFSET && + *length - namelen != BGP4V2_NLRI_V6_V6_OFFSET) return NULL; - /* Set OID offset for prefix */ + /* Set OID offset for prefix type */ offset = name + namelen; - if (family == AF_INET) - oid2in_addr(offset, afi_len, &addr->u.prefix4); - else + + /* Bgp4V2SubsequentAddressFamilyIdentifierTC */ + /* limited to Labeled unicast */ + if (*offset > IANA_SAFI_LABELED_UNICAST) + return NULL; + safi = safi_iana2int(*offset); + offset++; + + /* get bgp4V2NlriPrefixType */ + prefix_type = *offset; + offset++; + + /* get bgp4V2NlriPrefix */ + if (prefix_type == IANA_AFI_IPV4) { + oid2in_addr(offset, IN_ADDR_SIZE, &addr->u.prefix4); + addr->family = AF_INET; + offset += IN_ADDR_SIZE; + } else if (prefix_type == IANA_AFI_IPV6) { oid2in6_addr(offset, &addr->u.prefix6); - offset += afi_len; + addr->family = AF_INET6; + offset += IN6_ADDR_SIZE; + } - /* Prefix length */ + /* get bgp4V2NlriPrefixLen */ addr->prefixlen = *offset; - addr->family = family; + offset++; + + /* get bgp4V2PeerRemoteAddrType */ + peer_addr_type = *offset; + if (peer_addr_type == IANA_AFI_IPV4) + family = AF_INET; + else + family = AF_INET6; offset++; /* Peer address */ su.sin.sin_family = family; - if (family == AF_INET) - oid2in_addr(offset, afi_len, &su.sin.sin_addr); - else + + /* get bgp4V2PeerRemoteAddr*/ + if (family == AF_INET) { + oid2in_addr(offset, IN_ADDR_SIZE, &su.sin.sin_addr); + offset += IN_ADDR_SIZE; + } else { oid2in6_addr(offset, &su.sin6.sin6_addr); + offset += IN6_ADDR_SIZE; + } + + /* bgp4V2NlriIndex */ + nrli_index = *offset; + offset++; /* Lookup node */ - dest = bgp_node_lookup(bgp->rib[afi][SAFI_UNICAST], addr); + dest = bgp_node_lookup(bgp->rib[afi][safi], addr); if (dest) { for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) if (sockunion_same(&path->peer->connection->su, - &su)) - return path; + &su)) { + cur_index++; + if (cur_index == nrli_index) + return path; + } bgp_dest_unlock_node(dest); } @@ -490,120 +541,218 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, return NULL; } + /* Set OID offset for prefix type */ offset = name + namelen; offsetlen = *length - namelen; - len = offsetlen; if (offsetlen == 0) { dest = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); } else { - if (len > afi_len) - len = afi_len; - if (family == AF_INET) - oid2in_addr(offset, len, &addr->u.prefix4); - else - oid2in6_addr(offset, &addr->u.prefix6); + /* bgp4V2NlriAfi is already get */ + /* it is comming from the name parameter */ + + /* get bgp4V2NlriSafi */ + /* Bgp4V2SubsequentAddressFamilyIdentifierTC */ + /* limited to Labeled unicast */ + if (*offset > IANA_SAFI_LABELED_UNICAST) + return NULL; + safi = safi_iana2int(*offset); + offset++; - offset += afi_len; - offsetlen -= afi_len; + /* get bgp4V2NlriPrefixType */ + prefix_type = *offset; + offset++; + /* get bgp4V2NlriPrefix */ + if (prefix_type == IANA_AFI_IPV4) { + oid2in_addr(offset, IN_ADDR_SIZE, &addr->u.prefix4); + addr->family = AF_INET; + offset += IN_ADDR_SIZE; + offsetlen -= IN_ADDR_SIZE; + } else if (prefix_type == IANA_AFI_IPV6) { + oid2in6_addr(offset, &addr->u.prefix6); + addr->family = AF_INET6; + offset += IN6_ADDR_SIZE; + offsetlen -= IN6_ADDR_SIZE; + } + /* get bgp4V2NlriPrefixLen */ if (offsetlen > 0) addr->prefixlen = *offset; else - addr->prefixlen = len * 8; - - addr->family = family; - - dest = bgp_node_get(bgp->rib[afi][SAFI_UNICAST], addr); + addr->prefixlen = afi_len * 8; offset++; offsetlen--; + + /* get node */ + dest = bgp_node_lookup(bgp->rib[afi][safi], addr); } - if (offsetlen > 0) { - len = offsetlen; - if (len > afi_len) - len = afi_len; + if (!dest) + return NULL; - if (family == AF_INET) - oid2in_addr(offset, len, &paddr.ip._v4_addr); + if (offsetlen > 0) { + /* get bgp4V2PeerRemoteAddrType */ + peer_addr_type = *offset; + if (peer_addr_type == IANA_AFI_IPV4) + family = AF_INET; else + family = AF_INET6; + offset++; + + if (family == AF_INET) { + oid2in_addr(offset, IN_ADDR_SIZE, &paddr.ip._v4_addr); + offset += IN_ADDR_SIZE; + } else { oid2in6_addr(offset, &paddr.ip._v6_addr); + offset += IN6_ADDR_SIZE; + } + /* get bgp4V2NlriIndex */ + nrli_index = *offset; + offset++; + } else { - if (family == AF_INET) - memset(&paddr.ip._v4_addr, 0, afi_len); + /* default case start with ipv4*/ + if (afi == AFI_IP) + family = AF_INET; else - memset(&paddr.ip._v6_addr, 0, afi_len); + family = AF_INET6; + memset(&paddr.ip, 0, sizeof(paddr.ip)); + nrli_index = 1; } - if (!dest) - return NULL; - do { min = NULL; + min_family = 0; + cur_index = 0; for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) { sa_family_t path_family = sockunion_family(&path->peer->connection->su); + /* the next addr must be > to the current */ + if (path_family < family) + continue; - if (path_family == AF_INET && + if (family == AF_INET && IPV4_ADDR_CMP(&paddr.ip._v4_addr, &path->peer->connection->su.sin - .sin_addr) < 0) { - if (!min || - (min && - IPV4_ADDR_CMP(&path->peer->connection->su - .sin.sin_addr, - &min->peer->connection->su - .sin.sin_addr) < 0)) + .sin_addr) > 0) + continue; + else if (family == AF_INET6 && + IPV6_ADDR_CMP(&paddr.ip._v6_addr, + &path->peer->connection->su.sin6 + .sin6_addr) > 0) + continue; + + if (family == AF_INET && + IPV4_ADDR_CMP(&paddr.ip._v4_addr, + &path->peer->connection->su.sin + .sin_addr) == 0) { + if (cur_index == nrli_index) { min = path; - } else if (path_family == AF_INET6 && + min_family = family; + nrli_index++; + break; + } + cur_index++; + continue; + } else if (family == AF_INET6 && IPV6_ADDR_CMP(&paddr.ip._v6_addr, &path->peer->connection->su - .sin6.sin6_addr) < 0) { - if (!min || - (min && - IPV6_ADDR_CMP(&path->peer->connection->su - .sin6.sin6_addr, - &min->peer->connection->su - .sin6.sin6_addr) < - 0)) + .sin6.sin6_addr) == 0) { + if (cur_index == nrli_index) { min = path; + min_family = family; + nrli_index++; + break; + } + cur_index++; + continue; + } + + /* first valid path its the min peer addr*/ + if (!min) { + min = path; + min_family = path_family; + continue; + } + + /* consider path < min */ + if (path_family < min_family) { + min = path; + min_family = path_family; + continue; + } + + if (path_family == AF_INET + && IPV4_ADDR_CMP(&path->peer->connection->su.sin.sin_addr, + &min->peer->connection->su.sin.sin_addr) + < 0) { + min = path; + min_family = path_family; + + } else if (path_family == AF_INET6 + && IPV6_ADDR_CMP( + &path->peer->connection->su.sin6.sin6_addr, + &min->peer->connection->su.sin6.sin6_addr) + < 0) { + min = path; + min_family = path_family; } } if (min) { const struct prefix *rn_p = bgp_dest_get_prefix(dest); - *length = namelen + BGP_NLRI_ENTRY_OFFSET; - offset = name + namelen; - /* Encode prefix into OID */ - if (family == AF_INET) + /* encode bgp4V2NlriSafi*/ + *offset = SAFI_UNICAST; + offset++; + /* encode bgp4V2NlriPrefixType into index*/ + /* encode bgp4V2NlriPrefix into index */ + if (rn_p->family == AF_INET) { + *offset = IANA_AFI_IPV4; + offset++; oid_copy_in_addr(offset, &rn_p->u.prefix4); - else + offset += IN_ADDR_SIZE; + } else { + *offset = IANA_AFI_IPV6; + offset++; oid_copy_in6_addr(offset, &rn_p->u.prefix6); - - offset += afi_len; + offset += IN6_ADDR_SIZE; + } + /* encode bgp4V2NlriPrefixLen into index*/ *offset = rn_p->prefixlen; offset++; - /* Encode peer's IP into OID */ - if (family == AF_INET) { + /* Encode bgp4V2PeerRemoteAddrType */ + /* Encode bgp4V2PeerRemoteAddr */ + if (min_family == AF_INET) { + *offset = IANA_AFI_IPV4; + offset++; oid_copy_in_addr(offset, - &min->peer->connection->su.sin - .sin_addr); + &min->peer->connection->su.sin.sin_addr); + offset += IN_ADDR_SIZE; addr->u.prefix4 = rn_p->u.prefix4; } else { - oid_copy_in6_addr(offset, - &min->peer->connection->su - .sin6.sin6_addr); + *offset = IANA_AFI_IPV6; + offset++; + oid_copy_in6_addr( + offset, &min->peer->connection->su.sin6.sin6_addr); + offset += IN6_ADDR_SIZE; addr->u.prefix6 = rn_p->u.prefix6; } + /* Encode bgp4V2NlriIndex*/ + + *offset = nrli_index; + offset++; + + *length = offset - name; + addr->prefixlen = rn_p->prefixlen; addr->family = rn_p->family; @@ -612,10 +761,9 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, return min; } - if (family == AF_INET) - memset(&paddr.ip._v4_addr, 0, afi_len); - else - memset(&paddr.ip._v6_addr, 0, afi_len); + memset(&paddr.ip, 0, sizeof(paddr.ip)); + nrli_index = 1; + } while ((dest = bgp_route_next(dest))); return NULL; @@ -706,7 +854,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_INTEGER(2); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_INTEGER(2); else return SNMP_INTEGER(4); @@ -720,7 +869,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_IP6ADDRESS( path->attr->mp_nexthop_global); else @@ -793,6 +943,37 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], return NULL; } +/* BGP V2 Traps. */ +static struct trap_object bgpv2TrapEstListv4[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1 } } +}; + +static struct trap_object bgpv2TrapEstListv6[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2 } } +}; + +static struct trap_object bgpv2TrapBackListv4[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 1 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 1 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 1 } } +}; + +static struct trap_object bgpv2TrapBackListv6[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 2 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 2 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 2 } } +}; + static struct variable bgpv2_variables[] = { /* bgp4V2PeerEntry */ {BGP4V2_PEER_INSTANCE, @@ -1412,6 +1593,79 @@ static struct variable bgpv2_variables[] = { {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 2}}, }; +int bgpv2TrapEstablished(struct peer *peer) +{ + oid index[sizeof(oid) * IN6_ADDR_SIZE]; + size_t length; + + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + return 0; + + /* Check if this peer just went to Established */ + if ((peer->connection->ostatus != OpenConfirm) || + !(peer_established(peer->connection))) + return 0; + + switch (sockunion_family(&peer->connection->su)) { + case AF_INET: + oid_copy_in_addr(index, &peer->connection->su.sin.sin_addr); + length = IN_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapEstListv4, array_size(bgpv2TrapEstListv4), + BGP4V2ESTABLISHED); + break; + case AF_INET6: + oid_copy_in6_addr(index, &peer->connection->su.sin6.sin6_addr); + length = IN6_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapEstListv6, array_size(bgpv2TrapEstListv6), + BGP4V2ESTABLISHED); + break; + default: + break; + } + + return 0; +} + +int bgpv2TrapBackwardTransition(struct peer *peer) +{ + oid index[sizeof(oid) * IN6_ADDR_SIZE]; + size_t length; + + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + return 0; + + switch (sockunion_family(&peer->connection->su)) { + case AF_INET: + oid_copy_in_addr(index, &peer->connection->su.sin.sin_addr); + length = IN_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapBackListv4, array_size(bgpv2TrapBackListv4), + BGP4V2BACKWARDTRANSITION); + break; + case AF_INET6: + oid_copy_in6_addr(index, &peer->connection->su.sin6.sin6_addr); + length = IN6_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapBackListv6, array_size(bgpv2TrapBackListv6), + BGP4V2BACKWARDTRANSITION); + break; + default: + break; + } + + return 0; +} + int bgp_snmp_bgp4v2_init(struct event_loop *tm) { REGISTER_MIB("mibII/bgpv2", bgpv2_variables, variable, bgpv2_oid); diff --git a/bgpd/bgp_snmp_bgp4v2.h b/bgpd/bgp_snmp_bgp4v2.h index 6587a825c585..ca355338a658 100644 --- a/bgpd/bgp_snmp_bgp4v2.h +++ b/bgpd/bgp_snmp_bgp4v2.h @@ -16,6 +16,14 @@ * offset 1.3.6.1.3.5.1.1.2.1.x.(1|2).(4|16) = 13 * offset 1.3.6.1.4.1.7336.3.2.1.1.2.1.x.1.(1|2) = 16 */ + + +/* bgpTraps */ +#define BGP4V2ESTABLISHED 1 +#define BGP4V2BACKWARDTRANSITION 2 + +/* bgpPeerTable */ + #define BGP4V2_PEER_ENTRY_OFFSET 13 #define BGP4V2_PEER_INSTANCE 1 #define BGP4V2_PEER_LOCAL_ADDR_TYPE 2 @@ -84,5 +92,7 @@ #define BGP4V2_BACKWARD_TRANSITION_NOTIFICATION 2 extern int bgp_snmp_bgp4v2_init(struct event_loop *tm); +extern int bgpv2TrapEstablished(struct peer *peer); +extern int bgpv2TrapBackwardTransition(struct peer *peer); #endif /* _FRR_BGP_SNMP_BGP4V2_H_ */ diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 8465ada99671..781909b65dd7 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -239,7 +239,11 @@ static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea, if (!dest) return bputs(buf, "(null)"); +#if !defined(DEV_BUILD) /* need to get the real length even if buffer too small */ prefix2str(p, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); +#else + return bprintfrr(buf, "%s(%p)", prefix2str(p, cbuf, sizeof(cbuf)), dest); +#endif } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 5b4c3be21224..130f5ca749e5 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -76,6 +76,11 @@ struct bgp_dest { STAILQ_ENTRY(bgp_dest) pq; + struct zebra_announce_item zai; + struct bgp_path_info *za_bgp_pi; + struct bgpevpn *za_vpn; + bool za_is_sync; + uint64_t version; mpls_label_t local_label; @@ -91,12 +96,16 @@ struct bgp_dest { #define BGP_NODE_LABEL_REQUESTED (1 << 7) #define BGP_NODE_SOFT_RECONFIG (1 << 8) #define BGP_NODE_PROCESS_CLEAR (1 << 9) +#define BGP_NODE_SCHEDULE_FOR_INSTALL (1 << 10) +#define BGP_NODE_SCHEDULE_FOR_DELETE (1 << 11) struct bgp_addpath_node_data tx_addpath; enum bgp_path_selection_reason reason; }; +DECLARE_LIST(zebra_announce, struct bgp_dest, zai); + extern void bgp_delete_listnode(struct bgp_dest *dest); /* * bgp_table_iter_t diff --git a/bgpd/bgp_trace.c b/bgpd/bgp_trace.c index 02afbeb46fea..af45e7a9b880 100644 --- a/bgpd/bgp_trace.c +++ b/bgpd/bgp_trace.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index 964393a9f5d1..a77a25e435e1 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -135,11 +135,12 @@ TRACEPOINT_LOGLEVEL(frr_bgp, bmp_mirror_packet, TRACE_INFO) TRACEPOINT_EVENT( frr_bgp, bmp_eor, - TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags), + TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags, uint8_t, peer_type_flag), TP_FIELDS( ctf_integer(afi_t, afi, afi) ctf_integer(safi_t, safi, safi) ctf_integer(uint8_t, flags, flags) + ctf_integer(uint8_t, peer_type_flag, peer_type_flag) ) ) @@ -307,7 +308,8 @@ TRACEPOINT_EVENT( struct in_addr, vtep, esi_t *, esi), TP_FIELDS( ctf_string(action, add ? "add" : "del") - ctf_integer(vni_t, vni, vpn->vni) + ctf_integer(vni_t, vni, (vpn ? vpn->vni : 0)) + ctf_integer(uint32_t, eth_tag, &pfx->prefix.macip_addr.eth_tag) ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac, sizeof(struct ethaddr)) ctf_array(unsigned char, ip, &pfx->prefix.macip_addr.ip, @@ -325,7 +327,7 @@ TRACEPOINT_EVENT( const struct prefix_evpn *, pfx), TP_FIELDS( ctf_string(action, add ? "add" : "del") - ctf_integer(vni_t, vni, vpn->vni) + ctf_integer(vni_t, vni, (vpn ? vpn->vni : 0)) ctf_integer_network_hex(unsigned int, vtep, pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr) ) @@ -434,6 +436,64 @@ TRACEPOINT_EVENT( ) TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_es_evi_del_zrecv, TRACE_INFO) +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_es_evi_vtep_add, + TP_ARGS(esi_t *, esi, vni_t, vni, struct in_addr, vtep, + uint8_t, ead_es), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer(uint8_t, ead_es, ead_es) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_es_evi_vtep_add, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_es_evi_vtep_del, + TP_ARGS(esi_t *, esi, vni_t, vni, struct in_addr, vtep, + uint8_t, ead_es), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer(uint8_t, ead_es, ead_es) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_es_evi_vtep_del, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_ead_es_evi_route_upd, + TP_ARGS(esi_t *, esi, vni_t, vni, + uint8_t, route_type, + struct in_addr, vtep), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer(uint8_t, route_type, route_type) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_ead_es_evi_route_upd, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_ead_es_evi_route_del, + TP_ARGS(esi_t *, esi, vni_t, vni, + uint8_t, route_type, + struct in_addr, vtep), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer(uint8_t, route_type, route_type) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_ead_es_evi_route_del, TRACE_INFO) + TRACEPOINT_EVENT( frr_bgp, evpn_local_vni_add_zrecv, @@ -494,6 +554,34 @@ TRACEPOINT_EVENT( ) TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_macip_del_zrecv, TRACE_INFO) +TRACEPOINT_EVENT( + frr_bgp, + evpn_advertise_type5, + TP_ARGS(vrf_id_t, vrf, const struct prefix_evpn *, pfx, + struct ethaddr *, rmac, struct in_addr, vtep), + TP_FIELDS( + ctf_integer(int, vrf_id, vrf) + ctf_array(unsigned char, ip, &pfx->prefix.prefix_addr.ip, + sizeof(struct ipaddr)) + ctf_array(unsigned char, rmac, rmac, + sizeof(struct ethaddr)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_advertise_type5, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_withdraw_type5, + TP_ARGS(vrf_id_t, vrf, const struct prefix_evpn *, pfx), + TP_FIELDS( + ctf_integer(int, vrf_id, vrf) + ctf_array(unsigned char, ip, &pfx->prefix.prefix_addr.ip, + sizeof(struct ipaddr)) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_withdraw_type5, TRACE_INFO) + TRACEPOINT_EVENT( frr_bgp, evpn_local_l3vni_add_zrecv, diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index a2006c3508d4..6194f15d6a9a 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -128,6 +128,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->bgp = src->bgp; dst->sort = src->sort; + dst->sub_sort = src->sub_sort; dst->as = src->as; dst->v_routeadv = src->v_routeadv; dst->flags = src->flags; @@ -138,17 +139,19 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host); dst->cap = src->cap; + dst->afc[AFI_IP][SAFI_RTC] = src->afc[AFI_IP][SAFI_RTC]; dst->af_cap[afi][safi] = src->af_cap[afi][safi]; dst->afc_nego[afi][safi] = src->afc_nego[afi][safi]; dst->orf_plist[afi][safi] = src->orf_plist[afi][safi]; dst->addpath_type[afi][safi] = src->addpath_type[afi][safi]; dst->addpath_best_selected[afi][safi] = src->addpath_best_selected[afi][safi]; + dst->addpath_paths_limit[afi][safi] = + src->addpath_paths_limit[afi][safi]; dst->local_as = src->local_as; dst->change_local_as = src->change_local_as; dst->shared_network = src->shared_network; dst->local_role = src->local_role; - dst->as_path_loop_detection = src->as_path_loop_detection; if (src->soo[afi][safi]) { ecommunity_free(&dst->soo[afi][safi]); @@ -341,11 +344,19 @@ static unsigned int updgrp_hash_key_make(const void *p) key = 0; - key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ + /* `remote-as auto` technically uses identical peer->sort. + * After OPEN message is parsed, this is updated accordingly, but + * we need to call the peer_sort() here also to properly create + * separate subgroups. + */ + key = jhash_1word(peer_sort((struct peer *)peer), key); + key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key); key = jhash_1word(peer->addpath_best_selected[afi][safi], key); + key = jhash_1word(peer->addpath_paths_limit[afi][safi].receive, key); + key = jhash_1word(peer->addpath_paths_limit[afi][safi].send, key); key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key); key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS), key); @@ -354,9 +365,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word(peer->max_packet_size, key); key = jhash_1word(peer->pmax_out[afi][safi], key); - if (peer->as_path_loop_detection) - key = jhash_2words(peer->as, peer->as_path_loop_detection, key); + if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION)) + key = jhash_2words(peer->as, + CHECK_FLAG(peer->flags, + PEER_FLAG_AS_LOOP_DETECTION), + key); if (peer->group) key = jhash_1word(jhash(peer->group->name, strlen(peer->group->name), SEED1), @@ -425,6 +439,13 @@ static unsigned int updgrp_hash_key_make(const void *p) || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT)) key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2), key); + + if (afi == AFI_L2VPN && safi == SAFI_EVPN && + peer->afc[AFI_IP][SAFI_RTC]) { + key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2), + key); + } + /* * Multiple sessions with the same neighbor should get their own * update-group if they have different roles. @@ -437,7 +458,7 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key); if (peer->soo[afi][safi]) { - char *soo_str = ecommunity_str(peer->soo[afi][safi]); + const char *soo_str = ecommunity_str(peer->soo[afi][safi]); key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key); } @@ -447,19 +468,22 @@ static unsigned int updgrp_hash_key_make(const void *p) * STATEMENT STAYS UP TO DATE */ if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%pBP Update Group Hash: sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju", - peer, peer->sort, - (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS), - (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS)); - zlog_debug( - "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d", - peer, (uint32_t)peer->addpath_type[afi][safi], - CHECK_FLAG(peer->cap, PEER_UPDGRP_CAP_FLAGS), - CHECK_FLAG(peer->af_cap[afi][safi], - PEER_UPDGRP_AF_CAP_FLAGS), - peer->v_routeadv, peer->change_local_as, - peer->as_path_loop_detection); + zlog_debug("%pBP Update Group Hash: sort: %d sub_sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju", + peer, peer->sort, peer->sub_sort, + (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS), + (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS)); + zlog_debug("%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %ju UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d", + peer, (uint32_t)peer->addpath_type[afi][safi], + (intmax_t)CHECK_FLAG(peer->cap, + PEER_UPDGRP_CAP_FLAGS), + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_UPDGRP_AF_CAP_FLAGS), + peer->v_routeadv, peer->change_local_as, + !!CHECK_FLAG(peer->flags, + PEER_FLAG_AS_LOOP_DETECTION)); + zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)", + peer, peer->addpath_paths_limit[afi][safi].send, + peer->addpath_paths_limit[afi][safi].receive); zlog_debug( "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s", peer, peer->max_packet_size, peer->pmax_out[afi][safi], @@ -498,6 +522,10 @@ static unsigned int updgrp_hash_key_make(const void *p) PEER_CAP_ORF_PREFIX_SM_RCV), (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT)); + + zlog_debug("%pBP Update Group Hash: RTC: %u", peer, + peer->afc[AFI_IP][SAFI_RTC]); + zlog_debug( "%pBP Update Group Hash: local role: %u AIGP: %d SOO: %s", peer, peer->local_role, @@ -639,6 +667,11 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) !sockunion_same(&pe1->connection->su, &pe2->connection->su)) return false; + if (afi == AFI_L2VPN && safi == SAFI_EVPN && + (pe1->afc[AFI_IP][SAFI_RTC] != pe2->afc[AFI_IP][SAFI_RTC])) { + return false; + } + return true; } @@ -1698,14 +1731,14 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg) */ UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - subgroup_default_originate(subgrp, 0); + subgroup_default_originate(subgrp, false); } else { /* * This is a explicit withdraw, since the * routemap is not present in routemap lib. need - * to pass 1 for withdraw arg. + * to pass `true` for withdraw arg. */ - subgroup_default_originate(subgrp, 1); + subgroup_default_originate(subgrp, true); } } update_subgroup_set_needs_refresh(subgrp, 0); @@ -1721,18 +1754,6 @@ static int update_group_walkcb(struct hash_bucket *bucket, void *arg) return ret; } -static int update_group_periodic_merge_walkcb(struct update_group *updgrp, - void *arg) -{ - struct update_subgroup *subgrp; - struct update_subgroup *tmp_subgrp; - const char *reason = arg; - - UPDGRP_FOREACH_SUBGRP_SAFE (updgrp, subgrp, tmp_subgrp) - update_subgroup_check_merge(subgrp, reason); - return UPDWALK_CONTINUE; -} - /******************** * PUBLIC FUNCTIONS ********************/ @@ -2071,14 +2092,6 @@ void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx) } } -void update_group_periodic_merge(struct bgp *bgp) -{ - char reason[] = "periodic merge check"; - - update_group_walk(bgp, update_group_periodic_merge_walkcb, - (void *)reason); -} - static int update_group_default_originate_route_map_walkcb(struct update_group *updgrp, void *arg) @@ -2101,7 +2114,7 @@ update_group_default_originate_route_map_walkcb(struct update_group *updgrp, */ UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - subgroup_default_originate(subgrp, 0); + subgroup_default_originate(subgrp, false); } } diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index 0d866f3be7e4..d0fd226d9988 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -40,17 +40,16 @@ (PEER_FLAG_LOCAL_AS_NO_PREPEND | PEER_FLAG_LOCAL_AS_REPLACE_AS) #define PEER_UPDGRP_AF_FLAGS \ - (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY \ - | PEER_FLAG_SEND_LARGE_COMMUNITY \ - | PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT \ - | PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF \ - | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF \ - | PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED \ - | PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS \ - | PEER_FLAG_REMOVE_PRIVATE_AS_ALL \ - | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE \ - | PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE \ - | PEER_FLAG_AS_OVERRIDE) + (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY | \ + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI | PEER_FLAG_SEND_LARGE_COMMUNITY | \ + PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT | \ + PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF | \ + PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF | \ + PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED | \ + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS | \ + PEER_FLAG_REMOVE_PRIVATE_AS_ALL | \ + PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \ + PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | PEER_FLAG_AS_OVERRIDE) #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV) @@ -370,7 +369,6 @@ extern void update_group_policy_update(struct bgp *bgp, extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi, updgrp_walkcb cb, void *ctx); extern void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx); -extern void update_group_periodic_merge(struct bgp *bgp); extern void update_group_refresh_default_originate_route_map(struct event *thread); extern void update_group_start_advtimer(struct bgp *bgp); @@ -428,7 +426,7 @@ extern void subgroup_announce_route(struct update_subgroup *subgrp); extern void subgroup_announce_all(struct update_subgroup *subgrp); extern void subgroup_default_originate(struct update_subgroup *subgrp, - int withdraw); + bool withdraw); extern void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *dest, struct bgp_path_info *pi); @@ -442,7 +440,7 @@ extern struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp, extern void bgp_adj_out_remove_subgroup(struct bgp_dest *dest, struct bgp_adj_out *adj, struct update_subgroup *subgrp); -extern void bgp_adj_out_set_subgroup(struct bgp_dest *dest, +extern bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, struct update_subgroup *subgrp, struct attr *attr, struct bgp_path_info *path); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index ccbb23ebb4d6..250378af6845 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -78,6 +78,8 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_dest *dest, static void adj_free(struct bgp_adj_out *adj) { + bgp_labels_unintern(&adj->labels); + TAILQ_REMOVE(&(adj->subgroup->adjq), adj, subgrp_adj_train); SUBGRP_DECR_STAT(adj->subgroup, adj_count); @@ -97,13 +99,19 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest, enum bgp_path_selection_reason reason; char pfx_buf[PREFIX2STR_BUFFER] = {}; int paths_eq = 0; - int best_path_count = 0; struct list *list = list_new(); struct bgp_path_info *pi = NULL; + uint16_t paths_count = 0; + uint16_t paths_limit = peer->addpath_paths_limit[afi][safi].receive; if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) { - while (best_path_count++ < - peer->addpath_best_selected[afi][safi]) { + paths_limit = + paths_limit + ? MIN(paths_limit, + peer->addpath_best_selected[afi][safi]) + : peer->addpath_best_selected[afi][safi]; + + while (paths_count++ < paths_limit) { struct bgp_path_info *exist = NULL; for (pi = bgp_dest_get_bgp_path_info(dest); pi; @@ -139,8 +147,26 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest, subgroup_process_announce_selected( subgrp, NULL, dest, afi, safi, id); } else { - subgroup_process_announce_selected(subgrp, pi, dest, - afi, safi, id); + /* No Paths-Limit involved */ + if (!paths_limit) { + subgroup_process_announce_selected(subgrp, pi, + dest, afi, + safi, id); + continue; + } + + /* If we have Paths-Limit capability, we MUST + * not send more than the number of paths expected + * by the peer. + */ + if (paths_count++ < paths_limit) + subgroup_process_announce_selected(subgrp, pi, + dest, afi, + safi, id); + else + subgroup_process_announce_selected(subgrp, NULL, + dest, afi, + safi, id); } } @@ -198,9 +224,8 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg) addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); if (BGP_DEBUG(update, UPDATE_OUT)) - zlog_debug("%s: afi=%s, safi=%s, p=%pRN", __func__, - afi2str(afi), safi2str(safi), - bgp_dest_to_rnode(ctx->dest)); + zlog_debug("%s: afi=%s, safi=%s, p=%pBD", __func__, + afi2str(afi), safi2str(safi), ctx->dest); UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { /* @@ -305,15 +330,16 @@ static void subgrp_show_adjq_vty(struct update_subgroup *subgrp, } if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv && adj->adv->baa) { - route_vty_out_tmp( - vty, dest, dest_p, adj->adv->baa->attr, - SUBGRP_SAFI(subgrp), 0, NULL, false); + route_vty_out_tmp(vty, bgp, dest, dest_p, + adj->adv->baa->attr, + SUBGRP_SAFI(subgrp), 0, NULL, + false); output_count++; } if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr) { - route_vty_out_tmp(vty, dest, dest_p, adj->attr, - SUBGRP_SAFI(subgrp), 0, NULL, - false); + route_vty_out_tmp(vty, bgp, dest, dest_p, + adj->attr, SUBGRP_SAFI(subgrp), + 0, NULL, false); output_count++; } } @@ -479,7 +505,7 @@ bgp_advertise_clean_subgroup(struct update_subgroup *subgrp, bgp_advertise_delete(baa, adv); /* Fetch next advertise candidate. */ - next = baa->adv; + next = bgp_advertise_attr_fifo_first(&baa->fifo); /* Unintern BGP advertise attribute. */ bgp_advertise_attr_unintern(subgrp->hash, baa); @@ -497,7 +523,7 @@ bgp_advertise_clean_subgroup(struct update_subgroup *subgrp, return next; } -void bgp_adj_out_set_subgroup(struct bgp_dest *dest, +bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, struct update_subgroup *subgrp, struct attr *attr, struct bgp_path_info *path) { @@ -509,7 +535,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, struct peer *adv_peer; struct peer_af *paf; struct bgp *bgp; - uint32_t attr_hash = attrhash_key_make(attr); + uint32_t attr_hash = 0; peer = SUBGRP_PEER(subgrp); afi = SUBGRP_AFI(subgrp); @@ -517,7 +543,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp = SUBGRP_INST(subgrp); if (DISABLE_BGP_ANNOUNCE) - return; + return false; /* Look for adjacency information. */ adj = adj_lookup( @@ -533,7 +559,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_addpath_id_for_peer(peer, afi, safi, &path->tx_addpath)); if (!adj) - return; + return false; subgrp->pscount++; } @@ -544,9 +570,13 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, * the route wasn't changed actually. * Do not suppress BGP UPDATES for route-refresh. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES) - && !CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) - && adj->attr_hash == attr_hash) { + if (likely(CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES))) + attr_hash = attrhash_key_make(attr); + + if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) && + attr_hash && adj->attr_hash == attr_hash && + bgp_labels_cmp(path->extra ? path->extra->labels : NULL, + adj->labels)) { if (BGP_DEBUG(update, UPDATE_OUT)) { char attr_str[BUFSIZ] = {0}; @@ -572,7 +602,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, * will never be able to coalesce the 3rd peer down */ subgrp->version = MAX(subgrp->version, dest->version); - return; + return false; } if (adj->adv) @@ -588,6 +618,10 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr); adv->adj = adj; adj->attr_hash = attr_hash; + if (path->extra) + adj->labels = bgp_labels_intern(path->extra->labels); + else + adj->labels = NULL; /* Add new advertisement to advertisement attribute list. */ bgp_advertise_add(adv->baa, adv); @@ -620,6 +654,8 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_adv_fifo_add_tail(&subgrp->sync->update, adv); subgrp->version = MAX(subgrp->version, dest->version); + + return true; } /* The only time 'withdraw' will be false is if we are sending @@ -734,7 +770,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp, if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) - subgroup_default_originate(subgrp, 0); + subgroup_default_originate(subgrp, false); subgrp->pscount = 0; SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); @@ -826,11 +862,12 @@ void subgroup_announce_route(struct update_subgroup *subgrp) } } -void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) +void subgroup_default_originate(struct update_subgroup *subgrp, bool withdraw) { struct bgp *bgp; - struct attr attr; + struct attr attr = { 0 }; struct attr *new_attr = &attr; + struct aspath *aspath; struct prefix p; struct peer *from; struct bgp_dest *dest; @@ -868,6 +905,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) /* make coverity happy */ assert(attr.aspath); + aspath = attr.aspath; attr.med = 0; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); @@ -915,8 +953,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) bgp_attr_flush(new_attr); new_attr = bgp_attr_intern( tmp_pi.attr); - bgp_attr_flush(tmp_pi.attr); } + bgp_attr_flush(tmp_pi.attr); subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 @@ -941,7 +979,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) SUBGRP_STATUS_DEFAULT_ORIGINATE))) SET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - withdraw = 1; + withdraw = true; } } @@ -968,18 +1006,19 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) if (dest) { for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { - if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) - if (subgroup_announce_check( - dest, pi, subgrp, - bgp_dest_get_prefix(dest), - &attr, NULL)) { - struct attr *default_attr = - bgp_attr_intern(&attr); - - bgp_adj_out_set_subgroup( - dest, subgrp, - default_attr, pi); - } + if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + continue; + + if (subgroup_announce_check(dest, pi, subgrp, + bgp_dest_get_prefix( + dest), + &attr, NULL)) { + if (!bgp_adj_out_set_subgroup(dest, + subgrp, + &attr, pi)) + bgp_attr_flush(&attr); + } else + bgp_attr_flush(&attr); } bgp_dest_unlock_node(dest); } @@ -1023,7 +1062,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) } } - aspath_unintern(&attr.aspath); + aspath_unintern(&aspath); } /* diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 7502bf2ec6dc..8cd851b9ac5c 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -665,7 +665,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) uint32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL; - uint32_t num_labels = 0; + uint8_t num_labels = 0; if (!subgrp) return NULL; @@ -812,9 +812,12 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) path); label_pnt = &label; num_labels = 1; - } else if (path && path->extra) { - label_pnt = &path->extra->label[0]; - num_labels = path->extra->num_labels; + } else { + num_labels = bgp_path_info_num_labels(path); + label_pnt = + num_labels + ? &path->extra->labels->label[0] + : NULL; } if (stream_empty(snlri)) @@ -858,7 +861,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, label_pnt, num_labels, addpath_capable, addpath_tx_id, - &adv->baa->attr->evpn_overlay, + bgp_attr_get_evpn_overlay( + adv->baa->attr), pfx_buf, sizeof(pfx_buf)); zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", subgrp->update_group->id, subgrp->id, @@ -1081,7 +1085,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, struct bpacket_attr_vec_arr vecarr; bool addpath_capable = false; mpls_label_t label = MPLS_LABEL_IMPLICIT_NULL; - uint32_t num_labels = 0; + uint8_t num_labels = 0; if (DISABLE_BGP_ANNOUNCE) return; diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index 0ed1d04d83ea..2470fb884409 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -30,8 +30,6 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, int rd_header; int header = 1; json_object *json = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; json_object *json_adv = NULL; json_object *json_routes = NULL; char rd_str[BUFSIZ]; @@ -47,21 +45,8 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, } if (use_json) { - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); json = json_object_new_object(); json_adv = json_object_new_object(); - - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "internal", "i"); - - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); } for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; @@ -117,12 +102,6 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, json_object_int_add( json, "localAS", bgp->as); - json_object_object_add(json, - "bgpStatusCodes", - json_scode); - json_object_object_add(json, - "bgpOriginCodes", - json_ocode); } else { vty_out(vty, "BGP table version is 0, local router ID is %pI4\n", @@ -212,7 +191,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, } rd_header = 0; } - route_vty_out_tmp(vty, rm, bgp_dest_get_prefix(rm), + route_vty_out_tmp(vty, bgp, rm, bgp_dest_get_prefix(rm), attr, safi, use_json, json_routes, false); output_count++; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bbe74ef5a712..4711aa7f283b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5,6 +5,10 @@ #include +#ifdef GNU_LINUX +#include //RT_TABLE_XXX +#endif + #include "command.h" #include "lib/json.h" #include "lib/sockopt.h" @@ -61,6 +65,7 @@ #include "bgpd/bgp_mac.h" #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_conditional_adv.h" +#include "bgpd/bgp_rtc.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif @@ -122,12 +127,21 @@ FRR_CFG_DEFAULT_BOOL(BGP_SOFT_VERSION_CAPABILITY, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, ); +FRR_CFG_DEFAULT_BOOL(BGP_DYNAMIC_CAPABILITY, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, +); +FRR_CFG_DEFAULT_BOOL(BGP_ENFORCE_FIRST_AS, + { .val_bool = false, .match_version = "< 9.1", }, + { .val_bool = true }, +); DEFINE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), (bgp, vty)); DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)); DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)); +DEFINE_HOOK(bgp_snmp_traps_config_write, (struct vty * vty), (vty)); static struct peer_group *listen_range_exists(struct bgp *bgp, struct prefix *range, int exact); @@ -168,6 +182,8 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_VPNV4_NODE; case SAFI_FLOWSPEC: return BGP_FLOWSPECV4_NODE; + case SAFI_RTC: + return BGP_RTC_NODE; case SAFI_UNSPEC: case SAFI_ENCAP: case SAFI_EVPN: @@ -188,6 +204,7 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) return BGP_VPNV6_NODE; case SAFI_FLOWSPEC: return BGP_FLOWSPECV6_NODE; + case SAFI_RTC: case SAFI_UNSPEC: case SAFI_ENCAP: case SAFI_EVPN: @@ -223,6 +240,8 @@ static const char *get_afi_safi_vty_str(afi_t afi, safi_t safi) return "IPv4 Encap"; if (safi == SAFI_FLOWSPEC) return "IPv4 Flowspec"; + if (safi == SAFI_RTC) + return "IPv4 RT-Constraint"; } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) return "IPv6 Unicast"; @@ -265,6 +284,8 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi) return "ipv4Encap"; if (safi == SAFI_FLOWSPEC) return "ipv4Flowspec"; + if (safi == SAFI_RTC) + return "ipv4Rtc"; } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) return "ipv6Unicast"; @@ -310,7 +331,7 @@ static int bgp_srv6_locator_unset(struct bgp *bgp) /* refresh functions */ for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } /* refresh tovpn_sid */ @@ -403,6 +424,9 @@ safi_t bgp_node_safi(struct vty *vty) case BGP_FLOWSPECV6_NODE: safi = SAFI_FLOWSPEC; break; + case BGP_RTC_NODE: + safi = SAFI_RTC; + break; default: safi = SAFI_UNICAST; break; @@ -467,6 +491,8 @@ safi_t bgp_vty_safi_from_str(const char *safi_str) safi = SAFI_LABELED_UNICAST; else if (strmatch(safi_str, "flowspec")) safi = SAFI_FLOWSPEC; + else if (strmatch(safi_str, "rt-constraint")) + safi = SAFI_RTC; return safi; } @@ -533,6 +559,8 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) return "ipv4-labeled-unicast"; case SAFI_FLOWSPEC: return "ipv4-flowspec"; + case SAFI_RTC: + return "rt-constraint"; case SAFI_UNSPEC: case SAFI_EVPN: case SAFI_MAX: @@ -553,6 +581,7 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) return "ipv6-labeled-unicast"; case SAFI_FLOWSPEC: return "ipv6-flowspec"; + case SAFI_RTC: case SAFI_UNSPEC: case SAFI_EVPN: case SAFI_MAX: @@ -568,6 +597,7 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: case SAFI_ENCAP: case SAFI_LABELED_UNICAST: + case SAFI_RTC: case SAFI_FLOWSPEC: case SAFI_UNSPEC: case SAFI_MAX: @@ -614,6 +644,11 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, if (DFLT_BGP_SOFT_VERSION_CAPABILITY) SET_FLAG((*bgp)->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY); + if (DFLT_BGP_DYNAMIC_CAPABILITY) + SET_FLAG((*bgp)->flags, + BGP_FLAG_DYNAMIC_CAPABILITY); + if (DFLT_BGP_ENFORCE_FIRST_AS) + SET_FLAG((*bgp)->flags, BGP_FLAG_ENFORCE_FIRST_AS); ret = BGP_SUCCESS; } @@ -1591,8 +1626,9 @@ DEFUN_NOSH (router_bgp, * - update asnotation if explicitly mentioned */ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) { - XFREE(MTYPE_BGP, bgp->as_pretty); - bgp->as_pretty = XSTRDUP(MTYPE_BGP, argv[idx_asn]->arg); + XFREE(MTYPE_BGP_NAME, bgp->as_pretty); + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, + argv[idx_asn]->arg); if (!CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION) && asnotation != ASNOTATION_UNDEFINED) { SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION); @@ -1676,12 +1712,19 @@ DEFUN (no_router_bgp, /* Cannot delete default instance if vrf instances exist */ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { - struct listnode *node; + struct listnode *node, *nnode; struct bgp *tmp_bgp; - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, tmp_bgp)) { if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + + if (CHECK_FLAG(tmp_bgp->vrf_flags, + BGP_VRF_AUTO)) { + bgp_delete(tmp_bgp); + continue; + } + if (CHECK_FLAG( tmp_bgp->af_flags[AFI_IP] [SAFI_UNICAST], @@ -1741,10 +1784,10 @@ DEFPY (bgp_session_dscp, bgp_session_dscp_cmd, "bgp session-dscp (0-63)$dscp", BGP_STR - "Override default (C6) bgp TCP session DSCP value\n" - "Manually configured dscp parameter\n") + "Override default (CS6) DSCP for BGP connections\n" + "Manually configured DSCP value\n") { - bm->tcp_dscp = dscp << 2; + bm->ip_tos = dscp << 2; return CMD_SUCCESS; } @@ -1754,10 +1797,10 @@ DEFPY (no_bgp_session_dscp, "no bgp session-dscp [(0-63)]", NO_STR BGP_STR - "Override default (C6) bgp TCP session DSCP value\n" - "Manually configured dscp parameter\n") + "Override default (CS6) DSCP for BGP connections\n" + "Manually configured DSCP value\n") { - bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL; + bm->ip_tos = IPTOS_PREC_INTERNETCONTROL; return CMD_SUCCESS; } @@ -2244,9 +2287,9 @@ static int bgp_global_update_delay_config_vty(struct vty *vty, * Note that we only need to check this if this is the first time * setting the global config. */ - if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay == BGP_UPDATE_DELAY_DEFAULT) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { - if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "%% update-delay configuration found in vrf %s\n", bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT @@ -2291,7 +2334,7 @@ static int bgp_global_update_delay_deconfig_vty(struct vty *vty) struct listnode *node, *nnode; struct bgp *bgp; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bm->v_establish_wait = bm->v_update_delay; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { @@ -2345,7 +2388,7 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty) "%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n"); return CMD_WARNING_CONFIG_FAILED; } - bgp->v_update_delay = BGP_UPDATE_DELAY_DEF; + bgp->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; bgp->v_establish_wait = bgp->v_update_delay; return CMD_SUCCESS; @@ -2827,6 +2870,23 @@ DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, return CMD_SUCCESS; } +DEFPY(bgp_enforce_first_as, + bgp_enforce_first_as_cmd, + "[no] bgp enforce-first-as", + NO_STR + BGP_STR + "Enforce the first AS for EBGP routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (no) + UNSET_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS); + else + SET_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS); + + return CMD_SUCCESS; +} + DEFPY(bgp_lu_uses_explicit_null, bgp_lu_uses_explicit_null_cmd, "[no] bgp labeled-unicast $value", NO_STR BGP_STR @@ -2888,11 +2948,10 @@ DEFUN(bgp_reject_as_sets, bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return CMD_SUCCESS; @@ -2914,11 +2973,10 @@ DEFUN(no_bgp_reject_as_sets, no_bgp_reject_as_sets_cmd, * with aspath containing AS_SET or AS_CONFED_SET. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + peer->last_reset = PEER_DOWN_AS_SETS_REJECT; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return CMD_SUCCESS; @@ -2983,6 +3041,98 @@ DEFUN (no_bgp_deterministic_med, return CMD_SUCCESS; } +static int bgp_inst_gr_config_vty(struct vty *vty, struct bgp *bgp, bool on, + bool disable) +{ + int ret = BGP_GR_FAILURE; + + /* + * Update the instance and all its peers, if appropriate. + * Then, inform zebra of BGP's GR capabilities, if needed. + */ + if (disable) + ret = bgp_gr_update_all(bgp, on ? GLOBAL_DISABLE_CMD + : NO_GLOBAL_DISABLE_CMD); + else + ret = bgp_gr_update_all(bgp, + on ? GLOBAL_GR_CMD : NO_GLOBAL_GR_CMD); + + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, + ret); + return ret; +} + +static int bgp_global_gr_config_vty(struct vty *vty, bool on, bool disable) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + bool vrf_cfg = false; + int ret = BGP_GR_FAILURE; + + if (disable) { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED))) + return CMD_SUCCESS; + } else { + if ((on && CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) || + (!on && !CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER))) + return CMD_SUCCESS; + } + + /* See if GR is set per-vrf and warn user to delete */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + enum global_mode gr_mode = bgp_global_gr_mode_get(bgp); + + if (gr_mode != GLOBAL_HELPER) { + vty_out(vty, + "%% graceful-restart configuration found in %s, mode %d\n", + bgp->name_pretty, gr_mode); + vrf_cfg = true; + } + } + } + + if (vrf_cfg) { + vty_out(vty, + "%%Failed: global graceful-restart not permitted with per-vrf configuration\n"); + return CMD_WARNING; + } + + /* Set flag globally */ + if (on) { + if (disable) { + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + SET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } else { + SET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + } + } else { + if (disable) + UNSET_FLAG(bm->flags, BM_FLAG_GR_DISABLED); + else + UNSET_FLAG(bm->flags, BM_FLAG_GR_RESTARTER); + } + + /* Initiate processing for all BGP instances. */ + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + ret = bgp_inst_gr_config_vty(vty, bgp, on, disable); + if (ret != BGP_GR_SUCCESS) + vty_out(vty, + "%% Applying global graceful-restart %s config to vrf %s failed, error %d\n", + (disable) ? "disable" : "", + bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT + ? "Default" + : bgp->name, + ret); + } + + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + return bgp_vty_return(vty, ret); +} + /* "bgp graceful-restart mode" configuration. */ DEFUN (bgp_graceful_restart, bgp_graceful_restart_cmd, @@ -2991,22 +3141,18 @@ DEFUN (bgp_graceful_restart, GR_CMD ) { - int ret = BGP_GR_FAILURE; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, false); + int ret = BGP_GR_FAILURE; VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, - ret); + ret = bgp_inst_gr_config_vty(vty, bgp, true, false); + if (ret == BGP_GR_SUCCESS) { + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); return bgp_vty_return(vty, ret); } @@ -3018,22 +3164,20 @@ DEFUN (no_bgp_graceful_restart, NO_GR_CMD ) { - VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, false); + VTY_DECLVAR_CONTEXT(bgp, bgp); int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, - ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); + ret = bgp_inst_gr_config_vty(vty, bgp, false, false); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, + bgp->peer, + ret); + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + } return bgp_vty_return(vty, ret); } @@ -3046,12 +3190,21 @@ DEFUN (bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t stalepath; stalepath = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->stalepath_time = stalepath; + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->stalepath_time = stalepath; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = stalepath; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = stalepath; + } return CMD_SUCCESS; } @@ -3063,20 +3216,32 @@ DEFUN (bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t restart; struct listnode *node, *nnode; struct peer *peer; restart = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->restart_time = restart; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_SET); + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; + bm->restart_time = restart; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->restart_time = restart; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->restart_time = restart; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_SET); + } return CMD_SUCCESS; } @@ -3088,16 +3253,32 @@ DEFUN (bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds, 0 - disable)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_number = 3; uint32_t defer_time; defer_time = strtoul(argv[idx_number]->arg, NULL, 10); - bgp->select_defer_time = defer_time; - if (defer_time == 0) - SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); - else - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + bm->select_defer_time = defer_time; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, + BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = defer_time; + if (defer_time == 0) + SET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + else + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3111,9 +3292,17 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + } return CMD_SUCCESS; } @@ -3126,17 +3315,30 @@ DEFUN (no_bgp_graceful_restart_restart_time, "Set the time to wait to delete stale routes before a BGP open message is received\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); struct listnode *node, *nnode; struct peer *peer; - bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + if (vty->node == CONFIG_NODE) { + struct bgp *bgp; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_UNSET); + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->restart_time = BGP_DEFAULT_RESTART_TIME; + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + } return CMD_SUCCESS; } @@ -3149,10 +3351,21 @@ DEFUN (no_bgp_graceful_restart_select_defer_time, "Set the time to defer the BGP route selection after restart\n" "Delay value (seconds)\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; - bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; - UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + bgp->select_defer_time = + BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + UNSET_FLAG(bgp->flags, BGP_FLAG_SELECT_DEFER_DISABLE); + } return CMD_SUCCESS; } @@ -3164,8 +3377,17 @@ DEFUN (bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Sets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + SET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3177,8 +3399,17 @@ DEFUN (no_bgp_graceful_restart_preserve_fw, "Graceful restart capability parameters\n" "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n") { - VTY_DECLVAR_CONTEXT(bgp, bgp); - UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + if (vty->node == CONFIG_NODE) { + struct listnode *node, *nnode; + struct bgp *bgp; + + UNSET_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD); + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } else { + VTY_DECLVAR_CONTEXT(bgp, bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + } return CMD_SUCCESS; } @@ -3230,24 +3461,29 @@ DEFUN (bgp_graceful_restart_disable, BGP_STR GR_DISABLE) { - int ret = BGP_GR_FAILURE; + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, true, true); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_graceful_restart_disable_cmd : START "); + int ret = BGP_GR_FAILURE; + struct listnode *node, *nnode; + struct peer *peer; VTY_DECLVAR_CONTEXT(bgp, bgp); - ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, ret); + ret = bgp_inst_gr_config_vty(vty, bgp, true, true); + if (ret == BGP_GR_SUCCESS) { + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_graceful_restart_disable_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_LLGR, + CAPABILITY_ACTION_UNSET); + } + } return bgp_vty_return(vty, ret); } @@ -3260,24 +3496,17 @@ DEFUN (no_bgp_graceful_restart_disable, NO_GR_DISABLE ) { - VTY_DECLVAR_CONTEXT(bgp, bgp); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START "); + if (vty->node == CONFIG_NODE) + return bgp_global_gr_config_vty(vty, false, true); + VTY_DECLVAR_CONTEXT(bgp, bgp); int ret = BGP_GR_FAILURE; - ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, - ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); + ret = bgp_inst_gr_config_vty(vty, bgp, false, true); + if (ret == BGP_GR_SUCCESS) { + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + } return bgp_vty_return(vty, ret); } @@ -3292,28 +3521,26 @@ DEFUN (bgp_neighbor_graceful_restart_set, { int idx_peer = 1; struct peer *peer; - int ret = BGP_GR_FAILURE; + int result = BGP_GR_FAILURE, ret = BGP_GR_SUCCESS; VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } - ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); + result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); + if (result == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } return bgp_vty_return(vty, ret); } @@ -3328,7 +3555,7 @@ DEFUN (no_bgp_neighbor_graceful_restart, ) { int idx_peer = 2; - int ret = BGP_GR_FAILURE; + int result = BGP_GR_FAILURE, ret = BGP_GR_SUCCESS; struct peer *peer; VTY_BGP_GR_DEFINE_LOOP_VARIABLE; @@ -3336,23 +3563,21 @@ DEFUN (no_bgp_neighbor_graceful_restart, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START "); - - ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); + result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } - return bgp_vty_return(vty, ret); + return bgp_vty_return(vty, result); } DEFUN (bgp_neighbor_graceful_restart_helper_set, @@ -3369,26 +3594,22 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) return CMD_WARNING_CONFIG_FAILED; - + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } return bgp_vty_return(vty, ret); } @@ -3411,21 +3632,19 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } return bgp_vty_return(vty, ret); } @@ -3444,27 +3663,23 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, VTY_BGP_GR_DEFINE_LOOP_VARIABLE; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START "); - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); + if (ret == BGP_GR_SUCCESS) { + if (peer->bgp->t_startup || bgp_in_graceful_restart()) + bgp_peer_gr_flags_update(peer); - if (peer->bgp->t_startup) - bgp_peer_gr_flags_update(peer); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + } return bgp_vty_return(vty, ret); } @@ -3487,21 +3702,17 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START "); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + vty_out(vty, + "Per peer-group graceful-restart configuration is not yet supported\n"); + return CMD_WARNING_CONFIG_FAILED; + } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + } return bgp_vty_return(vty, ret); } @@ -3517,9 +3728,10 @@ DEFPY (neighbor_graceful_shutdown, afi_t afi; safi_t safi; struct peer *peer; - VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; + VTY_DECLVAR_CONTEXT(bgp, bgp); + peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) return CMD_WARNING_CONFIG_FAILED; @@ -4258,6 +4470,24 @@ DEFPY (bgp_default_software_version_capability, return CMD_SUCCESS; } +DEFPY (bgp_default_dynamic_capability, + bgp_default_dynamic_capability_cmd, + "[no] bgp default dynamic-capability", + NO_STR + BGP_STR + "Configure BGP defaults\n" + "Advertise dynamic capability for all neighbors\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (no) + UNSET_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY); + else + SET_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY); + + return CMD_SUCCESS; +} + /* "bgp network import-check" configuration. */ DEFUN (bgp_network_import_check, bgp_network_import_check_cmd, @@ -4275,6 +4505,9 @@ DEFUN (bgp_network_import_check, return CMD_SUCCESS; } +#if CONFDATE > 20241013 +CPP_NOTICE("Drop `bgp network import-check exact` command") +#endif ALIAS_HIDDEN(bgp_network_import_check, bgp_network_import_check_exact_cmd, "bgp network import-check exact", BGP_STR @@ -4651,7 +4884,7 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; as_t as; - int as_type = AS_SPECIFIED; + enum peer_asn_type as_type = AS_SPECIFIED; union sockunion su; if (as_str[0] == 'i') { @@ -4660,6 +4893,9 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, } else if (as_str[0] == 'e') { as = 0; as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as = 0; + as_type = AS_AUTO; } else if (!asn_str2asn(as_str, &as)) as_type = AS_UNSPECIFIED; @@ -4765,13 +5001,14 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd, DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, - "neighbor remote-as ", + "neighbor remote-as ", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_peer = 1; int idx_remote_as = 3; @@ -4826,7 +5063,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, { VTY_DECLVAR_CONTEXT(bgp, bgp); as_t as = 0; - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; struct peer *peer; struct peer_group *group; int ret = 0; @@ -4843,6 +5080,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, as_type = AS_INTERNAL; } else if (as_str[0] == 'e') { as_type = AS_EXTERNAL; + } else if (as_str[0] == 'a') { + as_type = AS_AUTO; } else { /* Get AS number. */ if (asn_str2asn(as_str, &as)) @@ -4886,12 +5125,13 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if, else peer_flag_unset(peer, PEER_FLAG_IFPEER_V6ONLY); + peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + /* v6only flag changed. Reset bgp seesion */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_V6ONLY_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } @@ -4959,14 +5199,15 @@ DEFUN (neighbor_interface_config_v6only, DEFUN (neighbor_interface_config_remote_as, neighbor_interface_config_remote_as_cmd, - "neighbor WORD interface remote-as ", + "neighbor WORD interface remote-as ", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP on interface\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 4; @@ -4976,7 +5217,7 @@ DEFUN (neighbor_interface_config_remote_as, DEFUN (neighbor_interface_v6only_config_remote_as, neighbor_interface_v6only_config_remote_as_cmd, - "neighbor WORD interface v6only remote-as ", + "neighbor WORD interface v6only remote-as ", NEIGHBOR_STR "Interface name or neighbor tag\n" "Enable BGP with v6 link-local only\n" @@ -4984,7 +5225,8 @@ DEFUN (neighbor_interface_v6only_config_remote_as, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { int idx_word = 1; int idx_remote_as = 5; @@ -5021,14 +5263,15 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor [remote-as <(1-4294967295)|internal|external>]>", + "no neighbor [remote-as <(1-4294967295)|internal|external|auto>]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_peer = 2; @@ -5037,6 +5280,8 @@ DEFUN (no_neighbor, struct peer_group *group; struct peer *peer; struct peer *other; + afi_t afi; + int lr_count; ret = str2sockunion(argv[idx_peer]->arg, &su); if (ret < 0) { @@ -5054,6 +5299,15 @@ DEFUN (no_neighbor, group = peer_group_lookup(bgp, argv[idx_peer]->arg); if (group) { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + lr_count = listcount(group->listen_range[afi]); + if (lr_count) { + vty_out(vty, + "%%Peer-group %s is attached to %d listen-range(s), delete them first\n", + group->name, lr_count); + return CMD_WARNING_CONFIG_FAILED; + } + } peer_group_notify_unconfig(group); peer_group_delete(group); } else { @@ -5088,7 +5342,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", NO_STR NEIGHBOR_STR "Interface name\n" @@ -5099,7 +5353,8 @@ DEFUN (no_neighbor_interface_config, "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -5131,9 +5386,20 @@ DEFUN (no_neighbor_peer_group, VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; struct peer_group *group; + afi_t afi; + int lr_count; group = peer_group_lookup(bgp, argv[idx_word]->arg); if (group) { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + lr_count = listcount(group->listen_range[afi]); + if (lr_count) { + vty_out(vty, + "%%Peer-group %s is attached to %d listen-range(s), delete them first\n", + group->name, lr_count); + return CMD_WARNING_CONFIG_FAILED; + } + } peer_group_notify_unconfig(group); peer_group_delete(group); } else { @@ -5145,14 +5411,15 @@ DEFUN (no_neighbor_peer_group, DEFUN (no_neighbor_interface_peer_group_remote_as, no_neighbor_interface_peer_group_remote_as_cmd, - "no neighbor WORD remote-as ", + "no neighbor WORD remote-as ", NO_STR NEIGHBOR_STR "Interface name or neighbor tag\n" "Specify a BGP neighbor\n" AS_STR "Internal BGP peer\n" - "External BGP peer\n") + "External BGP peer\n" + "Automatically detect remote ASN\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; @@ -5706,6 +5973,37 @@ DEFUN (no_neighbor_dont_capability_negotiate, PEER_FLAG_DONT_CAPABILITY); } +/* neighbor capability fqdn */ +DEFPY (neighbor_capability_fqdn, + neighbor_capability_fqdn_cmd, + "[no$no] neighbor $neighbor capability fqdn", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise fqdn capability to the peer\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + ret = peer_flag_unset_vty(vty, neighbor, + PEER_FLAG_CAPABILITY_FQDN); + else + ret = peer_flag_set_vty(vty, neighbor, + PEER_FLAG_CAPABILITY_FQDN); + + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, CAPABILITY_CODE_FQDN, + no ? CAPABILITY_ACTION_UNSET + : CAPABILITY_ACTION_SET); + + return ret; +} + /* neighbor capability extended next hop encoding */ DEFUN (neighbor_capability_enhe, neighbor_capability_enhe_cmd, @@ -5831,24 +6129,37 @@ DEFUN (neighbor_capability_orf_prefix, struct peer *peer; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (strmatch(argv[idx_send_recv]->text, "send")) - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM); + if (strmatch(argv[idx_send_recv]->text, "send")) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_SET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "receive")) - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "receive")) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_SET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "both")) - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM) - | peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "both")) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) | + peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_SET); + return ret; + } return CMD_WARNING_CONFIG_FAILED; } @@ -5883,24 +6194,37 @@ DEFUN (no_neighbor_capability_orf_prefix, struct peer *peer; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (strmatch(argv[idx_send_recv]->text, "send")) - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM); + if (strmatch(argv[idx_send_recv]->text, "send")) { + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_UNSET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "receive")) - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "receive")) { + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_UNSET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "both")) - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM) - | peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "both")) { + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) | + peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_UNSET); + return ret; + } return CMD_WARNING_CONFIG_FAILED; } @@ -6387,6 +6711,32 @@ ALIAS_HIDDEN( "Send Standard Community attributes\n" "Send Large Community attributes\n") +DEFPY (neighbor_ecommunity_rpki, + neighbor_ecommunity_rpki_cmd, + "[no$no] neighbor $neighbor send-community extended rpki", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n" + "Send Extended Community attributes\n" + "Send RPKI Extended Community attributes\n") +{ + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + return peer_af_flag_unset_vty(vty, neighbor, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); + else + return peer_af_flag_set_vty(vty, neighbor, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); +} + /* neighbor soft-reconfig. */ DEFUN (neighbor_soft_reconfiguration, neighbor_soft_reconfiguration_cmd, @@ -6900,6 +7250,28 @@ DEFPY(no_neighbor_role, return ret; } +DEFPY (neighbor_oad, + neighbor_oad_cmd, + "[no$no] neighbor $neighbor oad", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set peering session type to EBGP-OAD\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + peer->sub_sort = 0; + else if (peer->sort == BGP_PEER_EBGP) + peer->sub_sort = BGP_PEER_EBGP_OAD; + + return CMD_SUCCESS; +} + /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, @@ -6928,6 +7300,26 @@ DEFUN (no_neighbor_disable_connected_check, PEER_FLAG_DISABLE_CONNECTED_CHECK); } +DEFPY(neighbor_extended_link_bw, + neighbor_extended_link_bw_cmd, + "[no] neighbor $neighbor extended-link-bandwidth", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Extended (64-bit) version of encoding for Link-Bandwidth\n") +{ + int ret; + + if (no) + ret = peer_flag_unset_vty(vty, neighbor, + PEER_FLAG_EXTENDED_LINK_BANDWIDTH); + else + ret = peer_flag_set_vty(vty, neighbor, + PEER_FLAG_EXTENDED_LINK_BANDWIDTH); + + return ret; +} + /* disable-link-bw-encoding-ieee */ DEFUN(neighbor_disable_link_bw_encoding_ieee, neighbor_disable_link_bw_encoding_ieee_cmd, @@ -8840,13 +9232,21 @@ DEFUN(neighbor_disable_addpath_rx, struct peer *peer; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret; + int action; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_DISABLE_ADDPATH_RX); + action = bgp_addpath_capability_action(peer->addpath_type[afi][safi], 0); + + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_DISABLE_ADDPATH_RX); + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action); + + return ret; } DEFUN(no_neighbor_disable_addpath_rx, @@ -8861,13 +9261,21 @@ DEFUN(no_neighbor_disable_addpath_rx, struct peer *peer; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret; + int action; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_DISABLE_ADDPATH_RX); + action = bgp_addpath_capability_action(peer->addpath_type[afi][safi], 0); + + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_DISABLE_ADDPATH_RX); + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action); + + return ret; } DEFUN (neighbor_addpath_tx_all_paths, @@ -8879,13 +9287,15 @@ DEFUN (neighbor_addpath_tx_all_paths, { int idx_peer = 1; struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), - BGP_ADDPATH_ALL, 0); + bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_ALL, 0); + return CMD_SUCCESS; } @@ -8905,20 +9315,20 @@ DEFUN (no_neighbor_addpath_tx_all_paths, { int idx_peer = 2; struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (peer->addpath_type[bgp_node_afi(vty)][bgp_node_safi(vty)] - != BGP_ADDPATH_ALL) { + if (peer->addpath_type[afi][safi] != BGP_ADDPATH_ALL) { vty_out(vty, "%% Peer not currently configured to transmit all paths."); return CMD_WARNING_CONFIG_FAILED; } - bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), - BGP_ADDPATH_NONE, 0); + bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE, 0); return CMD_SUCCESS; } @@ -9034,16 +9444,65 @@ DEFPY( NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Detect AS loops before sending to neighbor\n") +{ + return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION); +} + +DEFPY (neighbor_addpath_paths_limit, + neighbor_addpath_paths_limit_cmd, + "neighbor $neighbor addpath-rx-paths-limit (1-65535)$paths_limit", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Paths Limit for Addpath to receive from the peer\n" + "Maximum number of paths\n") { struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret; peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) return CMD_WARNING_CONFIG_FAILED; - peer->as_path_loop_detection = true; + ret = peer_af_flag_set_vty(vty, neighbor, afi, safi, + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT); - return CMD_SUCCESS; + peer->addpath_paths_limit[afi][safi].send = paths_limit; + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, + CAPABILITY_ACTION_SET); + + return ret; +} + +DEFPY (no_neighbor_addpath_paths_limit, + no_neighbor_addpath_paths_limit_cmd, + "no neighbor $neighbor addpath-rx-paths-limit [(1-65535)]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Paths Limit for Addpath to receive from the peer\n" + "Maximum number of paths\n") +{ + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + ret = peer_af_flag_unset_vty(vty, neighbor, afi, safi, + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT); + + peer->addpath_paths_limit[afi][safi].send = 0; + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, + CAPABILITY_ACTION_SET); + + return ret; } DEFPY( @@ -9055,15 +9514,7 @@ DEFPY( NEIGHBOR_ADDR_STR2 "Detect AS loops before sending to neighbor\n") { - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, neighbor); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - peer->as_path_loop_detection = false; - - return CMD_SUCCESS; + return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION); } DEFPY(neighbor_path_attribute_discard, @@ -9180,6 +9631,92 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw, return CMD_SUCCESS; } +DEFPY(neighbor_damp, + neighbor_damp_cmd, + "neighbor $neighbor dampening [(1-45)$half [(1-20000)$reuse (1-20000)$suppress (1-255)$max]]", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable neighbor route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") +{ + struct peer *peer = peer_and_group_lookup_vty(vty, neighbor); + + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + if (!half) + half = DEFAULT_HALF_LIFE; + if (!reuse) { + reuse = DEFAULT_REUSE; + suppress = DEFAULT_SUPPRESS; + max = half * 4; + } + if (suppress < reuse) { + vty_out(vty, "Suppress value cannot be less than reuse value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + bgp_peer_damp_enable(peer, bgp_node_afi(vty), bgp_node_safi(vty), + half * 60, reuse, suppress, max * 60); + return CMD_SUCCESS; +} + +DEFPY(no_neighbor_damp, + no_neighbor_damp_cmd, + "no neighbor $neighbor dampening [HALF [REUSE SUPPRESS MAX]]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable neighbor route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") +{ + struct peer *peer = peer_and_group_lookup_vty(vty, neighbor); + + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + bgp_peer_damp_disable(peer, bgp_node_afi(vty), bgp_node_safi(vty)); + return CMD_SUCCESS; +} + +DEFPY (show_ip_bgp_neighbor_damp_param, + show_ip_bgp_neighbor_damp_param_cmd, + "show [ip] bgp [ [unicast]] neighbors $neighbor dampening parameters [json]$json", + SHOW_STR + IP_STR + BGP_STR + BGP_AFI_HELP_STR + "Address Family modifier\n" + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor route-flap dampening information\n" + "Display detail of configured dampening parameters\n" + JSON_STR) +{ + bool use_json = false; + int idx = 0; + afi_t afi = AFI_IP; + safi_t safi = SAFI_UNICAST; + struct peer *peer; + + if (argv_find(argv, argc, "ip", &idx)) + afi = AFI_IP; + if (argv_find(argv, argc, "ipv4", &idx)) + afi = AFI_IP; + if (argv_find(argv, argc, "ipv6", &idx)) + afi = AFI_IP6; + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING; + if (json) + use_json = true; + bgp_show_peer_dampening_parameters(vty, peer, afi, safi, use_json); + return CMD_SUCCESS; +} + static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv, struct ecommunity **list, bool is_rt6) { @@ -9298,13 +9835,13 @@ DEFPY (af_rd_vpn_export, bgp_get_default(), bgp); if (yes) { - bgp->vpn_policy[afi].tovpn_rd_pretty = - XSTRDUP(MTYPE_BGP, rd_str); + bgp->vpn_policy[afi].tovpn_rd_pretty = XSTRDUP(MTYPE_BGP_NAME, + rd_str); bgp->vpn_policy[afi].tovpn_rd = prd; SET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET); } else { - XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty); + XFREE(MTYPE_BGP_NAME, bgp->vpn_policy[afi].tovpn_rd_pretty); UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET); } @@ -9394,7 +9931,7 @@ DEFPY (af_label_vpn_export, "Automatically assign a label\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - mpls_label_t label = MPLS_LABEL_NONE; + mpls_label_t label = (mpls_label_t)label_val; afi_t afi; int idx = 0; bool yes = true; @@ -9402,24 +9939,28 @@ DEFPY (af_label_vpn_export, if (argv_find(argv, argc, "no", &idx)) yes = false; - /* If "no ...", squash trailing parameter */ - if (!yes) - label_auto = NULL; - - if (yes) { - if (!label_auto) - label = label_val; /* parser should force unsigned */ - } - afi = vpn_policy_getafi(vty, bgp, false); if (afi == AFI_MAX) return CMD_WARNING_CONFIG_FAILED; - - if (label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) - /* no change */ - return CMD_SUCCESS; + if (yes) { + if (label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) + /* no change */ + return CMD_SUCCESS; + if (!label_auto && label == bgp->vpn_policy[afi].tovpn_label) + /* no change */ + return CMD_SUCCESS; + } else { + if (label_auto && !CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) + /* no match */ + return CMD_WARNING_CONFIG_FAILED; + if (!label_auto && label_val && + label != bgp->vpn_policy[afi].tovpn_label) + /* no change */ + return CMD_WARNING_CONFIG_FAILED; + } /* * pre-change: un-export vpn routes (vpn->vrf routes unaffected) @@ -9427,9 +9968,16 @@ DEFPY (af_label_vpn_export, vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp_get_default(), bgp); - if (!label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG)) { + bgp_zebra_release_label_range(bgp->vpn_policy[afi].tovpn_label, + bgp->vpn_policy[afi].tovpn_label); + UNSET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); + } else if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + /* release any previous auto label */ if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) { /* @@ -9446,16 +9994,30 @@ DEFPY (af_label_vpn_export, &bgp->vpn_policy[afi], bgp->vpn_policy[afi].tovpn_label); } - UNSET_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO); } - bgp->vpn_policy[afi].tovpn_label = label; - if (label_auto) { - SET_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO); - bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi], - vpn_leak_label_callback); + if (yes) { + if (label_auto) { + SET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO); + /* fetch a label */ + bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; + } else { + bgp->vpn_policy[afi].tovpn_label = label; + UNSET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO); + if (bgp->vpn_policy[afi].tovpn_label >= + MPLS_LABEL_UNRESERVED_MIN && + bgp_zebra_request_label_range(bgp->vpn_policy[afi] + .tovpn_label, + 1, false)) + SET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); + } + } else { + UNSET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO); + bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; } /* post-change: re-export vpn routes */ @@ -9729,6 +10291,26 @@ static int vpn_policy_getdirs(struct vty *vty, const char *dstr, int *dodir) return CMD_SUCCESS; } +/* For testing purpose, static route of RTC. */ +DEFUN(rtc_network, rtc_network_cmd, "rt WORD", + "Add a route-target to announce\n" + "Specify the route-target e.g 65000:100/96\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + return bgp_rtc_static_from_str(vty, bgp, argv[1]->arg, true); +} + + +/* For testing purpose, static route of RTC. */ +DEFUN(no_rtc_network, no_rtc_network_cmd, "no rt WORD", + NO_STR + "Remove a route-target no longer to announce\n" + "Specify the route-target e.g 65000:100/96\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + return bgp_rtc_static_from_str(vty, bgp, argv[2]->arg, false); +} + DEFPY (af_rt_vpn_imexport, af_rt_vpn_imexport_cmd, "[no] vpn $direction_str RTLIST...", @@ -10028,12 +10610,20 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, vrf_bgp = bgp_lookup_by_name(import_name); if (!vrf_bgp) { - if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) + if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) { vrf_bgp = bgp_default; - else + } else { /* Auto-create assuming the same AS */ ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type, NULL, ASNOTATION_UNDEFINED); + + /* Auto created VRF instances should be marked + * properly, otherwise we have a state after bgpd + * restart where VRF instance has default VRF's ASN. + */ + SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO); + } + if (ret) { vty_out(vty, "VRF %s is not configured as a bgp instance\n", @@ -10278,6 +10868,15 @@ DEFUN_NOSH (address_family_evpn, return CMD_SUCCESS; } +DEFUN_NOSH(address_family_rtc, address_family_rtc_cmd, + "address-family ipv4 rt-constraint", + "Enter Address Family command mode\n" BGP_AF_STR BGP_AF_MODIFIER_STR) +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + vty->node = BGP_RTC_NODE; + return CMD_SUCCESS; +} + DEFUN_NOSH (bgp_segment_routing_srv6, bgp_segment_routing_srv6_cmd, "segment-routing srv6", @@ -10412,13 +11011,12 @@ DEFUN_NOSH (exit_address_family, "exit-address-family", "Exit from Address Family configuration mode\n") { - if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE - || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE - || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE - || vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE - || vty->node == BGP_EVPN_NODE - || vty->node == BGP_FLOWSPECV4_NODE - || vty->node == BGP_FLOWSPECV6_NODE) + if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || + vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || + vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE || + vty->node == BGP_IPV6L_NODE || vty->node == BGP_VPNV6_NODE || + vty->node == BGP_EVPN_NODE || vty->node == BGP_FLOWSPECV4_NODE || + vty->node == BGP_FLOWSPECV6_NODE || vty->node == BGP_RTC_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -10482,7 +11080,10 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, if (rm_p->prefixlen == match.prefixlen) { SET_FLAG(rm->flags, BGP_NODE_USER_CLEAR); - bgp_process(bgp, rm, afi, safi); + bgp_process(bgp, rm, + bgp_dest_get_bgp_path_info( + rm), + afi, safi); } bgp_dest_unlock_node(rm); } @@ -10494,7 +11095,9 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, if (dest_p->prefixlen == match.prefixlen) { SET_FLAG(dest->flags, BGP_NODE_USER_CLEAR); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, + bgp_dest_get_bgp_path_info(dest), + afi, safi); } bgp_dest_unlock_node(dest); } @@ -10506,7 +11109,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, /* one clear bgp command to rule them all */ DEFUN (clear_ip_bgp_all, clear_ip_bgp_all_cmd, - "clear [ip] bgp [ VIEWVRFNAME] [ []] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> []|in [prefix-filter]|out|message-stats>]", + "clear [ip] bgp [ VIEWVRFNAME] [ []] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> []|in [prefix-filter]|out|message-stats|capabilities>]", CLEAR_STR IP_STR BGP_STR @@ -10529,7 +11132,8 @@ DEFUN (clear_ip_bgp_all, BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n" BGP_SOFT_OUT_STR - "Reset message statistics\n") + "Reset message statistics\n" + "Resend capabilities\n") { char *vrf = NULL; @@ -10586,7 +11190,7 @@ DEFUN (clear_ip_bgp_all, clr_sort = clear_external; } - /* []|in [prefix-filter]|out|message-stats>] */ + /* []|in [prefix-filter]|out|message-stats|capabilities>] */ if (argv_find(argv, argc, "soft", &idx)) { if (argv_find(argv, argc, "in", &idx) || argv_find(argv, argc, "out", &idx)) @@ -10603,6 +11207,8 @@ DEFUN (clear_ip_bgp_all, clr_type = BGP_CLEAR_SOFT_OUT; } else if (argv_find(argv, argc, "message-stats", &idx)) { clr_type = BGP_CLEAR_MESSAGE_STATS; + } else if (argv_find(argv, argc, "capabilities", &idx)) { + clr_type = BGP_CLEAR_CAPABILITIES; } else clr_type = BGP_CLEAR_SOFT_NONE; @@ -11215,11 +11821,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, msgbuf, sizeof(msgbuf), (uint8_t *)peer->notify.data, peer->notify.length); - if (msg_str) - json_object_string_add( - json_peer, - "lastShutdownDescription", - msg_str); + json_object_string_add(json_peer, + "lastShutdownDescription", + msg_str); } } @@ -11248,10 +11852,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, BGP_NOTIFY_CEASE_HARD_RESET) : ""); } else { - vty_out(vty, " %s (%s)\n", + vty_out(vty, " %s (%s)\n", peer_down_str[(int)peer->last_reset], - peer->soft_version ? peer->soft_version - : "n/a"); + peer->soft_version ? peer->soft_version : "n/a"); } } } @@ -11343,7 +11946,8 @@ static char *bgp_peer_description_stripped(char *desc, uint32_t size) /* Determine whether var peer should be filtered out of the summary. */ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, - struct peer *fpeer, int as_type, + struct peer *fpeer, + enum peer_asn_type as_type, as_t as) { @@ -11354,7 +11958,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, /* filter remote-as (internal|external) */ if (as_type != AS_UNSPECIFIED) { if (peer->as_type == AS_SPECIFIED) { - if (as_type == AS_INTERNAL) { + if (CHECK_FLAG(as_type, AS_INTERNAL)) { if (peer->as != peer->local_as) return true; } else if (peer->as == peer->local_as) @@ -11377,8 +11981,8 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer, * whitespaces and the whole output will be tricky. */ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, - struct peer *fpeer, int as_type, as_t as, - uint16_t show_flags) + struct peer *fpeer, enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct peer *peer; struct listnode *node, *nnode; @@ -11490,6 +12094,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (show_failed && !failed_count) { if (use_json) { + json_object_free(json_peers); + json_object_int_add(json, "failedPeersCount", 0); json_object_int_add(json, "dynamicPeers", dn_count); json_object_int_add(json, "totalPeers", count); @@ -11536,8 +12142,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, : bgp->name); } else { vty_out(vty, - "BGP router identifier %pI4, local AS number %s vrf-id %d", + "BGP router identifier %pI4, local AS number %s %s vrf-id %d", &bgp->router_id, bgp->as_pretty, + bgp->name_pretty, bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id); @@ -11771,6 +12378,12 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_string_add(json_peer, "domainname", peer->domainname); + json_object_string_add(json_peer, + "softwareVersion", + peer->soft_version + ? peer->soft_version + : "n/a"); + asn_asn2json(json_peer, "remoteAs", peer->as, bgp->asnotation); asn_asn2json(json_peer, "localAs", @@ -12154,12 +12767,10 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, safi, true)); } else { - vty_out(vty, - "\n%s Summary (%s):\n", + vty_out(vty, "\n%s Summary:\n", get_afi_safi_str(afi, safi, - false), - bgp->name_pretty); + false)); } } bgp_show_summary(vty, bgp, afi, safi, fpeer, @@ -12186,10 +12797,9 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, } static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, - safi_t safi, - const char *neighbor, - int as_type, as_t as, - uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, + as_t as, uint16_t show_flags) { struct listnode *node, *nnode; struct bgp *bgp; @@ -12202,6 +12812,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + nbr_output = true; if (use_json) { if (!is_first) @@ -12231,8 +12844,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, } int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags) + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags) { struct bgp *bgp; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); @@ -12347,6 +12961,8 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd, as_type = AS_INTERNAL; else if (argv[idx + 1]->arg[0] == 'e') as_type = AS_EXTERNAL; + else if (argv[idx + 1]->arg[0] == 'a') + as_type = AS_AUTO; else if (!asn_str2asn(argv[idx + 1]->arg, &as)) { vty_out(vty, "%% Invalid neighbor remote-as value: %s\n", @@ -12494,7 +13110,7 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty, if (json) json_object_string_add(json, "remoteGrMode", mode); else - vty_out(vty, "%s\n", mode); + vty_out(vty, "%s", mode); } static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty, @@ -12526,7 +13142,7 @@ static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty, if (json) json_object_string_add(json, "localGrMode", mode); else - vty_out(vty, "%s\n", mode); + vty_out(vty, "%s", mode); } static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( @@ -13470,9 +14086,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_object_boolean_true_add(json_neigh, "localAsReplaceAs"); } else { - if ((p->as_type == AS_SPECIFIED) || - (p->as_type == AS_EXTERNAL) || - (p->as_type == AS_INTERNAL)) { + if (p->as_type == AS_SPECIFIED || + CHECK_FLAG(p->as_type, AS_AUTO) || + CHECK_FLAG(p->as_type, AS_EXTERNAL) || + CHECK_FLAG(p->as_type, AS_INTERNAL)) { vty_out(vty, "remote AS "); vty_out(vty, ASN_FORMAT(bgp->asnotation), &p->as); vty_out(vty, ", "); @@ -13491,7 +14108,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, : ""); } /* peer type internal or confed-internal */ - if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) { + if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) { if (use_json) { if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) json_object_boolean_true_add( @@ -13880,33 +14497,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, CHECK_FLAG( p->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV)) { - if (CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) && - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - json_object_boolean_true_add( - json_sub, - "txAdvertisedAndReceived"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV)) - json_object_boolean_true_add( - json_sub, - "txAdvertised"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - json_object_boolean_true_add( - json_sub, - "txReceived"); + json_object_boolean_add( + json_sub, + "txAdvertisedAndReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV) && + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_RCV)); + + json_object_boolean_add( + json_sub, "txAdvertised", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV)); + + json_object_boolean_add( + json_sub, "txReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_RCV)); } if (CHECK_FLAG( @@ -13915,33 +14527,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, CHECK_FLAG( p->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV)) { - if (CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) && - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_boolean_true_add( - json_sub, - "rxAdvertisedAndReceived"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV)) - json_object_boolean_true_add( - json_sub, - "rxAdvertised"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_boolean_true_add( - json_sub, - "rxReceived"); + json_object_boolean_add( + json_sub, + "rxAdvertisedAndReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_ADV) && + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)); + + json_object_boolean_add( + json_sub, "rxAdvertised", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_ADV)); + + json_object_boolean_add( + json_sub, "rxReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)); } if (CHECK_FLAG( @@ -13967,6 +14574,86 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_add); } + /* Paths-Limit */ + if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) { + json_object *json_add = NULL; + const char *print_store; + + json_add = json_object_new_object(); + + FOREACH_AFI_SAFI (afi, safi) { + json_object *json_sub = NULL; + + json_sub = json_object_new_object(); + print_store = get_afi_safi_str(afi, safi, + true); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) && + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + json_object_boolean_true_add( + json_sub, + "advertisedAndReceived"); + json_object_int_add( + json_sub, + "advertisedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .send); + json_object_int_add( + json_sub, + "receivedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .receive); + } else if (CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_ADV)) { + json_object_boolean_true_add( + json_sub, + "advertised"); + json_object_int_add( + json_sub, + "advertisedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .send); + } else if (CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + json_object_boolean_true_add( + json_sub, + "received"); + json_object_int_add( + json_sub, + "receivedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .receive); + } + } + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) + json_object_object_add(json_add, + print_store, + json_sub); + else + json_object_free(json_sub); + } + + json_object_object_add(json_cap, "pathsLimit", + json_add); + } + /* Dynamic */ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { @@ -14420,6 +15107,47 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } } + /* Paths-Limit */ + if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) { + vty_out(vty, " Paths-Limit:\n"); + + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + vty_out(vty, " %s: ", + get_afi_safi_str(afi, + safi, + false)); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV)) + vty_out(vty, + "advertised (%u)", + p->addpath_paths_limit + [afi][safi] + .send); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) + vty_out(vty, + "%sreceived (%u)", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) + ? " and " + : "", + p->addpath_paths_limit + [afi][safi] + .receive); + + vty_out(vty, "\n"); + } + } + } + /* Dynamic */ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { @@ -15472,6 +16200,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + nbr_output = true; if (use_json) { if (!(json = json_object_new_object())) { @@ -16031,6 +16762,9 @@ static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi, if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) vrf_name = bgp->name; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (use_json) { json_vrf = json_object_new_object(); } else { @@ -16121,6 +16855,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, struct bgp *bgp; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (!uj) vty_out(vty, "\nInstance %s:\n", (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) @@ -16368,7 +17105,7 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, &conf->as); vty_out(vty, "\n"); } - } else if (conf->as_type == AS_INTERNAL) { + } else if (CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) asn_asn2json(json, "remoteAs", group->bgp->as, group->bgp->asnotation); @@ -16380,7 +17117,8 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, vty_out(vty, "\nBGP peer-group %s\n", group->name); } - if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) { + if ((group->bgp->as == conf->as) || + CHECK_FLAG(conf->as_type, AS_INTERNAL)) { if (json) json_object_string_add(json_peer_group, "type", "internal"); @@ -16782,10 +17520,11 @@ ALIAS_HIDDEN( DEFUN (bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_cmd, - "redistribute (1-65535)", + "redistribute (1-65535)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); @@ -16805,7 +17544,18 @@ DEFUN (bgp_redistribute_ipv4_ospf, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16813,18 +17563,20 @@ DEFUN (bgp_redistribute_ipv4_ospf, } ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_hidden_cmd, - "redistribute (1-65535)", + "redistribute (1-65535)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n") DEFUN (bgp_redistribute_ipv4_ospf_rmap, bgp_redistribute_ipv4_ospf_rmap_cmd, - "redistribute (1-65535) route-map RMAP_NAME", + "redistribute (1-65535) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n") @@ -16840,6 +17592,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, struct route_map *route_map = route_map_lookup_warn_noexist(vty, argv[idx_word]->arg); + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -16849,10 +17603,20 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map); @@ -16861,20 +17625,22 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_rmap, bgp_redistribute_ipv4_ospf_rmap_hidden_cmd, - "redistribute (1-65535) route-map RMAP_NAME", + "redistribute (1-65535) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n") DEFUN (bgp_redistribute_ipv4_ospf_metric, bgp_redistribute_ipv4_ospf_metric_cmd, - "redistribute (1-65535) metric (0-4294967295)", + "redistribute (1-65535) metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n") @@ -16889,6 +17655,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, int protocol; bool changed; + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -16898,10 +17666,20 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16912,20 +17690,22 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_metric, bgp_redistribute_ipv4_ospf_metric_hidden_cmd, - "redistribute (1-65535) metric (0-4294967295)", + "redistribute (1-65535) metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n") DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, bgp_redistribute_ipv4_ospf_rmap_metric_cmd, - "redistribute (1-65535) route-map RMAP_NAME metric (0-4294967295)", + "redistribute (1-65535) route-map RMAP_NAME metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n" @@ -16945,6 +17725,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, struct route_map *route_map = route_map_lookup_warn_noexist(vty, argv[idx_word]->arg); + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -16954,10 +17736,20 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16971,10 +17763,11 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, ALIAS_HIDDEN( bgp_redistribute_ipv4_ospf_rmap_metric, bgp_redistribute_ipv4_ospf_rmap_metric_hidden_cmd, - "redistribute (1-65535) route-map RMAP_NAME metric (0-4294967295)", + "redistribute (1-65535) route-map RMAP_NAME metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n" @@ -16983,10 +17776,11 @@ ALIAS_HIDDEN( DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, bgp_redistribute_ipv4_ospf_metric_rmap_cmd, - "redistribute (1-65535) metric (0-4294967295) route-map RMAP_NAME", + "redistribute (1-65535) metric (0-4294967295) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17006,6 +17800,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, struct route_map *route_map = route_map_lookup_warn_noexist(vty, argv[idx_word]->arg); + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -17014,8 +17810,18 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, "%% Only default BGP instance can use '%s'\n", argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; - } - protocol = ZEBRA_ROUTE_TABLE; + } else if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } instance = strtoul(argv[idx_number]->arg, NULL, 10); @@ -17032,10 +17838,11 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, ALIAS_HIDDEN( bgp_redistribute_ipv4_ospf_metric_rmap, bgp_redistribute_ipv4_ospf_metric_rmap_hidden_cmd, - "redistribute (1-65535) metric (0-4294967295) route-map RMAP_NAME", + "redistribute (1-65535) metric (0-4294967295) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17044,11 +17851,12 @@ ALIAS_HIDDEN( DEFUN (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_cmd, - "no redistribute (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", + "no redistribute (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17061,6 +17869,8 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, unsigned short instance; int protocol; + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -17070,21 +17880,32 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); bgp_redistribute_unset(bgp, AFI_IP, protocol, instance); return CMD_SUCCESS; } ALIAS_HIDDEN( no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_hidden_cmd, - "no redistribute (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", + "no redistribute (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17239,6 +18060,76 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed); } +DEFPY(bgp_redistribute_ipv6_table, bgp_redistribute_ipv6_table_cmd, + "redistribute table-direct (1-65535)$table_id [{metric$metric (0-4294967295)$metric_val|route-map WORD$rmap}]", + "Redistribute information from another routing protocol\n" + "Non-main Kernel Routing Table - Direct\n" + "Table ID\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bool changed = false; + struct route_map *route_map = NULL; + struct bgp_redist *red; + + if (rmap) + route_map = route_map_lookup_warn_noexist(vty, rmap); + + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use 'table-direct'\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (table_id == RT_TABLE_MAIN || table_id == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %lu routing table\n", + table_id); + return CMD_WARNING_CONFIG_FAILED; + } + + red = bgp_redist_add(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, table_id); + if (rmap) + changed = bgp_redistribute_rmap_set(red, rmap, route_map); + if (metric) + changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP6, + ZEBRA_ROUTE_TABLE_DIRECT, + metric_val); + return bgp_redistribute_set(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, + table_id, changed); +} + +DEFPY(no_bgp_redistribute_ipv6_table, no_bgp_redistribute_ipv6_table_cmd, + "no redistribute table-direct (1-65535)$table_id [{metric (0-4294967295)|route-map WORD}]", + NO_STR + "Redistribute information from another routing protocol\n" + "Non-main Kernel Routing Table - Direct\n" + "Table ID\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use 'table-direct'\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (table_id == RT_TABLE_MAIN || table_id == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %lu routing table\n", + table_id); + return CMD_WARNING_CONFIG_FAILED; + } + + bgp_redistribute_unset(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, table_id); + return CMD_SUCCESS; +} + DEFUN (bgp_redistribute_ipv6_metric_rmap, bgp_redistribute_ipv6_metric_rmap_cmd, "redistribute " FRR_IP6_REDIST_STR_BGPD " metric (0-4294967295) route-map RMAP_NAME", @@ -17429,8 +18320,8 @@ bool peergroup_flag_check(struct peer *peer, uint64_t flag) return !!CHECK_FLAG(peer->flags_override, flag); } -static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, - uint64_t flag) +bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint64_t flag) { if (!peer_group_active(peer)) { if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag)) @@ -17729,6 +18620,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } else if (peer->as_type == AS_EXTERNAL) { vty_out(vty, " remote-as external"); if_ras_printed = true; + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " remote-as auto"); + if_ras_printed = true; } vty_out(vty, "\n"); @@ -17751,6 +18645,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } @@ -17780,6 +18677,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s remote-as external\n", addr); + } else if (CHECK_FLAG(peer->as_type, AS_AUTO)) { + vty_out(vty, " neighbor %s remote-as auto\n", + addr); } } } @@ -17878,6 +18778,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, ? " strict-mode" : ""); + if (peer->sub_sort == BGP_PEER_EBGP_OAD) + vty_out(vty, " neighbor %s oad\n", addr); + /* ttl-security hops */ if (peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) { if (!peer_group_active(peer) @@ -17896,14 +18799,22 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n", addr); + if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) + vty_out(vty, " neighbor %s extended-link-bandwidth\n", addr); + /* extended-optional-parameters */ if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS)) vty_out(vty, " neighbor %s extended-optional-parameters\n", addr); /* enforce-first-as */ - if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) - vty_out(vty, " neighbor %s enforce-first-as\n", addr); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) { + if (!peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + vty_out(vty, " no neighbor %s enforce-first-as\n", addr); + } else { + if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + vty_out(vty, " neighbor %s enforce-first-as\n", addr); + } /* update-source */ if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) { @@ -17950,9 +18861,15 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s timers delayopen %u\n", addr, peer->bgp->default_delayopen); - /* capability dynamic */ - if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) - vty_out(vty, " neighbor %s capability dynamic\n", addr); + /* capability software-version */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY)) { + if (!peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) + vty_out(vty, " no neighbor %s capability dynamic\n", + addr); + } else { + if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) + vty_out(vty, " neighbor %s capability dynamic\n", addr); + } /* capability extended-nexthop */ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) { @@ -17968,14 +18885,30 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } /* capability software-version */ - if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION)) - vty_out(vty, " neighbor %s capability software-version\n", - addr); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) { + if (!peergroup_flag_check(peer, + PEER_FLAG_CAPABILITY_SOFT_VERSION)) + vty_out(vty, + " no neighbor %s capability software-version\n", + addr); + } else { + if (peergroup_flag_check(peer, + PEER_FLAG_CAPABILITY_SOFT_VERSION)) + vty_out(vty, + " neighbor %s capability software-version\n", + addr); + } /* dont-capability-negotiation */ if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY)) vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr); + /* capability fqdn */ + if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_FQDN)) + vty_out(vty, + " no neighbor %s capability fqdn\n", + addr); + /* override-capability */ if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY)) vty_out(vty, " neighbor %s override-capability\n", addr); @@ -17985,7 +18918,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s strict-capability-match\n", addr); /* Sender side AS path loop detection. */ - if (peer->as_path_loop_detection) + if (peergroup_flag_check(peer, PEER_FLAG_AS_LOOP_DETECTION)) vty_out(vty, " neighbor %s sender-as-path-loop-detection\n", addr); @@ -18107,6 +19040,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX)) vty_out(vty, " neighbor %s disable-addpath-rx\n", addr); + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT)) + vty_out(vty, " neighbor %s addpath-rx-paths-limit %u\n", addr, + peer->addpath_paths_limit[afi][safi].send); + /* ORF capability. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) || peergroup_af_flag_check(peer, afi, safi, @@ -18192,6 +19130,12 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, if (flag_slcomm) vty_out(vty, " no neighbor %s send-community large\n", addr); + + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI)) + vty_out(vty, + " no neighbor %s send-community extended rpki\n", + addr); } /* Default information */ @@ -18349,6 +19293,8 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, vty_frame(vty, "ipv4 encap"); else if (safi == SAFI_FLOWSPEC) vty_frame(vty, "ipv4 flowspec"); + if (safi == SAFI_RTC) + vty_frame(vty, "ipv4 rt-constraint"); } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) vty_frame(vty, "ipv6 unicast"); @@ -18376,7 +19322,16 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, /* BGP flag dampening. */ if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) - bgp_config_write_damp(vty, afi, safi); + bgp_config_write_damp(vty, bgp, afi, safi); + for (ALL_LIST_ELEMENTS_RO(bgp->group, node, group)) + if (peer_af_flag_check(group->conf, afi, safi, + PEER_FLAG_CONFIG_DAMPENING)) + bgp_config_write_peer_damp(vty, group->conf, afi, safi); + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_CONFIG_DAMPENING)) + bgp_config_write_peer_damp(vty, peer, afi, safi); for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi); @@ -18436,11 +19391,14 @@ int bgp_config_write(struct vty *vty) safi_t safi; uint32_t tovpn_sid_index = 0; + hook_call(bgp_snmp_traps_config_write, vty); + + vty_out(vty, "!\n"); if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); - if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) { + if (bm->v_update_delay != BGP_UPDATE_DELAY_DEFAULT) { vty_out(vty, "bgp update-delay %d", bm->v_update_delay); if (bm->v_update_delay != bm->v_establish_wait) vty_out(vty, " %d", bm->v_establish_wait); @@ -18450,6 +19408,30 @@ int bgp_config_write(struct vty *vty) if (bm->wait_for_fib) vty_out(vty, "bgp suppress-fib-pending\n"); + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, "bgp graceful-restart stalepath-time %u\n", + bm->stalepath_time); + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, "bgp graceful-restart restart-time %u\n", + bm->restart_time); + + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, "bgp graceful-restart select-defer-time %u\n", + bm->select_defer_time); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + vty_out(vty, "bgp graceful-restart\n"); + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + vty_out(vty, "bgp graceful-restart-disable\n"); + + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, "bgp graceful-restart preserve-fw-state\n"); + + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, "bgp graceful-restart rib-stale-time %u\n", + bm->rib_stale_time); + if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, "bgp graceful-shutdown\n"); @@ -18460,9 +19442,9 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) vty_out(vty, "bgp send-extra-data zebra\n"); - /* BGP session DSCP value */ - if (bm->tcp_dscp != IPTOS_PREC_INTERNETCONTROL) - vty_out(vty, "bgp session-dscp %u\n", bm->tcp_dscp >> 2); + /* DSCP value for outgoing packets in BGP connections */ + if (bm->ip_tos != IPTOS_PREC_INTERNETCONTROL) + vty_out(vty, "bgp session-dscp %u\n", bm->ip_tos >> 2); /* BGP InQ limit */ if (bm->inq_limit != BM_DEFAULT_Q_LIMIT) @@ -18471,6 +19453,8 @@ int bgp_config_write(struct vty *vty) if (bm->outq_limit != BM_DEFAULT_Q_LIMIT) vty_out(vty, "bgp output-queue-limit %u\n", bm->outq_limit); + vty_out(vty, "!\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { @@ -18526,6 +19510,15 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); + /* bgp enforce-first-as */ + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS) != + SAVE_BGP_ENFORCE_FIRST_AS) + vty_out(vty, " %sbgp enforce-first-as\n", + CHECK_FLAG(bgp->flags, + BGP_FLAG_ENFORCE_FIRST_AS) + ? "" + : "no "); + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_LU_IPV4_EXPLICIT_NULL) && !!CHECK_FLAG(bgp->flags, BGP_FLAG_LU_IPV6_EXPLICIT_NULL)) vty_out(vty, " bgp labeled-unicast explicit-null\n"); @@ -18605,6 +19598,15 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY) != + SAVE_BGP_DYNAMIC_CAPABILITY) + vty_out(vty, + " %sbgp default dynamic-capability\n", + CHECK_FLAG(bgp->flags, + BGP_FLAG_DYNAMIC_CAPABILITY) + ? "" + : "no "); + /* BGP default subgroup-pkt-queue-max. */ if (bgp->default_subgroup_pkt_queue_max != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX) @@ -18694,15 +19696,21 @@ int bgp_config_write(struct vty *vty) " bgp long-lived-graceful-restart stale-time %u\n", bgp->llgr_stale_time); - /* BGP graceful-restart. */ - if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) - vty_out(vty, - " bgp graceful-restart stalepath-time %u\n", - bgp->stalepath_time); + /* BGP per-instance graceful-restart. */ + /* BGP-wide settings and per-instance settings are mutually + * exclusive. + */ + if (bm->stalepath_time == BGP_DEFAULT_STALEPATH_TIME) + if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + vty_out(vty, + " bgp graceful-restart stalepath-time %u\n", + bgp->stalepath_time); - if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) - vty_out(vty, " bgp graceful-restart restart-time %u\n", - bgp->restart_time); + if (bm->restart_time == BGP_DEFAULT_RESTART_TIME) + if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME) + vty_out(vty, + " bgp graceful-restart restart-time %u\n", + bgp->restart_time); if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION) != SAVE_BGP_GRACEFUL_NOTIFICATION) @@ -18712,30 +19720,34 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); - if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) - vty_out(vty, - " bgp graceful-restart select-defer-time %u\n", - bgp->select_defer_time); + if (bm->select_defer_time == BGP_DEFAULT_SELECT_DEFERRAL_TIME) + if (bgp->select_defer_time != + BGP_DEFAULT_SELECT_DEFERRAL_TIME) + vty_out(vty, + " bgp graceful-restart select-defer-time %u\n", + bgp->select_defer_time); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) - vty_out(vty, " bgp graceful-restart\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_CONFIGURED)) { + if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR) + vty_out(vty, " bgp graceful-restart\n"); - if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) - vty_out(vty, " bgp graceful-restart-disable\n"); + if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE) + vty_out(vty, " bgp graceful-restart-disable\n"); + } - /* BGP graceful-restart Preserve State F bit. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) - vty_out(vty, - " bgp graceful-restart preserve-fw-state\n"); + if (!CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) + vty_out(vty, + " bgp graceful-restart preserve-fw-state\n"); /* BGP TCP keepalive */ bgp_config_tcp_keepalive(vty, bgp); - /* Stale timer for RIB */ - if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) - vty_out(vty, - " bgp graceful-restart rib-stale-time %u\n", - bgp->rib_stale_time); + if (bm->rib_stale_time == BGP_DEFAULT_RIB_STALE_TIME) + if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + vty_out(vty, + " bgp graceful-restart rib-stale-time %u\n", + bgp->rib_stale_time); /* BGP bestpath method. */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) @@ -18908,6 +19920,8 @@ int bgp_config_write(struct vty *vty) /* EVPN configuration. */ bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_RTC); + hook_call(bgp_inst_config_write, bgp, vty); #ifdef ENABLE_BGP_VNC @@ -19032,6 +20046,13 @@ static struct cmd_node bgp_srv6_node = { .prompt = "%s(config-router-srv6)# ", }; +static struct cmd_node bgp_rtc_node = { + .name = "bgp rt-constraint", + .node = BGP_RTC_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-af-rtc)# ", +}; + static void community_list_vty(void); static void bgp_ac_peergroup(vector comps, struct cmd_token *token) @@ -19346,6 +20367,7 @@ void bgp_vty_init(void) install_node(&bgp_flowspecv4_node); install_node(&bgp_flowspecv6_node); install_node(&bgp_srv6_node); + install_node(&bgp_rtc_node); /* Install default VTY commands to new nodes. */ install_default(BGP_NODE); @@ -19362,6 +20384,7 @@ void bgp_vty_init(void) install_default(BGP_EVPN_NODE); install_default(BGP_EVPN_VNI_NODE); install_default(BGP_SRV6_NODE); + install_default(BGP_RTC_NODE); /* "global bgp inq-limit command */ install_element(CONFIG_NODE, &bgp_inq_limit_cmd); @@ -19394,6 +20417,26 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_graceful_shutdown_cmd); install_element(CONFIG_NODE, &no_bgp_graceful_shutdown_cmd); + /* BGP-wide graceful-restart commands. */ + install_element(CONFIG_NODE, &bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_disable_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_stalepath_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_restart_time_cmd); + install_element(CONFIG_NODE, + &bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_select_defer_time_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &no_bgp_graceful_restart_preserve_fw_cmd); + install_element(CONFIG_NODE, &bgp_graceful_restart_rib_stale_time_cmd); + install_element(CONFIG_NODE, + &no_bgp_graceful_restart_rib_stale_time_cmd); + /* Dummy commands (Currently not supported) */ install_element(BGP_NODE, &no_synchronization_cmd); install_element(BGP_NODE, &no_auto_summary_cmd); @@ -19445,6 +20488,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &neighbor_role_strict_cmd); install_element(BGP_NODE, &no_neighbor_role_cmd); + /* "neighbor oad" commands. */ + install_element(BGP_NODE, &neighbor_oad_cmd); + /* "neighbor aigp" commands. */ install_element(BGP_NODE, &neighbor_aigp_cmd); @@ -19493,6 +20539,13 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &bgp_maxpaths_ibgp_cluster_cmd); install_element(BGP_IPV6L_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element(BGP_RTC_NODE, &no_rtc_network_cmd); + install_element(BGP_RTC_NODE, &rtc_network_cmd); + install_element(BGP_RTC_NODE, &bgp_maxpaths_ibgp_cmd); + install_element(BGP_RTC_NODE, &no_bgp_maxpaths_ibgp_cmd); + install_element(BGP_RTC_NODE, &bgp_maxpaths_ibgp_cluster_cmd); + + /* "timers bgp" commands. */ install_element(BGP_NODE, &bgp_timers_cmd); install_element(BGP_NODE, &no_bgp_timers_cmd); @@ -19518,6 +20571,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* bgp enforce-first-as */ + install_element(BGP_NODE, &bgp_enforce_first_as_cmd); + /* bgp labeled-unicast explicit-null */ install_element(BGP_NODE, &bgp_lu_uses_explicit_null_cmd); @@ -19647,6 +20703,9 @@ void bgp_vty_init(void) /* bgp default software-version-capability */ install_element(BGP_NODE, &bgp_default_software_version_capability_cmd); + /* bgp default dynamic-capability */ + install_element(BGP_NODE, &bgp_default_dynamic_capability_cmd); + /* "bgp default subgroup-pkt-queue-max" commands. */ install_element(BGP_NODE, &bgp_default_subgroup_pkt_queue_max_cmd); install_element(BGP_NODE, &no_bgp_default_subgroup_pkt_queue_max_cmd); @@ -19715,6 +20774,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &neighbor_activate_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &neighbor_activate_cmd); + install_element(BGP_RTC_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element(BGP_NODE, &no_neighbor_activate_hidden_cmd); @@ -19729,6 +20789,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_activate_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_activate_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group" set commands. */ install_element(BGP_NODE, &neighbor_set_peer_group_cmd); @@ -19743,6 +20804,8 @@ void bgp_vty_init(void) &neighbor_set_peer_group_hidden_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_set_peer_group_hidden_cmd); + install_element(BGP_RTC_NODE, &neighbor_set_peer_group_hidden_cmd); + /* "no neighbor peer-group unset" commands. */ install_element(BGP_NODE, &no_neighbor_set_peer_group_cmd); @@ -19757,6 +20820,7 @@ void bgp_vty_init(void) &no_neighbor_set_peer_group_hidden_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_set_peer_group_hidden_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_set_peer_group_hidden_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element(BGP_NODE, &neighbor_soft_reconfiguration_hidden_cmd); @@ -19787,6 +20851,8 @@ void bgp_vty_init(void) &no_neighbor_soft_reconfiguration_cmd); install_element(BGP_EVPN_NODE, &neighbor_soft_reconfiguration_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element(BGP_RTC_NODE, &neighbor_soft_reconfiguration_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element(BGP_NODE, &neighbor_attr_unchanged_hidden_cmd); @@ -19810,6 +20876,8 @@ void bgp_vty_init(void) install_element(BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd); + install_element(BGP_RTC_NODE, &neighbor_attr_unchanged_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_attr_unchanged_cmd); install_element(BGP_FLOWSPECV4_NODE, &neighbor_attr_unchanged_cmd); install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_attr_unchanged_cmd); @@ -19842,6 +20910,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_nexthop_self_cmd); install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_cmd); + install_element(BGP_RTC_NODE, &neighbor_nexthop_self_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor next-hop-self force" commands. */ install_element(BGP_NODE, &neighbor_nexthop_self_force_hidden_cmd); @@ -19890,6 +20960,8 @@ void bgp_vty_init(void) &no_neighbor_nexthop_self_all_hidden_cmd); install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_force_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_force_cmd); + install_element(BGP_RTC_NODE, &neighbor_nexthop_self_force_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_nexthop_self_force_cmd); /* "neighbor as-override" commands. */ install_element(BGP_NODE, &neighbor_as_override_hidden_cmd); @@ -20022,6 +21094,18 @@ void bgp_vty_init(void) &neighbor_remove_private_as_all_replace_as_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_remove_private_as_all_replace_as_cmd); + install_element(BGP_RTC_NODE, &neighbor_remove_private_as_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_remove_private_as_cmd); + install_element(BGP_RTC_NODE, &neighbor_remove_private_as_all_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_remove_private_as_all_cmd); + install_element(BGP_RTC_NODE, + &neighbor_remove_private_as_replace_as_cmd); + install_element(BGP_RTC_NODE, + &no_neighbor_remove_private_as_replace_as_cmd); + install_element(BGP_RTC_NODE, + &neighbor_remove_private_as_all_replace_as_cmd); + install_element(BGP_RTC_NODE, + &no_neighbor_remove_private_as_all_replace_as_cmd); /* "neighbor send-community" commands.*/ install_element(BGP_NODE, &neighbor_send_community_hidden_cmd); @@ -20060,6 +21144,19 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_send_community_type_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd); + install_element(BGP_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV4_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV6_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_RTC_NODE, &neighbor_send_community_cmd); + install_element(BGP_RTC_NODE, &neighbor_send_community_type_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_send_community_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_send_community_type_cmd); /* "neighbor route-reflector" commands.*/ install_element(BGP_NODE, &neighbor_route_reflector_client_hidden_cmd); @@ -20097,6 +21194,8 @@ void bgp_vty_init(void) &no_neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd); + install_element(BGP_RTC_NODE, &neighbor_route_reflector_client_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd); @@ -20125,6 +21224,8 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_server_client_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_server_client_cmd); + install_element(BGP_RTC_NODE, &neighbor_route_server_client_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor disable-addpath-rx" commands. */ install_element(BGP_IPV4_NODE, &neighbor_disable_addpath_rx_cmd); @@ -20236,6 +21337,26 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); + /* "neighbor addpath-rx-paths-limit" commands.*/ + install_element(BGP_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_paths_limit_cmd); + /* "neighbor sender-as-path-loop-detection" commands. */ install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd); install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd); @@ -20286,6 +21407,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element(BGP_IPV6L_NODE, &neighbor_capability_orf_prefix_cmd); install_element(BGP_IPV6L_NODE, &no_neighbor_capability_orf_prefix_cmd); + install_element(BGP_RTC_NODE, &neighbor_capability_orf_prefix_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_capability_orf_prefix_cmd); /* "neighbor capability dynamic" commands.*/ install_element(BGP_NODE, &neighbor_capability_dynamic_cmd); @@ -20295,6 +21418,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &neighbor_dont_capability_negotiate_cmd); install_element(BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd); + /* "neighbor capability fqdn" command. */ + install_element(BGP_NODE, &neighbor_capability_fqdn_cmd); + /* "neighbor ebgp-multihop" commands. */ install_element(BGP_NODE, &neighbor_ebgp_multihop_cmd); install_element(BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd); @@ -20309,6 +21435,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_neighbor_disable_link_bw_encoding_ieee_cmd); + + install_element(BGP_NODE, &neighbor_extended_link_bw_cmd); + /* "neighbor extended-optional-parameters" commands. */ install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd); install_element(BGP_NODE, @@ -20422,6 +21551,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); install_element(BGP_VPNV6_NODE, &neighbor_distribute_list_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_distribute_list_cmd); + install_element(BGP_RTC_NODE, &neighbor_distribute_list_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_distribute_list_cmd); /* "neighbor prefix-list" commands. */ install_element(BGP_NODE, &neighbor_prefix_list_hidden_cmd); @@ -20446,6 +21577,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_prefix_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_prefix_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_prefix_list_cmd); + install_element(BGP_RTC_NODE, &neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element(BGP_NODE, &neighbor_filter_list_hidden_cmd); @@ -20470,6 +21602,8 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_filter_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &neighbor_filter_list_cmd); install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_filter_list_cmd); + install_element(BGP_RTC_NODE, &neighbor_filter_list_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element(BGP_NODE, &neighbor_route_map_hidden_cmd); @@ -20496,6 +21630,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd); + install_element(BGP_RTC_NODE, &neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd); @@ -20516,6 +21651,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd); + install_element(BGP_RTC_NODE, &neighbor_unsuppress_map_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor advertise-map" commands. */ install_element(BGP_NODE, &bgp_condadv_period_cmd); @@ -20635,6 +21772,24 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element(BGP_EVPN_NODE, + &neighbor_maximum_prefix_threshold_warning_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element(BGP_EVPN_NODE, + &neighbor_maximum_prefix_threshold_restart_cmd); + install_element(BGP_EVPN_NODE, &no_neighbor_maximum_prefix_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element(BGP_RTC_NODE, + &neighbor_maximum_prefix_threshold_warning_cmd); + install_element(BGP_RTC_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element(BGP_RTC_NODE, + &neighbor_maximum_prefix_threshold_restart_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_maximum_prefix_cmd); /* "neighbor allowas-in" */ install_element(BGP_NODE, &neighbor_allowas_in_hidden_cmd); @@ -20657,6 +21812,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_allowas_in_cmd); install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd); + install_element(BGP_RTC_NODE, &neighbor_allowas_in_cmd); + install_element(BGP_RTC_NODE, &no_neighbor_allowas_in_cmd); /* neighbor accept-own */ install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd); @@ -20682,6 +21839,23 @@ void bgp_vty_init(void) install_element(BGP_EVPN_NODE, &neighbor_soo_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_soo_cmd); + /* "neighbor dampening" commands. */ + install_element(BGP_NODE, &neighbor_damp_cmd); + install_element(BGP_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV4_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV6_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_damp_cmd); + install_element(VIEW_NODE, &show_ip_bgp_neighbor_damp_param_cmd); + /* address-family commands. */ install_element(BGP_NODE, &address_family_ipv4_safi_cmd); install_element(BGP_NODE, &address_family_ipv6_safi_cmd); @@ -20692,6 +21866,8 @@ void bgp_vty_init(void) install_element(BGP_NODE, &address_family_evpn_cmd); + install_element(BGP_NODE, &address_family_rtc_cmd); + /* "exit-address-family" command. */ install_element(BGP_IPV4_NODE, &exit_address_family_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); @@ -20704,6 +21880,7 @@ void bgp_vty_init(void) install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); + install_element(BGP_RTC_NODE, &exit_address_family_cmd); /* BGP retain all route-target */ install_element(BGP_VPNV4_NODE, &bgp_retain_route_target_cmd); @@ -20785,6 +21962,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd); install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd); install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); + install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_table_cmd); + install_element(BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_table_cmd); /* import|export vpn [route-map RMAP_NAME] */ install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd); @@ -20894,9 +22073,6 @@ static const char *community_direct_str(int direct) static void community_list_perror(struct vty *vty, int ret) { switch (ret) { - case COMMUNITY_LIST_ERR_CANT_FIND_LIST: - vty_out(vty, "%% Can't find community-list\n"); - break; case COMMUNITY_LIST_ERR_MALFORMED_VAL: vty_out(vty, "%% Malformed community-list value\n"); break; @@ -21006,16 +22182,11 @@ DEFUN (no_community_list_standard_all, argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; - int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq, - direct, style); + community_list_unset(bgp_clist, cl_name_or_number, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -21119,16 +22290,11 @@ DEFUN (no_community_list_expanded_all, argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; - int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq, - direct, style); + community_list_unset(bgp_clist, cl_name_or_number, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -21284,7 +22450,6 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, static int lcommunity_list_unset_vty(struct vty *vty, int argc, struct cmd_token **argv, int style) { - int ret; int direct = 0; char *str = NULL; int idx = 0; @@ -21317,18 +22482,13 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx); /* Unset community list. */ - ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct, - style); + lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct, + style); /* Free temporary community list string allocated by argv_concat(). */ XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -21725,16 +22885,11 @@ DEFUN (no_extcommunity_list_standard_all, argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; - int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, - seq, direct, style); + extcommunity_list_unset(bgp_clist, cl_number_or_name, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -21790,16 +22945,11 @@ DEFUN (no_extcommunity_list_expanded_all, argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; - int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, - seq, direct, style); + extcommunity_list_unset(bgp_clist, cl_number_or_name, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index a105b6de3fa9..f88f5c812569 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -13,8 +13,6 @@ struct bgp; #define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n" #define BGP_INSTANCE_ALL_HELP_STR "BGP view\nBGP VRF\nAll Views/VRFs\n" -#define BGP_AF_STR "Address Family\n" -#define BGP_AF_MODIFIER_STR "Address Family modifier\n" #define BGP_AFI_CMD_STR "" #define BGP_AFI_HELP_STR BGP_AF_STR BGP_AF_STR #define BGP_SAFI_CMD_STR "" @@ -62,8 +60,6 @@ struct bgp; #define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \ do { \ - if (_peer->bgp->t_startup) \ - bgp_peer_gr_flags_update(_peer); \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ if (CHECK_FLAG(peer_loop->flags, \ PEER_FLAG_GRACEFUL_RESTART)) \ @@ -86,30 +82,27 @@ struct bgp; } \ } while (0) -#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \ - _bgp, _peer_list, _ret) \ - do { \ - struct peer *peer_loop; \ - bool gr_router_detected = false; \ - struct listnode *node = {0}; \ - struct listnode *nnode = {0}; \ - for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ - if (peer_loop->bgp->t_startup) \ - bgp_peer_gr_flags_update(peer_loop); \ - if (CHECK_FLAG(peer_loop->flags, \ - PEER_FLAG_GRACEFUL_RESTART)) \ - gr_router_detected = true; \ - } \ - if (gr_router_detected \ - && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, false)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } else if (!gr_router_detected \ - && _bgp->present_zebra_gr_state \ - == ZEBRA_GR_ENABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, true)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } \ +#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \ + _peer_list, _ret) \ + do { \ + struct peer *peer_loop; \ + bool gr_router_detected = false; \ + struct listnode *node = { 0 }; \ + struct listnode *nnode = { 0 }; \ + for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ + if (CHECK_FLAG(peer_loop->flags, \ + PEER_FLAG_GRACEFUL_RESTART)) \ + gr_router_detected = true; \ + } \ + if (gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, false)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } else if (!gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, true)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } \ } while (0) @@ -168,8 +161,11 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int argc, struct bgp **bgp, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags); + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); +extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint64_t flag); #endif /* _QUAGGA_BGP_VTY_H */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 9e02f1b5505f..2d9100b89517 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -24,6 +24,7 @@ #include "mpls.h" #include "vxlan.h" #include "pbr.h" +#include "frrdistance.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -72,9 +73,10 @@ static inline bool bgp_install_info_to_zebra(struct bgp *bgp) return false; if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { - zlog_debug( - "%s: No zebra instance to talk to, not installing information", - __func__); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: No zebra instance to talk to, not installing information", + __func__); return false; } @@ -98,13 +100,6 @@ static int bgp_router_id_update(ZAPI_CALLBACK_ARGS) return 0; } -/* Nexthop update message from zebra. */ -static int bgp_read_nexthop_update(ZAPI_CALLBACK_ARGS) -{ - bgp_parse_nexthop_update(cmd, vrf_id); - return 0; -} - /* Set or clear interface on which unnumbered neighbor is configured. This * would in turn cause BGP to initiate or turn off IPv6 RAs on this * interface. @@ -151,7 +146,6 @@ static void bgp_start_interface_nbrs(struct bgp *bgp, struct interface *ifp) static void bgp_nbr_connected_add(struct bgp *bgp, struct nbr_connected *ifc) { - struct listnode *node; struct connected *connected; struct interface *ifp; struct prefix *p; @@ -160,7 +154,7 @@ static void bgp_nbr_connected_add(struct bgp *bgp, struct nbr_connected *ifc) * valid local address on the interface. */ ifp = ifc->ifp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) @@ -201,7 +195,7 @@ static int bgp_ifp_destroy(struct interface *ifp) bgp = ifp->vrf->info; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf del VRF %s IF %s", ifp->vrf->name, ifp->name); if (bgp) { @@ -226,13 +220,12 @@ static int bgp_ifp_up(struct interface *ifp) bgp_mac_add_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id, - ifp->name); + zlog_debug("Rx Intf up VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) return 0; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) + frr_each (if_connected, ifp->connected, c) bgp_connected_add(bgp, c); for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) @@ -241,6 +234,14 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); + if (bgp_get_default() && if_is_vrf(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -257,13 +258,13 @@ static int bgp_ifp_down(struct interface *ifp) bgp_mac_del_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf down VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) return 0; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) + frr_each (if_connected, ifp->connected, c) bgp_connected_delete(bgp, c); for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) @@ -288,6 +289,14 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); + if (bgp_get_default() && if_is_vrf(ifp)) { + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -309,8 +318,8 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address add VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (!bgp) return 0; @@ -388,8 +397,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address del VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (bgp && if_is_operative(ifc->ifp)) { bgp_connected_delete(bgp, ifc); @@ -440,8 +449,8 @@ static int bgp_interface_nbr_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -463,8 +472,8 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -477,66 +486,6 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; } -/* VRF update for an interface. */ -static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - struct connected *c; - struct nbr_connected *nc; - struct listnode *node, *nnode; - struct bgp *bgp; - struct peer *peer; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf VRF change VRF %u IF %s NewVRF %u", vrf_id, - ifp->name, new_vrf_id); - - bgp = bgp_lookup_by_vrf_id(vrf_id); - - if (bgp) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) - bgp_connected_delete(bgp, c); - - for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_delete(bgp, nc, 1); - - /* Fast external-failover */ - if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) { - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if ((peer->ttl != BGP_DEFAULT_TTL) - && (peer->gtsm_hops - != BGP_GTSM_HOPS_CONNECTED)) - continue; - - if (ifp == peer->nexthop.ifp) - BGP_EVENT_ADD(peer->connection, - BGP_Stop); - } - } - } - - if_update_to_new_vrf(ifp, new_vrf_id); - - bgp = bgp_lookup_by_vrf_id(new_vrf_id); - if (!bgp) - return 0; - - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) - bgp_connected_add(bgp, c); - - for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) - bgp_nbr_connected_add(bgp, nc); - - hook_call(bgp_vrf_status_changed, bgp, ifp); - return 0; -} - /* Zebra route add and delete treatment. */ static int zebra_read_route(ZAPI_CALLBACK_ARGS) { @@ -606,13 +555,14 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) if (add) { inet_ntop(api.prefix.family, &nexthop, buf, sizeof(buf)); - zlog_debug( - "Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, &api.prefix, buf, nhtype, ifindex, - api.metric, api.distance, api.tag); + zlog_debug("Rx route ADD %s %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, + bgp->name_pretty, + zebra_route_string(api.type), api.instance, + &api.prefix, buf, nhtype, ifindex, + api.metric, api.distance, api.tag); } else { - zlog_debug("Rx route DEL VRF %u %s[%d] %pFX", vrf_id, + zlog_debug("Rx route DEL %s %s[%d] %pFX", + bgp->name_pretty, zebra_route_string(api.type), api.instance, &api.prefix); } @@ -624,7 +574,6 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv4 p; @@ -639,7 +588,7 @@ struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) p.prefixlen = IPV4_MAX_BITLEN; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET) @@ -653,7 +602,6 @@ struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; @@ -663,7 +611,7 @@ struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id) return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET) @@ -678,7 +626,6 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv6 p; @@ -693,7 +640,7 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex, p.prefixlen = IPV6_MAX_BITLEN; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -714,7 +661,6 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; @@ -724,7 +670,7 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -743,11 +689,10 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -761,11 +706,10 @@ static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr) static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -779,11 +723,10 @@ static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr) static int if_get_ipv4_address(struct interface *ifp, struct in_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4))) { @@ -1000,7 +943,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (path->attr->mp_nexthop_prefer_global) { + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; @@ -1154,6 +1098,8 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, struct attr *attr, bool is_evpn, struct zapi_nexthop *api_nh) { + struct bgp_route_evpn *bre = bgp_attr_get_evpn_overlay(attr); + api_nh->gate.ipv4 = *nexthop; api_nh->vrf_id = nh_bgp->vrf_id; @@ -1170,7 +1116,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, * treat the nexthop as NEXTHOP_TYPE_IPV4 * Else, mark the nexthop as onlink. */ - if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) api_nh->type = NEXTHOP_TYPE_IPV4; else { api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; @@ -1196,9 +1142,11 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, struct zapi_nexthop *api_nh) { struct attr *attr; + struct bgp_route_evpn *bre; attr = pi->attr; api_nh->vrf_id = nh_bgp->vrf_id; + bre = bgp_attr_get_evpn_overlay(attr); if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) { api_nh->type = attr->nh_type; @@ -1209,7 +1157,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, * treat the nexthop as NEXTHOP_TYPE_IPV4 * Else, mark the nexthop as onlink. */ - if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) + if (bre && bre->type == OVERLAY_INDEX_GATEWAY_IP) api_nh->type = NEXTHOP_TYPE_IPV6; else { api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; @@ -1267,83 +1215,50 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, } static bool bgp_zebra_use_nhop_weighted(struct bgp *bgp, struct attr *attr, - uint64_t tot_bw, uint32_t *nh_weight) + uint64_t *nh_weight) { - uint32_t bw; - uint64_t tmp; - - bw = attr->link_bw; /* zero link-bandwidth and link-bandwidth not present are treated * as the same situation. */ - if (!bw) { + if (!attr->link_bw) { /* the only situations should be if we're either told * to skip or use default weight. */ if (bgp->lb_handling == BGP_LINK_BW_SKIP_MISSING) return false; *nh_weight = BGP_ZEBRA_DEFAULT_NHOP_WEIGHT; - } else { - tmp = (uint64_t)bw * 100; - *nh_weight = ((uint32_t)(tmp / tot_bw)); - } + } else + *nh_weight = attr->link_bw; return true; } -void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, - struct bgp_path_info *info, struct bgp *bgp, afi_t afi, - safi_t safi) +static void bgp_zebra_announce_parse_nexthop( + struct bgp_path_info *info, const struct prefix *p, struct bgp *bgp, + struct zapi_route *api, unsigned int *valid_nh_count, afi_t afi, + safi_t safi, uint32_t *nhg_id, uint32_t *metric, route_tag_t *tag, + bool *allow_recursion) { - struct zapi_route api = { 0 }; struct zapi_nexthop *api_nh; int nh_family; - unsigned int valid_nh_count = 0; - bool allow_recursion = false; - uint8_t distance; - struct peer *peer; struct bgp_path_info *mpinfo; struct bgp *bgp_orig; - uint32_t metric; struct attr local_attr; struct bgp_path_info local_info; struct bgp_path_info *mpinfo_cp = &local_info; - route_tag_t tag; mpls_label_t *labels; - uint32_t num_labels = 0; + uint8_t num_labels = 0; mpls_label_t nh_label; int nh_othervrf = 0; bool nh_updated = false; bool do_wt_ecmp; - uint64_t cum_bw = 0; - uint32_t nhg_id = 0; - bool is_add; uint32_t ttl = 0; uint32_t bos = 0; uint32_t exp = 0; + struct bgp_route_evpn *bre = NULL; - /* - * BGP is installing this route and bgp has been configured - * to suppress announcements until the route has been installed - * let's set the fact that we expect this route to be installed - */ - if (BGP_SUPPRESS_FIB_ENABLED(bgp)) - SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - - /* Don't try to install if we're not connected to Zebra or Zebra doesn't - * know of this instance. - */ - if (!bgp_install_info_to_zebra(bgp)) - return; - - if (bgp->main_zebra_update_hold) - return; - - if (safi == SAFI_FLOWSPEC) { - bgp_pbr_update_entry(bgp, bgp_dest_get_prefix(dest), info, afi, - safi, true); - return; - } + /* Determine if we're doing weighted ECMP or not */ + do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); /* * vrf leaking support (will have only one nexthop) @@ -1352,74 +1267,20 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, info->extra->vrfleak->bgp_orig) nh_othervrf = 1; - /* Make Zebra API structure. */ - api.vrf_id = bgp->vrf_id; - api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; - api.prefix = *p; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - - peer = info->peer; - - if (info->type == ZEBRA_ROUTE_BGP - && info->sub_type == BGP_ROUTE_IMPORTED) { - - /* Obtain peer from parent */ - if (info->extra && info->extra->vrfleak && - info->extra->vrfleak->parent) - peer = ((struct bgp_path_info *)(info->extra->vrfleak - ->parent)) - ->peer; - } - - tag = info->attr->tag; - - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED - || info->sub_type == BGP_ROUTE_AGGREGATE) { - SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); - SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); - } - - if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) - || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) - || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - - allow_recursion = true; - - if (info->attr->rmap_table_id) { - SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); - api.tableid = info->attr->rmap_table_id; - } - - if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); - - /* Metric is currently based on the best-path only */ - metric = info->attr->med; - - /* Determine if we're doing weighted ECMP or not */ - do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); - if (do_wt_ecmp) - cum_bw = bgp_path_info_mpath_cumbw(info); - /* EVPN MAC-IP routes are installed with a L3 NHG id */ - if (bgp_evpn_path_es_use_nhg(bgp, info, &nhg_id)) { + if (nhg_id && bgp_evpn_path_es_use_nhg(bgp, info, nhg_id)) { mpinfo = NULL; - api.nhgid = nhg_id; - if (nhg_id) - SET_FLAG(api.message, ZAPI_MESSAGE_NHG); + zapi_route_set_nhg_id(api, nhg_id); } else { mpinfo = info; } for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { - labels = NULL; - num_labels = 0; - uint32_t nh_weight; + uint64_t nh_weight; bool is_evpn; bool is_parent_evpn; - if (valid_nh_count >= multipath_num) + if (*valid_nh_count >= multipath_num) break; *mpinfo_cp = *mpinfo; @@ -1442,25 +1303,22 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, */ if (do_wt_ecmp) { if (!bgp_zebra_use_nhop_weighted(bgp, mpinfo->attr, - cum_bw, &nh_weight)) + &nh_weight)) continue; } - api_nh = &api.nexthops[valid_nh_count]; + api_nh = &api->nexthops[*valid_nh_count]; - if (CHECK_FLAG(info->attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - api_nh->srte_color = bgp_attr_get_color(info->attr); + api_nh->srte_color = bgp_attr_get_color(info->attr); - if (bgp_debug_zebra(&api.prefix)) { - if (mpinfo->extra) { + if (bgp_debug_zebra(&api->prefix)) { + if (bgp_path_info_num_labels(mpinfo)) { zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d", __func__, p, bgp_is_valid_label( - &mpinfo->extra->label[0])); + &mpinfo->extra->labels + ->label[0])); } else { - zlog_debug( - "%s: p=%pFX, extra is NULL, no label", - __func__, p); + zlog_debug("%s: p=%pFX, no label", __func__, p); } } @@ -1476,8 +1334,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* metric/tag is only allowed to be * overridden on 1st nexthop */ if (mpinfo == info) { - metric = mpinfo_cp->attr->med; - tag = mpinfo_cp->attr->tag; + if (metric) + *metric = mpinfo_cp->attr->med; + if (tag) + *tag = mpinfo_cp->attr->tag; } } @@ -1510,6 +1370,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, } is_evpn = !!CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN); + bre = bgp_attr_get_evpn_overlay(mpinfo->attr); /* Did we get proper nexthop info to update zebra? */ if (!nh_updated) @@ -1518,19 +1379,16 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* Allow recursion if it is a multipath group with both * eBGP and iBGP paths. */ - if (!allow_recursion - && CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) - && (mpinfo->peer->sort == BGP_PEER_IBGP - || mpinfo->peer->sort == BGP_PEER_CONFED)) - allow_recursion = true; - - if (mpinfo->extra) { - labels = mpinfo->extra->label; - num_labels = mpinfo->extra->num_labels; - } + if (allow_recursion && !*allow_recursion && + CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) && + (mpinfo->peer->sort == BGP_PEER_IBGP || + mpinfo->peer->sort == BGP_PEER_CONFED)) + *allow_recursion = true; - if (labels && (num_labels > 0) && - (is_evpn || bgp_is_valid_label(&labels[0]))) { + num_labels = bgp_path_info_num_labels(mpinfo); + labels = num_labels ? mpinfo->extra->labels->label : NULL; + + if (num_labels && (is_evpn || bgp_is_valid_label(&labels[0]))) { enum lsp_types_t nh_label_type = ZEBRA_LSP_NONE; if (is_evpn) { @@ -1548,9 +1406,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api_nh->labels[0] = nh_label; } - if (is_evpn - && mpinfo->attr->evpn_overlay.type - != OVERLAY_INDEX_GATEWAY_IP) + if (is_evpn && !(bre && bre->type == OVERLAY_INDEX_GATEWAY_IP)) memcpy(&api_nh->rmac, &(mpinfo->attr->rmac), sizeof(struct ethaddr)); @@ -1575,7 +1431,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, &exp, &bos); if (nh_label < MPLS_LABEL_UNRESERVED_MIN) { - if (bgp_debug_zebra(&api.prefix)) + if (bgp_debug_zebra(&api->prefix)) zlog_debug( "skip invalid SRv6 routes: transposition scheme is used, but label is too small"); continue; @@ -1592,12 +1448,142 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } - valid_nh_count++; + (*valid_nh_count)++; } +} - is_add = (valid_nh_count || nhg_id) ? true : false; +static void bgp_debug_zebra_nh(struct zapi_route *api) +{ + int i; + int nh_family; + char nh_buf[INET6_ADDRSTRLEN]; + char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' }; + char buf1[ETHER_ADDR_STRLEN]; + char label_buf[20]; + char sid_buf[20]; + char segs_buf[256]; + struct zapi_nexthop *api_nh; + int count; + + count = api->nexthop_num; + for (i = 0; i < count; i++) { + api_nh = &api->nexthops[i]; + switch (api_nh->type) { + case NEXTHOP_TYPE_IFINDEX: + nh_buf[0] = '\0'; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + nh_family = AF_INET; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + nh_family = AF_INET6; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + strlcpy(nh_buf, "blackhole", sizeof(nh_buf)); + break; + default: + /* Note: add new nexthop case */ + assert(0); + break; + } + + label_buf[0] = '\0'; + eth_buf[0] = '\0'; + segs_buf[0] = '\0'; + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) + snprintf(label_buf, sizeof(label_buf), "label %u", + api_nh->labels[0]); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { + inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf, + sizeof(sid_buf)); + snprintf(segs_buf, sizeof(segs_buf), "segs %s", sid_buf); + } + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && + !is_zero_mac(&api_nh->rmac)) + snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", + prefix_mac2str(&api_nh->rmac, buf1, + sizeof(buf1))); + zlog_debug(" nhop [%d]: %s if %u VRF %u wt %" PRIu64 + " %s %s %s", + i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id, + api_nh->weight, label_buf, segs_buf, eth_buf); + } +} - if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { +static enum zclient_send_status +bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp) +{ + struct bgp_path_info *bpi_ultimate; + struct zapi_route api = { 0 }; + unsigned int valid_nh_count = 0; + bool allow_recursion = false; + uint8_t distance; + struct peer *peer; + uint32_t metric; + route_tag_t tag; + uint32_t nhg_id = 0; + struct bgp_table *table = bgp_dest_table(dest); + const struct prefix *p = bgp_dest_get_prefix(dest); + + if (table->safi == SAFI_FLOWSPEC) { + bgp_pbr_update_entry(bgp, p, info, table->afi, table->safi, + true); + return ZCLIENT_SEND_SUCCESS; + } + + /* Make Zebra API structure. */ + api.vrf_id = bgp->vrf_id; + api.type = ZEBRA_ROUTE_BGP; + api.safi = table->safi; + api.prefix = *p; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + peer = info->peer; + + if (info->type == ZEBRA_ROUTE_BGP) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(info); + peer = bpi_ultimate->peer; + } + + tag = info->attr->tag; + + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED + || info->sub_type == BGP_ROUTE_AGGREGATE) { + SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + } + + if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) + || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) + || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) + + allow_recursion = true; + + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + + if (info->attr->srte_color) + SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); + + /* Metric is currently based on the best-path only */ + metric = info->attr->med; + + bgp_zebra_announce_parse_nexthop(info, p, bgp, &api, &valid_nh_count, + table->afi, table->safi, &nhg_id, + &metric, &tag, &allow_recursion); + + if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { struct bgp_zebra_opaque bzo = {}; const char *reason = bgp_path_selection_reason2str(dest->reason); @@ -1646,93 +1632,27 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api.tag = tag; } - distance = bgp_distance_apply(p, info, afi, safi, bgp); + distance = bgp_distance_apply(p, info, table->afi, table->safi, bgp); if (distance) { SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } if (bgp_debug_zebra(p)) { - char nh_buf[INET6_ADDRSTRLEN]; - char eth_buf[ETHER_ADDR_STRLEN + 7] = {'\0'}; - char buf1[ETHER_ADDR_STRLEN]; - char label_buf[20]; - char sid_buf[20]; - char segs_buf[256]; - int i; - - zlog_debug( - "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI - " count %d nhg %d", - is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, - api.metric, api.tag, api.nexthop_num, nhg_id); - for (i = 0; i < api.nexthop_num; i++) { - api_nh = &api.nexthops[i]; - - switch (api_nh->type) { - case NEXTHOP_TYPE_IFINDEX: - nh_buf[0] = '\0'; - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - nh_family = AF_INET; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - nh_family = AF_INET6; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - strlcpy(nh_buf, "blackhole", sizeof(nh_buf)); - break; - default: - /* Note: add new nexthop case */ - assert(0); - break; - } - - label_buf[0] = '\0'; - eth_buf[0] = '\0'; - segs_buf[0] = '\0'; - if (CHECK_FLAG(api_nh->flags, - ZAPI_NEXTHOP_FLAG_LABEL) && - !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) - snprintf(label_buf, sizeof(label_buf), - "label %u", api_nh->labels[0]); - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && - !CHECK_FLAG(api_nh->flags, - ZAPI_NEXTHOP_FLAG_EVPN)) { - inet_ntop(AF_INET6, &api_nh->seg6_segs[0], - sid_buf, sizeof(sid_buf)); - snprintf(segs_buf, sizeof(segs_buf), "segs %s", - sid_buf); - } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && - !is_zero_mac(&api_nh->rmac)) - snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", - prefix_mac2str(&api_nh->rmac, - buf1, sizeof(buf1))); - zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", - i + 1, nh_buf, api_nh->ifindex, - api_nh->vrf_id, api_nh->weight, - label_buf, segs_buf, eth_buf); - } - - int recursion_flag = 0; - - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION)) - recursion_flag = 1; + zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI + " count %d nhg %d", + bgp->name_pretty, api.tableid, &api.prefix, + api.metric, api.tag, api.nexthop_num, nhg_id); + bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", - __func__, p, (recursion_flag ? "" : "NOT ")); + __func__, p, (allow_recursion ? "" : "NOT ")); } - zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + + return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } + /* Announce all routes of a table to zebra */ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) { @@ -1753,14 +1673,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && - (pi->type == ZEBRA_ROUTE_BGP && (pi->sub_type == BGP_ROUTE_NORMAL || pi->sub_type == BGP_ROUTE_IMPORTED))) - - bgp_zebra_announce(dest, - bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } /* Announce routes of any bgp subtype of a table to zebra */ @@ -1782,39 +1699,30 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && pi->type == ZEBRA_ROUTE_BGP) - bgp_zebra_announce(dest, - bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } -void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, - struct bgp *bgp, safi_t safi) +enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, + struct bgp_path_info *info, + struct bgp *bgp) { struct zapi_route api; struct peer *peer; + struct bgp_table *table = bgp_dest_table(dest); + const struct prefix *p = bgp_dest_get_prefix(dest); - /* - * If we are withdrawing the route, we don't need to have this - * flag set. So unset it. - */ - UNSET_FLAG(info->net->flags, BGP_NODE_FIB_INSTALL_PENDING); - - /* Don't try to install if we're not connected to Zebra or Zebra doesn't - * know of this instance. - */ - if (!bgp_install_info_to_zebra(bgp)) - return; - - if (safi == SAFI_FLOWSPEC) { + if (table->safi == SAFI_FLOWSPEC) { peer = info->peer; - bgp_pbr_update_entry(peer->bgp, p, info, AFI_IP, safi, false); - return; + bgp_pbr_update_entry(peer->bgp, p, info, table->afi, + table->safi, false); + return ZCLIENT_SEND_SUCCESS; } memset(&api, 0, sizeof(api)); api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; + api.safi = table->safi; api.prefix = *p; if (info->attr->rmap_table_id) { @@ -1823,10 +1731,222 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) - zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, - &api.prefix); + zlog_debug("Tx route delete %s (table id %u) %pFX", + bgp->name_pretty, api.tableid, &api.prefix); + + return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); +} + +/* + * Walk the new Fifo list one by one and invoke bgp_zebra_announce/withdraw + * to install/withdraw the routes to zebra. + * + * If status = ZCLIENT_SEND_SUCCESS (Buffer empt)y i.e. Zebra is free to + * receive more incoming data, then pick the next item on the list and + * continue processing. + * + * If status = ZCLIENT_SEND_BUFFERED (Buffer pending) i.e. Zebra is busy, + * break and bail out of the function because once at some point when zebra + * is free, a callback is triggered which inturn call this same function and + * continue processing items on list. + */ +#define ZEBRA_ANNOUNCEMENTS_LIMIT 1000 +static void bgp_handle_route_announcements_to_zebra(struct event *e) +{ + bool is_evpn = false; + uint32_t count = 0; + struct bgp_dest *dest = NULL; + struct bgp_table *table = NULL; + enum zclient_send_status status = ZCLIENT_SEND_SUCCESS; + bool install; + const struct prefix_evpn *evp = NULL; + + while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) { + is_evpn = false; + + dest = zebra_announce_pop(&bm->zebra_announce_head); + + if (!dest) + break; + + table = bgp_dest_table(dest); + install = CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + if (table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) { + is_evpn = true; + evp = (const struct prefix_evpn *)bgp_dest_get_prefix( + dest); + } + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra", + install ? "announcing" : "withdrawing", + is_evpn ? " evpn" : " ", dest, + table->bgp->name_pretty, dest, dest->flags); + + if (install) { + if (is_evpn) + status = + evpn_zebra_install(table->bgp, + dest->za_vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + dest->za_bgp_pi); + else + status = bgp_zebra_announce_actual(dest, + dest->za_bgp_pi, + table->bgp); + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + } else { + if (is_evpn) + status = evpn_zebra_uninstall( + table->bgp, dest->za_vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix(dest), + dest->za_bgp_pi, false); + else + status = bgp_zebra_withdraw_actual(dest, + dest->za_bgp_pi, + table->bgp); + + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + } + + if (is_evpn && status == ZCLIENT_SEND_FAILURE) + flog_err(EC_BGP_EVPN_FAIL, + "%s (%u): Failed to %s EVPN %pFX %s route in VNI %u", + vrf_id_to_name(table->bgp->vrf_id), + table->bgp->vrf_id, + install ? "install" : "uninstall", evp, + evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + dest->za_vpn->vni); + + bgp_path_info_unlock(dest->za_bgp_pi); + dest->za_bgp_pi = NULL; + dest->za_vpn = NULL; + bgp_dest_unlock_node(dest); + + if (status == ZCLIENT_SEND_BUFFERED) + break; + + count++; + } + + if (status != ZCLIENT_SEND_BUFFERED && + zebra_announce_count(&bm->zebra_announce_head)) + event_add_event(bm->master, + bgp_handle_route_announcements_to_zebra, NULL, + 0, &bm->t_bgp_zebra_route); +} + +/* + * Callback function invoked when zclient_flush_data() receives a BUFFER_EMPTY + * i.e. zebra is free to receive more incoming data. + */ +static void bgp_zebra_buffer_write_ready(void) +{ + bgp_handle_route_announcements_to_zebra(NULL); +} + +/* + * BGP is now keeping a list of dests with the dest having a pointer + * to the bgp_path_info that it will be working on. + * Here is the sequence of events that should happen: + * + * Current State New State Action + * ------------- --------- ------ + * ---- Install Place dest on list, save pi, mark + * as going to be installed + * ---- Withdrawal Place dest on list, save pi, mark + * as going to be deleted + * + * Install Install Leave dest on list, release old pi, + * save new pi, mark as going to be + * Installed + * Install Withdrawal Leave dest on list, release old pi, + * save new pi, mark as going to be + * withdrawan, remove install flag + * + * Withdrawal Install Leave dest on list, release old pi, + * save new pi, mark as going to be + * installed. + * Withdrawal Withdrawal Leave dest on list, release old pi, + * save new pi, mark as going to be + * withdrawn. + */ +void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp, bool install, struct bgpevpn *vpn, + bool is_sync) +{ + bool is_evpn = false; + struct bgp_table *table = NULL; + + table = bgp_dest_table(dest); + if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + is_evpn = true; + + /* + * BGP is installing this route and bgp has been configured + * to suppress announcements until the route has been installed + * let's set the fact that we expect this route to be installed + */ + if (install) { + if (BGP_SUPPRESS_FIB_ENABLED(bgp)) + SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + + if (bgp->main_zebra_update_hold && !is_evpn) + return; + } else { + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + } + + /* + * Don't try to install if we're not connected to Zebra or Zebra doesn't + * know of this instance. + */ + if (!bgp_install_info_to_zebra(bgp) && !is_evpn) + return; + + if (!CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL) && + !CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { + zebra_announce_add_tail(&bm->zebra_announce_head, dest); + /* + * If neither flag is set and za_bgp_pi is not set then it is a bug + */ + assert(!dest->za_bgp_pi); + bgp_path_info_lock(info); + bgp_dest_lock_node(dest); + dest->za_bgp_pi = info; + } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL)) { + assert(dest->za_bgp_pi); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_path_info_lock(info); + dest->za_bgp_pi = info; + } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { + assert(dest->za_bgp_pi); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_path_info_lock(info); + dest->za_bgp_pi = info; + } - zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + if (is_evpn) { + dest->za_vpn = vpn; + dest->za_is_sync = is_sync; + } + + if (install) { + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + } else { + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + } + + event_add_event(bm->master, bgp_handle_route_announcements_to_zebra, + NULL, 0, &bm->t_bgp_zebra_route); } /* Withdraw all entries in a BGP instances RIB table from Zebra */ @@ -1847,8 +1967,8 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && (pi->type == ZEBRA_ROUTE_BGP)) - bgp_zebra_withdraw(bgp_dest_get_prefix(dest), - pi, bgp, safi); + bgp_zebra_route_install(dest, pi, bgp, false, + NULL, false); } } } @@ -1950,8 +2070,8 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, return CMD_SUCCESS; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -1971,8 +2091,8 @@ int bgp_redistribute_resend(struct bgp *bgp, afi_t afi, int type, return -1; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute del/add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2033,7 +2153,7 @@ bool bgp_redistribute_metric_set(struct bgp *bgp, struct bgp_redist *red, bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); - bgp_process(bgp, dest, afi, SAFI_UNICAST); + bgp_process(bgp, dest, pi, afi, SAFI_UNICAST); } } } @@ -2066,9 +2186,9 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, if (bgp_install_info_to_zebra(bgp)) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), - instance); + zlog_debug("Tx redistribute del %s afi %d %s %d", + bgp->name_pretty, afi, + zebra_route_string(type), instance); zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance, bgp->vrf_id); } @@ -2120,7 +2240,8 @@ void bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, struct listnode *node, *nnode; struct bgp_redist *red; - if (type != ZEBRA_ROUTE_TABLE || instance != 0) + if ((type != ZEBRA_ROUTE_TABLE && type != ZEBRA_ROUTE_TABLE_DIRECT) || + instance != 0) return _bgp_redistribute_unset(bgp, afi, type, instance); /* walk over instance */ @@ -2170,7 +2291,7 @@ void bgp_zebra_instance_register(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Registering VRF %u", bgp->vrf_id); + zlog_debug("Registering %s", bgp->name_pretty); /* Register for router-id, interfaces, redistributed routes. */ zclient_send_reg_requests(zclient, bgp->vrf_id); @@ -2192,7 +2313,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Deregistering VRF %u", bgp->vrf_id); + zlog_debug("Deregistering %s", bgp->name_pretty); /* For EVPN instance, unregister learning about VNIs, if appropriate. */ if (bgp->advertise_all_vni) @@ -2419,7 +2540,7 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) enum zapi_rule_notify_owner note; struct bgp_pbr_action *bgp_pbra; struct bgp_pbr_rule *bgp_pbr = NULL; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique, ifname, ¬e)) @@ -2665,8 +2786,12 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, /* Find the bgp route node */ dest = bgp_safi_node_lookup(bgp->rib[afi][safi], safi, &p, &bgp->vrf_prd); - if (!dest) + if (!dest) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: %pFX does not exist in the BGP table, nothing to do for %u", + __func__, &p, note); return -1; + } switch (note) { case ZAPI_ROUTE_INSTALLED: @@ -2675,7 +2800,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN : INSTALLED", (void *)dest); + zlog_debug("route %pBD : INSTALLED", dest); /* Find the best route */ for (pi = dest->info; pi; pi = pi->next) { /* Process aggregate route */ @@ -2688,7 +2813,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, group_announce_route(bgp, afi, safi, dest, new_select); else { flog_err(EC_BGP_INVALID_ROUTE, - "selected route %pRN not found", (void *)dest); + "selected route %pBD not found", dest); bgp_dest_unlock_node(dest); return -1; @@ -2701,13 +2826,13 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, */ UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN: Removed from Fib", (void *)dest); + zlog_debug("route %pBD: Removed from Fib", dest); break; case ZAPI_ROUTE_FAIL_INSTALL: new_select = NULL; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route: %pRN Failed to Install into Fib", - (void *)dest); + zlog_debug("route: %pBD Failed to Install into Fib", + dest); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { @@ -2720,8 +2845,8 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, break; case ZAPI_ROUTE_BETTER_ADMIN_WON: if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route: %pRN removed due to better admin won", - (void *)dest); + zlog_debug("route: %pBD removed due to better admin won", + dest); new_select = NULL; UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); @@ -2735,8 +2860,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, /* No action required */ break; case ZAPI_ROUTE_REMOVE_FAIL: - zlog_warn("%s: Route %pRN failure to remove", - __func__, (void *)dest); + zlog_warn("%s: Route %pBD failure to remove", __func__, dest); break; } @@ -3018,12 +3142,11 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac = stream_getl(s); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug( - "Rx L3-VNI ADD VRF %s VNI %u Originator-IP %pI4 RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", - vrf_id_to_name(vrf_id), l3vni, &originator_ip, - &svi_rmac, &vrr_rmac, - filter ? "prefix-routes-only" : "none", - svi_ifindex); + zlog_debug("Rx L3VNI ADD VRF %s VNI %u Originator-IP %pI4 RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, + &originator_ip, &svi_rmac, &vrr_rmac, + filter ? "prefix-routes-only" : "none", + svi_ifindex); frrtrace(8, frr_bgp, evpn_local_l3vni_add_zrecv, l3vni, vrf_id, &svi_rmac, &vrr_rmac, filter, originator_ip, @@ -3034,7 +3157,7 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac); } else { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", + zlog_debug("Rx L3VNI DEL VRF %s VNI %u", vrf_id_to_name(vrf_id), l3vni); frrtrace(2, frr_bgp, evpn_local_l3vni_del_zrecv, l3vni, vrf_id); @@ -3203,7 +3326,7 @@ static int bgp_ifp_create(struct interface *ifp) struct bgp *bgp; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf add VRF %s IF %s", ifp->vrf->name, ifp->name); bgp = ifp->vrf->info; @@ -3214,6 +3337,15 @@ static int bgp_ifp_create(struct interface *ifp) bgp_update_interface_nbrs(bgp, ifp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp); + + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -3253,12 +3385,12 @@ static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) struct bgp *bgp = bgp_get_default(); const char *loc_name = bgp->srv6_locator_name; - if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) - return -1; - if (!bgp || !bgp->srv6_enabled) return 0; + if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) + return -1; + if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) return -1; @@ -3276,6 +3408,9 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) struct in6_addr *tovpn_sid; struct prefix_ipv6 tmp_prefi; + if (!bgp) + return 0; + if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) return -1; @@ -3295,7 +3430,7 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) if (prefix_match((struct prefix *)&loc.prefix, (struct prefix *)&tmp_prefi)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } } @@ -3397,10 +3532,8 @@ static zclient_handler *const bgp_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_DELETE] = bgp_interface_address_delete, [ZEBRA_INTERFACE_NBR_ADDRESS_ADD] = bgp_interface_nbr_address_add, [ZEBRA_INTERFACE_NBR_ADDRESS_DELETE] = bgp_interface_nbr_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = bgp_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = zebra_read_route, - [ZEBRA_NEXTHOP_UPDATE] = bgp_read_nexthop_update, [ZEBRA_FEC_UPDATE] = bgp_read_fec_update, [ZEBRA_LOCAL_ES_ADD] = bgp_zebra_process_local_es_add, [ZEBRA_LOCAL_ES_DEL] = bgp_zebra_process_local_es_del, @@ -3493,6 +3626,9 @@ static bool bgp_zebra_label_manager_connect(void) /* tell label pool that zebra is connected */ bgp_lp_event_zebra_up(); + /* tell BGP L3VPN that label manager is available */ + if (bgp_get_default()) + vpn_leak_postchange_all(); return true; } @@ -3503,24 +3639,25 @@ static void bgp_zebra_capabilities(struct zclient_capabilities *cap) void bgp_zebra_init(struct event_loop *master, unsigned short instance) { - struct zclient_options options = zclient_options_default; - - options.synchronous = true; zclient_num_connects = 0; - if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up, - bgp_ifp_down, bgp_ifp_destroy); + hook_register_prio(if_real, 0, bgp_ifp_create); + hook_register_prio(if_up, 0, bgp_ifp_up); + hook_register_prio(if_down, 0, bgp_ifp_down); + hook_register_prio(if_unreal, 0, bgp_ifp_destroy); /* Set default values. */ zclient = zclient_new(master, &zclient_options_default, bgp_handlers, array_size(bgp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); + zclient->zebra_buffer_write_ready = bgp_zebra_buffer_write_ready; zclient->zebra_connected = bgp_zebra_connected; zclient->zebra_capabilities = bgp_zebra_capabilities; + zclient->nexthop_update = bgp_nexthop_update; zclient->instance = instance; /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_BGP; zclient_sync->instance = instance; @@ -3827,6 +3964,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) return BGP_GR_FAILURE; } + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s(%d): Sending GR capability %s to zebra", + bgp->name_pretty, bgp->vrf_id, + disable ? "disabled" : "enabled"); + /* Check if capability is already sent. If the flag force is set * send the capability since this can be initial bgp configuration */ @@ -3842,8 +3984,8 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api) == ZCLIENT_SEND_FAILURE) { - zlog_err("%s: %s error sending capability", __func__, - bgp->name_pretty); + zlog_err("%s(%d): Error sending GR capability to zebra", + bgp->name_pretty, bgp->vrf_id); ret = BGP_GR_FAILURE; } else { if (disable) @@ -3851,9 +3993,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) else bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: %s send capabilty success", __func__, - bgp->name_pretty); ret = BGP_GR_SUCCESS; } return ret; @@ -3954,8 +4093,7 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name) void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, ifindex_t ifindex, vrf_id_t vrf_id, enum lsp_types_t ltype, struct prefix *p, - uint32_t num_labels, - mpls_label_t out_labels[]) + uint8_t num_labels, mpls_label_t out_labels[]) { struct zapi_labels zl = {}; struct zapi_nexthop *znh; @@ -3991,7 +4129,8 @@ void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, zebra_send_mpls_labels(zclient, cmd, &zl); } -bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size) +bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size, + bool label_auto) { int ret; uint32_t start, end; @@ -4013,7 +4152,13 @@ bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size) return false; } - bgp_lp_event_chunk(start, end); + if (label_auto) + /* label automatic is serviced by the bgp label pool + * manager, which allocates label chunks in + * pre-pools, and which needs to be notified about + * new chunks availability + */ + bgp_lp_event_chunk(start, end); return true; } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 0edae041d2f9..55a4185bde71 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -28,13 +28,11 @@ extern void bgp_zebra_destroy(void); extern int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int bgp_if_update_all(void); -extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, - struct bgp_path_info *path, struct bgp *bgp, - afi_t afi, safi_t safi); +extern void bgp_zebra_route_install(struct bgp_dest *dest, + struct bgp_path_info *path, struct bgp *bgp, + bool install, struct bgpevpn *vpn, + bool is_sync); extern void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi); -extern void bgp_zebra_withdraw(const struct prefix *p, - struct bgp_path_info *path, struct bgp *bgp, - safi_t safi); /* Announce routes of any bgp subtype of a table to zebra */ extern void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, @@ -122,8 +120,12 @@ extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name); extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, ifindex_t index, vrf_id_t vrfid, enum lsp_types_t ltype, - struct prefix *p, uint32_t num_labels, + struct prefix *p, uint8_t num_labels, mpls_label_t out_labels[]); -extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size); +extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size, + bool label_auto); extern void bgp_zebra_release_label_range(uint32_t start, uint32_t end); +extern enum zclient_send_status +bgp_zebra_withdraw_actual(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp); #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 585863954cc0..c3ac4f8e9cca 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -63,6 +63,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_nhg.h" #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" @@ -148,7 +149,7 @@ void bgp_session_reset(struct peer *peer) * during walk of peer list, we would end up accessing the freed next * node. This function moves the next node along. */ -static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) +void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) { struct listnode *n; struct peer *npeer; @@ -186,7 +187,6 @@ int bgp_option_set(int flag) int bgp_option_unset(int flag) { switch (flag) { - /* Fall through. */ case BGP_OPT_NO_ZEBRA: case BGP_OPT_NO_FIB: UNSET_FLAG(bm->options, flag); @@ -306,11 +306,11 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY(&peer->local_id, id); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RID_CHANGE; + peer->last_reset = PEER_DOWN_RID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } /* EVPN uses router id in RD, update them */ @@ -410,6 +410,9 @@ void bgp_router_id_static_set(struct bgp *bgp, struct in_addr id) void bm_wait_for_fib_set(bool set) { bool send_msg = false; + struct bgp *bgp; + struct peer *peer; + struct listnode *next, *node; if (bm->wait_for_fib == set) return; @@ -428,12 +431,33 @@ void bm_wait_for_fib_set(bool set) if (send_msg && zclient) zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, set); + + /* + * If this is configed at a time when peers are already set + * FRR needs to reset the connection(s) as that some installs + * may have already happened in some shape fashion or form + * let's just start over + */ + for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + + if (!BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) + continue; + + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } } /* Set the suppress fib pending for the bgp configuration */ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) { bool send_msg = false; + struct peer *peer; + struct listnode *node; if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) return; @@ -465,6 +489,22 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, set); } + + /* + * If this is configed at a time when peers are already set + * FRR needs to reset the connection as that some installs + * may have already happened in some shape fashion or form + * let's just start over + */ + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + + if (!BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + continue; + + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } } /* BGP's cluster-id control. */ @@ -485,11 +525,11 @@ void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -509,11 +549,11 @@ void bgp_cluster_id_unset(struct bgp *bgp) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -577,8 +617,8 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str) already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION); bgp->confed_id = as; if (bgp->confed_id_pretty) - XFREE(MTYPE_BGP, bgp->confed_id_pretty); - bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP, as_str); + XFREE(MTYPE_BGP_NAME, bgp->confed_id_pretty); + bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION); /* If we were doing confederation already, this is just an external @@ -631,21 +671,19 @@ void bgp_confederation_id_unset(struct bgp *bgp) struct listnode *node, *nnode; bgp->confed_id = 0; - XFREE(MTYPE_BGP, bgp->confed_id_pretty); + XFREE(MTYPE_BGP_NAME, bgp->confed_id_pretty); bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION); for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { /* We're looking for peers who's AS is not local */ if (peer_sort(peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->connection->status)) { - peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } - else bgp_session_reset_safe(peer, &nnode); } @@ -685,7 +723,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str) bgp->confed_peers[bgp->confed_peers_cnt].as = as; bgp->confed_peers[bgp->confed_peers_cnt].as_pretty = - XSTRDUP(MTYPE_BGP, as_str); + XSTRDUP(MTYPE_BGP_NAME, as_str); bgp->confed_peers_cnt++; if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) { @@ -723,7 +761,7 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i].as == as) { - XFREE(MTYPE_BGP, bgp->confed_peers[i].as_pretty); + XFREE(MTYPE_BGP_NAME, bgp->confed_peers[i].as_pretty); for (j = i + 1; j < bgp->confed_peers_cnt; j++) { bgp->confed_peers[j - 1].as = bgp->confed_peers[j].as; @@ -1036,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) /* Peer-group */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (peer->as_type == AS_INTERNAL) + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) return BGP_PEER_IBGP; - else if (peer->as_type == AS_EXTERNAL) + if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) return BGP_PEER_EBGP; else if (peer->as_type == AS_SPECIFIED && peer->as) { @@ -1094,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; - } else if (peer->group->conf->as_type - == AS_INTERNAL) + } else if (CHECK_FLAG(peer->group->conf->as_type, + AS_INTERNAL)) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; } /* no AS information anywhere, let caller know */ return BGP_PEER_UNSPECIFIED; - } else if (peer->as_type != AS_SPECIFIED) - return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP - : BGP_PEER_EBGP); + } else if (peer->as_type != AS_SPECIFIED) { + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) + return BGP_PEER_IBGP; + else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) + return BGP_PEER_EBGP; + } return (local_as == 0 ? BGP_PEER_INTERNAL : local_as == peer->as ? BGP_PEER_IBGP @@ -1266,9 +1307,9 @@ static void peer_free(struct peer *peer) bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE, 0); if (peer->change_local_as_pretty) - XFREE(MTYPE_BGP, peer->change_local_as_pretty); + XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); if (peer->as_pretty) - XFREE(MTYPE_BGP, peer->as_pretty); + XFREE(MTYPE_BGP_NAME, peer->as_pretty); bgp_peer_connection_free(&peer->connection); @@ -1339,7 +1380,7 @@ int bgp_global_gr_init(struct bgp *bgp) /*GLOBAL_GR_cmd */ /*no_Global_GR_cmd*/ GLOBAL_GR, GLOBAL_INVALID, /*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/ - GLOBAL_INVALID, GLOBAL_HELPER + GLOBAL_DISABLE, GLOBAL_HELPER }, /* GLOBAL_INVALID Mode */ { @@ -1353,9 +1394,31 @@ int bgp_global_gr_init(struct bgp *bgp) memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM, sizeof(local_GLOBAL_GR_FSM)); - bgp->global_gr_present_state = GLOBAL_HELPER; + /* Inherit any BGP-wide configuration. */ + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + bgp->global_gr_present_state = GLOBAL_GR; + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + bgp->global_gr_present_state = GLOBAL_DISABLE; + else + bgp->global_gr_present_state = GLOBAL_HELPER; + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + bgp->restart_time = bm->restart_time; + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + bgp->stalepath_time = bm->stalepath_time; + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + bgp->select_defer_time = bm->select_defer_time; + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + bgp->rib_stale_time = bm->rib_stale_time; + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Global GR state is %s", bgp->name_pretty, + print_global_gr_mode(bgp->global_gr_present_state)); + return BGP_GR_SUCCESS; } @@ -1373,13 +1436,13 @@ int bgp_peer_gr_init(struct peer *peer) /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ {PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL }, /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ - { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT, + { PEER_HELPER, NULL }, {PEER_GLOBAL_INHERIT, bgp_peer_gr_action } }, { /* PEER_GR Mode */ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ - { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT, + { PEER_GR, NULL }, { PEER_GLOBAL_INHERIT, bgp_peer_gr_action }, /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ {PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL }, @@ -1391,7 +1454,7 @@ int bgp_peer_gr_init(struct peer *peer) /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL }, /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ - { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT, + { PEER_DISABLE, NULL }, { PEER_GLOBAL_INHERIT, bgp_peer_gr_action }, /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL } @@ -1408,16 +1471,14 @@ int bgp_peer_gr_init(struct peer *peer) { /* PEER_GLOBAL_INHERIT Mode */ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ - { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL }, + { PEER_GR, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL }, /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ - { PEER_DISABLE, bgp_peer_gr_action}, { PEER_INVALID, NULL }, + { PEER_DISABLE, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL }, /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ - { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL } + { PEER_HELPER, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL } } }; - memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, - sizeof(local_Peer_GR_FSM)); - peer->peer_gr_present_state = PEER_GLOBAL_INHERIT; + memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, sizeof(local_Peer_GR_FSM)); bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT); return BGP_GR_SUCCESS; @@ -1428,11 +1489,36 @@ static void bgp_srv6_init(struct bgp *bgp) bgp->srv6_enabled = false; memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name)); bgp->srv6_locator_chunks = list_new(); + bgp->srv6_locator_chunks->del = srv6_locator_chunk_list_free; bgp->srv6_functions = list_new(); + bgp->srv6_functions->del = (void (*)(void *))srv6_function_free; } static void bgp_srv6_cleanup(struct bgp *bgp) { + for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { + if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL) + srv6_locator_chunk_free( + &bgp->vpn_policy[afi].tovpn_sid_locator); + if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent != NULL) + XFREE(MTYPE_BGP_SRV6_SID, + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); + if (bgp->vpn_policy[afi].tovpn_sid != NULL) { + sid_unregister(bgp, bgp->vpn_policy[afi].tovpn_sid); + XFREE(MTYPE_BGP_SRV6_SID, + bgp->vpn_policy[afi].tovpn_sid); + } + } + + if (bgp->tovpn_sid_locator != NULL) + srv6_locator_chunk_free(&bgp->tovpn_sid_locator); + if (bgp->tovpn_zebra_vrf_sid_last_sent != NULL) + XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); + if (bgp->tovpn_sid != NULL) { + sid_unregister(bgp, bgp->tovpn_sid); + XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_sid); + } + if (bgp->srv6_locator_chunks) list_delete(&bgp->srv6_locator_chunks); if (bgp->srv6_functions) @@ -1472,6 +1558,8 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); + SET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY); @@ -1479,10 +1567,14 @@ struct peer *peer_new(struct bgp *bgp) PEER_FLAG_SEND_COMMUNITY); SET_FLAG(peer->af_flags_invert[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); + SET_FLAG(peer->af_flags_invert[afi][safi], + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); SET_FLAG(peer->af_flags_invert[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY); peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE; peer->addpath_best_selected[afi][safi] = 0; + peer->addpath_paths_limit[afi][safi].receive = 0; + peer->addpath_paths_limit[afi][safi].send = 0; peer->soo[afi][safi] = NULL; } @@ -1492,6 +1584,18 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) + peer_flag_set(peer, PEER_FLAG_ENFORCE_FIRST_AS); + + if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) + peer_flag_set(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION); + + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY)) + peer_flag_set(peer, PEER_FLAG_DYNAMIC_CAPABILITY); + + SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_FQDN); + SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN); + /* Initialize per peer bgp GR FSM */ bgp_peer_gr_init(peer); @@ -1538,6 +1642,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) /* copy tcp_mss value */ peer_dst->tcp_mss = peer_src->tcp_mss; (void)peer_sort(peer_dst); + peer_dst->sub_sort = peer_src->sub_sort; peer_dst->rmap_type = peer_src->rmap_type; peer_dst->local_role = peer_src->local_role; @@ -1569,6 +1674,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->weight[afi][safi] = peer_src->weight[afi][safi]; peer_dst->addpath_type[afi][safi] = peer_src->addpath_type[afi][safi]; + peer_dst->addpath_paths_limit[afi][safi] = + peer_src->addpath_paths_limit[afi][safi]; } for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { @@ -1603,6 +1710,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname); } peer_dst->ttl = peer_src->ttl; + peer_dst->gtsm_hops = peer_src->gtsm_hops; } static int bgp_peer_conf_if_to_su_update_v4(struct peer_connection *connection, @@ -1611,12 +1719,11 @@ static int bgp_peer_conf_if_to_su_update_v4(struct peer_connection *connection, struct connected *ifc; struct prefix p; uint32_t addr; - struct listnode *node; /* If our IPv4 address on the interface is /30 or /31, we can derive the * IPv4 address of the other end. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { if (ifc->address && (ifc->address->family == AF_INET)) { prefix_copy(&p, CONNECTED_PREFIX(ifc)); if (p.prefixlen == 30) { @@ -1792,21 +1899,31 @@ void bgp_peer_conf_if_to_su_update(struct peer_connection *connection) void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi) { struct bgp_dest *dest, *ndest; + struct bgp_path_info *pi, *next; struct bgp_table *table; for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); - if (table != NULL) { - /* Special handling for 2-level routing - * tables. */ - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP - || safi == SAFI_EVPN) { - for (ndest = bgp_table_top(table); ndest; - ndest = bgp_route_next(ndest)) - bgp_process(bgp, ndest, afi, safi); - } else - bgp_process(bgp, dest, afi, safi); + + if (!table) + continue; + + /* Special handling for 2-level routing + * tables. */ + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP + || safi == SAFI_EVPN) { + for (ndest = bgp_table_top(table); ndest; + ndest = bgp_route_next(ndest)) { + for (pi = bgp_dest_get_bgp_path_info(ndest); + (pi != NULL) && (next = pi->next, 1); + pi = next) + bgp_process(bgp, ndest, pi, afi, safi); + } + } else { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) + bgp_process(bgp, dest, pi, afi, safi); } } } @@ -1835,7 +1952,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, + enum peer_asn_type as_type, struct peer_group *group, bool config_node, const char *as_str) { int active; @@ -1863,7 +1980,7 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer->as = remote_as; /* internal and external values do not use as_pretty */ if (as_str && asn_str2asn(as_str, NULL)) - peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str); + peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); peer->as_type = as_type; peer->local_id = bgp->router_id; peer->v_holdtime = bgp->default_holdtime; @@ -1967,29 +2084,29 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) } /* Change peer's AS number. */ -void peer_as_change(struct peer *peer, as_t as, int as_specified, +void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, const char *as_str) { enum bgp_peer_sort origtype, newtype; /* Stop peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } origtype = peer_sort_lookup(peer); peer->as = as; - if (as_specified == AS_SPECIFIED && as_str) { + if (as_type == AS_SPECIFIED && as_str) { if (peer->as_pretty) - XFREE(MTYPE_BGP, peer->as_pretty); - peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str); + XFREE(MTYPE_BGP_NAME, peer->as_pretty); + peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty) - XFREE(MTYPE_BGP, peer->as_pretty); - peer->as_type = as_specified; + XFREE(MTYPE_BGP_NAME, peer->as_pretty); + peer->as_type = as_type; if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION) && !bgp_confederation_peers_check(peer->bgp, as) @@ -2026,6 +2143,8 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_FLOWSPEC], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_RTC], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_MULTICAST], @@ -2046,7 +2165,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, - as_t *as, int as_type, const char *as_str) + as_t *as, enum peer_asn_type as_type, const char *as_str) { struct peer *peer; as_t local_as; @@ -2087,10 +2206,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, } } else { /* internal/external used, compare as-types */ - if (((peer_sort_type == BGP_PEER_IBGP) - && (as_type != AS_INTERNAL)) - || ((peer_sort_type == BGP_PEER_EBGP) - && (as_type != AS_EXTERNAL))) { + if (((peer_sort_type == BGP_PEER_IBGP) && + !CHECK_FLAG(as_type, AS_INTERNAL)) || + ((peer_sort_type == BGP_PEER_EBGP) && + !CHECK_FLAG(as_type, AS_EXTERNAL))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } @@ -2166,7 +2285,7 @@ static void peer_group2peer_config_copy_af(struct peer_group *group, flags_tmp = conf->af_flags[afi][safi] & ~pflags_ovrd; flags_tmp ^= conf->af_flags_invert[afi][safi] ^ peer->af_flags_invert[afi][safi]; - flags_tmp &= ~pflags_ovrd; + UNSET_FLAG(flags_tmp, pflags_ovrd); UNSET_FLAG(peer->af_flags[afi][safi], ~pflags_ovrd); SET_FLAG(peer->af_flags[afi][safi], flags_tmp); @@ -2329,6 +2448,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) if (!active && peer_active(peer)) { bgp_timer_set(peer->connection); } else { + peer->last_reset = PEER_DOWN_AF_ACTIVATE; + if (peer_established(peer->connection)) { if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 1; @@ -2341,18 +2462,15 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) false); } } else { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } if (peer->connection->status == OpenSent || - peer->connection->status == OpenConfirm) { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; + peer->connection->status == OpenConfirm) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } /* * If we are turning on a AFI/SAFI locally and we've * started bringing a peer up, we need to tell @@ -2364,11 +2482,9 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) */ other = peer->doppelganger; if (other && (other->connection->status == OpenSent || - other->connection->status == OpenConfirm)) { - other->last_reset = PEER_DOWN_AF_ACTIVATE; + other->connection->status == OpenConfirm)) bgp_notify_send(other->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return 0; @@ -2406,10 +2522,10 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= peer_activate_af(tmp_peer, afi, safi); + SET_FLAG(ret, peer_activate_af(tmp_peer, afi, safi)); } } else { - ret |= peer_activate_af(peer, afi, safi); + SET_FLAG(ret, peer_activate_af(peer, afi, safi)); } /* If this is the first peer to be activated for this @@ -2462,6 +2578,8 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, } if (peer_established(peer->connection)) { + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; @@ -2473,13 +2591,11 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, bgp_clear_route(peer, afi, safi); peer->pcount[afi][safi] = 0; } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -2508,10 +2624,11 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= non_peergroup_deactivate_af(tmp_peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(tmp_peer, afi, + safi)); } } else { - ret |= non_peergroup_deactivate_af(peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(peer, afi, safi)); } bgp = peer->bgp; @@ -2614,6 +2731,14 @@ int peer_delete(struct peer *peer) if (peer->bfd_config) bgp_peer_remove_bfd_config(peer); + /* Delete peer route flap dampening configuration. This needs to happen + * before removing the peer from peer groups. + */ + FOREACH_AFI_SAFI (afi, safi) + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_CONFIG_DAMPENING)) + bgp_peer_damp_disable(peer, afi, safi); + /* If this peer belongs to peer group, clear up the relationship. */ if (peer->group) { @@ -2805,9 +2930,9 @@ static void peer_group2peer_config_copy(struct peer_group *group, peer->gtsm_hops = conf->gtsm_hops; /* peer flags apply */ - flags_tmp = conf->flags & ~peer->flags_override; + flags_tmp = CHECK_FLAG(conf->flags, ~peer->flags_override); flags_tmp ^= conf->flags_invert ^ peer->flags_invert; - flags_tmp &= ~peer->flags_override; + UNSET_FLAG(flags_tmp, peer->flags_override); UNSET_FLAG(peer->flags, ~peer->flags_override); SET_FLAG(peer->flags, flags_tmp); @@ -2861,6 +2986,13 @@ static void peer_group2peer_config_copy(struct peer_group *group, SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION); + /* capability dynamic apply */ + if (!CHECK_FLAG(peer->flags_override, + PEER_FLAG_DYNAMIC_CAPABILITY)) + if (CHECK_FLAG(conf->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) + SET_FLAG(peer->flags, + PEER_FLAG_DYNAMIC_CAPABILITY); + /* password apply */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD)) PEER_STR_ATTR_INHERIT(peer, group, password, @@ -2896,7 +3028,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* Peer group's remote AS configuration. */ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, - int as_type, const char *as_str) + enum peer_asn_type as_type, const char *as_str) { struct peer_group *group; struct peer *peer; @@ -2915,9 +3047,21 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, peer_as_change(group->conf, *as, as_type, as_str); for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) - || (peer->as_type != as_type)) + if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) || + (peer->as_type != as_type)) { peer_as_change(peer, *as, as_type, as_str); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s peer %s set to as_type %u curr status %s trigger BGP_Start", + __func__, peer->host, peer->as_type, + lookup_msg(bgp_status_msg, + peer->connection->status, NULL)); + /* Start Peer FSM to form neighbor using new as, + * NOTE: the connection is triggered upon start + * timer expiry. + */ + if (!BGP_PEER_START_SUPPRESSED(peer)) + BGP_EVENT_ADD(peer->connection, BGP_Start); + } } return 0; @@ -3012,7 +3156,7 @@ int peer_group_delete(struct peer_group *group) int peer_group_remote_as_delete(struct peer_group *group) { - struct peer *peer, *other; + struct peer *peer; struct listnode *node, *nnode; if ((group->conf->as_type == AS_UNSPECIFIED) @@ -3020,19 +3164,12 @@ int peer_group_remote_as_delete(struct peer_group *group) return 0; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - other = peer->doppelganger; - if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) bgp_zebra_terminate_radv(peer->bgp, peer); - peer_delete(peer); - - if (other && other->connection->status != Deleted) { - other->group = NULL; - peer_delete(other); - } + /* reset existing peer connection */ + peer_as_change(peer, 0, AS_UNSPECIFIED, NULL); } - list_delete_all_node(group->peer); group->conf->as = 0; group->conf->as_type = AS_UNSPECIFIED; @@ -3147,6 +3284,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer->as_type = group->conf->as_type; peer->as = group->conf->as; peer->sort = group->conf->sort; + peer->sub_sort = group->conf->sub_sort; } ptype = peer_sort(peer); @@ -3207,13 +3345,13 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RMAP_BIND; + peer->last_reset = PEER_DOWN_RMAP_BIND; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else { + else bgp_session_reset(peer); - } } /* Create a new peer. */ @@ -3287,9 +3425,9 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp)); bgp->as = *as; if (as_pretty) - bgp->as_pretty = XSTRDUP(MTYPE_BGP, as_pretty); + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty); else - bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as)); + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as)); if (asnotation != ASNOTATION_UNDEFINED) { bgp->asnotation = asnotation; @@ -3418,14 +3556,14 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp_mplsvpn_nh_label_bind_cache_init(&bgp->mplsvpn_nh_label_bind); if (name) - bgp->name = XSTRDUP(MTYPE_BGP, name); + bgp->name = XSTRDUP(MTYPE_BGP_NAME, name); event_add_timer(bm->master, bgp_startup_timer_expire, bgp, bgp->restart_time, &bgp->t_startup); /* printable name we can use in debug messages */ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) { - bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default"); + bgp->name_pretty = XSTRDUP(MTYPE_BGP_NAME, "VRF default"); } else { const char *n; int len; @@ -3437,7 +3575,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, len = 4 + 1 + strlen(n) + 1; /* "view foo\0" */ - bgp->name_pretty = XCALLOC(MTYPE_BGP, len); + bgp->name_pretty = XCALLOC(MTYPE_BGP_NAME, len); snprintf(bgp->name_pretty, len, "%s %s", (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) ? "VRF" @@ -3505,10 +3643,13 @@ struct bgp *bgp_lookup_by_name(const char *name) struct bgp *bgp; struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; if ((bgp->name == NULL && name == NULL) || (bgp->name && name && strcmp(bgp->name, name) == 0)) return bgp; + } return NULL; } @@ -3757,6 +3898,9 @@ void bgp_instance_down(struct bgp *bgp) struct listnode *node; struct listnode *next; + /* Cleanup evpn instance state */ + bgp_evpn_instance_down(bgp); + /* Stop timers. */ if (bgp->t_rmap_def_originate_eval) EVENT_OFF(bgp->t_rmap_def_originate_eval); @@ -3791,10 +3935,35 @@ int bgp_delete(struct bgp *bgp) afi_t afi; safi_t safi; int i; + struct bgp_dest *dest = NULL; + struct bgp_dest *dest_next = NULL; + struct bgp_table *dest_table = NULL; struct graceful_restart_info *gr_info; + uint32_t cnt_before, cnt_after; assert(bgp); + /* + * Iterate the pending dest list and remove all the dest pertaininig to + * the bgp under delete. + */ + cnt_before = zebra_announce_count(&bm->zebra_announce_head); + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; + dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); + dest_table = bgp_dest_table(dest); + if (dest_table->bgp == bgp) { + zebra_announce_del(&bm->zebra_announce_head, dest); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_dest_unlock_node(dest); + } + } + + cnt_after = zebra_announce_count(&bm->zebra_announce_head); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra Announce Fifo cleanup count before %u and after %u during BGP %s deletion", + cnt_before, cnt_after, bgp->name_pretty); + bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL); /* make sure we withdraw any exported routes */ @@ -3843,6 +4012,11 @@ int bgp_delete(struct bgp *bgp) EVENT_OFF(gr_info->t_route_select); } + /* Delete route flap dampening configuration */ + FOREACH_AFI_SAFI (afi, safi) { + bgp_damp_disable(bgp, afi, safi); + } + if (BGP_DEBUG(zebra, ZEBRA)) { if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) zlog_debug("Deleting Default VRF"); @@ -4040,27 +4214,20 @@ void bgp_free(struct bgp *bgp) if (bgp->vpn_policy[afi].rtlist[dir]) ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]); if (bgp->vpn_policy[afi].tovpn_rd_pretty) - XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty); - if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL) - srv6_locator_chunk_free( - &bgp->vpn_policy[afi].tovpn_sid_locator); - if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent != NULL) - XFREE(MTYPE_BGP_SRV6_SID, - bgp->vpn_policy[afi] - .tovpn_zebra_vrf_sid_last_sent); - if (bgp->vpn_policy[afi].tovpn_sid != NULL) { - sid_unregister(bgp, bgp->vpn_policy[afi].tovpn_sid); - XFREE(MTYPE_BGP_SRV6_SID, - bgp->vpn_policy[afi].tovpn_sid); - } + XFREE(MTYPE_BGP_NAME, + bgp->vpn_policy[afi].tovpn_rd_pretty); } bgp_srv6_cleanup(bgp); bgp_confederation_id_unset(bgp); - XFREE(MTYPE_BGP, bgp->as_pretty); - XFREE(MTYPE_BGP, bgp->name); - XFREE(MTYPE_BGP, bgp->name_pretty); - XFREE(MTYPE_BGP, bgp->snmp_stats); + for (int i = 0; i < bgp->confed_peers_cnt; i++) + XFREE(MTYPE_BGP_NAME, bgp->confed_peers[i].as_pretty); + + XFREE(MTYPE_BGP_NAME, bgp->as_pretty); + XFREE(MTYPE_BGP_NAME, bgp->name); + XFREE(MTYPE_BGP_NAME, bgp->name_pretty); + XFREE(MTYPE_BGP_NAME, bgp->snmp_stats); + XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers); XFREE(MTYPE_BGP, bgp); } @@ -4314,6 +4481,11 @@ struct peer *peer_lookup_dynamic_neighbor(struct bgp *bgp, union sockunion *su) zlog_debug("%s Dynamic Neighbor added, group %s count %d", peer->host, group->name, dncount); + if (dncount == gbgp->dynamic_neighbors_limit) { + zlog_warn("Dynamic Neighbor %s added as last connection. Peer-group %s reached maximum listen limit %d", + peer->host, group->name, + gbgp->dynamic_neighbors_limit); + } return peer; } @@ -4374,10 +4546,17 @@ bool peer_active(struct peer *peer) { if (BGP_CONNECTION_SU_UNSPEC(peer->connection)) return false; + + if (peer->bfd_config) { + if (bfd_session_is_down(peer->bfd_config->session)) + return false; + } + if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP][SAFI_FLOWSPEC] + || peer->afc[AFI_IP][SAFI_RTC] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] @@ -4392,19 +4571,20 @@ bool peer_active(struct peer *peer) /* If peer is negotiated at least one address family return 1. */ bool peer_active_nego(struct peer *peer) { - if (peer->afc_nego[AFI_IP][SAFI_UNICAST] - || peer->afc_nego[AFI_IP][SAFI_MULTICAST] - || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] - || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] - || peer->afc_nego[AFI_IP][SAFI_ENCAP] - || peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] - || peer->afc_nego[AFI_IP6][SAFI_UNICAST] - || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] - || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] - || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc_nego[AFI_IP6][SAFI_ENCAP] - || peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) + if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || + peer->afc_nego[AFI_IP][SAFI_MULTICAST] || + peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] || + peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || + peer->afc_nego[AFI_IP][SAFI_ENCAP] || + peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] || + peer->afc_nego[AFI_IP][SAFI_RTC] || + peer->afc_nego[AFI_IP6][SAFI_UNICAST] || + peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || + peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] || + peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || + peer->afc_nego[AFI_IP6][SAFI_ENCAP] || + peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] || + peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) return true; return false; } @@ -4500,7 +4680,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none}, - {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset}, + {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset}, {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset}, {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in}, @@ -4522,6 +4702,9 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_AIGP, 0, peer_change_none}, {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none}, {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_none}, + {PEER_FLAG_CAPABILITY_FQDN, 0, peer_change_none}, + {PEER_FLAG_AS_LOOP_DETECTION, 0, peer_change_none}, + {PEER_FLAG_EXTENDED_LINK_BANDWIDTH, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { @@ -4552,9 +4735,11 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { {PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out}, {PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out}, {PEER_FLAG_WEIGHT, 0, peer_change_reset_in}, - {PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset}, + {PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_none}, {PEER_FLAG_SOO, 0, peer_change_reset}, {PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset}, + {PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out}, + {PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none}, {0, 0, 0}}; /* Proper action set. */ @@ -4575,7 +4760,7 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, if (match->flag == 0) break; - if (match->flag & flag) { + if (CHECK_FLAG(match->flag, flag)) { found = 1; if (match->type == peer_change_reset_in) @@ -4606,6 +4791,13 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, static void peer_flag_modify_action(struct peer *peer, uint64_t flag) { + if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_PASSIVE) + peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; + else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) + peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; + if (flag == PEER_FLAG_SHUTDOWN) { if (CHECK_FLAG(peer->flags, flag)) { if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) @@ -4654,13 +4846,6 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) BGP_EVENT_ADD(peer->connection, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - else if (flag == PEER_FLAG_PASSIVE) - peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; - else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) - peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; - bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else @@ -4685,6 +4870,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) /* iterate through peers of BGP instance */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + /* continue, if peer is already in administrative shutdown. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) continue; @@ -4739,8 +4926,10 @@ void bgp_shutdown_disable(struct bgp *bgp) /* clear the BGP instances shutdown flag */ UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN); - for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { bgp_timer_set(peer->connection); + peer->last_reset = PEER_DOWN_WAITING_OPEN; + } } /* Change specified peer flag. */ @@ -4812,6 +5001,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) bgp_zebra_terminate_radv(peer->bgp, peer); } + if (flag == PEER_FLAG_SHUTDOWN) + peer->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer. */ if (action.type == peer_change_reset) peer_flag_modify_action(peer, flag); @@ -4847,6 +5040,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) set ? bgp_zebra_initiate_radv(member->bgp, member) : bgp_zebra_terminate_radv(member->bgp, member); + if (flag == PEER_FLAG_SHUTDOWN) + member->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer-group member. */ if (action.type == peer_change_reset) peer_flag_modify_action(member, flag); @@ -4890,15 +5087,17 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, ptype = peer_sort(peer); /* Special check for reflector client. */ - if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REFLECTOR_CLIENT) && + ptype != BGP_PEER_IBGP) return BGP_ERR_NOT_INTERNAL_PEER; /* Special check for remove-private-AS. */ - if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REMOVE_PRIVATE_AS) && + ptype == BGP_PEER_IBGP) return BGP_ERR_REMOVE_PRIVATE_AS; /* as-override is not allowed for IBGP peers */ - if (flag & PEER_FLAG_AS_OVERRIDE && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_AS_OVERRIDE) && ptype == BGP_PEER_IBGP) return BGP_ERR_AS_OVERRIDE; /* Handle flag updates where desired state matches current state. */ @@ -4949,7 +5148,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, * If the peer is a route server client let's not * muck with the nexthop on the way out the door */ - if (flag & PEER_FLAG_RSERVER_CLIENT) { + if (CHECK_FLAG(flag, PEER_FLAG_RSERVER_CLIENT)) { if (set) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED); @@ -4979,6 +5178,16 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, else if (flag == PEER_FLAG_ORF_PREFIX_RM) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + /* We should not reset the session if + * dynamic capability is enabled and we + * are changing the ORF prefix flags. + */ + if ((CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) && + (flag == PEER_FLAG_ORF_PREFIX_RM || + flag == PEER_FLAG_ORF_PREFIX_SM)) + action.type = peer_change_none; + peer_change_action(peer, afi, safi, action.type); } } @@ -5039,6 +5248,18 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, member->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + /* We should not reset the session if + * dynamic capability is enabled and we + * are changing the ORF prefix flags. + */ + if ((CHECK_FLAG(peer->cap, + PEER_CAP_DYNAMIC_RCV) && + CHECK_FLAG(peer->cap, + PEER_CAP_DYNAMIC_ADV)) && + (flag == PEER_FLAG_ORF_PREFIX_RM || + flag == PEER_FLAG_ORF_PREFIX_SM)) + action.type = peer_change_none; + peer_change_action(member, afi, safi, action.type); } @@ -5344,12 +5565,12 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5381,13 +5602,13 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) member->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname); sockunion_free(member->update_source); member->update_source = NULL; + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5415,12 +5636,12 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5451,13 +5672,13 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE); member->update_source = sockunion_dup(su); XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5503,12 +5724,12 @@ void peer_update_source_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5538,13 +5759,13 @@ void peer_update_source_unset(struct peer *peer) sockunion_free(member->update_source); member->update_source = NULL; XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5624,7 +5845,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, if (peer_established(peer->connection) && peer->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); - bgp_default_originate(peer, afi, safi, 0); + bgp_default_originate(peer, afi, safi, false); bgp_announce_route(peer, afi, safi, false); } @@ -5667,7 +5888,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, member->afc_nego[afi][safi]) { update_group_adjust_peer( peer_af_find(member, afi, safi)); - bgp_default_originate(member, afi, safi, 0); + bgp_default_originate(member, afi, safi, false); bgp_announce_route(member, afi, safi, false); } } @@ -5712,7 +5933,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer_established(peer->connection) && peer->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); - bgp_default_originate(peer, afi, safi, 1); + bgp_default_originate(peer, afi, safi, true); bgp_announce_route(peer, afi, safi, false); } @@ -5751,7 +5972,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer_established(member->connection) && member->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(member, afi, safi)); - bgp_default_originate(member, afi, safi, 1); + bgp_default_originate(member, afi, safi, true); bgp_announce_route(member, afi, safi, false); } } @@ -6440,8 +6661,8 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, peer->change_local_as = as; if (as_str) { if (peer->change_local_as_pretty) - XFREE(MTYPE_BGP, peer->change_local_as_pretty); - peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP, as_str); + XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); + peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } (void)peer_sort(peer); @@ -6478,8 +6699,8 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, replace_as); member->change_local_as = as; if (as_str) - member->change_local_as_pretty = - XSTRDUP(MTYPE_BGP, as_str); + member->change_local_as_pretty = XSTRDUP(MTYPE_BGP_NAME, + as_str); } return 0; @@ -6505,17 +6726,17 @@ int peer_local_as_unset(struct peer *peer) peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND); peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS); peer->change_local_as = 0; - XFREE(MTYPE_BGP, peer->change_local_as_pretty); + XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); } /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else BGP_EVENT_ADD(peer->connection, BGP_Stop); /* Skip peer-group mechanics for regular peers. */ @@ -6536,14 +6757,14 @@ int peer_local_as_unset(struct peer *peer) UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); member->change_local_as = 0; - XFREE(MTYPE_BGP, member->change_local_as_pretty); + XFREE(MTYPE_BGP_NAME, member->change_local_as_pretty); + member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); } @@ -6570,6 +6791,7 @@ int peer_password_set(struct peer *peer, const char *password) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, @@ -6607,6 +6829,7 @@ int peer_password_set(struct peer *peer, const char *password) XFREE(MTYPE_PEER_PASSWORD, member->password); member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); + member->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, @@ -7827,8 +8050,9 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops) struct listnode *node, *nnode; int ret; - zlog_debug("%s: set gtsm_hops to %d for %s", __func__, gtsm_hops, - peer->host); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s: set gtsm_hops to %d for %s", __func__, + gtsm_hops, peer->host); /* We cannot configure ttl-security hops when ebgp-multihop is already set. For non peer-groups, the check is simple. For peer-groups, @@ -7937,7 +8161,9 @@ int peer_ttl_security_hops_unset(struct peer *peer) struct listnode *node, *nnode; int ret = 0; - zlog_debug("%s: set gtsm_hops to zero for %s", __func__, peer->host); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s: set gtsm_hops to zero for %s", __func__, + peer->host); /* if a peer-group member, then reset to peer-group default rather than * 0 */ @@ -8021,6 +8247,16 @@ static void peer_reset_message_stats(struct peer *peer) } } +/* Helper function to resend some BGP capabilities that are uncontrolled. + * For instance, FQDN capability, that can't be turned off, but let's say + * we changed the hostname, we need to resend it. + */ +static void peer_clear_capabilities(struct peer *peer, afi_t afi, safi_t safi) +{ + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_FQDN, + CAPABILITY_ACTION_SET); +} + /* * If peer clear is invoked in a loop for all peers on the BGP instance, * it may end up freeing the doppelganger, and if this was the next node @@ -8129,6 +8365,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi, if (stype == BGP_CLEAR_MESSAGE_STATS) peer_reset_message_stats(peer); + if (stype == BGP_CLEAR_CAPABILITIES) + peer_clear_capabilities(peer, afi, safi); + return 0; } @@ -8187,6 +8426,8 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, memset(&bgp_master, 0, sizeof(bgp_master)); bm = &bgp_master; + + zebra_announce_init(&bm->zebra_announce_head); bm->bgp = list_new(); bm->listen_sockets = list_new(); bm->port = BGP_PORT_DEFAULT; @@ -8195,16 +8436,21 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->start_time = monotime(NULL); bm->t_rmap_update = NULL; bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; - bm->v_establish_wait = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; + bm->v_establish_wait = BGP_UPDATE_DELAY_DEFAULT; bm->terminating = false; bm->socket_buffer = buffer_size; bm->wait_for_fib = false; - bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL; + bm->ip_tos = IPTOS_PREC_INTERNETCONTROL; bm->inq_limit = BM_DEFAULT_Q_LIMIT; bm->outq_limit = BM_DEFAULT_Q_LIMIT; bm->t_bgp_sync_label_manager = NULL; bm->t_bgp_start_label_manager = NULL; + bm->t_bgp_zebra_route = NULL; + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + bm->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME; bgp_mac_init(); /* init the rd id space. @@ -8217,7 +8463,7 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, /* mpls label dynamic allocation pool */ bgp_lp_init(bm->master, &bm->labelpool); - bgp_l3nhg_init(); + bgp_nhg_init(); bgp_evpn_mh_init(); QOBJ_REG(bm, bgp_master); } @@ -8237,10 +8483,9 @@ static void bgp_if_finish(struct bgp *bgp) return; FOR_ALL_INTERFACES (vrf, ifp) { - struct listnode *c_node, *c_nnode; struct connected *c; - for (ALL_LIST_ELEMENTS(ifp->connected, c_node, c_nnode, c)) + frr_each_safe (if_connected, ifp->connected, c) bgp_connected_delete(bgp, c); } } @@ -8372,6 +8617,7 @@ void bgp_init(unsigned short instance) /* BGP inits. */ bgp_attr_init(); + bgp_labels_init(); bgp_debug_init(); bgp_community_alias_init(); bgp_dump_init(); @@ -8456,6 +8702,7 @@ void bgp_terminate(void) EVENT_OFF(bm->t_rmap_update); EVENT_OFF(bm->t_bgp_sync_label_manager); EVENT_OFF(bm->t_bgp_start_label_manager); + EVENT_OFF(bm->t_bgp_zebra_route); bgp_mac_finish(); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index ca1411a3b179..a7965acf7678 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -18,6 +18,8 @@ #include "iana_afi.h" #include "asn.h" +PREDECL_LIST(zebra_announce); + /* For union sockunion. */ #include "queue.h" #include "sockunion.h" @@ -31,9 +33,13 @@ #include "bgp_addpath_types.h" #include "bgp_nexthop.h" #include "bgp_io.h" +#include "bgp_damp.h" #include "lib/bfd.h" +DECLARE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf), + (vty, vrf)); + #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ #define BGP_PEER_MAX_HASH_SIZE 16384 @@ -50,10 +56,12 @@ struct bgp_pbr_config; * behavior * in the system. */ -enum { AS_UNSPECIFIED = 0, - AS_SPECIFIED, - AS_INTERNAL, - AS_EXTERNAL, +enum peer_asn_type { + AS_UNSPECIFIED = 1, + AS_SPECIFIED = 2, + AS_INTERNAL = 4, + AS_EXTERNAL = 8, + AS_AUTO = 16, }; /* Zebra Gracaful Restart states */ @@ -81,6 +89,7 @@ enum bgp_af_index { BGP_AF_IPV6_LBL_UNICAST, BGP_AF_IPV4_FLOWSPEC, BGP_AF_IPV6_FLOWSPEC, + BGP_AF_RTC, BGP_AF_MAX }; @@ -121,6 +130,9 @@ struct bgp_master { #define BGP_OPT_NO_FIB (1 << 0) #define BGP_OPT_NO_LISTEN (1 << 1) #define BGP_OPT_NO_ZEBRA (1 << 2) +#define BGP_OPT_TRAPS_RFC4273 (1 << 3) +#define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4) +#define BGP_OPT_TRAPS_RFC4382 (1 << 5) uint64_t updgrp_idspace; uint64_t subgrp_idspace; @@ -155,11 +167,28 @@ struct bgp_master { uint32_t flags; #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) +#define BM_FLAG_MAINTENANCE_MODE (1 << 2) +#define BM_FLAG_GR_RESTARTER (1 << 3) +#define BM_FLAG_GR_DISABLED (1 << 4) +#define BM_FLAG_GR_PRESERVE_FWD (1 << 5) +#define BM_FLAG_GRACEFUL_RESTART (1 << 6) +#define BM_FLAG_GR_COMPLETE (1 << 7) + +#define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED) + + /* BGP-wide graceful restart config params */ + uint32_t restart_time; + uint32_t stalepath_time; + uint32_t select_defer_time; + uint32_t rib_stale_time; + + time_t startup_time; + time_t gr_completion_time; bool terminating; /* global flag that sigint terminate seen */ - /* DSCP value for TCP sessions */ - uint8_t tcp_dscp; + /* TOS value for outgoing packets in BGP connections */ + uint8_t ip_tos; #define BM_DEFAULT_Q_LIMIT 10000 uint32_t inq_limit; @@ -168,8 +197,13 @@ struct bgp_master { struct event *t_bgp_sync_label_manager; struct event *t_bgp_start_label_manager; + struct event *t_bgp_zebra_route; + bool v6_with_v4_nexthops; + /* To preserve ordering of installations into zebra across all Vrfs */ + struct zebra_announce_head zebra_announce_head; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp_master); @@ -217,6 +251,8 @@ struct vpn_policy { #define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET (1 << 2) #define BGP_VPN_POLICY_TOVPN_SID_AUTO (1 << 3) #define BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP (1 << 4) +/* Manual label is registered with zebra label manager */ +#define BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG (1 << 5) /* * If we are importing another vrf into us keep a list of @@ -278,9 +314,9 @@ struct graceful_restart_info { /* Best route select */ struct event *t_route_select; /* AFI, SAFI enabled */ - bool af_enabled[AFI_MAX][SAFI_MAX]; + bool af_enabled; /* Route update completed */ - bool route_sync[AFI_MAX][SAFI_MAX]; + bool route_sync; }; enum global_mode { @@ -455,16 +491,14 @@ struct bgp { uint32_t restarted_peers; uint32_t implicit_eors; uint32_t explicit_eors; -#define BGP_UPDATE_DELAY_DEF 0 -#define BGP_UPDATE_DELAY_MIN 0 -#define BGP_UPDATE_DELAY_MAX 3600 +#define BGP_UPDATE_DELAY_DEFAULT 0 /* Reference bandwidth for BGP link-bandwidth. Used when * the LB value has to be computed based on some other * factor (e.g., number of multipaths for the prefix) * Value is in Mbps */ - uint32_t lb_ref_bw; + uint64_t lb_ref_bw; #define BGP_LINK_BW_REF_BW 1 /* BGP flags. */ @@ -514,6 +548,9 @@ struct bgp { /* For BGP-LU, force IPv6 local prefixes to use ipv6-explicit-null label */ #define BGP_FLAG_LU_IPV6_EXPLICIT_NULL (1ULL << 34) #define BGP_FLAG_SOFT_VERSION_CAPABILITY (1ULL << 35) +#define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36) +#define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37) +#define BGP_FLAG_VNI_DOWN (1ULL << 38) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance. @@ -529,6 +566,9 @@ struct bgp { */ enum zebra_gr_mode present_zebra_gr_state; + /* Is deferred path selection still not complete? */ + bool gr_route_sync_pending; + /* BGP Per AF flags */ uint16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) @@ -817,6 +857,9 @@ struct bgp { enum asnotation_mode asnotation; + /* BGP route flap dampening configuration */ + struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp); @@ -832,7 +875,10 @@ DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), (bgp, vty)); +DECLARE_HOOK(bgp_snmp_traps_config_write, (struct vty *vty), (vty)); DECLARE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp)); +DECLARE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), + (vrf, enabled)); /* Thread callback information */ struct afi_safi_info { @@ -877,10 +923,10 @@ struct peer_group { struct bgp_notify { uint8_t code; uint8_t subcode; - char *data; bgp_size_t length; - uint8_t *raw_data; bool hard_reset; + char *data; + uint8_t *raw_data; }; /* Next hop self address. */ @@ -971,6 +1017,14 @@ enum bgp_peer_sort { BGP_PEER_CONFED, }; +/* BGP peering sub-types + * E.g.: + * EBGP-OAD - https://datatracker.ietf.org/doc/html/draft-uttaro-idr-bgp-oad + */ +enum bgp_peer_sub_sort { + BGP_PEER_EBGP_OAD = 1, +}; + /* BGP message header and packet size. */ #define BGP_MARKER_SIZE 16 #define BGP_HEADER_SIZE 19 @@ -1032,7 +1086,8 @@ enum peer_gr_command { NO_PEER_HELPER_CMD }; -typedef unsigned int (*bgp_peer_gr_action_ptr)(struct peer *, int, int); +typedef unsigned int (*bgp_peer_gr_action_ptr)(struct peer *, enum peer_mode, + enum peer_mode); struct bgp_peer_gr { enum peer_mode next_state; @@ -1120,6 +1175,11 @@ struct llgr_info { uint8_t flags; }; +struct addpath_paths_limit { + uint16_t send; + uint16_t receive; +}; + struct peer_connection { struct peer *peer; @@ -1129,6 +1189,11 @@ struct peer_connection { int fd; + /* Thread flags */ + _Atomic uint32_t thread_flags; +#define PEER_THREAD_WRITES_ON (1U << 0) +#define PEER_THREAD_READS_ON (1U << 1) + /* Packet receive and send buffer. */ pthread_mutex_t io_mtx; // guards ibuf, obuf struct stream_fifo *ibuf; // packets waiting to be processed @@ -1159,11 +1224,6 @@ struct peer_connection { union sockunion su; #define BGP_CONNECTION_SU_UNSPEC(connection) \ (connection->su.sa.sa_family == AF_UNSPEC) - - /* Thread flags */ - _Atomic uint32_t thread_flags; -#define PEER_THREAD_WRITES_ON (1U << 0) -#define PEER_THREAD_READS_ON (1U << 1) }; extern struct peer_connection *bgp_peer_connection_new(struct peer *peer); extern void bgp_peer_connection_free(struct peer_connection **connection); @@ -1188,7 +1248,7 @@ struct peer { struct peer_af *peer_af_array[BGP_AF_MAX]; /* Peer's remote AS number. */ - int as_type; + enum peer_asn_type as_type; as_t as; /* for vty as format */ char *as_pretty; @@ -1197,6 +1257,7 @@ struct peer { as_t local_as; enum bgp_peer_sort sort; + enum bgp_peer_sub_sort sub_sort; /* Peer's Change local AS number. */ as_t change_local_as; @@ -1279,39 +1340,41 @@ struct peer { uint8_t afc_recv[AFI_MAX][SAFI_MAX]; /* Capability flags (reset in bgp_stop) */ - uint32_t cap; -#define PEER_CAP_REFRESH_ADV (1U << 0) /* refresh advertised */ -#define PEER_CAP_REFRESH_RCV (1U << 2) /* refresh rfc received */ -#define PEER_CAP_DYNAMIC_ADV (1U << 3) /* dynamic advertised */ -#define PEER_CAP_DYNAMIC_RCV (1U << 4) /* dynamic received */ -#define PEER_CAP_RESTART_ADV (1U << 5) /* restart advertised */ -#define PEER_CAP_RESTART_RCV (1U << 6) /* restart received */ -#define PEER_CAP_AS4_ADV (1U << 7) /* as4 advertised */ -#define PEER_CAP_AS4_RCV (1U << 8) /* as4 received */ + uint64_t cap; +#define PEER_CAP_REFRESH_ADV (1ULL << 0) /* refresh advertised */ +#define PEER_CAP_REFRESH_RCV (1ULL << 2) /* refresh rfc received */ +#define PEER_CAP_DYNAMIC_ADV (1ULL << 3) /* dynamic advertised */ +#define PEER_CAP_DYNAMIC_RCV (1ULL << 4) /* dynamic received */ +#define PEER_CAP_RESTART_ADV (1ULL << 5) /* restart advertised */ +#define PEER_CAP_RESTART_RCV (1ULL << 6) /* restart received */ +#define PEER_CAP_AS4_ADV (1ULL << 7) /* as4 advertised */ +#define PEER_CAP_AS4_RCV (1ULL << 8) /* as4 received */ /* sent graceful-restart restart (R) bit */ -#define PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV (1U << 9) +#define PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV (1ULL << 9) /* received graceful-restart restart (R) bit */ -#define PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV (1U << 10) -#define PEER_CAP_ADDPATH_ADV (1U << 11) /* addpath advertised */ -#define PEER_CAP_ADDPATH_RCV (1U << 12) /* addpath received */ -#define PEER_CAP_ENHE_ADV (1U << 13) /* Extended nexthop advertised */ -#define PEER_CAP_ENHE_RCV (1U << 14) /* Extended nexthop received */ -#define PEER_CAP_HOSTNAME_ADV (1U << 15) /* hostname advertised */ -#define PEER_CAP_HOSTNAME_RCV (1U << 16) /* hostname received */ -#define PEER_CAP_ENHANCED_RR_ADV (1U << 17) /* enhanced rr advertised */ -#define PEER_CAP_ENHANCED_RR_RCV (1U << 18) /* enhanced rr received */ -#define PEER_CAP_EXTENDED_MESSAGE_ADV (1U << 19) -#define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20) -#define PEER_CAP_LLGR_ADV (1U << 21) -#define PEER_CAP_LLGR_RCV (1U << 22) +#define PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV (1ULL << 10) +#define PEER_CAP_ADDPATH_ADV (1ULL << 11) /* addpath advertised */ +#define PEER_CAP_ADDPATH_RCV (1ULL << 12) /* addpath received */ +#define PEER_CAP_ENHE_ADV (1ULL << 13) /* Extended nexthop advertised */ +#define PEER_CAP_ENHE_RCV (1ULL << 14) /* Extended nexthop received */ +#define PEER_CAP_HOSTNAME_ADV (1ULL << 15) /* hostname advertised */ +#define PEER_CAP_HOSTNAME_RCV (1ULL << 16) /* hostname received */ +#define PEER_CAP_ENHANCED_RR_ADV (1ULL << 17) /* enhanced rr advertised */ +#define PEER_CAP_ENHANCED_RR_RCV (1ULL << 18) /* enhanced rr received */ +#define PEER_CAP_EXTENDED_MESSAGE_ADV (1ULL << 19) +#define PEER_CAP_EXTENDED_MESSAGE_RCV (1ULL << 20) +#define PEER_CAP_LLGR_ADV (1ULL << 21) +#define PEER_CAP_LLGR_RCV (1ULL << 22) /* sent graceful-restart notification (N) bit */ -#define PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV (1U << 23) +#define PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV (1ULL << 23) /* received graceful-restart notification (N) bit */ -#define PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV (1U << 24) -#define PEER_CAP_ROLE_ADV (1U << 25) /* role advertised */ -#define PEER_CAP_ROLE_RCV (1U << 26) /* role received */ -#define PEER_CAP_SOFT_VERSION_ADV (1U << 27) -#define PEER_CAP_SOFT_VERSION_RCV (1U << 28) +#define PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV (1ULL << 24) +#define PEER_CAP_ROLE_ADV (1ULL << 25) /* role advertised */ +#define PEER_CAP_ROLE_RCV (1ULL << 26) /* role received */ +#define PEER_CAP_SOFT_VERSION_ADV (1ULL << 27) +#define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28) +#define PEER_CAP_PATHS_LIMIT_ADV (1U << 29) +#define PEER_CAP_PATHS_LIMIT_RCV (1U << 30) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1330,6 +1393,8 @@ struct peer { #define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */ #define PEER_CAP_LLGR_AF_ADV (1U << 15) #define PEER_CAP_LLGR_AF_RCV (1U << 16) +#define PEER_CAP_PATHS_LIMIT_AF_ADV (1U << 17) +#define PEER_CAP_PATHS_LIMIT_AF_RCV (1U << 18) /* Global configuration flags. */ /* @@ -1439,6 +1504,9 @@ struct peer { #define PEER_FLAG_AIGP (1ULL << 34) #define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35) #define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36) +#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */ +#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */ +#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39) /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1466,6 +1534,9 @@ struct peer { /* Last update packet sent time */ time_t pkt_stime[AFI_MAX][SAFI_MAX]; + /* Peer / peer group route flap dampening configuration */ + struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; + /* Peer Per AF flags */ /* * Please consult the comments for *flags_override*, *flags_invert* and @@ -1505,6 +1576,9 @@ struct peer { #define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 26) #define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27) #define PEER_FLAG_SOO (1ULL << 28) +#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29) +#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30) +#define PEER_FLAG_CONFIG_DAMPENING (1U << 31) #define PEER_FLAG_ACCEPT_OWN (1ULL << 63) enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -1624,6 +1698,8 @@ struct peer { uint32_t stat_pfx_nh_invalid; uint32_t stat_pfx_dup_withdraw; uint32_t stat_upd_7606; /* RFC7606: treat-as-withdraw */ + uint64_t stat_pfx_loc_rib; /* RFC7854 : Number of routes in Loc-RIB */ + uint64_t stat_pfx_adj_rib_in; /* RFC7854 : Number of routes in Adj-RIBs-In */ /* BGP state count */ uint32_t established; /* Established */ @@ -1678,6 +1754,9 @@ struct peer { /* ORF Prefix-list */ struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; + /* Route Target Constrain list */ + struct prefix_list *rtc_plist; + /* Text description of last attribute rcvd */ char rcvd_attr_str[BUFSIZ]; @@ -1742,6 +1821,8 @@ struct peer { #define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */ #define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */ #define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */ +#define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */ +#define PEER_DOWN_PASSWORD_CHANGE 37U /* neighbor password command */ /* * Remember to update peer_down_str in bgp_fsm.c when you add * a new value to the last_reset reason @@ -1789,9 +1870,6 @@ struct peer { char *hostname; char *domainname; - /* Sender side AS path loop detection. */ - bool as_path_loop_detection; - /* Extended Message Support */ uint16_t max_packet_size; @@ -1821,6 +1899,9 @@ struct peer { /* Add-Path Best selected paths number to advertise */ uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX]; + /* Add-Path Paths-Limit */ + struct addpath_paths_limit addpath_paths_limit[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(peer); @@ -1868,11 +1949,11 @@ struct bgp_nlri { /* SAFI. */ uint8_t safi; /* iana_safi_t */ - /* Pointer to NLRI byte stream. */ - uint8_t *nlri; - /* Length of whole NLRI. */ bgp_size_t length; + + /* Pointer to NLRI byte stream. */ + uint8_t *nlri; }; /* BGP versions. */ @@ -1927,7 +2008,6 @@ struct bgp_nlri { #define BGP_ATTR_LARGE_COMMUNITIES 32 #define BGP_ATTR_OTC 35 #define BGP_ATTR_PREFIX_SID 40 -#define BGP_ATTR_SRTE_COLOR 51 #ifdef ENABLE_BGP_VNC_ATTR #define BGP_ATTR_VNC 255 #endif @@ -1946,6 +2026,7 @@ struct bgp_nlri { #define BGP_NOTIFY_FSM_ERR 5 #define BGP_NOTIFY_CEASE 6 #define BGP_NOTIFY_ROUTE_REFRESH_ERR 7 +#define BGP_NOTIFY_SEND_HOLD_ERR 8 /* Subcodes for BGP Finite State Machine Error */ #define BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC 0 @@ -2042,7 +2123,6 @@ struct bgp_nlri { #define BGP_UPTIME_LEN 25 /* Default configuration settings for bgpd. */ -#define BGP_VTY_PORT 2605 #define BGP_DEFAULT_CONFIG "bgpd.conf" /* BGP Dynamic Neighbors feature */ @@ -2064,7 +2144,8 @@ enum bgp_clear_type { BGP_CLEAR_SOFT_IN, BGP_CLEAR_SOFT_BOTH, BGP_CLEAR_SOFT_IN_ORF_PREFIX, - BGP_CLEAR_MESSAGE_STATS + BGP_CLEAR_MESSAGE_STATS, + BGP_CLEAR_CAPABILITIES, }; /* Macros. */ @@ -2206,8 +2287,9 @@ extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, - bool config_node, const char *as_str); + enum peer_asn_type as_type, + struct peer_group *group, bool config_node, + const char *as_str); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, @@ -2280,13 +2362,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp); extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *); extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); -extern void peer_as_change(struct peer *peer, as_t as, int as_type, - const char *as_str); +extern void peer_as_change(struct peer *peer, as_t as, + enum peer_asn_type as_type, const char *as_str); extern int peer_remote_as(struct bgp *bgp, union sockunion *su, - const char *conf_if, as_t *as, int as_type, - const char *as_str); + const char *conf_if, as_t *as, + enum peer_asn_type as_type, const char *as_str); extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as, - int as_type, const char *as_str); + enum peer_asn_type as_type, const char *as_str); extern int peer_delete(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); @@ -2430,6 +2512,8 @@ extern enum asnotation_mode bgp_get_asnotation(struct bgp *bgp); extern void bgp_route_map_terminate(void); +extern bool bgp_route_map_has_extcommunity_rt(const struct route_map *map); + extern int peer_cmp(struct peer *p1, struct peer *p2); extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi, @@ -2504,6 +2588,8 @@ static inline int afindex(afi_t afi, safi_t safi) return BGP_AF_IPV4_ENCAP; case SAFI_FLOWSPEC: return BGP_AF_IPV4_FLOWSPEC; + case SAFI_RTC: + return BGP_AF_RTC; case SAFI_EVPN: case SAFI_UNSPEC: case SAFI_MAX: @@ -2524,6 +2610,7 @@ static inline int afindex(afi_t afi, safi_t safi) return BGP_AF_IPV6_ENCAP; case SAFI_FLOWSPEC: return BGP_AF_IPV6_FLOWSPEC; + case SAFI_RTC: case SAFI_EVPN: case SAFI_UNSPEC: case SAFI_MAX: @@ -2541,6 +2628,7 @@ static inline int afindex(afi_t afi, safi_t safi) case SAFI_ENCAP: case SAFI_FLOWSPEC: case SAFI_UNSPEC: + case SAFI_RTC: case SAFI_MAX: return BGP_AF_MAX; } @@ -2564,13 +2652,13 @@ static inline int peer_group_active(struct peer *peer) /* If peer is negotiated at least one address family return 1. */ static inline int peer_afi_active_nego(const struct peer *peer, afi_t afi) { - if (peer->afc_nego[afi][SAFI_UNICAST] - || peer->afc_nego[afi][SAFI_MULTICAST] - || peer->afc_nego[afi][SAFI_LABELED_UNICAST] - || peer->afc_nego[afi][SAFI_MPLS_VPN] - || peer->afc_nego[afi][SAFI_ENCAP] - || peer->afc_nego[afi][SAFI_FLOWSPEC] - || peer->afc_nego[afi][SAFI_EVPN]) + if (peer->afc_nego[afi][SAFI_UNICAST] || + peer->afc_nego[afi][SAFI_MULTICAST] || + peer->afc_nego[afi][SAFI_LABELED_UNICAST] || + peer->afc_nego[afi][SAFI_MPLS_VPN] || + peer->afc_nego[afi][SAFI_ENCAP] || + peer->afc_nego[afi][SAFI_FLOWSPEC] || + peer->afc_nego[afi][SAFI_EVPN] || peer->afc_nego[afi][SAFI_RTC]) return 1; return 0; } @@ -2580,17 +2668,18 @@ static inline int peer_group_af_configured(struct peer_group *group) { struct peer *peer = group->conf; - if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] - || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] - || peer->afc[AFI_IP][SAFI_FLOWSPEC] - || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] - || peer->afc[AFI_IP6][SAFI_UNICAST] - || peer->afc[AFI_IP6][SAFI_MULTICAST] - || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] - || peer->afc[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc[AFI_IP6][SAFI_ENCAP] - || peer->afc[AFI_IP6][SAFI_FLOWSPEC] - || peer->afc[AFI_L2VPN][SAFI_EVPN]) + if (peer->afc[AFI_IP][SAFI_UNICAST] || + peer->afc[AFI_IP][SAFI_MULTICAST] || + peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || + peer->afc[AFI_IP][SAFI_FLOWSPEC] || + peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || + peer->afc[AFI_IP][SAFI_RTC] || peer->afc[AFI_IP6][SAFI_UNICAST] || + peer->afc[AFI_IP6][SAFI_MULTICAST] || + peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || + peer->afc[AFI_IP6][SAFI_MPLS_VPN] || + peer->afc[AFI_IP6][SAFI_ENCAP] || + peer->afc[AFI_IP6][SAFI_FLOWSPEC] || + peer->afc[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; } @@ -2685,6 +2774,59 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp) !!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)); } +static inline bool bgp_in_graceful_restart(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is not complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline bool bgp_is_graceful_restart_complete(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is marked as complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline void bgp_update_gr_completion(void) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + /* + * Check and mark GR complete. This is done when deferred + * path selection has been completed for all instances and + * route-advertisement/EOR and route-sync with zebra has + * been invoked. + */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) + return; + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (bgp->gr_route_sync_pending) + return; + } + + SET_FLAG(bm->flags, BM_FLAG_GR_COMPLETE); + bm->gr_completion_time = monotime(NULL); +} + +static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp) +{ + /* + * Is forwarding state preserved? Based either on config + * or if BGP restarted gracefully. + * TBD: Additional AFI/SAFI based checks etc. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)); +} + /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); @@ -2721,6 +2863,11 @@ extern bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size); extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, size_t size); + +extern void srv6_function_free(struct bgp_srv6_function *func); + +extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode); + #ifdef _FRR_ATTRIBUTE_PRINTFRR /* clang-format off */ #pragma FRR printfrr_ext "%pBP" (struct peer *) diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 5b6961d18af5..a452ebe48eb4 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -531,7 +531,7 @@ rfapi_group_new(struct bgp *bgp, rfapi_group_cfg_type_t type, const char *name) rfg = XCALLOC(MTYPE_RFAPI_GROUP_CFG, sizeof(struct rfapi_nve_group_cfg)); rfg->type = type; - rfg->name = strdup(name); + rfg->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, name); /* add to tail of list */ listnode_add(bgp->rfapi_cfg->nve_groups_sequential, rfg); rfg->label = MPLS_LABEL_NONE; @@ -832,8 +832,8 @@ DEFUN (vnc_redistribute_protocol, if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) { VNC_REDIST_DISABLE(bgp, afi, type); /* disabled view implicitly */ - free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); - bgp->rfapi_cfg->redist_bgp_exterior_view_name = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + bgp->rfapi_cfg->redist_bgp_exterior_view_name); } bgp->rfapi_cfg->redist_bgp_exterior_view = bgp; } @@ -873,10 +873,8 @@ DEFUN (vnc_no_redistribute_protocol, VNC_REDIST_DISABLE(bgp, afi, type); if (type == ZEBRA_ROUTE_BGP_DIRECT_EXT) { - if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) { - free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); - bgp->rfapi_cfg->redist_bgp_exterior_view_name = NULL; - } + XFREE(MTYPE_RFAPI_GROUP_CFG, + bgp->rfapi_cfg->redist_bgp_exterior_view_name); bgp->rfapi_cfg->redist_bgp_exterior_view = NULL; } @@ -905,9 +903,10 @@ DEFUN (vnc_redistribute_bgp_exterior, return CMD_WARNING_CONFIG_FAILED; } - if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) - free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); - bgp->rfapi_cfg->redist_bgp_exterior_view_name = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, + bgp->rfapi_cfg->redist_bgp_exterior_view_name); + bgp->rfapi_cfg->redist_bgp_exterior_view_name = + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); /* could be NULL if name is not defined yet */ bgp->rfapi_cfg->redist_bgp_exterior_view = bgp_lookup_by_name(argv[5]->arg); @@ -935,9 +934,9 @@ DEFUN (vnc_redistribute_nvegroup, */ bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname( bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE); - if (bgp->rfapi_cfg->rfg_redist_name) - free(bgp->rfapi_cfg->rfg_redist_name); - bgp->rfapi_cfg->rfg_redist_name = strdup(argv[3]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, bgp->rfapi_cfg->rfg_redist_name); + bgp->rfapi_cfg->rfg_redist_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[3]->arg); vnc_redistribute_postchange(bgp); @@ -959,9 +958,7 @@ DEFUN (vnc_redistribute_no_nvegroup, vnc_redistribute_prechange(bgp); bgp->rfapi_cfg->rfg_redist = NULL; - if (bgp->rfapi_cfg->rfg_redist_name) - free(bgp->rfapi_cfg->rfg_redist_name); - bgp->rfapi_cfg->rfg_redist_name = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, bgp->rfapi_cfg->rfg_redist_name); vnc_redistribute_postchange(bgp); @@ -1030,9 +1027,7 @@ DEFUN (vnc_redist_bgpdirect_no_prefixlist, vnc_redistribute_prechange(bgp); - if (hc->plist_redist_name[route_type][afi]) - free(hc->plist_redist_name[route_type][afi]); - hc->plist_redist_name[route_type][afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_redist_name[route_type][afi]); hc->plist_redist[route_type][afi] = NULL; vnc_redistribute_postchange(bgp); @@ -1074,9 +1069,9 @@ DEFUN (vnc_redist_bgpdirect_prefixlist, vnc_redistribute_prechange(bgp); - if (hc->plist_redist_name[route_type][afi]) - free(hc->plist_redist_name[route_type][afi]); - hc->plist_redist_name[route_type][afi] = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_redist_name[route_type][afi]); + hc->plist_redist_name[route_type][afi] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[5]->arg); hc->plist_redist[route_type][afi] = prefix_list_lookup(afi, argv[5]->arg); @@ -1110,9 +1105,7 @@ DEFUN (vnc_redist_bgpdirect_no_routemap, vnc_redistribute_prechange(bgp); - if (hc->routemap_redist_name[route_type]) - free(hc->routemap_redist_name[route_type]); - hc->routemap_redist_name[route_type] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_redist_name[route_type]); hc->routemap_redist[route_type] = NULL; vnc_redistribute_postchange(bgp); @@ -1144,15 +1137,16 @@ DEFUN (vnc_redist_bgpdirect_routemap, vnc_redistribute_prechange(bgp); - if (hc->routemap_redist_name[route_type]) - free(hc->routemap_redist_name[route_type]); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_redist_name[route_type]); /* If the old route map config overwrite with new * route map config , old routemap counter have to be * reduced. */ route_map_counter_decrement(hc->routemap_redist[route_type]); - hc->routemap_redist_name[route_type] = strdup(argv[4]->arg); + hc->routemap_redist_name[route_type] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[4]->arg); + hc->routemap_redist[route_type] = route_map_lookup_by_name(argv[4]->arg); route_map_counter_increment(hc->routemap_redist[route_type]); @@ -1197,9 +1191,8 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_prefixlist, vnc_redistribute_prechange(bgp); - if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) - free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); - rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; vnc_redistribute_postchange(bgp); @@ -1238,10 +1231,10 @@ DEFUN (vnc_nve_group_redist_bgpdirect_prefixlist, vnc_redistribute_prechange(bgp); - if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) - free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = - strdup(argv[4]->arg); + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[4]->arg); rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = prefix_list_lookup(afi, argv[4]->arg); @@ -1272,11 +1265,10 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_routemap, vnc_redistribute_prechange(bgp); - if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) - free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); route_map_counter_decrement( rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); - rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = NULL; rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = NULL; vnc_redistribute_postchange(bgp); @@ -1305,12 +1297,12 @@ DEFUN (vnc_nve_group_redist_bgpdirect_routemap, vnc_redistribute_prechange(bgp); - if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) - free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); route_map_counter_decrement( rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = - strdup(argv[3]->arg); + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[3]->arg); rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = route_map_lookup_by_name(argv[3]->arg); route_map_counter_increment( @@ -1451,7 +1443,7 @@ DEFUN (vnc_export_nvegroup, } rfgn = rfgn_new(); - rfgn->name = strdup(argv[5]->arg); + rfgn->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); rfgn->rfg = rfg_new; /* OK if not set yet */ listnode_add(bgp->rfapi_cfg->rfg_export_direct_bgp_l, rfgn); @@ -1487,7 +1479,7 @@ DEFUN (vnc_export_nvegroup, } rfgn = rfgn_new(); - rfgn->name = strdup(argv[5]->arg); + rfgn->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); rfgn->rfg = rfg_new; /* OK if not set yet */ listnode_add(bgp->rfapi_cfg->rfg_export_zebra_l, rfgn); @@ -1531,7 +1523,7 @@ DEFUN (vnc_no_export_nvegroup, if (rfgn->rfg) vnc_direct_bgp_del_group(bgp, rfgn->rfg); - free(rfgn->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfgn->name); list_delete_node( bgp->rfapi_cfg->rfg_export_direct_bgp_l, node); @@ -1548,7 +1540,7 @@ DEFUN (vnc_no_export_nvegroup, if (rfgn->name && !strcmp(rfgn->name, argv[6]->arg)) { if (rfgn->rfg) vnc_zebra_del_group(bgp, rfgn->rfg); - free(rfgn->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfgn->name); list_delete_node( bgp->rfapi_cfg->rfg_export_zebra_l, node); @@ -1612,9 +1604,8 @@ DEFUN (vnc_nve_group_export_no_prefixlist, || (rfg->plist_export_zebra_name[afi] && strmatch(argv[idx]->arg, rfg->plist_export_zebra_name[afi]))) { - if (rfg->plist_export_zebra_name[afi]) - free(rfg->plist_export_zebra_name[afi]); - rfg->plist_export_zebra_name[afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->plist_export_zebra_name[afi]); rfg->plist_export_zebra[afi] = NULL; vnc_zebra_reexport_group_afi(bgp, rfg, afi); @@ -1667,18 +1658,18 @@ DEFUN (vnc_nve_group_export_prefixlist, idx = argc - 1; if (is_bgp) { - if (rfg->plist_export_bgp_name[afi]) - free(rfg->plist_export_bgp_name[afi]); - rfg->plist_export_bgp_name[afi] = strdup(argv[idx]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->plist_export_bgp_name[afi]); + rfg->plist_export_bgp_name[afi] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[idx]->arg); rfg->plist_export_bgp[afi] = prefix_list_lookup(afi, argv[idx]->arg); vnc_direct_bgp_reexport_group_afi(bgp, rfg, afi); } else { - if (rfg->plist_export_zebra_name[afi]) - free(rfg->plist_export_zebra_name[afi]); - rfg->plist_export_zebra_name[afi] = strdup(argv[idx]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->plist_export_zebra_name[afi]); + rfg->plist_export_zebra_name[afi] = + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[idx]->arg); rfg->plist_export_zebra[afi] = prefix_list_lookup(afi, argv[idx]->arg); @@ -1720,7 +1711,8 @@ DEFUN (vnc_nve_group_export_no_routemap, switch (argv[idx]->text[0]) { case 'z': is_bgp = 0; - /* fall thru */ + idx += 2; + break; case 'b': idx += 2; break; @@ -1734,10 +1726,9 @@ DEFUN (vnc_nve_group_export_no_routemap, || (rfg->routemap_export_bgp_name && strmatch(argv[idx]->arg, rfg->routemap_export_bgp_name))) { - if (rfg->routemap_export_bgp_name) - free(rfg->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->routemap_export_bgp_name); route_map_counter_decrement(rfg->routemap_export_bgp); - rfg->routemap_export_bgp_name = NULL; rfg->routemap_export_bgp = NULL; vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); @@ -1748,10 +1739,8 @@ DEFUN (vnc_nve_group_export_no_routemap, || (rfg->routemap_export_zebra_name && strmatch(argv[idx]->arg, rfg->routemap_export_zebra_name))) { - if (rfg->routemap_export_zebra_name) - free(rfg->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->routemap_export_zebra_name); route_map_counter_decrement(rfg->routemap_export_zebra); - rfg->routemap_export_zebra_name = NULL; rfg->routemap_export_zebra = NULL; vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP); @@ -1795,20 +1784,20 @@ DEFUN (vnc_nve_group_export_routemap, idx = argc - 1; if (is_bgp) { - if (rfg->routemap_export_bgp_name) - free(rfg->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->routemap_export_bgp_name); route_map_counter_decrement(rfg->routemap_export_bgp); - rfg->routemap_export_bgp_name = strdup(argv[idx]->arg); + rfg->routemap_export_bgp_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[idx]->arg); rfg->routemap_export_bgp = route_map_lookup_by_name(argv[idx]->arg); route_map_counter_increment(rfg->routemap_export_bgp); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); } else { - if (rfg->routemap_export_zebra_name) - free(rfg->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->routemap_export_zebra_name); route_map_counter_decrement(rfg->routemap_export_zebra); - rfg->routemap_export_zebra_name = strdup(argv[idx]->arg); + rfg->routemap_export_zebra_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[idx]->arg); rfg->routemap_export_zebra = route_map_lookup_by_name(argv[idx]->arg); route_map_counter_increment(rfg->routemap_export_zebra); @@ -1853,9 +1842,8 @@ DEFUN (vnc_nve_export_no_prefixlist, if (((argc > 6) && hc->plist_export_bgp_name[afi] && strmatch(argv[6]->text, hc->plist_export_bgp_name[afi])) || (argc <= 6)) { - - free(hc->plist_export_bgp_name[afi]); - hc->plist_export_bgp_name[afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + hc->plist_export_bgp_name[afi]); hc->plist_export_bgp[afi] = NULL; vnc_direct_bgp_reexport(bgp, afi); } @@ -1864,9 +1852,8 @@ DEFUN (vnc_nve_export_no_prefixlist, && strmatch(argv[6]->text, hc->plist_export_zebra_name[afi])) || (argc <= 6)) { - - free(hc->plist_export_zebra_name[afi]); - hc->plist_export_zebra_name[afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + hc->plist_export_zebra_name[afi]); hc->plist_export_zebra[afi] = NULL; /* TBD vnc_zebra_rh_reexport(bgp, afi); */ } @@ -1899,16 +1886,16 @@ DEFUN (vnc_nve_export_prefixlist, } if (argv[2]->arg[0] == 'b') { - if (hc->plist_export_bgp_name[afi]) - free(hc->plist_export_bgp_name[afi]); - hc->plist_export_bgp_name[afi] = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_export_bgp_name[afi]); + hc->plist_export_bgp_name[afi] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[5]->arg); hc->plist_export_bgp[afi] = prefix_list_lookup(afi, argv[5]->arg); vnc_direct_bgp_reexport(bgp, afi); } else { - if (hc->plist_export_zebra_name[afi]) - free(hc->plist_export_zebra_name[afi]); - hc->plist_export_zebra_name[afi] = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_export_zebra_name[afi]); + hc->plist_export_zebra_name[afi] = + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); hc->plist_export_zebra[afi] = prefix_list_lookup(afi, argv[5]->arg); /* TBD vnc_zebra_rh_reexport(bgp, afi); */ @@ -1936,10 +1923,9 @@ DEFUN (vnc_nve_export_no_routemap, if (((argc > 5) && hc->routemap_export_bgp_name && strmatch(argv[5]->text, hc->routemap_export_bgp_name)) || (argc <= 5)) { - - free(hc->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, + hc->routemap_export_bgp_name); route_map_counter_decrement(hc->routemap_export_bgp); - hc->routemap_export_bgp_name = NULL; hc->routemap_export_bgp = NULL; vnc_direct_bgp_reexport(bgp, AFI_IP); vnc_direct_bgp_reexport(bgp, AFI_IP6); @@ -1949,9 +1935,8 @@ DEFUN (vnc_nve_export_no_routemap, && strmatch(argv[5]->text, hc->routemap_export_zebra_name)) || (argc <= 5)) { - free(hc->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_export_zebra_name); route_map_counter_decrement(hc->routemap_export_zebra); - hc->routemap_export_zebra_name = NULL; hc->routemap_export_zebra = NULL; /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ @@ -1976,20 +1961,20 @@ DEFUN (vnc_nve_export_routemap, hc = bgp->rfapi_cfg; if (argv[2]->arg[0] == 'b') { - if (hc->routemap_export_bgp_name) - free(hc->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_export_bgp_name); route_map_counter_decrement(hc->routemap_export_bgp); - hc->routemap_export_bgp_name = strdup(argv[4]->arg); + hc->routemap_export_bgp_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[4]->arg); hc->routemap_export_bgp = route_map_lookup_by_name(argv[4]->arg); route_map_counter_increment(hc->routemap_export_bgp); vnc_direct_bgp_reexport(bgp, AFI_IP); vnc_direct_bgp_reexport(bgp, AFI_IP6); } else { - if (hc->routemap_export_zebra_name) - free(hc->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_export_zebra_name); route_map_counter_decrement(hc->routemap_export_zebra); - hc->routemap_export_zebra_name = strdup(argv[4]->arg); + hc->routemap_export_zebra_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[4]->arg); hc->routemap_export_zebra = route_map_lookup_by_name(argv[4]->arg); route_map_counter_increment(hc->routemap_export_zebra); @@ -2319,7 +2304,7 @@ static void bgp_rfapi_delete_nve_group(struct vty *vty, /* NULL = no output */ } /* delete it */ - free(rfg->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->name); if (rfg->rfapi_import_table) rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); if (rfg->rt_import_list) @@ -3410,7 +3395,7 @@ DEFUN_NOSH (vnc_l2_group, vty_out(vty, "Can't allocate memory for L2 group\n"); return CMD_WARNING_CONFIG_FAILED; } - rfg->name = strdup(argv[2]->arg); + rfg->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[2]->arg); /* add to tail of list */ listnode_add(bgp->rfapi_cfg->l2_groups, rfg); } @@ -3428,7 +3413,7 @@ static void bgp_rfapi_delete_l2_group(struct vty *vty, /* NULL = no output */ struct rfapi_l2_group_cfg *rfg) { /* delete it */ - free(rfg->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->name); if (rfg->rt_import_list) ecommunity_free(&rfg->rt_import_list); if (rfg->rt_export_list) @@ -3590,7 +3575,9 @@ DEFUN (vnc_l2_group_rt, switch (argv[1]->arg[0]) { case 'b': - do_export = 1; /* fall through */ + do_export = 1; + do_import = 1; + break; case 'i': do_import = 1; break; @@ -3840,7 +3827,8 @@ struct rfapi_cfg *bgp_rfapi_cfg_new(struct rfapi_rfp_cfg *cfg) static void bgp_rfapi_rfgn_list_delete(void *data) { struct rfapi_rfg_name *rfgn = data; - free(rfgn->name); + + XFREE(MTYPE_RFAPI_GROUP_CFG, rfgn->name); rfgn_free(rfgn); } diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index ff7137bdd908..23e3eb482308 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -46,11 +46,6 @@ #include "bgpd/rfapi/rfapi_encap_tlv.h" #include "bgpd/rfapi/vnc_debug.h" -#ifdef HAVE_GLIBC_BACKTRACE -/* for backtrace and friends */ -#include -#endif /* HAVE_GLIBC_BACKTRACE */ - #define DEBUG_CLEANUP 0 struct ethaddr rfapi_ethaddr0 = {{0}}; @@ -371,20 +366,19 @@ void del_vnc_route(struct rfapi_descriptor *rfd, for (bpi = (bn ? bgp_dest_get_bgp_path_info(bn) : NULL); bpi; bpi = bpi->next) { - vnc_zlog_debug_verbose( "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64, __func__, bpi, bpi->peer, bpi->type, bpi->sub_type, - (bpi->extra ? bpi->extra->vnc.export.rfapi_handle + (bpi->extra ? bpi->extra->vnc->vnc.export.rfapi_handle : NULL), CHECK_FLAG(bpi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) - ? bpi->attr->local_pref : 0)); - - if (bpi->peer == peer && bpi->type == type - && bpi->sub_type == sub_type && bpi->extra - && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { + ? bpi->attr->local_pref + : 0)); + if (bpi->peer == peer && bpi->type == type && + bpi->sub_type == sub_type && bpi->extra && + bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) { vnc_zlog_debug_verbose("%s: matched it", __func__); break; @@ -397,8 +391,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd, * route. Leave the route itself in place. * TBD add return code reporting of success/failure */ - if (!bpi || !bpi->extra - || !bpi->extra->vnc.export.local_nexthops) { + if (!bpi || !bpi->extra || + !bpi->extra->vnc->vnc.export.local_nexthops) { /* * no local nexthops */ @@ -414,16 +408,16 @@ void del_vnc_route(struct rfapi_descriptor *rfd, struct listnode *node; struct rfapi_nexthop *pLnh = NULL; - for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc.export.local_nexthops, + for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc->vnc.export + .local_nexthops, node, pLnh)) { - if (prefix_same(&pLnh->addr, &lnh->addr)) { break; } } if (pLnh) { - listnode_delete(bpi->extra->vnc.export.local_nexthops, + listnode_delete(bpi->extra->vnc->vnc.export.local_nexthops, pLnh); /* silly rabbit, listnode_delete doesn't invoke @@ -464,12 +458,12 @@ void del_vnc_route(struct rfapi_descriptor *rfd, /* * Delete local_nexthops list */ - if (bpi->extra && bpi->extra->vnc.export.local_nexthops) - list_delete(&bpi->extra->vnc.export.local_nexthops); + if (bpi->extra && bpi->extra->vnc->vnc.export.local_nexthops) + list_delete(&bpi->extra->vnc->vnc.export.local_nexthops); bgp_aggregate_decrement(bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, bpi, afi, safi); } else { vnc_zlog_debug_verbose( "%s: Couldn't find route (safi=%d) at prefix %pFX", @@ -555,6 +549,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ int flags) { afi_t afi; /* of the VN address */ + struct bgp_labels bgp_labels = {}; struct bgp_path_info *new; struct bgp_path_info *bpi; struct bgp_dest *bn; @@ -598,7 +593,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ } } - if (label) + if (label && *label != MPLS_INVALID_LABEL) label_val = *label; else label_val = MPLS_LABEL_IMPLICIT_NULL; @@ -907,11 +902,10 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { /* probably only need to check - * bpi->extra->vnc.export.rfapi_handle */ - if (bpi->peer == rfd->peer && bpi->type == type - && bpi->sub_type == sub_type && bpi->extra - && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { - + * bpi->extra->vnc->vnc.export.rfapi_handle */ + if (bpi->peer == rfd->peer && bpi->type == type && + bpi->sub_type == sub_type && bpi->extra && + bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) { break; } } @@ -923,11 +917,11 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ * what is advertised via BGP */ if (lnh) { - if (!bpi->extra->vnc.export.local_nexthops) { + if (!bpi->extra->vnc->vnc.export.local_nexthops) { /* TBD make arrangements to free when needed */ - bpi->extra->vnc.export.local_nexthops = + bpi->extra->vnc->vnc.export.local_nexthops = list_new(); - bpi->extra->vnc.export.local_nexthops->del = + bpi->extra->vnc->vnc.export.local_nexthops->del = rfapi_nexthop_free; } @@ -937,10 +931,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ struct listnode *node; struct rfapi_nexthop *pLnh = NULL; - for (ALL_LIST_ELEMENTS_RO( - bpi->extra->vnc.export.local_nexthops, - node, pLnh)) { - + for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc->vnc.export + .local_nexthops, + node, pLnh)) { if (prefix_same(&pLnh->addr, &lnh->addr)) { break; } @@ -951,9 +944,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ */ if (!pLnh) { pLnh = rfapi_nexthop_new(lnh); - listnode_add( - bpi->extra->vnc.export.local_nexthops, - pLnh); + listnode_add(bpi->extra->vnc->vnc.export + .local_nexthops, + pLnh); } } @@ -1009,7 +1002,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ /* Process change. */ bgp_aggregate_increment(bgp, p, bpi, afi, safi); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, bpi, afi, safi); bgp_dest_unlock_node(bn); vnc_zlog_debug_any( @@ -1025,8 +1018,13 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ /* save backref to rfapi handle */ bgp_path_info_extra_get(new); - new->extra->vnc.export.rfapi_handle = (void *)rfd; - encode_label(label_val, &new->extra->label[0]); + new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC, + sizeof(struct bgp_path_info_extra_vnc)); + new->extra->vnc->vnc.export.rfapi_handle = (void *)rfd; + + encode_label(label_val, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + new->extra->labels = bgp_labels_intern(&bgp_labels); /* debug */ @@ -1052,7 +1050,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ } bgp_dest_unlock_node(bn); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, new, afi, safi); vnc_zlog_debug_any( "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRDP)", @@ -2091,24 +2089,7 @@ int rfapi_close(void *handle) vnc_zlog_debug_verbose("%s: rfd=%p", __func__, rfd); #ifdef RFAPI_WHO_IS_CALLING_ME -#ifdef HAVE_GLIBC_BACKTRACE -#define RFAPI_DEBUG_BACKTRACE_NENTRIES 5 - { - void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES]; - char **syms; - int i; - size_t size; - - size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES); - syms = backtrace_symbols(buf, size); - for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; - ++i) { - vnc_zlog_debug_verbose("backtrace[%2d]: %s", i, - syms[i]); - } - free(syms); - } -#endif + zlog_backtrace(LOG_INFO); #endif bgp = rfd->bgp; diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index a93e186f8d82..4b3cce0b9513 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -44,11 +44,6 @@ #include "bgpd/rfapi/rfapi_encap_tlv.h" #include "bgpd/rfapi/vnc_debug.h" -#ifdef HAVE_GLIBC_BACKTRACE -/* for backtrace and friends */ -#include -#endif /* HAVE_GLIBC_BACKTRACE */ - #undef DEBUG_MONITOR_MOVE_SHORTER #undef DEBUG_RETURNED_NHL #undef DEBUG_ROUTE_COUNTERS @@ -77,32 +72,6 @@ struct rfapi_withdraw { int lockoffset; }; -/* - * DEBUG FUNCTION - * It's evil and fiendish. It's compiler-dependent. - * ? Might need LDFLAGS -rdynamic to produce all function names - */ -void rfapiDebugBacktrace(void) -{ -#ifdef HAVE_GLIBC_BACKTRACE -#define RFAPI_DEBUG_BACKTRACE_NENTRIES 200 - void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES]; - char **syms; - size_t i; - size_t size; - - size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES); - syms = backtrace_symbols(buf, size); - - for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) { - vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i, syms[i]); - } - - free(syms); -#else -#endif -} - /* * DEBUG FUNCTION * Count remote routes and compare with actively-maintained values. @@ -248,6 +217,7 @@ void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, int lockoffset) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: assert(!"Passed in safi should be impossible"); } @@ -428,18 +398,22 @@ int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p) * advertisement */ if (bpi->extra) { - switch (bpi->extra->vnc.import.un_family) { + switch (bpi->extra->vnc->vnc.import.un_family) { case AF_INET: if (p) { - p->family = bpi->extra->vnc.import.un_family; - p->u.prefix4 = bpi->extra->vnc.import.un.addr4; + p->family = + bpi->extra->vnc->vnc.import.un_family; + p->u.prefix4 = + bpi->extra->vnc->vnc.import.un.addr4; p->prefixlen = IPV4_MAX_BITLEN; } return 0; case AF_INET6: if (p) { - p->family = bpi->extra->vnc.import.un_family; - p->u.prefix6 = bpi->extra->vnc.import.un.addr6; + p->family = + bpi->extra->vnc->vnc.import.un_family; + p->u.prefix6 = + bpi->extra->vnc->vnc.import.un.addr6; p->prefixlen = IPV6_MAX_BITLEN; } return 0; @@ -469,18 +443,24 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, uint32_t *label) { struct bgp_path_info *new; + struct bgp_labels bgp_labels = {}; new = info_make(type, sub_type, 0, peer, attr, NULL); new->attr = bgp_attr_intern(attr); bgp_path_info_extra_get(new); + new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC, + sizeof(struct bgp_path_info_extra_vnc)); if (prd) { - new->extra->vnc.import.rd = *prd; - new->extra->vnc.import.create_time = monotime(NULL); + new->extra->vnc->vnc.import.rd = *prd; + new->extra->vnc->vnc.import.create_time = monotime(NULL); + } + if (label && *label != MPLS_INVALID_LABEL) { + encode_label(*label, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + new->extra->labels = bgp_labels_intern(&bgp_labels); } - if (label) - encode_label(*label, &new->extra->label[0]); peer_lock(peer); @@ -842,13 +822,13 @@ static void rfapiBgpInfoChainFree(struct bgp_path_info *bpi) * If there is a timer waiting to delete this bpi, cancel * the timer and delete immediately */ - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) - && bpi->extra->vnc.import.timer) { + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = - EVENT_ARG(bpi->extra->vnc.import.timer); + EVENT_ARG(bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import.timer); } next = bpi->next; @@ -1136,15 +1116,15 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, */ if (rfapiGetVncTunnelUnAddr(bpi1->attr, &pfx_un1)) { if (bpi1->extra) { - pfx_un1.family = bpi1->extra->vnc.import.un_family; - switch (bpi1->extra->vnc.import.un_family) { + pfx_un1.family = bpi1->extra->vnc->vnc.import.un_family; + switch (bpi1->extra->vnc->vnc.import.un_family) { case AF_INET: pfx_un1.u.prefix4 = - bpi1->extra->vnc.import.un.addr4; + bpi1->extra->vnc->vnc.import.un.addr4; break; case AF_INET6: pfx_un1.u.prefix6 = - bpi1->extra->vnc.import.un.addr6; + bpi1->extra->vnc->vnc.import.un.addr6; break; default: pfx_un1.family = AF_UNSPEC; @@ -1155,15 +1135,15 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, if (rfapiGetVncTunnelUnAddr(bpi2->attr, &pfx_un2)) { if (bpi2->extra) { - pfx_un2.family = bpi2->extra->vnc.import.un_family; - switch (bpi2->extra->vnc.import.un_family) { + pfx_un2.family = bpi2->extra->vnc->vnc.import.un_family; + switch (bpi2->extra->vnc->vnc.import.un_family) { case AF_INET: pfx_un2.u.prefix4 = - bpi2->extra->vnc.import.un.addr4; + bpi2->extra->vnc->vnc.import.un.addr4; break; case AF_INET6: pfx_un2.u.prefix6 = - bpi2->extra->vnc.import.un.addr6; + bpi2->extra->vnc->vnc.import.un.addr6; break; default: pfx_un2.family = AF_UNSPEC; @@ -1268,9 +1248,8 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, new->prefix = *rprefix; - if (bpi->extra - && decode_rd_type(bpi->extra->vnc.import.rd.val) - == RD_TYPE_VNC_ETH) { + if (bpi->extra && decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) == + RD_TYPE_VNC_ETH) { /* ethernet */ struct rfapi_vn_option *vo; @@ -1289,10 +1268,14 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, &vo->v.l2addr.tag_id); /* local_nve_id comes from lower byte of RD type */ - vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; + vo->v.l2addr.local_nve_id = + bpi->extra->vnc->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); + vo->v.l2addr.label = + bgp_path_info_num_labels(bpi) + ? decode_label(&bpi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; new->vn_options = vo; @@ -1300,8 +1283,9 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, * If there is an auxiliary prefix (i.e., host IP address), * use it as the nexthop prefix instead of the query prefix */ - if (bpi->extra->vnc.import.aux_prefix.family) { - rfapiQprefix2Rprefix(&bpi->extra->vnc.import.aux_prefix, + if (bpi->extra->vnc->vnc.import.aux_prefix.family) { + rfapiQprefix2Rprefix(&bpi->extra->vnc->vnc.import + .aux_prefix, &new->prefix); } } @@ -1402,15 +1386,16 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, /* * use cached UN address from ENCAP route */ - new->un_address.addr_family = bpi->extra->vnc.import.un_family; + new->un_address.addr_family = + bpi->extra->vnc->vnc.import.un_family; switch (new->un_address.addr_family) { case AF_INET: new->un_address.addr.v4 = - bpi->extra->vnc.import.un.addr4; + bpi->extra->vnc->vnc.import.un.addr4; break; case AF_INET6: new->un_address.addr.v6 = - bpi->extra->vnc.import.un.addr6; + bpi->extra->vnc->vnc.import.un.addr6; break; default: zlog_warn("%s: invalid UN addr family (%d) for bpi %p", @@ -1537,7 +1522,7 @@ static int rfapiNhlAddNodeRoutes( if (is_l2) { /* L2 routes: semantic nexthop in aux_prefix; VN addr * ain't it */ - pfx_vn = bpi->extra->vnc.import.aux_prefix; + pfx_vn = bpi->extra->vnc->vnc.import.aux_prefix; } else { rfapiNexthop2Prefix(bpi->attr, &pfx_vn); } @@ -1709,7 +1694,7 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList( #ifdef DEBUG_RETURNED_NHL vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn); - rfapiDebugBacktrace(); + zlog_backtrace(LOG_INFO); #endif rfapiQprefix2Rprefix(p, &rprefix); @@ -2011,9 +1996,10 @@ static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2) /* * compare RDs */ - return vnc_prefix_cmp( - (const struct prefix *)&bpi1->extra->vnc.import.rd, - (const struct prefix *)&bpi2->extra->vnc.import.rd); + return vnc_prefix_cmp((const struct prefix *)&bpi1->extra->vnc->vnc + .import.rd, + (const struct prefix *)&bpi2->extra->vnc->vnc + .import.rd); } /* @@ -2038,8 +2024,8 @@ static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2) /* * compare RDs */ - rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd, - (struct prefix *)&bpi2->extra->vnc.import.rd); + rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc->vnc.import.rd, + (struct prefix *)&bpi2->extra->vnc->vnc.import.rd); if (rc) { return rc; } @@ -2056,19 +2042,18 @@ static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2) * because there is no guarantee of the order the test key and * the real key will be passed) */ - if ((bpi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET - && (bpi1->extra->vnc.import.aux_prefix.prefixlen == 1)) - || (bpi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET - && (bpi2->extra->vnc.import.aux_prefix.prefixlen == 1))) { - + if ((bpi1->extra->vnc->vnc.import.aux_prefix.family == AF_ETHERNET && + (bpi1->extra->vnc->vnc.import.aux_prefix.prefixlen == 1)) || + (bpi2->extra->vnc->vnc.import.aux_prefix.family == AF_ETHERNET && + (bpi2->extra->vnc->vnc.import.aux_prefix.prefixlen == 1))) { /* * wildcard aux address specified */ return 0; } - return vnc_prefix_cmp(&bpi1->extra->vnc.import.aux_prefix, - &bpi2->extra->vnc.import.aux_prefix); + return vnc_prefix_cmp(&bpi1->extra->vnc->vnc.import.aux_prefix, + &bpi2->extra->vnc->vnc.import.aux_prefix); } @@ -2086,7 +2071,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */ assert(bpi->extra); vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi, - bpi->peer, &bpi->extra->vnc.import.rd); + bpi->peer, &bpi->extra->vnc->vnc.import.rd); sl = RFAPI_RDINDEX_W_ALLOC(rn); if (!sl) { @@ -2123,11 +2108,10 @@ static void rfapiItBiIndexDump(struct agg_node *rn) char buf[RD_ADDRSTRLEN]; char buf_aux_pfx[PREFIX_STRLEN]; - prefix_rd2str( - &k->extra->vnc.import.rd, buf, sizeof(buf), - bgp_get_asnotation(k->peer ? k->peer->bgp : NULL)); - if (k->extra->vnc.import.aux_prefix.family) { - prefix2str(&k->extra->vnc.import.aux_prefix, + prefix_rd2str(&k->extra->vnc->vnc.import.rd, buf, sizeof(buf), + bgp_get_asnotation(k->peer ? k->peer->bgp : NULL)); + if (k->extra->vnc->vnc.import.aux_prefix.family) { + prefix2str(&k->extra->vnc->vnc.import.aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx)); @@ -2146,6 +2130,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch( int rc; struct bgp_path_info bpi_fake = {0}; struct bgp_path_info_extra bpi_extra = {0}; + struct bgp_path_info_extra_vnc bpi_extra_vnc = { 0 }; struct bgp_path_info *bpi_result; sl = RFAPI_RDINDEX(rn); @@ -2178,27 +2163,25 @@ static struct bgp_path_info *rfapiItBiIndexSearch( for (bpi_result = rn->info; bpi_result; bpi_result = bpi_result->next) { #ifdef DEBUG_BI_SEARCH - vnc_zlog_debug_verbose( - "%s: bpi has prd=%pRDP, peer=%p", __func__, - &bpi_result->extra->vnc.import.rd, - bpi_result->peer); + vnc_zlog_debug_verbose("%s: bpi has prd=%pRDP, peer=%p", + __func__, + &bpi_result->extra->vnc->vnc + .import.rd, + bpi_result->peer); #endif - if (peer == bpi_result->peer - && !prefix_cmp((struct prefix *)&bpi_result->extra - ->vnc.import.rd, - (struct prefix *)prd)) { - + if (peer == bpi_result->peer && + !prefix_cmp((struct prefix *)&bpi_result->extra->vnc + ->vnc.import.rd, + (struct prefix *)prd)) { #ifdef DEBUG_BI_SEARCH vnc_zlog_debug_verbose( "%s: peer and RD same, doing aux_prefix check", __func__); #endif - if (!aux_prefix - || !prefix_cmp( - aux_prefix, - &bpi_result->extra->vnc.import - .aux_prefix)) { - + if (!aux_prefix || + !prefix_cmp(aux_prefix, + &bpi_result->extra->vnc->vnc + .import.aux_prefix)) { #ifdef DEBUG_BI_SEARCH vnc_zlog_debug_verbose("%s: match", __func__); @@ -2212,13 +2195,14 @@ static struct bgp_path_info *rfapiItBiIndexSearch( bpi_fake.peer = peer; bpi_fake.extra = &bpi_extra; - bpi_fake.extra->vnc.import.rd = *prd; + bpi_fake.extra->vnc = &bpi_extra_vnc; + bpi_fake.extra->vnc->vnc.import.rd = *prd; if (aux_prefix) { - bpi_fake.extra->vnc.import.aux_prefix = *aux_prefix; + bpi_fake.extra->vnc->vnc.import.aux_prefix = *aux_prefix; } else { /* wildcard */ - bpi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET; - bpi_fake.extra->vnc.import.aux_prefix.prefixlen = 1; + bpi_fake.extra->vnc->vnc.import.aux_prefix.family = AF_ETHERNET; + bpi_fake.extra->vnc->vnc.import.aux_prefix.prefixlen = 1; } rc = skiplist_search(sl, (void *)&bpi_fake, (void *)&bpi_result); @@ -2244,7 +2228,7 @@ static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */ int rc; vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi, - bpi->peer, &bpi->extra->vnc.import.rd); + bpi->peer, &bpi->extra->vnc->vnc.import.rd); sl = RFAPI_RDINDEX(rn); assert(sl); @@ -2292,11 +2276,10 @@ rfapiMonitorEncapAdd(struct rfapi_import_table *import_table, RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m; /* for easy lookup when deleting vpn route */ - vpn_bpi->extra->vnc.import.hme = m; + vpn_bpi->extra->vnc->vnc.import.hme = m; - vnc_zlog_debug_verbose( - "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p", - __func__, import_table, vpn_bpi, afi, rn, m); + vnc_zlog_debug_verbose("%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc->vnc.import.hme=%p", + __func__, import_table, vpn_bpi, afi, rn, m); RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0); bgp_attr_intern(vpn_bpi->attr); @@ -2310,7 +2293,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi) vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi); if (vpn_bpi->extra) { struct rfapi_monitor_encap *hme = - vpn_bpi->extra->vnc.import.hme; + vpn_bpi->extra->vnc->vnc.import.hme; if (hme) { @@ -2334,7 +2317,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi) agg_unlock_node(hme->rn); /* decr ref count */ XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme); - vpn_bpi->extra->vnc.import.hme = NULL; + vpn_bpi->extra->vnc->vnc.import.hme = NULL; } } } @@ -2573,21 +2556,21 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi, vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__, vpn_bpi->extra); - vpn_bpi->extra->vnc.import.un_family = AF_INET; - vpn_bpi->extra->vnc.import.un.addr4 = + vpn_bpi->extra->vnc->vnc.import.un_family = AF_INET; + vpn_bpi->extra->vnc->vnc.import.un.addr4 = encap_bpi->attr->mp_nexthop_global_in; break; case AF_INET6: - vpn_bpi->extra->vnc.import.un_family = AF_INET6; - vpn_bpi->extra->vnc.import.un.addr6 = + vpn_bpi->extra->vnc->vnc.import.un_family = AF_INET6; + vpn_bpi->extra->vnc->vnc.import.un.addr6 = encap_bpi->attr->mp_nexthop_global; break; default: zlog_warn("%s: invalid encap nexthop length: %d", __func__, encap_bpi->attr->mp_nexthop_len); - vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC; + vpn_bpi->extra->vnc->vnc.import.un_family = AF_UNSPEC; break; } } @@ -2612,9 +2595,9 @@ rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table, __func__); return 1; } - vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC; - memset(&vpn_bpi->extra->vnc.import.un, 0, - sizeof(vpn_bpi->extra->vnc.import.un)); + vpn_bpi->extra->vnc->vnc.import.un_family = AF_UNSPEC; + memset(&vpn_bpi->extra->vnc->vnc.import.un, 0, + sizeof(vpn_bpi->extra->vnc->vnc.import.un)); if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) { if (rfapiGetVncTunnelUnAddr(vpn_bpi->attr, NULL)) { UNSET_FLAG(vpn_bpi->flags, BGP_PATH_VALID); @@ -2785,9 +2768,9 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, assert(bpi->extra); if (lifetime > UINT32_MAX / 1001) { /* sub-optimal case, but will probably never happen */ - bpi->extra->vnc.import.timer = NULL; + bpi->extra->vnc->vnc.import.timer = NULL; event_add_timer(bm->master, timer_service_func, wcb, lifetime, - &bpi->extra->vnc.import.timer); + &bpi->extra->vnc->vnc.import.timer); } else { static uint32_t jitter; uint32_t lifetime_msec; @@ -2801,10 +2784,10 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, lifetime_msec = (lifetime * 1000) + jitter; - bpi->extra->vnc.import.timer = NULL; + bpi->extra->vnc->vnc.import.timer = NULL; event_add_timer_msec(bm->master, timer_service_func, wcb, lifetime_msec, - &bpi->extra->vnc.import.timer); + &bpi->extra->vnc->vnc.import.timer); } /* re-sort route list (BGP_PATH_REMOVED routes are last) */ @@ -3017,17 +3000,16 @@ static void rfapiBgpInfoFilteredImportEncap( * Compare RDs * * RD of import table bpi is in - * bpi->extra->vnc.import.rd RD of info_orig is in prd + * bpi->extra->vnc->vnc.import.rd RD of info_orig is in prd */ if (!bpi->extra) { vnc_zlog_debug_verbose("%s: no bpi->extra", __func__); continue; } - if (prefix_cmp( - (struct prefix *)&bpi->extra->vnc.import.rd, - (struct prefix *)prd)) { - + if (prefix_cmp((struct prefix *)&bpi->extra->vnc->vnc + .import.rd, + (struct prefix *)prd)) { vnc_zlog_debug_verbose("%s: prd does not match", __func__); continue; @@ -3071,13 +3053,14 @@ static void rfapiBgpInfoFilteredImportEncap( * a previous withdraw, we must cancel its * timer. */ - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) - && bpi->extra->vnc.import.timer) { + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = EVENT_ARG( - bpi->extra->vnc.import.timer); + bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import + .timer); } if (action == FIF_ACTION_UPDATE) { @@ -3163,12 +3146,12 @@ static void rfapiBgpInfoFilteredImportEncap( vnc_zlog_debug_verbose( "%s: removing holddown bpi matching NVE of new route", __func__); - if (bpi->extra->vnc.import.timer) { + if (bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = - EVENT_ARG(bpi->extra->vnc.import.timer); + EVENT_ARG(bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import.timer); } rfapiExpireEncapNow(import_table, rn, bpi); } @@ -3523,13 +3506,14 @@ void rfapiBgpInfoFilteredImportVPN( * a previous withdraw, we must cancel its * timer. */ - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) - && bpi->extra->vnc.import.timer) { + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = EVENT_ARG( - bpi->extra->vnc.import.timer); + bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import + .timer); import_table->holddown_count[afi] -= 1; RFAPI_UPDATE_ITABLE_COUNT( @@ -3602,7 +3586,7 @@ void rfapiBgpInfoFilteredImportVPN( /* Not a big deal, just means VPN route got here first */ vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX", __func__, &vn_prefix); - info_new->extra->vnc.import.un_family = AF_UNSPEC; + info_new->extra->vnc->vnc.import.un_family = AF_UNSPEC; } if (rn) { @@ -3624,7 +3608,7 @@ void rfapiBgpInfoFilteredImportVPN( vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix", __func__); - info_new->extra->vnc.import.aux_prefix = *aux_prefix; + info_new->extra->vnc->vnc.import.aux_prefix = *aux_prefix; } vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d", @@ -3742,12 +3726,12 @@ void rfapiBgpInfoFilteredImportVPN( vnc_zlog_debug_verbose( "%s: removing holddown bpi matching NVE of new route", __func__); - if (bpi->extra->vnc.import.timer) { + if (bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = - EVENT_ARG(bpi->extra->vnc.import.timer); + EVENT_ARG(bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import.timer); } rfapiExpireVpnNow(import_table, rn, bpi, 0); } @@ -3819,6 +3803,7 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: /* not expected */ flog_err(EC_LIB_DEVELOPMENT, "%s: bad safi %d", __func__, safi); @@ -4063,6 +4048,7 @@ static void rfapiProcessPeerDownRt(struct peer *peer, case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: /* Suppress uninitialized variable warning */ rt = NULL; @@ -4178,15 +4164,16 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp, for (bpi = bgp_dest_get_bgp_path_info(dest2); bpi; bpi = bpi->next) { - uint32_t label = 0; + uint32_t label = MPLS_INVALID_LABEL; if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) continue; - if (bpi->extra) + if (bgp_path_info_num_labels(bpi)) label = decode_label( - &bpi->extra->label[0]); + &bpi->extra->labels + ->label[0]); (*rfapiBgpInfoFilteredImportFunction( safi))( it, /* which import table */ @@ -4479,12 +4466,10 @@ static void rfapiDeleteRemotePrefixesIt( if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { if (!delete_holddown) continue; - if (bpi->extra->vnc.import.timer) { - struct rfapi_withdraw *wcb = - EVENT_ARG( - bpi->extra->vnc - .import - .timer); + if (bpi->extra->vnc->vnc.import.timer) { + struct rfapi_withdraw *wcb = EVENT_ARG( + bpi->extra->vnc->vnc + .import.timer); wcb->import_table ->holddown_count[afi] -= @@ -4494,8 +4479,8 @@ static void rfapiDeleteRemotePrefixesIt( afi, 1); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import - .timer); + EVENT_OFF(bpi->extra->vnc->vnc + .import.timer); } } else { if (!delete_active) diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h index dd06afe7e26a..1a37e1c2dbfe 100644 --- a/bgpd/rfapi/rfapi_import.h +++ b/bgpd/rfapi/rfapi_import.h @@ -57,8 +57,6 @@ struct rfapi_import_table { extern uint8_t rfapiRfpCost(struct attr *attr); -extern void rfapiDebugBacktrace(void); - extern void rfapiCheckRouteCount(void); /* diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index 3fe957ba4de7..fcfad22631ba 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -237,6 +237,7 @@ void rfapiMonitorExtraFlush(safi_t safi, struct agg_node *rn) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: assert(0); } @@ -305,6 +306,7 @@ void rfapiMonitorExtraPrune(safi_t safi, struct agg_node *rn) case SAFI_EVPN: case SAFI_LABELED_UNICAST: case SAFI_FLOWSPEC: + case SAFI_RTC: case SAFI_MAX: assert(0); } @@ -354,7 +356,7 @@ struct agg_node *rfapiMonitorGetAttachNode(struct rfapi_descriptor *rfd, * If there is a cached ENCAP UN address, it's a usable * VPN route */ - if (bpi->extra && bpi->extra->vnc.import.un_family) { + if (bpi->extra && bpi->extra->vnc->vnc.import.un_family) { break; } diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 5784f95b2786..a0bdf4961f23 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -663,9 +663,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, /* * VN options */ - if (bpi->extra - && decode_rd_type(bpi->extra->vnc.import.rd.val) - == RD_TYPE_VNC_ETH) { + if (bpi->extra && decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) == + RD_TYPE_VNC_ETH) { /* ethernet route */ struct rfapi_vn_option *vo; @@ -678,8 +677,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, /* copy from RD already stored in bpi, so we don't need it_node */ - memcpy(&vo->v.l2addr.macaddr, bpi->extra->vnc.import.rd.val + 2, - ETH_ALEN); + memcpy(&vo->v.l2addr.macaddr, + bpi->extra->vnc->vnc.import.rd.val + 2, ETH_ALEN); (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr), &vo->v.l2addr.logical_net_id); @@ -688,10 +687,14 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, &vo->v.l2addr.tag_id); /* local_nve_id comes from RD */ - vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; + vo->v.l2addr.local_nve_id = + bpi->extra->vnc->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); + vo->v.l2addr.label = + bgp_path_info_num_labels(bpi) + ? decode_label(&bpi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; rfapi_vn_options_free( ri->vn_options); /* maybe free old version */ @@ -701,8 +704,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, /* * If there is an auxiliary IP address (L2 can have it), copy it */ - if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { - ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; + if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) { + ri->rk.aux_prefix = bpi->extra->vnc->vnc.import.aux_prefix; } } @@ -746,13 +749,13 @@ int rfapiRibPreloadBi( memset((void *)&rk, 0, sizeof(rk)); rk.vn = *pfx_vn; - rk.rd = bpi->extra->vnc.import.rd; + rk.rd = bpi->extra->vnc->vnc.import.rd; /* * If there is an auxiliary IP address (L2 can have it), copy it */ - if (bpi->extra->vnc.import.aux_prefix.family) { - rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; + if (bpi->extra->vnc->vnc.import.aux_prefix.family) { + rk.aux_prefix = bpi->extra->vnc->vnc.import.aux_prefix; } /* @@ -1629,12 +1632,13 @@ void rfapiRibUpdatePendingNode( ri = rfapi_info_new(); ri->rk.vn = pfx_nh; - ri->rk.rd = bpi->extra->vnc.import.rd; + ri->rk.rd = bpi->extra->vnc->vnc.import.rd; /* * If there is an auxiliary IP address (L2 can have it), copy it */ - if (bpi->extra->vnc.import.aux_prefix.family) { - ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; + if (bpi->extra->vnc->vnc.import.aux_prefix.family) { + ri->rk.aux_prefix = + bpi->extra->vnc->vnc.import.aux_prefix; } if (rfapiGetUnAddrOfVpnBi(bpi, &ri->un)) { diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 252b6d632aef..9bfb6c4b45e6 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -413,28 +413,27 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, XFREE(MTYPE_ECOMMUNITY_STR, s); } - if (bpi->extra != NULL) { - if (bpi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + if (bgp_path_info_num_labels(bpi)) { + if (bpi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) vty_out(vty, " label=VRF2VRF"); else vty_out(vty, " label=%u", - decode_label(&bpi->extra->label[0])); - - if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { - struct in6_addr *sid_tmp = - bpi->attr->srv6_l3vpn - ? (&bpi->attr->srv6_l3vpn->sid) - : (&bpi->attr->srv6_vpn->sid); - vty_out(vty, " sid=%pI6", sid_tmp); - - if (bpi->attr->srv6_l3vpn && - bpi->attr->srv6_l3vpn->loc_block_len != 0) { - vty_out(vty, " sid_structure=[%d,%d,%d,%d]", - bpi->attr->srv6_l3vpn->loc_block_len, - bpi->attr->srv6_l3vpn->loc_node_len, - bpi->attr->srv6_l3vpn->func_len, - bpi->attr->srv6_l3vpn->arg_len); - } + decode_label(&bpi->extra->labels->label[0])); + } + + if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { + struct in6_addr *sid_tmp = + bpi->attr->srv6_l3vpn ? (&bpi->attr->srv6_l3vpn->sid) + : (&bpi->attr->srv6_vpn->sid); + vty_out(vty, " sid=%pI6", sid_tmp); + + if (bpi->attr->srv6_l3vpn && + bpi->attr->srv6_l3vpn->loc_block_len != 0) { + vty_out(vty, " sid_structure=[%d,%d,%d,%d]", + bpi->attr->srv6_l3vpn->loc_block_len, + bpi->attr->srv6_l3vpn->loc_node_len, + bpi->attr->srv6_l3vpn->func_len, + bpi->attr->srv6_l3vpn->arg_len); } } @@ -519,9 +518,10 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) if (!bpi) return; - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra - && bpi->extra->vnc.import.timer) { - struct event *t = (struct event *)bpi->extra->vnc.import.timer; + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra && + bpi->extra->vnc->vnc.import.timer) { + struct event *t = + (struct event *)bpi->extra->vnc->vnc.import.timer; r = snprintf(p, REMAIN, " [%4lu] ", event_timer_remain_second(t)); @@ -534,12 +534,12 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) if (bpi->extra) { /* TBD This valid only for SAFI_MPLS_VPN, but not for encap */ - if (decode_rd_type(bpi->extra->vnc.import.rd.val) - == RD_TYPE_VNC_ETH) { + if (decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) == + RD_TYPE_VNC_ETH) { has_macaddr = 1; - memcpy(macaddr.octet, bpi->extra->vnc.import.rd.val + 2, - 6); - l2hid = bpi->extra->vnc.import.rd.val[1]; + memcpy(macaddr.octet, + bpi->extra->vnc->vnc.import.rd.val + 2, 6); + l2hid = bpi->extra->vnc->vnc.import.rd.val[1]; } } @@ -670,11 +670,11 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) l2o_buf.label, l2o_buf.logical_net_id, l2o_buf.local_nve_id, HVTYNL); } - if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { + if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) { const char *sp; - sp = rfapi_ntop(bpi->extra->vnc.import.aux_prefix.family, - &bpi->extra->vnc.import.aux_prefix.u.prefix, + sp = rfapi_ntop(bpi->extra->vnc->vnc.import.aux_prefix.family, + &bpi->extra->vnc->vnc.import.aux_prefix.u.prefix, buf, BUFSIZ); buf[BUFSIZ - 1] = 0; if (sp) { @@ -1052,8 +1052,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, snprintf(buf_un, sizeof(buf_un), "%s", inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, sizeof(buf_ntop))); - if (bpi->extra) { - uint32_t l = decode_label(&bpi->extra->label[0]); + if (bgp_path_info_num_labels(bpi)) { + uint32_t l = decode_label(&bpi->extra->labels->label[0]); snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l); } else /* should never happen */ { @@ -1097,14 +1097,14 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, fp(out, "%-10s ", buf_lifetime); } - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra - && bpi->extra->vnc.import.timer) { - + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra && + bpi->extra->vnc->vnc.import.timer) { uint32_t remaining; time_t age; char buf_age[BUFSIZ]; - struct event *t = (struct event *)bpi->extra->vnc.import.timer; + struct event *t = + (struct event *)bpi->extra->vnc->vnc.import.timer; remaining = event_timer_remain_second(t); #ifdef RFAPI_REGISTRATIONS_REPORT_AGE @@ -1125,11 +1125,10 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, fp(out, "%-10s ", buf_age); } else if (RFAPI_LOCAL_BI(bpi)) { - char buf_age[BUFSIZ]; - if (bpi->extra && bpi->extra->vnc.import.create_time) { - rfapiFormatAge(bpi->extra->vnc.import.create_time, + if (bpi->extra && bpi->extra->vnc->vnc.import.create_time) { + rfapiFormatAge(bpi->extra->vnc->vnc.import.create_time, buf_age, BUFSIZ); } else { buf_age[0] = '?'; @@ -1145,13 +1144,14 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, * print that on the next line */ - if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { + if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) { const char *sp; - sp = rfapi_ntop( - bpi->extra->vnc.import.aux_prefix.family, - &bpi->extra->vnc.import.aux_prefix.u.prefix, - buf_ntop, BUFSIZ); + sp = rfapi_ntop(bpi->extra->vnc->vnc.import.aux_prefix + .family, + &bpi->extra->vnc->vnc.import.aux_prefix + .u.prefix, + buf_ntop, BUFSIZ); buf_ntop[BUFSIZ - 1] = 0; if (sp && strcmp(buf_vn, sp) != 0) { @@ -1161,8 +1161,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, } } } - if (tun_type != BGP_ENCAP_TYPE_MPLS && bpi->extra) { - uint32_t l = decode_label(&bpi->extra->label[0]); + if (tun_type != BGP_ENCAP_TYPE_MPLS && bgp_path_info_num_labels(bpi)) { + uint32_t l = decode_label(&bpi->extra->labels->label[0]); if (!MPLS_LABEL_IS_NULL(l)) { fp(out, " Label: %d", l); @@ -1545,10 +1545,9 @@ void rfapiPrintAdvertisedInfo(struct vty *vty, struct rfapi_descriptor *rfd, vty_out(vty, " bd=%p%s", bd, HVTYNL); for (bpi = bgp_dest_get_bgp_path_info(bd); bpi; bpi = bpi->next) { - if (bpi->peer == rfd->peer && bpi->type == type - && bpi->sub_type == BGP_ROUTE_RFP && bpi->extra - && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { - + if (bpi->peer == rfd->peer && bpi->type == type && + bpi->sub_type == BGP_ROUTE_RFP && bpi->extra && + bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) { rfapiPrintBi(vty, bpi); printed = 1; } @@ -4151,6 +4150,7 @@ static int rfapi_vty_show_nve_summary(struct vty *vty, case SHOW_NVE_SUMMARY_RESPONSES: rfapiRibShowResponsesSummary(vty); + break; case SHOW_NVE_SUMMARY_UNKNOWN_NVES: case SHOW_NVE_SUMMARY_MAX: diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 7decb75782dc..4de2306609c9 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -388,7 +388,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct agg_node *rn, bgp_withdraw(bpi->peer, p, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not used for unicast */ + NULL, 0); /* tag not used for unicast */ } static void vnc_direct_bgp_vpn_enable_ce(struct bgp *bgp, afi_t afi) @@ -473,16 +473,14 @@ static void vnc_direct_bgp_vpn_disable_ce(struct bgp *bgp, afi_t afi) if (ri->type == ZEBRA_ROUTE_VNC_DIRECT && ri->sub_type == BGP_ROUTE_REDISTRIBUTE) { - - bgp_withdraw( - ri->peer, bgp_dest_get_prefix(dest), - 0, /* addpath_id */ - AFI_IP, SAFI_UNICAST, - ZEBRA_ROUTE_VNC_DIRECT, - BGP_ROUTE_REDISTRIBUTE, - NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast */ + bgp_withdraw(ri->peer, bgp_dest_get_prefix(dest), + 0, /* addpath_id */ + AFI_IP, SAFI_UNICAST, + ZEBRA_ROUTE_VNC_DIRECT, + BGP_ROUTE_REDISTRIBUTE, + NULL, /* RD not used for unicast */ + NULL, + 0); /* tag not used for unicast */ } } } @@ -863,9 +861,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, - NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast */ + NULL, /* RD not used for unicast */ + NULL, 0); /* tag not used for unicast */ /* * yuck! * - but consistent with rest of function @@ -892,9 +889,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, - NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast */ + NULL, /* RD not used for unicast */ + NULL, 0); /* tag not used for unicast */ } } } @@ -1125,13 +1121,13 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd) continue; bgp_withdraw(irfd->peer, p, /* prefix */ - 0, /* addpath_id */ + 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not + NULL, 0); /* tag not used for unicast */ } @@ -1359,7 +1355,7 @@ static void vnc_direct_del_rn_group_rd(struct bgp *bgp, 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not used for unicast */ + NULL, 0); /* tag not used for unicast */ return; } @@ -1471,16 +1467,15 @@ static void vnc_direct_bgp_unexport_table(afi_t afi, struct agg_table *rt, for (ALL_LIST_ELEMENTS_RO(nve_list, hln, irfd)) { - bgp_withdraw(irfd->peer, agg_node_get_prefix(rn), - 0, /* addpath_id */ + 0, /* addpath_id */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not + NULL, 0); /* tag not used for unicast, EVPN @@ -1715,8 +1710,7 @@ static void vncExportWithdrawTimer(struct event *t) bgp_withdraw(eti->peer, p, 0, /* addpath_id */ family2afi(p->family), SAFI_UNICAST, eti->type, eti->subtype, NULL, /* RD not used for unicast */ - NULL, 0, - NULL); /* tag not used for unicast, EVPN neither */ + NULL, 0); /* tag not used for unicast, EVPN neither */ /* * Free the eti @@ -2001,7 +1995,7 @@ void vnc_direct_bgp_rh_vpn_disable(struct bgp *bgp, afi_t afi) ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, 0, NULL); /* tag not used for + NULL, 0); /* tag not used for unicast, EVPN neither */ } diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index 3fcc0e6f5f4b..2bb7c1b161f5 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -414,7 +414,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( uint32_t lifetime; uint32_t *plifetime; struct bgp_attr_encap_subtlv *encaptlvs; - uint32_t label = 0; + uint32_t label; struct rfapi_un_option optary[3]; struct rfapi_un_option *opt = NULL; @@ -470,16 +470,19 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( if (bgp_attr_get_ecommunity(bpi->attr)) ecommunity_merge(new_ecom, bgp_attr_get_ecommunity(bpi->attr)); - if (bpi->extra) - label = decode_label(&bpi->extra->label[0]); + if (bgp_path_info_num_labels(bpi)) + label = decode_label(&bpi->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN, - prefix, /* unicast route prefix */ + prefix, /* unicast route prefix */ prd, &nexthop_h, /* new nexthop */ local_pref, plifetime, (struct bgp_tea_options *)encaptlvs, /* RFP options */ opt, NULL, new_ecom, med, /* NULL => don't set med */ - (label ? &label : NULL), /* NULL= default */ + ((label != MPLS_INVALID_LABEL) ? &label + : NULL), /* NULL= default */ ZEBRA_ROUTE_BGP_DIRECT, BGP_ROUTE_REDISTRIBUTE, RFAPI_AHR_RFPOPT_IS_VNCTLV); /* flags */ @@ -1678,7 +1681,7 @@ static void vnc_import_bgp_exterior_add_route_it( bpi_interior = bpi_interior->next) { struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; if (!is_usable_interior_route(bpi_interior)) continue; @@ -1695,14 +1698,19 @@ static void vnc_import_bgp_exterior_add_route_it( */ have_usable_route = 1; - if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import - .rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + if (bpi_interior->extra) + prd = &bpi_interior->extra->vnc->vnc + .import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(new_attr)); new_attr = *bpi_interior->attr; @@ -1851,7 +1859,7 @@ void vnc_import_bgp_exterior_del_route( for (bpi_interior = rn->info; bpi_interior; bpi_interior = bpi_interior->next) { struct prefix_rd *prd; - uint32_t label = 0; + uint32_t label; if (!is_usable_interior_route(bpi_interior)) continue; @@ -1864,14 +1872,19 @@ void vnc_import_bgp_exterior_del_route( */ have_usable_route = 1; - if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import - .rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + if (bpi_interior->extra) + prd = &bpi_interior->extra->vnc->vnc + .import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */ @@ -2007,18 +2020,22 @@ void vnc_import_bgp_exterior_add_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; assert(bpi_exterior); assert(pfx_exterior); - if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + if (bpi_interior->extra) + prd = &bpi_interior->extra->vnc->vnc.import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2097,7 +2114,7 @@ void vnc_import_bgp_exterior_add_route_interior( struct bgp_path_info *bpi; struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; /* do pull-down */ @@ -2124,14 +2141,18 @@ void vnc_import_bgp_exterior_add_route_interior( * parent routes. */ for (bpi = par->info; bpi; bpi = bpi->next) { + if (bpi->extra) + prd = &bpi->extra->vnc->vnc + .import.rd; + else + prd = NULL; - if (bpi->extra) { - prd = &bpi->extra->vnc.import - .rd; + if (bgp_path_info_num_labels(bpi)) label = decode_label( - &bpi->extra->label[0]); - } else - prd = NULL; + &bpi->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi->peer, @@ -2147,14 +2168,19 @@ void vnc_import_bgp_exterior_add_route_interior( * Add constructed exterior routes based on * the new interior route at longer prefix. */ - if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import - .rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + if (bpi_interior->extra) + prd = &bpi_interior->extra->vnc->vnc + .import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2237,7 +2263,7 @@ void vnc_import_bgp_exterior_add_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; /* do pull-down */ @@ -2266,13 +2292,17 @@ void vnc_import_bgp_exterior_add_route_interior( * Add constructed exterior routes based on the * new interior route at the longer prefix. */ - if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + if (bpi_interior->extra) + prd = &bpi_interior->extra->vnc->vnc.import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2372,14 +2402,19 @@ void vnc_import_bgp_exterior_del_route_interior( &cursor)) { struct prefix_rd *prd; - uint32_t label = 0; + uint32_t label; - if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import.rd; - label = decode_label(&bpi_interior->extra->label[0]); - } else + if (bpi_interior->extra) + prd = &bpi_interior->extra->vnc->vnc.import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */ pfx_exterior, NULL, afi, prd, bpi_interior->attr, @@ -2446,18 +2481,22 @@ void vnc_import_bgp_exterior_del_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; if (bpi->type == ZEBRA_ROUTE_BGP_DIRECT_EXT) continue; - if (bpi->extra) { - prd = &bpi->extra->vnc.import.rd; - label = decode_label( - &bpi->extra->label[0]); - } else + if (bpi->extra) + prd = &bpi->extra->vnc->vnc.import.rd; + else prd = NULL; + if (bgp_path_info_num_labels(bpi)) + label = decode_label( + &bpi->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(new_attr)); new_attr = *bpi->attr; @@ -2805,14 +2844,14 @@ void vnc_import_bgp_redist_disable(struct bgp *bgp, afi_t afi) assert(bpi->extra); - rfd = bpi->extra->vnc.export.rfapi_handle; + rfd = bpi->extra->vnc->vnc.export.rfapi_handle; vnc_zlog_debug_verbose( - "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]", + "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc->vnc.export.rfapi_handle=%p [passing rfd=%p]", __func__, bpi, bpi->peer, bpi->type, bpi->sub_type, - (bpi->extra ? bpi->extra->vnc.export - .rfapi_handle + (bpi->extra ? bpi->extra->vnc->vnc + .export.rfapi_handle : NULL), rfd); diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index c886beea9197..82c08cabde6e 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -872,7 +872,7 @@ static zclient_handler *const vnc_handlers[] = { void vnc_zebra_init(struct event_loop *master) { /* Set default values. */ - zclient_vnc = zclient_new(master, &zclient_options_default, + zclient_vnc = zclient_new(master, &zclient_options_auxiliary, vnc_handlers, array_size(vnc_handlers)); zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0, &bgpd_privs); } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index c2dd207a49d1..1442066de7e2 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -67,6 +67,7 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_routemap.c \ bgpd/bgp_routemap_nb.c \ bgpd/bgp_routemap_nb_config.c \ + bgpd/bgp_rtc.c \ bgpd/bgp_script.c \ bgpd/bgp_table.c \ bgpd/bgp_updgrp.c \ @@ -77,6 +78,7 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_zebra.c \ bgpd/bgpd.c \ bgpd/bgp_trace.c \ + bgpd/bgp_nhg.c \ # end if ENABLE_BGP_VNC @@ -147,6 +149,7 @@ noinst_HEADERS += \ bgpd/bgp_rd.h \ bgpd/bgp_regex.h \ bgpd/bgp_rpki.h \ + bgpd/bgp_rtc.h \ bgpd/bgp_route.h \ bgpd/bgp_routemap_nb.h \ bgpd/bgp_script.h \ @@ -160,6 +163,7 @@ noinst_HEADERS += \ bgpd/bgp_zebra.h \ bgpd/bgpd.h \ bgpd/bgp_trace.h \ + bgpd/bgp_nhg.h \ \ bgpd/rfapi/bgp_rfapi_cfg.h \ bgpd/rfapi/rfapi_import.h \ @@ -214,6 +218,7 @@ clippy_scan += \ bgpd/bgp_rpki.c \ bgpd/bgp_vty.c \ bgpd/bgp_nexthop.c \ + bgpd/bgp_snmp.c \ # end nodist_bgpd_bgpd_SOURCES = \ diff --git a/buildtest.sh b/buildtest.sh index 7edc4a5ee1dd..90ef60ee8b30 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -5,7 +5,7 @@ # builds some git commit of FRR in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=frr --enable-group=frr --enable-vty-group=frr --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/frr --localstatedir=/var/run/frr --libdir=/usr/lib64/frr --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror" +basecfg="--prefix=/usr --enable-user=frr --enable-group=frr --enable-vty-group=frr --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc --localstatedir=/var --libdir=/usr/lib64/frr --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror" configs_base="gcc|$basecfg" @@ -37,9 +37,10 @@ trap errfunc ERR COMMITREF="$1" COMMITISH="`git rev-list --max-count=1 ${COMMITREF:-HEAD}`" -TEMP="`mktemp -t -d frrbuild.XXXXXX`" +TEMP="`mktemp -d -t frrbuild.XXXXXX`" BASE="`pwd`" CONFIGS="$2" +MAKE="${MAKE:-make}" echo using temporary directory: $TEMP echo git commit used: @@ -59,7 +60,7 @@ echo -e "\n\n\n\n\033[33;1mmaking dist tarball\033[m" mkdir build_dist cd build_dist ../source/configure -make distdir=sdist dist-gzip +${MAKE} distdir=sdist dist-gzip cd .. tar zxvf build_dist/sdist.tar.gz @@ -79,9 +80,9 @@ for cfg in ${CONFIGS:-$defconfigs}; do mkdir "$bdir" cd "$bdir" ../sdist/configure $args - make -j5 - make check - make DESTDIR="$TEMP/inst_$cfg" install + ${MAKE} -j5 + ${MAKE} check + ${MAKE} DESTDIR="$TEMP/inst_$cfg" install cd .. done diff --git a/configure.ac b/configure.ac index 97f9e6a826bc..59636194f770 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.69]) -AC_INIT([frr], [9.1-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [10.2-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" @@ -20,6 +20,79 @@ AC_CONFIG_SRCDIR([lib/zebra.h]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([m4/ac]) +dnl ------------------------------ +dnl system paths +dnl ------------------------------ +dnl Versions of FRR (or Quagga, or Zebra) before ca. 9.2 used sysconfdir and +dnl localstatedir as-is, without appending /frr. The /frr was expected to be +dnl given on ./configure invocations. +dnl +dnl This does not match standard behavior by other packages and makes FRR +dnl specific packaging changes necessary to add these options. localstatedir +dnl was also misused to include the /run part (it normally is only /var), +dnl leaving no path configuration option that references /var itself. This +dnl is because runstatedir did not exist in ancient autoconf. +dnl +dnl The path options have been changed to expect plain / system prefix +dnl directories. As a temporary workaround to not break packaging, eventual +dnl /frr suffixes are stripped and a warning is printed. + +path_warn_banner=false + +AC_MSG_CHECKING([whether --sysconfdir option is FRR-specific]) +case "$sysconfdir" in + */frr) + AC_MSG_RESULT([yes, ends in /frr - removing suffix]) + AC_MSG_WARN([Please remove /frr suffix from --sysconfdir="${sysconfdir}" (it should be /etc in 99% of cases)]) + sysconfdir="${sysconfdir%/frr}" + path_warn_banner=true + ;; + *) + AC_MSG_RESULT([no, as expected]) + ;; +esac + +frr_sysconfdir="\${sysconfdir}/frr" + +AC_MSG_CHECKING([whether --localstatedir option is FRR-specific]) +case "$localstatedir" in + */run/frr) + AC_MSG_RESULT([yes, ends in /run/frr - removing suffix]) + AC_MSG_WARN([Please remove /run/frr suffix from --localstatedir=${localstatedir} (it should be /var in 99% of cases)]) + localstatedir="${localstatedir%/run/frr}" + path_warn_banner=true + ;; + */frr) + AC_MSG_RESULT([yes, ends in /frr - removing suffix]) + AC_MSG_WARN([The --localstatedir=${localstatedir} option seems to include /frr but not /run, this is unexpected. Please check for consistency.)]) + localstatedir="${localstatedir%/frr}" + path_warn_banner=true + ;; + *) + AC_MSG_RESULT([no, as expected]) + ;; +esac + +dnl runstatedir is either ${localstatedir}/run or plain /run +dnl the change of localstatedir above may impact this +dnl +dnl note runstatedir was never used with /frr as the other two above, so does +dnl not need the same cleanup hack +: "${runstatedir:=\${localstatedir\}/run}" +frr_runstatedir="\${runstatedir}/frr" + +if $path_warn_banner; then + AC_MSG_WARN([^]) + AC_MSG_WARN([^]) + AC_MSG_WARN([^ warnings regarding system path configuration were printed above]) + AC_MSG_WARN([^ paths have been adjusted by temporary workarounds]) + AC_MSG_WARN([^ please fix your ./configure invocation (remove /frr) so it will work without the workarounds]) + AC_MSG_WARN([^]) + AC_MSG_WARN([^]) +fi + +frr_libstatedir="\${localstatedir}/lib/frr" + dnl ----------------------------------- dnl Get hostname and other information. dnl ----------------------------------- @@ -130,10 +203,10 @@ AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directo ]) AC_SUBST([moduledir], [$moduledir]) -AC_ARG_WITH([scriptdir], [AS_HELP_STRING([--with-scriptdir=DIR], [script directory (${sysconfdir}/scripts)])], [ +AC_ARG_WITH([scriptdir], [AS_HELP_STRING([--with-scriptdir=DIR], [script directory (${sysconfdir}/frr/scripts)])], [ scriptdir="$withval" ], [ - scriptdir="\${sysconfdir}/scripts" + scriptdir="\${frr_sysconfdir}/scripts" ]) AC_SUBST([scriptdir], [$scriptdir]) @@ -202,7 +275,16 @@ AC_DEFUN([AC_C_FLAG], [{ AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [ AC_LANG_PUSH([C]) ac_c_flag_save="$CFLAGS" - CFLAGS="$CFLAGS $1" + dnl GCC ignores unknown -Wno-whatever flags, but errors on -Wwhatever + dnl except when it ignores them it prints: + dnl cc1: note: unrecognized command-line option ‘-Wno-whatever’ may have been intended to silence earlier diagnostics + dnl which is annoying as hell. So check for the positive flag instead. + flag_add="$1" + if test "$flag_add" != "${flag_add#-Wno-}"; then + CFLAGS="$CFLAGS -W${flag_add#-Wno-}" + else + CFLAGS="$CFLAGS $flag_add" + fi AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[$4]])], [ @@ -365,6 +447,7 @@ AC_C_FLAG([-Wpointer-arith]) AC_C_FLAG([-Wbad-function-cast]) AC_C_FLAG([-Wwrite-strings]) AC_C_FLAG([-Wundef]) +AC_C_FLAG([-Wimplicit-fallthrough]) if test "$enable_gcc_ultra_verbose" = "yes" ; then AC_C_FLAG([-Wcast-qual]) AC_C_FLAG([-Wmissing-noreturn]) @@ -378,6 +461,8 @@ else fi AC_C_FLAG([-Wno-unused-parameter]) AC_C_FLAG([-Wno-missing-field-initializers]) +AC_C_FLAG([-Wno-microsoft-anon-tag]) +AC_C_FLAG([-Wno-error=deprecated-declarations]) AC_C_FLAG([-Wc++-compat], [], [CXX_COMPAT_CFLAGS="-Wc++-compat"]) AC_SUBST([CXX_COMPAT_CFLAGS]) @@ -626,6 +711,10 @@ AC_ARG_ENABLE([mgmtd], AS_HELP_STRING([--disable-mgmtd], [do not build mgmtd])) AC_ARG_ENABLE([mgmtd_local_validations], AS_HELP_STRING([--enable-mgmtd-local-validations], [dev: unimplemented local validation])) +AC_ARG_ENABLE([mgmtd_test_be_client], + AS_HELP_STRING([--enable-mgmtd-test-be-client], [build test backend client])) +AC_ARG_ENABLE([fpm_listener], + AS_HELP_STRING([--enable-fpm-listener], [build fpm listener test program])) AC_ARG_ENABLE([ripd], AS_HELP_STRING([--disable-ripd], [do not build ripd])) AC_ARG_ENABLE([ripngd], @@ -672,8 +761,6 @@ AC_ARG_ENABLE([snmp], AS_HELP_STRING([--enable-snmp], [enable SNMP support for agentx])) AC_ARG_ENABLE([config_rollbacks], AS_HELP_STRING([--enable-config-rollbacks], [enable configuration rollbacks (requires sqlite3)])) -AC_ARG_ENABLE([confd], - AS_HELP_STRING([--enable-confd=ARG], [enable confd integration])) AC_ARG_ENABLE([sysrepo], AS_HELP_STRING([--enable-sysrepo], [enable sysrepo integration])) AC_ARG_ENABLE([grpc], @@ -707,24 +794,18 @@ AC_ARG_ENABLE([configfile_mask], AS_HELP_STRING([--enable-configfile-mask=ARG], [set mask for config files])) AC_ARG_ENABLE([logfile_mask], AS_HELP_STRING([--enable-logfile-mask=ARG], [set mask for log files])) -AC_ARG_ENABLE([shell_access], - AS_HELP_STRING([--enable-shell-access], [Allow users to access shell/telnet/ssh])) AC_ARG_ENABLE([realms], AS_HELP_STRING([--enable-realms], [enable REALMS support under Linux])) AC_ARG_ENABLE([rtadv], AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature])) AC_ARG_ENABLE([irdp], - AS_HELP_STRING([--disable-irdp], [disable IRDP server support in zebra (enabled by default if supported)])) + AS_HELP_STRING([--enable-irdp], [enable IRDP server support in zebra])) AC_ARG_ENABLE([capabilities], AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities])) AC_ARG_ENABLE([gcc_ultra_verbose], AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings])) AC_ARG_ENABLE([backtrace], AS_HELP_STRING([--disable-backtrace], [disable crash backtraces (default autodetect)])) -AC_ARG_ENABLE([time-check], - AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages])) -AC_ARG_ENABLE([cpu-time], - AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering])) AC_ARG_ENABLE([pcreposix], AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE([pcre2posix], @@ -810,22 +891,6 @@ fi AM_CONDITIONAL([NETLINK_DEBUG], [test "$enable_netlink_debug" != "no"]) -if test "$enable_time_check" != "no" ; then - if test "$enable_time_check" = "yes" -o "$enable_time_check" = "" ; then - AC_DEFINE([CONSUMED_TIME_CHECK], [5000000], [Consumed Time Check]) - else - AC_DEFINE_UNQUOTED([CONSUMED_TIME_CHECK], [$enable_time_check], [Consumed Time Check]) - fi -fi - -case "${enable_cpu_time}" in - "no") - AC_DEFINE([EXCLUDE_CPU_TIME], [1], [Exclude getrusage data gathering]) - ;; - "*") - ;; -esac - if test "$enable_datacenter" = "yes" ; then AC_DEFINE([HAVE_DATACENTER], [1], [Compile extensions for a DataCenter]) DFLT_NAME="datacenter" @@ -840,10 +905,6 @@ fi AC_SUBST([DFLT_NAME]) AC_DEFINE_UNQUOTED([DFLT_NAME], ["$DFLT_NAME"], [Name of the configuration default set]) -if test "$enable_shell_access" = "yes"; then - AC_DEFINE([HAVE_SHELL_ACCESS], [1], [Allow user to use ssh/telnet/bash, be aware this is considered insecure]) -fi - # # Python for clippy # @@ -1044,6 +1105,8 @@ dnl ------------------------- AC_CHECK_HEADERS([stropts.h sys/ksym.h \ linux/version.h asm/types.h endian.h sys/endian.h]) +AC_CHECK_LIB([atomic], [main], [LIBS="$LIBS -latomic"], [], []) + ac_stdatomic_ok=false AC_DEFINE([FRR_AUTOCONF_ATOMIC], [1], [did autoconf checks for atomic funcs]) AC_CHECK_HEADER([stdatomic.h],[ @@ -1199,9 +1262,6 @@ m4_define([FRR_INCLUDES], /* Required for MAXSIG */ #include #include -#ifdef __APPLE__ -# define __APPLE_USE_RFC_3542 -#endif #include #include #include @@ -1602,6 +1662,21 @@ FRR_INCLUDES #endif ])dnl +AC_CHECK_HEADERS([netinet6/ip6_mroute.h], [], [],[ + #include + #include + #include + #include + #include +]) + +m4_define([FRR_INCLUDES], +FRR_INCLUDES +[#ifdef HAVE_NETINET_IP6_MROUTE_H +# include +#endif +])dnl + AC_MSG_CHECKING([for RFC3678 protocol-independed API]) AC_COMPILE_IFELSE( [ AC_LANG_PROGRAM([[ @@ -1759,6 +1834,14 @@ AS_IF([test "$enable_mgmtd" != "no"], [ ]) ]) +AS_IF([test "$enable_mgmtd_test_be_client" = "yes"], [ + AC_DEFINE([HAVE_MGMTD_TESTC], [1], [mgmtd_testc]) +]) + +AS_IF([test "$enable_fpm_listener" = "yes"], [ + AC_DEFINE([HAVE_FPM_LISTENER], [1], [fpm_listener]) +]) + AS_IF([test "$enable_ripd" != "no"], [ AC_DEFINE([HAVE_RIPD], [1], [ripd]) ]) @@ -1974,9 +2057,9 @@ AC_SUBST([SNMP_CFLAGS]) dnl --------------- dnl libyang dnl --------------- -PKG_CHECK_MODULES([LIBYANG], [libyang >= 2.0.0], , [ - AC_MSG_ERROR([libyang (>= 2.0.0) was not found on your system.]) -]) +PKG_CHECK_MODULES([LIBYANG], [libyang >= 2.1.128], , [ +AC_MSG_ERROR([m4_normalize([libyang >= 2.1.128 is required, and was not found on your system. +Please consult doc/developer/building-libyang.rst for instructions on installing or building libyang.])])]) ac_cflags_save="$CFLAGS" CFLAGS="$CFLAGS $LIBYANG_CFLAGS" AC_CHECK_MEMBER([struct lyd_node.priv], [], [ @@ -1985,6 +2068,13 @@ AC_CHECK_MEMBER([struct lyd_node.priv], [], [ Instructions for this are included in the build documentation for your platform at http://docs.frrouting.org/projects/dev-guide/en/latest/building.html]) ]) ], [[#include ]]) + +AC_CHECK_LIB([yang],[lyd_find_xpath3],[],[AC_MSG_ERROR([m4_normalize([ +libyang missing lyd_find_xpath3])])]) +dnl -- don't add lyd_new_list3 to this list unless bug is fixed upstream +dnl -- https://github.com/CESNET/libyang/issues/2149 +AC_CHECK_FUNCS([ly_strerrcode ly_strvecode lyd_trim_xpath]) + CFLAGS="$ac_cflags_save" dnl --------------- @@ -2001,22 +2091,6 @@ if test "$enable_config_rollbacks" = "yes"; then ]) fi -dnl --------------- -dnl confd -dnl --------------- -if test "$enable_confd" != "" -a "$enable_confd" != "no"; then - AC_CHECK_PROG([CONFD], [confd], [confd], [/bin/false], "${enable_confd}/bin") - if test "$CONFD" = "/bin/false"; then - AC_MSG_ERROR([confd was not found on your system.])] - fi - AC_CHECK_PROG([CONFDC], [confdc], [confdc], [/bin/false], "${enable_confd}/bin") - CONFD_CFLAGS="-I${enable_confd}/include -L${enable_confd}/lib" - AC_SUBST([CONFD_CFLAGS]) - CONFD_LIBS="-lconfd" - AC_SUBST([CONFD_LIBS]) - AC_DEFINE([HAVE_CONFD], [1], [Enable confd integration]) -fi - dnl --------------- dnl sysrepo dnl --------------- @@ -2275,6 +2349,9 @@ yes) no) IRDP=false ;; +*) + IRDP=false + ;; esac @@ -2655,87 +2732,27 @@ else fi AC_SUBST([CONFDATE]) -dnl ------------------------------ -dnl set paths for state directory -dnl ------------------------------ -AC_MSG_CHECKING([directory to use for state file]) -if test "$prefix" = "NONE"; then - frr_statedir_prefix=""; -else - frr_statedir_prefix=${prefix} -fi -if test "$localstatedir" = '${prefix}/var'; then - for FRR_STATE_DIR in ${frr_statedir_prefix}/var/run dnl - ${frr_statedir_prefix}/var/adm dnl - ${frr_statedir_prefix}/etc dnl - /var/run dnl - /var/adm dnl - /etc dnl - /dev/null; - do - test -d $FRR_STATE_DIR && break - done - frr_statedir=$FRR_STATE_DIR -else - frr_statedir=${localstatedir} -fi -if test "$frr_statedir" = "/dev/null"; then - AC_MSG_ERROR([STATE DIRECTORY NOT FOUND! FIX OR SPECIFY --localstatedir!]) -fi -AC_MSG_RESULT([${frr_statedir}]) -AC_SUBST([frr_statedir]) - -AC_DEFINE_UNQUOTED([LDPD_SOCKET], ["$frr_statedir%s%s/ldpd.sock"], [ldpd control socket]) -AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra api socket]) -AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket]) -AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information]) -AC_DEFINE_UNQUOTED([MGMTD_FE_SERVER_PATH], ["$frr_statedir/mgmtd_fe.sock"], [mgmtd frontend server socket]) -AC_DEFINE_UNQUOTED([MGMTD_BE_SERVER_PATH], ["$frr_statedir/mgmtd_be.sock"], [mgmtd backend server socket]) -AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information]) -AC_DEFINE_UNQUOTED([ISISD_RESTART], ["$frr_statedir%s/isid-restart.json"], [isisd restart information]) -AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information]) -AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory]) -AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory]) - -dnl autoconf does this, but it does it too late... -test "$prefix" = "NONE" && prefix=$ac_default_prefix -test "$exec_prefix" = "NONE" && exec_prefix='${prefix}' - dnl get the full path, recursing through variables... -vtysh_bin="$bindir/vtysh" -for I in 1 2 3 4 5 6 7 8 9 10; do - eval vtysh_bin="\"$vtysh_bin\"" -done -AC_DEFINE_UNQUOTED([VTYSH_BIN_PATH], ["$vtysh_bin"], [path to vtysh binary]) -AC_SUBST([vtysh_bin]) - -CFG_SYSCONF="$sysconfdir" -CFG_SBIN="$sbindir" -CFG_BIN="$bindir" -CFG_STATE="$frr_statedir" -CFG_MODULE="$moduledir" -CFG_YANGMODELS="$yangmodelsdir" -CFG_SCRIPT="$scriptdir" -for I in 1 2 3 4 5 6 7 8 9 10; do - eval CFG_SYSCONF="\"$CFG_SYSCONF\"" - eval CFG_SBIN="\"$CFG_SBIN\"" - eval CFG_BIN="\"$CFG_BIN\"" - eval CFG_STATE="\"$CFG_STATE\"" - eval CFG_MODULE="\"$CFG_MODULE\"" - eval CFG_YANGMODELS="\"$CFG_YANGMODELS\"" - eval CFG_SCRIPT="\"$CFG_SCRIPT\"" -done -AC_SUBST([CFG_SYSCONF]) -AC_SUBST([CFG_SBIN]) -AC_SUBST([CFG_BIN]) -AC_SUBST([CFG_STATE]) -AC_SUBST([CFG_MODULE]) -AC_SUBST([CFG_SCRIPT]) -AC_SUBST([CFG_YANGMODELS]) -AC_DEFINE_UNQUOTED([MODULE_PATH], ["$CFG_MODULE"], [path to modules]) -AC_DEFINE_UNQUOTED([SCRIPT_PATH], ["$CFG_SCRIPT"], [path to scripts]) -AC_DEFINE_UNQUOTED([YANG_MODELS_PATH], ["$CFG_YANGMODELS"], [path to YANG data models]) -AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to watchfrr.sh]) +AC_DEFUN([AX_SUBST_EXPANDED], [ + AX_RECURSIVE_EVAL([[$]$1], [e_$1]) + AC_SUBST([e_$1]) +]) + +AX_SUBST_EXPANDED([bindir]) +AX_SUBST_EXPANDED([sbindir]) +AX_SUBST_EXPANDED([frr_sysconfdir]) +AX_SUBST_EXPANDED([frr_runstatedir]) +AX_SUBST_EXPANDED([frr_libstatedir]) +AX_SUBST_EXPANDED([moduledir]) +AX_SUBST_EXPANDED([yangmodelsdir]) +AX_SUBST_EXPANDED([scriptdir]) + +dnl strip duplicate trailing slashes if necessary +dnl note this uses e_bindir / e_sbindir created above +watchfrr_sh="\${e_sbindir%/}/watchfrr.sh" +AX_SUBST_EXPANDED([watchfrr_sh]) +vtysh_bin="\${e_bindir%/}/vtysh" +AX_SUBST_EXPANDED([vtysh_bin]) dnl various features AM_CONDITIONAL([SUPPORT_REALMS], [test "$enable_realms" = "yes"]) @@ -2743,7 +2760,6 @@ AM_CONDITIONAL([ENABLE_BGP_VNC], [test "$enable_bgp_vnc" != "no"]) AM_CONDITIONAL([BGP_BMP], [$bgpd_bmp]) dnl northbound AM_CONDITIONAL([SQLITE3], [$SQLITE3]) -AM_CONDITIONAL([CONFD], [test "$enable_confd" != ""]) AM_CONDITIONAL([SYSREPO], [test "$enable_sysrepo" = "yes"]) AM_CONDITIONAL([GRPC], [test "$enable_grpc" = "yes"]) AM_CONDITIONAL([ZEROMQ], [test "$ZEROMQ" = "true"]) @@ -2770,6 +2786,8 @@ AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"]) AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"]) AM_CONDITIONAL([BGPD], [test "$enable_bgpd" != "no"]) AM_CONDITIONAL([MGMTD], [test "$enable_mgmtd" != "no"]) +AM_CONDITIONAL([MGMTD_TESTC], [test "$enable_mgmtd_test_be_client" = "yes"]) +AM_CONDITIONAL([FPM_LISTENER], [test "enable_fpm_listener" = "yes"]) AM_CONDITIONAL([RIPD], [test "$enable_ripd" != "no"]) AM_CONDITIONAL([OSPFD], [test "$enable_ospfd" != "no"]) AM_CONDITIONAL([LDPD], [test "$enable_ldpd" != "no"]) @@ -2807,6 +2825,7 @@ AC_CONFIG_FILES([ alpine/APKBUILD snapcraft/snapcraft.yaml lib/version.h + lib/config_paths.h tests/lib/cli/test_cli.refout pkgsrc/mgmtd.sh pkgsrc/bgpd.sh pkgsrc/ospf6d.sh pkgsrc/ospfd.sh pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh @@ -2851,7 +2870,7 @@ fi FRR_ALL_CCLS_FLAGS="$(echo ${LIBYANG_CFLAGS} ${LUA_INCLUDE} ${SQLITE3_CFLAGS} | sed -e 's/ */ /g')" FRR_ALL_CCLS_CFLAGS="$(echo ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS} | sed -e 's/ */ /g')" ac_frr_confdate="${CONFDATE}" - ac_frr_sysconfdir="${sysconfdir}/" + ac_frr_sysconfdir="${frr_sysconfdir}/" ]) ]) @@ -2894,10 +2913,11 @@ compiler : ${CC} compiler flags : ${CFLAGS} ${WERROR} ${AC_CFLAGS} ${SAN_FLAGS} make : ${MAKE-make} linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} -state file directory : ${frr_statedir} -config file directory : `eval echo \`echo ${sysconfdir}\`` -module directory : ${CFG_MODULE} -script directory : ${CFG_SCRIPT} +local state file dir : ${e_frr_libstatedir} +run state file dir : ${e_frr_runstatedir} +config file directory : ${e_frr_sysconfdir} +module directory : ${e_moduledir} +script directory : ${e_scriptdir} user to run as : ${enable_user} group to run as : ${enable_group} group for vty sockets : ${enable_vty_group} @@ -2912,12 +2932,6 @@ directory and to the config files in the config file directory." if test -n "$enable_datacenter"; then AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.]) fi -if test -n "$enable_time_check"; then - AC_MSG_WARN([The --enable-time-check compile time option is deprecated. Please use the service cputime-stats configuration option instead.]) -fi -if test -n "$enable_cpu_time"; then - AC_MSG_WARN([The --enable-cpu-time compile time option is deprecated. Please use the service cputime-warning NNN configuration option instead.]) -fi if test "$enable_doc" != "no" -a "$frr_py_mod_sphinx" = "false"; then AC_MSG_WARN([sphinx is missing but required to build documentation]) @@ -2925,3 +2939,11 @@ fi if test "$frr_py_mod_pytest" = "false"; then AC_MSG_WARN([pytest is missing, unit tests cannot be performed]) fi + +if $path_warn_banner; then + AC_MSG_WARN([^]) + AC_MSG_WARN([^]) + AC_MSG_WARN([^ warnings regarding system path configuration were printed at the very top of output]) + AC_MSG_WARN([^ paths have been adjusted by temporary workarounds]) + AC_MSG_WARN([^ please fix your ./configure invocation (remove /frr) so it will work without the workarounds]) +fi diff --git a/debian/changelog b/debian/changelog index 5c0429d69deb..96c66db89bf6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,26 @@ -frr (9.1~dev-1) UNRELEASED; urgency=medium +frr (10.1~dev-1) UNRELEASED; urgency=medium - * FRR Dev 9.1 + * FRR Dev 10.1 - -- Jafar Al-Gharaibeh Tue, 06 Jun 2023 12:00:00 -0600 + -- Jafar Al-Gharaibeh Tue, 26 Mar 2024 02:00:00 -0600 + +frr (10.0-0) unstable; urgency=medium + + * New upstream release FRR 10.0 + + -- Jafar Al-Gharaibeh Mon, 25 Mar 2024 02:00:00 -0600 + +frr (9.1-0) unstable; urgency=medium + + * New upstream release FRR 9.1 + + -- Donatas Abraitis Thu, 09 Oct 2023 12:00:00 -0600 + +frr (9.0-0) unstable; urgency=medium + + * New upstream release FRR 9.0 + + -- Jafar Al-Gharaibeh Wed, 26 Jul 2023 02:00:00 -0600 frr (8.5-0) unstable; urgency=medium diff --git a/debian/control b/debian/control index b3c14f06f3d7..4a02a36b71d1 100644 --- a/debian/control +++ b/debian/control @@ -23,7 +23,7 @@ Build-Depends: bison, librtr-dev (>= 0.8.0~) , libsnmp-dev, libssh-dev , - libyang2-dev (>= 2.1.80), + libyang2-dev (>= 2.1.128) | libyang-dev ( >= 3.0.3), lsb-base, pkg-config, protobuf-c-compiler, @@ -33,7 +33,11 @@ Build-Depends: bison, python3-sphinx:native, texinfo (>= 4.7), lua5.3 , - liblua5.3-dev + liblua5.3-dev , + libgrpc-dev (>=1.16.1) , + libgrpc++-dev (>=1.16.1) , + protobuf-compiler (>=3.6.1) , + protobuf-compiler-grpc (>=1.16.1) Standards-Version: 4.5.0.3 Homepage: https://www.frrouting.org/ Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master @@ -102,6 +106,14 @@ Description: FRRouting suite - BGP RPKI support (rtrlib) number. Build-Profiles: +Package: frr-test-tools +Architecture: linux-any +Depends: frr (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Description: FRRouting suite - Testing Tools + Adds FRR test tools, used in testing FRR. + Package: frr-doc Section: doc Architecture: all @@ -128,3 +140,13 @@ Description: FRRouting suite - Python tools . Without this package installed, "reload" (as a systemd or init script invocation) will not work for the FRR daemons. + +Package: frr-grpc +Architecture: linux-any +Depends: frr (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Description: FRRouting suite - GRPC interface + This provides the GRPC interface to the daemons. +Build-Profiles: + diff --git a/debian/copyright b/debian/copyright index edd73020bd22..e1a944b338ad 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,6 +4,13 @@ Upstream-Contact: maintainers@frrouting.org, security@frrouting.org Source: https://www.frrouting.org/ Files: * +Comment: Note: GPL Versions of FRR binaries + If GRPC module is installed then please be aware that the + combination of the GRPC (licensed under Apache License) and + FRR (Licensed under GPLv2+) will force the resulting grpc + modules and related binaries to GPLv3 + Impacted binary files: frr/libfrrgrpc_pb.* frr/modules/grpc.so + FRR built or used without GRPC is not impacted Copyright: 1996-2003 by the original Zebra authors: Kunihiro Ishiguro Toshiaki Takada @@ -377,6 +384,24 @@ License: LGPL-2.1+ License version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. +License: GPL-3 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-3'. + License: BSD-0-clause Redistribution and use in source and binary forms, with or without modification, are permitted. diff --git a/debian/frr-grpc.install b/debian/frr-grpc.install new file mode 100644 index 000000000000..d006439e6fab --- /dev/null +++ b/debian/frr-grpc.install @@ -0,0 +1,2 @@ +usr/lib/*/frr/libfrrgrpc_pb.* +usr/lib/*/frr/modules/grpc.so diff --git a/debian/frr-test-tools.install b/debian/frr-test-tools.install new file mode 100644 index 000000000000..a8ad18f2c686 --- /dev/null +++ b/debian/frr-test-tools.install @@ -0,0 +1 @@ +usr/lib/frr/fpm_listener diff --git a/debian/frr.install b/debian/frr.install index 02912d448dee..d4b904b6e3f0 100644 --- a/debian/frr.install +++ b/debian/frr.install @@ -13,7 +13,6 @@ usr/lib/*/frr/modules/bgpd_bmp.so usr/lib/*/frr/modules/dplane_fpm_nl.so usr/lib/*/frr/modules/zebra_cumulus_mlag.so usr/lib/*/frr/modules/zebra_fpm.so -usr/lib/*/frr/modules/zebra_irdp.so usr/lib/*/frr/modules/pathd_pcep.so usr/lib/frr/*.sh usr/lib/frr/*d diff --git a/debian/frr.pam b/debian/frr.pam index 737b88953b59..1077243a12db 100644 --- a/debian/frr.pam +++ b/debian/frr.pam @@ -1,4 +1,4 @@ # Any user may call vtysh but only those belonging to the group frrvty can # actually connect to the socket and use the program. auth sufficient pam_permit.so -account sufficient pam_rootok.so +account sufficient pam_permit.so diff --git a/debian/frr.postinst b/debian/frr.postinst index eb9ec67dd982..9c9b4a821c65 100644 --- a/debian/frr.postinst +++ b/debian/frr.postinst @@ -17,8 +17,10 @@ adduser \ usermod -a -G frrvty frr mkdir -m 0755 -p /var/log/frr +mkdir -m 0700 -p /var/lib/frr mkdir -p /etc/frr +chown frr: /var/lib/frr # only change ownership of files when they were previously owned by root or # quagga; this is to ensure we don't trample over some custom user setup. diff --git a/debian/rules b/debian/rules index 43e5d7e614ad..ec8f92f755f6 100755 --- a/debian/rules +++ b/debian/rules @@ -33,6 +33,12 @@ else CONF_PIM6=--disable-pim6d endif +ifeq ($(filter pkg.frr.grpc,$(DEB_BUILD_PROFILES)),) + CONF_GRPC=--disable-grpc +else + CONF_GRPC=--enable-grpc +endif + export PYTHON=python3 %: @@ -41,9 +47,7 @@ export PYTHON=python3 override_dh_auto_configure: $(shell dpkg-buildflags --export=sh); \ dh_auto_configure -- \ - --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --with-vtysh-pager=/usr/bin/pager \ --libdir=/usr/lib/$(DEB_HOST_MULTIARCH)/frr \ --with-moduledir=/usr/lib/$(DEB_HOST_MULTIARCH)/frr/modules \ @@ -53,6 +57,7 @@ override_dh_auto_configure: $(CONF_RPKI) \ $(CONF_LUA) \ $(CONF_PIM6) \ + $(CONF_GRPC) \ --with-libpam \ --enable-doc \ --enable-doc-html \ diff --git a/doc/developer/.readthedocs.yaml b/doc/developer/.readthedocs.yaml new file mode 100644 index 000000000000..90ee5c767729 --- /dev/null +++ b/doc/developer/.readthedocs.yaml @@ -0,0 +1,18 @@ +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + apt_packages: + - graphviz + +python: + install: + - requirements: doc/developer/requirements.txt + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/developer/conf.py diff --git a/doc/developer/bmp.rst b/doc/developer/bmp.rst new file mode 100644 index 000000000000..1c0e4b045426 --- /dev/null +++ b/doc/developer/bmp.rst @@ -0,0 +1,49 @@ +.. _bmp: + +*** +BMP +*** + +RFC 7854 +======== +Missing features (non exhaustive): + - Per-Peer Header + + - Peer Type Flag + - Peer Distingsher + + - Peer Up + + - Reason codes (according to TODO comments in code) + +Peer Type Flag and Peer Distinguisher can be implemented easily using RFC 9069's base code. + +RFC 9069 +======== +Everything that isn't listed here is implemented and should be working. +Missing features (should be exhaustive): + +- Per-Peer Header + + - Timestamp + + - set to 0 + - value is now saved `struct bgp_path_info -> locrib_uptime` + - needs testing + +- Peer Up/Down + + - VRF/Table Name TLV + + - code for TLV exists + - need better RFC understanding + +- Peer Down Only + + - Reason code (bc not supported in RFC 7854 either) + +- Statistics Report + + - Stat Type = 8: (64-bit Gauge) Number of routes in Loc-RIB. + - Stat Type = 10: Number of routes in per-AFI/SAFI Loc-RIB. The value is + structured as: 2-byte AFI, 1-byte SAFI, followed by a 64-bit Gauge. diff --git a/doc/developer/building-docker.rst b/doc/developer/building-docker.rst index 9d42784e35fd..644e02bd6c62 100644 --- a/doc/developer/building-docker.rst +++ b/doc/developer/building-docker.rst @@ -14,7 +14,7 @@ source-built FRR on the following base platforms: The following platform images are used to support Travis CI and can also be used to reproduce topotest failures when the docker host is Ubuntu -(tested on 18.04 and 20.04): +(tested on 20.04 and 22.04): * Ubuntu 20.04 * Ubuntu 22.04 @@ -139,12 +139,12 @@ Build image (from project root directory):: Running Full Topotest:: - docker run --init -it --privileged --name frr -v /lib/modules:/lib/modules \ + docker run --init -it --privileged --name frr-ubuntu20 -v /lib/modules:/lib/modules \ frr-ubuntu20:latest bash -c 'cd ~/frr/tests/topotests ; sudo pytest -nauto --dist=loadfile' Extract results from the above run into `run-results` dir and analyze:: - tests/topotest/analyze.py -C frr -Ar run-results + tests/topotests/analyze.py -C frr-ubuntu20 -Ar run-results Start the container:: @@ -176,12 +176,12 @@ Build image (from project root directory):: Running Full Topotest:: - docker run --init -it --privileged --name frr -v /lib/modules:/lib/modules \ + docker run --init -it --privileged --name frr-ubuntu22 -v /lib/modules:/lib/modules \ frr-ubuntu22:latest bash -c 'cd ~/frr/tests/topotests ; sudo pytest -nauto --dist=loadfile' Extract results from the above run into `run-results` dir and analyze:: - tests/topotest/analyze.py -C frr -Ar run-results + tests/topotests/analyze.py -C frr-ubuntu22 -Ar run-results Start the container:: diff --git a/doc/developer/building-frr-for-archlinux.rst b/doc/developer/building-frr-for-archlinux.rst index 406d22d6180e..8b0df217a0b7 100644 --- a/doc/developer/building-frr-for-archlinux.rst +++ b/doc/developer/building-frr-for-archlinux.rst @@ -11,18 +11,12 @@ Installing Dependencies git autoconf automake libtool make cmake pcre readline texinfo \ pkg-config pam json-c bison flex python-pytest \ c-ares python python2-ipaddress python-sphinx \ - net-snmp perl libcap libelf libunwind + net-snmp perl libcap libelf libunwind protobuf-c .. include:: building-libunwind-note.rst .. include:: building-libyang.rst -Protobuf -^^^^^^^^ - -.. code-block:: console - - sudo pacman -S protobuf-c ZeroMQ ^^^^^^ diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index 233d089f7957..35311623608f 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -124,7 +124,7 @@ Install libyang and its dependencies: sudo yum install pcre-devel doxygen cmake git clone https://github.com/CESNET/libyang.git cd libyang - git checkout 090926a89d59a3c4000719505d563aaf6ac60f2 + git checkout v2.1.128 mkdir build ; cd build cmake -DENABLE_LYD_PRIV=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr -D CMAKE_BUILD_TYPE:String="Release" .. make build-rpm @@ -161,10 +161,8 @@ an example.) ./configure \ --bindir=/usr/bin \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --libdir=/usr/lib/frr \ --libexecdir=/usr/lib/frr \ - --localstatedir=/var/run/frr \ --with-moduledir=/usr/lib/frr/modules \ --disable-pimd \ --enable-snmp=agentx \ diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index e6da83019405..eabf515d2e77 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -58,10 +58,8 @@ an example.) ./configure \ --bindir=/usr/bin \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --libdir=/usr/lib/frr \ --libexecdir=/usr/lib/frr \ - --localstatedir=/var/run/frr \ --with-moduledir=/usr/lib/frr/modules \ --enable-snmp=agentx \ --enable-multipath=64 \ diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst index 6d18e7be93a3..2d514ead1e24 100644 --- a/doc/developer/building-frr-for-centos8.rst +++ b/doc/developer/building-frr-for-centos8.rst @@ -52,10 +52,8 @@ an example.) ./configure \ --bindir=/usr/bin \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --libdir=/usr/lib/frr \ --libexecdir=/usr/lib/frr \ - --localstatedir=/var/run/frr \ --with-moduledir=/usr/lib/frr/modules \ --enable-snmp=agentx \ --enable-multipath=64 \ diff --git a/doc/developer/building-frr-for-debian12.rst b/doc/developer/building-frr-for-debian12.rst new file mode 100644 index 000000000000..06bc18c25262 --- /dev/null +++ b/doc/developer/building-frr-for-debian12.rst @@ -0,0 +1,119 @@ +Debian 12 +========= + +Install required packages +------------------------- + +Add packages: + +:: + + sudo apt-get install git autoconf automake libtool make \ + libprotobuf-c-dev protobuf-c-compiler build-essential \ + python3-dev python3-pytest python3-sphinx libjson-c-dev \ + libelf-dev libreadline-dev cmake libcap-dev bison flex \ + pkg-config texinfo gdb libgrpc-dev python3-grpc-tools + +.. include:: building-libunwind-note.rst + +.. include:: building-libyang.rst + +Get FRR, compile it and install it (from Git) +--------------------------------------------- + +**This assumes you want to build and install FRR from source and not +using any packages** + +Add frr groups and user +^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + sudo addgroup --system --gid 92 frr + sudo addgroup --system --gid 85 frrvty + sudo adduser --system --ingroup frr --home /var/opt/frr/ \ + --gecos "FRR suite" --shell /bin/false frr + sudo usermod -a -G frrvty frr + +Download Source, configure and compile it +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +(You may prefer different options on configure statement. These are just +an example.) + +:: + + git clone https://github.com/frrouting/frr.git frr + cd frr + ./bootstrap.sh + ./configure \ + --sysconfdir=/etc \ + --localstatedir=/var \ + --sbindir=/usr/lib/frr \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + --enable-fpm \ + --with-pkg-git-version \ + --with-pkg-extra-version=-MyOwnFRRVersion + make + make check + sudo make install + +For more compile options, see ``./configure --help`` + +Create empty FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + sudo install -m 640 -o frr -g frr /dev/null /etc/frr/frr.conf + sudo install -m 640 -o frr -g frr tools/etc/frr/daemons /etc/frr/daemons + +Edit ``/etc/frr/daemons`` and enable the FRR daemons for the protocols you need + +Enable IP & IPv6 forwarding +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Edit ``/etc/sysctl.conf`` and uncomment the following values (ignore the +other settings) + +:: + + # Uncomment the next line to enable packet forwarding for IPv4 + net.ipv4.ip_forward=1 + + # Uncomment the next line to enable packet forwarding for IPv6 + # Enabling this option disables Stateless Address Autoconfiguration + # based on Router Advertisements for this host + net.ipv6.conf.all.forwarding=1 + +**Reboot** or use ``sysctl -p`` to apply the same config to the running +system + +Troubleshooting +--------------- + +Shared library error +^^^^^^^^^^^^^^^^^^^^ + +If you try and start any of the frrouting daemons you may see the below +error due to the frrouting shared library directory not being found: + +:: + + ./zebra: error while loading shared libraries: libfrr.so.0: cannot open + shared object file: No such file or directory + +The fix is to add the following line to /etc/ld.so.conf which will +continue to reference the library directory after the system reboots. To +load the library directory path immediately run the ldconfig command +after adding the line to the file eg: + +:: + + echo include /usr/local/lib >> /etc/ld.so.conf + ldconfig diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 7071cb660de8..fe4eeea601d0 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -57,9 +57,9 @@ an example.) cd frr ./bootstrap.sh ./configure \ - --localstatedir=/var/run/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --enable-multipath=64 \ --enable-user=frr \ --enable-group=frr \ @@ -118,9 +118,9 @@ Troubleshooting The local state directory must exist and have the correct permissions applied for the frrouting daemons to start. In the above ./configure -example the local state directory is set to /var/run/frr -(--localstatedir=/var/run/frr) Debian considers /var/run/frr to be -temporary and this is removed after a reboot. +example the local state directory is set to ``/var`` such that ``/var/run/frr`` +is used. Debian considers ``/var/run/frr`` to be temporary and this is removed +after a reboot. When using a different local state directory you need to create the new directory and change the ownership to the frr user, for example: diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index 1b2f1b933a42..a590cf7c7483 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -47,9 +47,9 @@ an example.) cd frr ./bootstrap.sh ./configure \ - --localstatedir=/var/opt/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --enable-multipath=64 \ --enable-user=frr \ --enable-group=frr \ diff --git a/doc/developer/building-frr-for-freebsd10.rst b/doc/developer/building-frr-for-freebsd10.rst index 707f1e703364..beefb59a2775 100644 --- a/doc/developer/building-frr-for-freebsd10.rst +++ b/doc/developer/building-frr-for-freebsd10.rst @@ -60,9 +60,9 @@ an example) export LDFLAGS="-L/usr/local/lib" export CPPFLAGS="-I/usr/local/include" ./configure \ - --sysconfdir=/usr/local/etc/frr \ + --sysconfdir=/usr/local/etc \ + --localstatedir=/var \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ - --localstatedir=/var/run/frr \ --prefix=/usr/local \ --enable-multipath=64 \ --enable-user=frr \ diff --git a/doc/developer/building-frr-for-freebsd11.rst b/doc/developer/building-frr-for-freebsd11.rst index af0b72b16def..7c8fb83cfa25 100644 --- a/doc/developer/building-frr-for-freebsd11.rst +++ b/doc/developer/building-frr-for-freebsd11.rst @@ -65,9 +65,9 @@ an example) setenv CPPFLAGS -I/usr/local/include ln -s /usr/local/bin/sphinx-build-3.6 /usr/local/bin/sphinx-build ./configure \ - --sysconfdir=/usr/local/etc/frr \ + --sysconfdir=/usr/local/etc \ + --localstatedir=/var \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ - --localstatedir=/var/run/frr \ --prefix=/usr/local \ --enable-multipath=64 \ --enable-user=frr \ diff --git a/doc/developer/building-frr-for-freebsd13.rst b/doc/developer/building-frr-for-freebsd13.rst index 0bc827793053..86506a9dd929 100644 --- a/doc/developer/building-frr-for-freebsd13.rst +++ b/doc/developer/building-frr-for-freebsd13.rst @@ -52,9 +52,9 @@ an example) ./bootstrap.sh export MAKE=gmake LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include ./configure \ - --sysconfdir=/usr/local/etc/frr \ + --sysconfdir=/usr/local/etc \ + --localstatedir=/var \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ - --localstatedir=/var/run/frr \ --prefix=/usr/local \ --enable-multipath=64 \ --enable-user=frr \ diff --git a/doc/developer/building-frr-for-freebsd14.rst b/doc/developer/building-frr-for-freebsd14.rst new file mode 100644 index 000000000000..b3fd37aa102f --- /dev/null +++ b/doc/developer/building-frr-for-freebsd14.rst @@ -0,0 +1,122 @@ +FreeBSD 14 +========== + +FreeBSD 14 restrictions: +------------------------ + +- MPLS is not supported on ``FreeBSD``. MPLS requires a Linux Kernel + (4.5 or higher). LDP can be built, but may have limited use without + MPLS +- PIM for IPv6 is not currently supported on ``FreeBSD``. + +Install required packages +------------------------- + +Add packages: (Allow the install of the package management tool if this +is first package install and asked) + +.. code-block:: shell + + pkg install autoconf automake bison c-ares git gmake json-c libtool \ + libunwind libyang2 pkgconf protobuf-c py39-pytest py39-sphinx texinfo + +.. include:: building-libunwind-note.rst + +Get FRR, compile it and install it (from Git) +--------------------------------------------- + +**This assumes you want to build and install FRR from source and not using any +packages** + +Add frr group and user +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + pw groupadd frr -g 101 + pw groupadd frrvty -g 102 + pw adduser frr -g 101 -u 101 -G 102 -c "FRR suite" \ + -d /usr/local/etc/frr -s /usr/sbin/nologin + + +Download Source, configure and compile it +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +(You may prefer different options on configure statement. These are just +an example) + +.. code-block:: shell + + git clone https://github.com/frrouting/frr.git frr + cd frr + ./bootstrap.sh + export MAKE=gmake LDFLAGS=-L/usr/local/lib CPPFLAGS=-I/usr/local/include + ./configure \ + --sysconfdir=/usr/local/etc \ + --localstatedir=/var \ + --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ + --prefix=/usr/local \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + --enable-fpm \ + --with-pkg-git-version \ + --with-pkg-extra-version=-MyOwnFRRVersion + gmake + gmake check + sudo gmake install + +Create empty FRR configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: shell + + sudo mkdir /usr/local/etc/frr + +For integrated config file: + +.. code-block:: shell + + sudo touch /usr/local/etc/frr/frr.conf + +For individual config files: + +.. note:: Integrated config is preferred to individual config. + +.. code-block:: shell + + sudo touch /usr/local/etc/frr/babeld.conf + sudo touch /usr/local/etc/frr/bfdd.conf + sudo touch /usr/local/etc/frr/bgpd.conf + sudo touch /usr/local/etc/frr/eigrpd.conf + sudo touch /usr/local/etc/frr/isisd.conf + sudo touch /usr/local/etc/frr/ldpd.conf + sudo touch /usr/local/etc/frr/nhrpd.conf + sudo touch /usr/local/etc/frr/ospf6d.conf + sudo touch /usr/local/etc/frr/ospfd.conf + sudo touch /usr/local/etc/frr/pbrd.conf + sudo touch /usr/local/etc/frr/pimd.conf + sudo touch /usr/local/etc/frr/ripd.conf + sudo touch /usr/local/etc/frr/ripngd.conf + sudo touch /usr/local/etc/frr/staticd.conf + sudo touch /usr/local/etc/frr/zebra.conf + sudo chown -R frr:frr /usr/local/etc/frr/ + sudo touch /usr/local/etc/frr/vtysh.conf + sudo chown frr:frrvty /usr/local/etc/frr/vtysh.conf + sudo chmod 640 /usr/local/etc/frr/*.conf + +Enable IP & IPv6 forwarding +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Add the following lines to the end of ``/etc/sysctl.conf``: + +:: + + # Routing: We need to forward packets + net.inet.ip.forwarding=1 + net.inet6.ip6.forwarding=1 + +**Reboot** or use ``sysctl`` to apply the same config to the running system. diff --git a/doc/developer/building-frr-for-freebsd9.rst b/doc/developer/building-frr-for-freebsd9.rst index 30332875a016..9f9073d4e2d0 100644 --- a/doc/developer/building-frr-for-freebsd9.rst +++ b/doc/developer/building-frr-for-freebsd9.rst @@ -70,9 +70,9 @@ an example) export LDFLAGS="-L/usr/local/lib" export CPPFLAGS="-I/usr/local/include" ./configure \ - --sysconfdir=/usr/local/etc/frr \ + --sysconfdir=/usr/local/etc \ + --localstatedir=/var \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ - --localstatedir=/var/run/frr \ --prefix=/usr/local \ --enable-multipath=64 \ --enable-user=frr \ diff --git a/doc/developer/building-frr-for-netbsd6.rst b/doc/developer/building-frr-for-netbsd6.rst index 8958862fea7e..77c0e008ef00 100644 --- a/doc/developer/building-frr-for-netbsd6.rst +++ b/doc/developer/building-frr-for-netbsd6.rst @@ -64,9 +64,9 @@ an example) export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib" export CPPFLAGS="-I/usr/pkg/include" ./configure \ - --sysconfdir=/usr/pkg/etc/frr \ + --sysconfdir=/usr/pkg/etc \ + --localstatedir=/var \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ - --localstatedir=/var/run/frr \ --enable-multipath=64 \ --enable-user=frr \ --enable-group=frr \ diff --git a/doc/developer/building-frr-for-netbsd7.rst b/doc/developer/building-frr-for-netbsd7.rst index e751ba338c11..abb04a028b27 100644 --- a/doc/developer/building-frr-for-netbsd7.rst +++ b/doc/developer/building-frr-for-netbsd7.rst @@ -55,9 +55,9 @@ an example) export LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib" export CPPFLAGS="-I/usr/pkg/include" ./configure \ - --sysconfdir=/usr/pkg/etc/frr \ + --sysconfdir=/usr/pkg/etc \ + --localstatedir=/var \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ - --localstatedir=/var/run/frr \ --enable-multipath=64 \ --enable-user=frr \ --enable-group=frr \ diff --git a/doc/developer/building-frr-for-openbsd6.rst b/doc/developer/building-frr-for-openbsd6.rst index 00bc2e5f091d..6d7f34623167 100644 --- a/doc/developer/building-frr-for-openbsd6.rst +++ b/doc/developer/building-frr-for-openbsd6.rst @@ -71,8 +71,8 @@ an example) export LDFLAGS="-L/usr/local/lib" export CPPFLAGS="-I/usr/local/include" ./configure \ - --sysconfdir=/etc/frr \ - --localstatedir=/var/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --enable-multipath=64 \ --enable-user=_frr \ --enable-group=_frr \ diff --git a/doc/developer/building-frr-for-opensuse.rst b/doc/developer/building-frr-for-opensuse.rst index 3ff445bcd062..6e9913de48db 100644 --- a/doc/developer/building-frr-for-opensuse.rst +++ b/doc/developer/building-frr-for-opensuse.rst @@ -13,11 +13,13 @@ Installing Dependencies zypper in git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig libjson-c-devel\ pam-devel python3-pytest bison flex c-ares-devel python3-devel\ - python3-Sphinx perl patch libcap-devel libyang-devel \ + python3-Sphinx perl patch libcap-devel \ libelf-devel libunwind-devel protobuf-c .. include:: building-libunwind-note.rst +.. include:: building-libyang.rst + Building & Installing FRR ------------------------- diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index cc6c3c03f383..dd3f98a58e34 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -14,16 +14,11 @@ Installing Dependencies git autoconf automake libtool make libreadline-dev texinfo \ pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev python3-sphinx install-info build-essential \ + protobuf-c-compiler libprotobuf-c-dev \ libsnmp-dev perl libcap-dev libelf-dev .. include:: building-libyang.rst -Protobuf -^^^^^^^^ - -.. code-block:: console - - sudo apt-get install protobuf-c-compiler libprotobuf-c-dev Building & Installing FRR ------------------------- diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index e5c2389f399c..f3b6aa0de973 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -19,12 +19,6 @@ Installing Dependencies .. include:: building-libyang.rst -Protobuf -^^^^^^^^ - -.. code-block:: console - - sudo apt-get install protobuf-c-compiler libprotobuf-c-dev Building & Installing FRR ------------------------- diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index fcfd94ec2cab..b4880e26be7e 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -15,18 +15,13 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl libcap-dev \ + protobuf-c-compiler libprotobuf-c-dev \ libelf-dev libunwind-dev .. include:: building-libunwind-note.rst .. include:: building-libyang.rst -Protobuf -^^^^^^^^ - -.. code-block:: console - - sudo apt-get install protobuf-c-compiler libprotobuf-c-dev ZeroMQ ^^^^^^ diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst index fdfc25da9df0..3db97c4b2df8 100644 --- a/doc/developer/building-frr-for-ubuntu2004.rst +++ b/doc/developer/building-frr-for-ubuntu2004.rst @@ -15,34 +15,33 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl \ - libcap-dev python2 libelf-dev libunwind-dev + protobuf-c-compiler libprotobuf-c-dev \ + libcap-dev libelf-dev libunwind-dev .. include:: building-libunwind-note.rst -Note that Ubuntu 20 no longer installs python 2.x, so it must be -installed explicitly. Ensure that your system has a symlink named -``/usr/bin/python`` pointing at ``/usr/bin/python3``. +.. include:: building-libyang.rst -In addition, ``pip`` for python2 must be installed if you wish to run -the FRR topotests. That version of ``pip`` is not available from the -ubuntu apt repositories; in order to install it: +GRPC +^^^^ +If GRPC is enabled using ``--enable-grpc`` the following packages should be +installed. -.. code-block:: shell +.. code-block:: console - curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py - sudo python2 ./get-pip.py + sudo apt-get install libgrpc++-dev protobuf-compiler-grpc - # And verify the installation - pip2 --version -.. include:: building-libyang.rst +Config Rollbacks +^^^^^^^^^^^^^^^^ -Protobuf -^^^^^^^^ +If config rollbacks are enabled using ``--enable-config-rollbacks`` +the sqlite3 developer package also should be installed. .. code-block:: console - sudo apt-get install protobuf-c-compiler libprotobuf-c-dev + sudo apt install libsqlite3-dev + ZeroMQ ^^^^^^ diff --git a/doc/developer/building-frr-for-ubuntu2204.rst b/doc/developer/building-frr-for-ubuntu2204.rst index 7e62d85763e7..c898c3cd2c1b 100644 --- a/doc/developer/building-frr-for-ubuntu2204.rst +++ b/doc/developer/building-frr-for-ubuntu2204.rst @@ -15,40 +15,21 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl \ - libcap-dev python2 libelf-dev libunwind-dev \ - libyang2 libyang2-dev + libcap-dev libelf-dev libunwind-dev \ + protobuf-c-compiler libprotobuf-c-dev .. include:: building-libunwind-note.rst -Note that Ubuntu >= 20 no longer installs python 2.x, so it must be -installed explicitly. Ensure that your system has a symlink named -``/usr/bin/python`` pointing at ``/usr/bin/python3``. +.. include:: building-libyang.rst -.. code-block:: shell - - sudo ln -s /usr/bin/python3 /usr/bin/python - python --version - -In addition, ``pip`` for python2 must be installed if you wish to run -the FRR topotests. That version of ``pip`` is not available from the -ubuntu apt repositories; in order to install it: - -.. code-block:: shell - - curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py - sudo python2 ./get-pip.py - - # And verify the installation - pip2 --version - - -Protobuf -^^^^^^^^ -This is optional +GRPC +^^^^ +If GRPC is enabled using ``--enable-grpc`` the following packages should be +installed. .. code-block:: console - sudo apt-get install protobuf-c-compiler libprotobuf-c-dev + sudo apt-get install libgrpc++-dev protobuf-compiler-grpc Config Rollbacks @@ -58,6 +39,7 @@ If config rollbacks are enabled using ``--enable-config-rollbacks`` the sqlite3 developer package also should be installed. .. code-block:: console + sudo apt install libsqlite3-dev diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index c36cd34287cf..8d9876c21ad4 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -10,11 +10,11 @@ The FRR project builds some binary ``libyang`` packages. RPM packages are at our `RPM repository `_. DEB packages are available as CI artifacts `here -`_. +`_. .. warning:: - ``libyang`` version 2.0.0 or newer is required to build FRR. + ``libyang`` version 2.1.128 or newer is required to build FRR. .. note:: @@ -39,9 +39,9 @@ DEB packages are available as CI artifacts `here git clone https://github.com/CESNET/libyang.git cd libyang - git checkout v2.0.0 + git checkout v2.1.128 mkdir build; cd build - cmake -D CMAKE_INSTALL_PREFIX:PATH=/usr \ + cmake --install-prefix /usr \ -D CMAKE_BUILD_TYPE:String="Release" .. make sudo make install diff --git a/doc/developer/building.rst b/doc/developer/building.rst index dac0f9a84d19..6762604f32d9 100644 --- a/doc/developer/building.rst +++ b/doc/developer/building.rst @@ -15,11 +15,13 @@ Building FRR building-frr-for-centos8 building-frr-for-debian8 building-frr-for-debian9 + building-frr-for-debian12 building-frr-for-fedora building-frr-for-freebsd9 building-frr-for-freebsd10 building-frr-for-freebsd11 building-frr-for-freebsd13 + building-frr-for-freebsd14 building-frr-for-netbsd6 building-frr-for-netbsd7 building-frr-for-openbsd6 diff --git a/doc/developer/checkpatch.rst b/doc/developer/checkpatch.rst index b52452bc2963..4ef261ba2209 100644 --- a/doc/developer/checkpatch.rst +++ b/doc/developer/checkpatch.rst @@ -1,5 +1,7 @@ .. SPDX-License-Identifier: GPL-2.0-only +.. _checkpatch: + ========== Checkpatch ========== @@ -759,15 +761,6 @@ Indentation and Line Breaks Macros, Attributes and Symbols ------------------------------ - **ARRAY_SIZE** - The ARRAY_SIZE(foo) macro should be preferred over - sizeof(foo)/sizeof(foo[0]) for finding number of elements in an - array. - - The macro is defined in include/linux/kernel.h:: - - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - **AVOID_EXTERNS** Function prototypes don't need to be declared extern in .h files. It's assumed by the compiler and is unnecessary. diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index 61b9cf6acb53..59073b39ab44 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -639,13 +639,14 @@ in order into ``*argv[]``. Before this happens the ``->arg`` field is set to point at the snippet of user input that matched it. For most nontrivial commands the handler function will need to determine which -of the possible matching inputs was entered. Previously this was done by looking -at the first few characters of input. This is now considered an anti-pattern and -should be avoided. Instead, the ``->type`` or ``->text`` fields for this logic. -The ``->type`` field can be used when the possible inputs differ in type. When -the possible types are the same, use the ``->text`` field. This field has the -full text of the corresponding token in the definition string and using it makes -for much more readable code. An example is helpful. +of the possible matching inputs was entered. Previously this was done by +looking at the first few characters of input. This is now considered an +anti-pattern and should be avoided. Instead, use the ``->type`` or ``->text`` +fields for this logic. The ``->type`` field can be used when the possible +inputs differ in type. When the possible types are the same, use the ``->text`` +field. This field has the full text of the corresponding token in the +definition string and using it makes for much more readable code. An example is +helpful. Command definition: @@ -654,9 +655,10 @@ Command definition: command <(1-10)|foo|BAR> In this example, the user may enter any one of: -- an integer between 1 and 10 -- "foo" -- anything at all + +* an integer between 1 and 10 +* "foo" +* anything at all If the user enters "command f", then: @@ -793,12 +795,12 @@ Adding a CLI Node To add a new CLI node, you should: -- define a new numerical node constant -- define a node structure in the relevant daemon -- call ``install_node()`` in the relevant daemon -- define and install the new node in vtysh -- define corresponding node entry commands in daemon and vtysh -- add a new entry to the ``ctx_keywords`` dictionary in ``tools/frr-reload.py`` +#. define a new numerical node constant +#. define a node structure in the relevant daemon +#. call ``install_node()`` in the relevant daemon +#. define and install the new node in vtysh +#. define corresponding node entry commands in daemon and vtysh +#. add a new entry to the ``ctx_keywords`` dictionary in ``tools/frr-reload.py`` Defining the numerical node constant ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 495c604ae091..634f4aa80420 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -18,6 +18,7 @@ import pygments from sphinx.highlighting import lexers from sphinx.util import logging + logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, @@ -53,18 +54,25 @@ master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" + +# Set canonical URL from the Read the Docs Domain +html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") + +# Tell Jinja2 templates the build is running on Read the Docs +if os.environ.get("READTHEDOCS", "") == "True": + html_context["READTHEDOCS"] = True # ----------------------------------------------------------------------------- @@ -95,7 +103,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): @@ -287,7 +295,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR Developer's Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR Developer's Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +323,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR Developer's Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR Developer's Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +338,7 @@ ( master_doc, "frr", - u"FRR Developer's Manual", + "FRR Developer's Manual", author, "FRR", "One line description of project.", @@ -358,27 +366,29 @@ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() -frrfmt_re = re.compile(r'^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$') +frrfmt_re = re.compile(r"^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$") + def parse_frrfmt(env, text, node): from sphinx import addnodes m = frrfmt_re.match(text) if not m: - logger.warning('could not parse frrfmt:: %r' % (text), location=node) + logger.warning("could not parse frrfmt:: %r" % (text), location=node) node += addnodes.desc_name(text, text) return text - spec, types = m.group('spec'), m.group('types') + spec, types = m.group("spec"), m.group("types") - node += addnodes.desc_sig_operator('%', '%') - node += addnodes.desc_name(spec + ' ', spec + ' ') + node += addnodes.desc_sig_operator("%", "%") + node += addnodes.desc_name(spec + " ", spec + " ") plist = addnodes.desc_parameterlist() - for typ in types.split(','): + for typ in types.split(","): typ = typ.strip() plist += addnodes.desc_parameter(typ, typ) node += plist - return '%' + spec + return "%" + spec + # custom extensions here def setup(app): diff --git a/doc/developer/cross-compiling.rst b/doc/developer/cross-compiling.rst index 3bf78f7633fc..c50348744140 100644 --- a/doc/developer/cross-compiling.rst +++ b/doc/developer/cross-compiling.rst @@ -148,7 +148,7 @@ be built and installed generally like: CC=${HOST_ARCH}-gcc \ CXX=${HOST_ARCH}-g++ \ cmake \ - -DCMAKE_INSTALL_PREFIX=/usr/${HOST_ARCH} \ + --install-prefix /usr/${HOST_ARCH} \ .. make make install @@ -239,9 +239,9 @@ the last thing to actually build is FRR itself: --host=${HOST_ARCH} \ --with-sysroot=/usr/${HOST_ARCH} \ --with-clippy=./build-clippy/lib/clippy \ - --sysconfdir=/etc/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir="\${prefix}/lib/frr" \ - --localstatedir=/var/run/frr \ --prefix=/usr \ --enable-user=frr \ --enable-group=frr \ diff --git a/doc/developer/cspf.rst b/doc/developer/cspf.rst index 9ff673a23944..7a5a55ee31b0 100644 --- a/doc/developer/cspf.rst +++ b/doc/developer/cspf.rst @@ -24,59 +24,59 @@ to the cost of the cuurent path from the source up to the current node. The algorithm is as followed: -``` - cost = MAX_COST; - Priority_Queue.empty(); - Visited_Node.empty(); - Processed_Path.empty(); - src = new_path(source_address); - src.cost = 0; - dst = new_destinatio(destination_address); - dst.cost = MAX_COST; - Processed_Path.add(src); - Processed_Path.add(dst); - while (Priority_Queue.count != 0) { - current_path = Priority_Queue.pop(); - current_node = next_path.destination; - Visited_Node.add(current_node); - for (current_node.edges: edge) { - if (prune_edge(current_path, edge) - continue; - if (relax(current_path) && cost > current_path.cost) { - optim_path = current_path; - cost = current_path.cost; - } - } - } - - prune_edge(path, edge) { - // check that path + edge meet constraints e.g. - if (current_path.cost + edge.cost > constrained_cost) - return false; - else - return true; - } - - relax_edge(current_path, edge) { - next_node = edge.destination; - if (Visited_Node.get(next_node)) - return false; - next_path = Processed_Path.get(edge.destination); - if (!next_path) { - next_path = new path(edge.destination); - Processed_Path.add(next_path); - } - total_cost = current_path.cost + edge.cost; - if (total_cost < next_path.cost) { - next_path = current_path; - next_path.add_edge(edge); - next_path.cost = total_cost; - Priority_Queue.add(next_path); - } - return (next_path.destination == destination); - } - -``` +.. code-block:: c + + cost = MAX_COST; + Priority_Queue.empty(); + Visited_Node.empty(); + Processed_Path.empty(); + src = new_path(source_address); + src.cost = 0; + dst = new_destinatio(destination_address); + dst.cost = MAX_COST; + Processed_Path.add(src); + Processed_Path.add(dst); + while (Priority_Queue.count != 0) { + current_path = Priority_Queue.pop(); + current_node = next_path.destination; + Visited_Node.add(current_node); + for (current_node.edges: edge) { + if (prune_edge(current_path, edge) + continue; + if (relax(current_path) && cost > current_path.cost) { + optim_path = current_path; + cost = current_path.cost; + } + } + } + + prune_edge(path, edge) { + // check that path + edge meet constraints e.g. + if (current_path.cost + edge.cost > constrained_cost) + return false; + else + return true; + } + + relax_edge(current_path, edge) { + next_node = edge.destination; + if (Visited_Node.get(next_node)) + return false; + next_path = Processed_Path.get(edge.destination); + if (!next_path) { + next_path = new path(edge.destination); + Processed_Path.add(next_path); + } + total_cost = current_path.cost + edge.cost; + if (total_cost < next_path.cost) { + next_path = current_path; + next_path.add_edge(edge); + next_path.cost = total_cost; + Priority_Queue.add(next_path); + } + return (next_path.destination == destination); + } + Definition ---------- @@ -163,34 +163,34 @@ To perform a Path Computation with given constraints, proceed as follow: .. code-block:: c - struct cspf *algo; - struct ls_ted *ted; - struct in_addr src; - struct in_addr dst; - struct constraints csts; - struct c_path *path; - - // Create a new CSPF structure - algo = cspf_new(); - - // Initialize constraints - csts.cost = 100; - csts.ctype = CSPF_TE_METRIC; - csts.family = AF_INET; - csts.type = SR_TE; - csts.bw = 1000000; - csts.cos = 3; - - // Then, initialise th CSPF with source, destination and constraints - cspf_init_v4(algo, ted, src, dst, &csts); - - // Finally, got the Computed Path; - path = compute_p2p_path(ted, algo); - - if (path.status == SUCCESS) - zlog_info("Got a valid constraints path"); - else - zlog_info("Unable to compute constraints path. Got %d status", path->status); + struct cspf *algo; + struct ls_ted *ted; + struct in_addr src; + struct in_addr dst; + struct constraints csts; + struct c_path *path; + + // Create a new CSPF structure + algo = cspf_new(); + + // Initialize constraints + csts.cost = 100; + csts.ctype = CSPF_TE_METRIC; + csts.family = AF_INET; + csts.type = SR_TE; + csts.bw = 1000000; + csts.cos = 3; + + // Then, initialise th CSPF with source, destination and constraints + cspf_init_v4(algo, ted, src, dst, &csts); + + // Finally, got the Computed Path; + path = compute_p2p_path(ted, algo); + + if (path.status == SUCCESS) + zlog_info("Got a valid constraints path"); + else + zlog_info("Unable to compute constraints path. Got %d status", path->status); If you would compute another path, you must call `cspf_init()` prior to diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst index 9378637dedb4..9dbc9b48d749 100644 --- a/doc/developer/frr-release-procedure.rst +++ b/doc/developer/frr-release-procedure.rst @@ -13,6 +13,13 @@ Stage 1 - Preparation Note: use ``tools/release_notes.py`` to help draft release notes changelog + .. code-block:: console + + ./tools/release_notes.py -b dev/9.1 -t frr-9.0.1 + + dev/9.1 is the branch to be renamed to stable/9.1, and frr-9.0.1 in this + example is the latest tag from which to generate the logs. + #. Checkout the existing ``dev/`` branch. .. code-block:: console diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst index b98d237e68a8..49fd6c854cb6 100644 --- a/doc/developer/include-compile.rst +++ b/doc/developer/include-compile.rst @@ -14,8 +14,8 @@ obtained by running ``./configure -h``. The options shown below are examples. --sbindir=\${prefix}/lib/frr \ --libdir=\${prefix}/lib/frr \ --libexecdir=\${prefix}/lib/frr \ - --localstatedir=/var/run/frr \ - --sysconfdir=/etc/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --with-moduledir=\${prefix}/lib/frr/modules \ --enable-configfile-mask=0640 \ --enable-logfile-mask=0640 \ diff --git a/doc/developer/index.rst b/doc/developer/index.rst index c2123f1ad209..bd794b11a8df 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -5,6 +5,7 @@ FRRouting Developer's Guide :maxdepth: 2 workflow + checkpatch building packaging process-architecture diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index 52653d37686c..82cc8b205eab 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -77,7 +77,14 @@ are available: .. note:: - ``printfrr()`` does not support the ``%n`` format. + ``printfrr()`` does not support the ``%n`` format. It does support ISO C23 + ``%b``, ``%w99d`` and ``%wf99d`` additions, but the latter two are not + supported by the ``frr-format`` plugin yet, and all 3 aren't supported by + the older compilers still in use on some supported platforms. + + ``%b`` can be used with ``FMT_NSTD``, but ``%w99d`` and ``%wf99d`` require + work in the ``frr-format`` plugin before they are really usable. + AS-Safety ^^^^^^^^^ @@ -376,7 +383,8 @@ bgpd .. frrfmt:: %pBD (struct bgp_dest *) - Print prefix for a BGP destination. + Print prefix for a BGP destination. When using ``--enable-dev-build`` include + the pointer value for the bgp_dest. :frrfmtout:`fe80::1234/64` @@ -557,8 +565,9 @@ Integer formats cause compiler warnings when used without the plugin. Use with :c:macro:`FMT_NSTD` if necessary. - It is possible ISO C23 may introduce another format for these, possibly - ``%w64d`` discussed in `JTC 1/SC 22/WG 14/N2680 `_. + As anticipated, ISO C23 has introduced new modifiers for this, specifically + ``%w64d`` (= ``%Ld``) and ``%w64u`` (= ``%Lu``). Unfortunately, these new + modifiers are not supported by ``frr-format`` yet. .. frrfmt:: %Lu (uint64_t) diff --git a/doc/developer/mgmtd-dev.rst b/doc/developer/mgmtd-dev.rst index 9839aa8b6c82..b979af06fa0d 100644 --- a/doc/developer/mgmtd-dev.rst +++ b/doc/developer/mgmtd-dev.rst @@ -12,7 +12,7 @@ MGMTD Development ================= Overview -^^^^^^^^ +-------- ``mgmtd`` (Management Daemon) is a new centralized management daemon for FRR. @@ -33,18 +33,64 @@ each daemon. ``mgmtd`` currently provides the CLI interface for each daemon that has been converted to it, but in the future RESTCONF and NETCONF servers can easily be added as *front-ends* to mgmtd to support those protocols as well. +Conversion Status +^^^^^^^^^^^^^^^^^ + +Fully Converted To MGMTD +"""""""""""""""""""""""" + +- lib/distribute +- lib/filter +- lib/if_rmap +- lib/routemap +- lib/affinitymap +- lib/if +- lib/vrf +- ripd +- ripngd +- staticd +- zebra (* - partial) + +Converted To Northbound +""""""""""""""""""""""" +- bfdd +- pathd +- pbrd +- pimd + +Converted To Northbound With Issues +""""""""""""""""""""""""""""""""""" +- eigrp +- isisd + +Unconverted +""""""""""" +- babel +- bgpd +- ldpd +- lib/event +- lib/keychain +- lib/log_vty +- lib/nexthop_group +- lib/zlog_5424_cli +- nhrpd +- ospfd +- ospf6d +- pceplib +- qdb +- sharpd +- vrrpd Converting A Daemon to MGMTD -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +---------------------------- -A daemon must first be transitioned to the new *northbound* interface if that -has not already been done (see `this northbound conversion documentation -`_ -for how to do this). Once this is done a few simple steps are all that is -required move the daemon over to ``mgmtd`` control. +A daemon must first be transitioned to the new :ref:`northbound` interface if that +has not already been done (see :ref:`nb-retrofit` for how to do this). Once this +is done a few simple steps are all that is required move the daemon over to +``mgmtd`` control. Overview of Changes -------------------- +^^^^^^^^^^^^^^^^^^^ Adding support for a *northbound* converted daemon involves very little work. It requires enabling *frontend* (CLI and YANG) and *backend* (YANG) support. @@ -52,64 +98,126 @@ requires enabling *frontend* (CLI and YANG) and *backend* (YANG) support. Front-End Interface: -1. Add YANG module file to ``mgmtd/subdir.am`` (e.g., ``yang/frr-staticd.c``) -2. Add YANG module description into array defined in ``mgmtd/mgmt_main.c`` -3. Add CLI handler file[s] to ``mgmtd/subdir.am`` (e.g., ``staticd/static_vty.c``) -4. [if needed] Exclude (#ifndef) non-configuration CLI handlers from CLI source - file (e.g., inside ``staticd/static_vty.c``) +#. Add YANG module file to ``mgmtd/subdir.am`` (e.g., ``yang/frr-staticd.yang.c``). + +#. Add CLI handler file[s] to ``mgmtd/subdir.am``. The `subdir.am` variable to + use is indicated in the next 2 steps. + + #. [if needed] Exclude (:code:`#ifndef`) non-configuration CLI handlers from + CLI source file (e.g., inside :file:`staticd/static_vty.c`) and add the + file to :code:`nodist_mgmtd_libmgmt_be_nb_la_SOURCES` in + :file:`mgmtd/subdir.am`. + + #. [otherwise] Remove CLI handler file from _SOURCES variable in the daemon + :file:`subdir.am` file (e.g in :file:`staticd/subdir.am`) and add to + :code:`mgmtd_libmgmtd_a_SOURCES` in :file:`mgmtd/subdir.am`. + +#. In order to have mgmtd try and load existing per-daemon config files, add + the daemon to the :code:`mgmt_daemons` array in :file:`lib/vty.c`. With the + official release of the mgmtd code FRR is no longer supporting per daemon log + files but it will take a while before all of the topotest is converted. + +#. In the daemon's :code:`struct frr_daemon_info` (i.e., inside it's + :code:`FRR_DAEMON_INFO()`) set the `.flags` bit `FRR_NO_SPLIT_CONFIG`. This + will keep the daemon from trying to read it's per-daemon config file as mgmtd + will now be doing this. + +#. Add the daemon's YANG module description[s] into the array + :code:`mgmt_yang_modules` defined in :file:`mgmtd/mgmt_main.c` (see + :ref:`mgmtd-config-write`). Make sure that all YANG modules that the daemon + uses are present in the mgmtd list. To find this list look in the daemon's + equivalent yang module array variable. + +#. Initialize the CLI handlers inside :code:`mgmt_vty_init` in :file:`mgmtd/mgmt_vty.c`. + +#. Direct ``vtysh`` to send CLI commands to ``mgmtd`` by modifying + ``vtysh/vtysh.h``. At the top of this file each daemon has a bit + ``#define``'d (e.g., ``#define VTYSH_STATICD 0x08000``) below this there are + groupings, replace all the uses of the daemons bit with ``VTYSH_MGMTD`` + instead so that the CLI commands get properly routed to ``mgmtd`` rather than + the daemon now. + + #. Remove initialization (and installation) of library CLI routines. These will + correspond with the VTYSH removals from the last step i.e.,: + + - change access_list_init() to access_list_init_new(false) and remove from + VTYSH_ACL_CONFIG (leave in VTYSH_ACL_SHOW). + - remove if_cmd_init_default() => remove from VTYSH_INTERFACE_SUBSET + - remove if_cmd_init() => remove from VTYSH_INTERFACE_SUBSET + - change route_map_init() to route_map_init_new(false) and remove from + VTYSH_ROUTE_MAP_CONFIG (leave in VTYSH_ROUTE_MAP_SHOW). + - remove vrf_cmd_init(NULL) => remove from VTYSH_INTERFACE_SUBSET + ... Back-End Interface: -5. Add XPATHs mappings to a couple arrays to direct ``mgmtd`` at your daemon in - ``mgmtd/mgmt_be_adapter.c`` - +#. In the daemon's main file initialize the BE client library. You add a global + `struct mgmt_be_client *mgmt_be_client` near the daemons `event_loop *master` + variable. Then where the daemon used to initialize it's CLI/VTY code replace + that with the client initialization by calling `mgmt_be_client_create`. + Likewise in the daemon's sigint cleanup code, operational walks should be + canceled with a call to `nb_oper_cancel_all_walks`, and then the BE client + should be destroyed with a call to `mgmt_be_client_destroy` and to be safe + NULL out the global `mgmt_be_client` variable. + +#. In ``mgmtd/mgmt_be_adapter.c`` add xpath prefix mappings to a one or both + mapping arrays (``be_client_config_xpaths`` and ``be_client_oper_xpaths``) to + direct ``mgmtd`` to send config and oper-state requests to your daemon. NOTE: + make sure to include library supported xpaths prefixes as well (e.g., + "/frr-interface:lib"). A good way to figure these paths out are to look in + each of the YANG modules that the daemon uses and include each of their paths + in the array. Add YANG and CLI into MGMTD ---------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As an example here is the addition made to ``mgmtd/subdir.am`` for adding ``staticd`` support. .. code-block:: make - if STATICD - nodist_mgmtd_mgmtd_SOURCES += \ + if STATICD + nodist_mgmtd_mgmtd_SOURCES += \ yang/frr-staticd.yang.c \ yang/frr-bfdd.yang.c \ # end - nodist_mgmtd_libmgmt_be_nb_la_SOURCES += staticd/static_vty.c - endif + nodist_mgmtd_libmgmt_be_nb_la_SOURCES += staticd/static_vty.c + endif An here is the addition to the modules array in ``mgmtd/mgmt_main.c``: .. code-block:: c - static const struct frr_yang_module_info *const mgmt_yang_modules[] = { + #ifdef HAVE_STATICD + extern const struct frr_yang_module_info frr_staticd_info; + #endif + + static const struct frr_yang_module_info *const mgmt_yang_modules[] = { &frr_filter_info, ... - #ifdef HAVE_STATICD - &(struct frr_yang_module_info){.name = "frr-staticd", - .ignore_cbs = true}, - #endif - } + #ifdef HAVE_STATICD + &frr_staticd_info, + #endif + } -CLI Handlers ------------- +CLI Config and Show Handlers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The daemon's CLI handlers for configuration (which having been converted to -*northbound* now simply generate YANG changes) will be linked directly into +The daemon's CLI handlers for configuration (which having been converted to the +:ref:`northbound` now simply generate YANG changes) will be linked directly into ``mgmtd``. If the operational and debug CLI commands are kept in files separate from the daemon's configuration CLI commands then no extra work is required. Otherwise some CPP #ifndef's will be required. -Currently ``mgmtd`` supports configuration CLI but not operational -state so if both types of CLI handlers are present in a single file (e.g. a -``xxx_vty.c`` or ``xxx_cli.c`` file ) then #ifndef will be used to exclude these -non-configuration CLI handlers from ``mgmtd``. The same goes for *debug* CLI -handlers. For example: +``mgmtd`` supports both config and operational state. However, many +daemons have not had their operational state CLI commands converted over to the +new YANG based methods. If that is the case and if both types of CLI handlers +are present in a single file (e.g. a ``xxx_vty.c`` or ``xxx_cli.c`` file) then +:code:`#ifndef` will need to be used to exclude the non-config CLI handlers from +``mgmtd``. The same goes for unconverted *debug* CLI handlers. For example: .. code-block:: c @@ -121,7 +229,7 @@ handlers. For example: } #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY - DEFPY(daemon_show_oepr, daemon_show_oepr_cmd, + DEFPY(daemon_show_oper, daemon_show_oper_cmd, "show daemon oper [all]" ... { @@ -140,83 +248,179 @@ handlers. For example: } +.. _mgmtd-config-write: + +CLI Config Write Handlers (:code:`cli_show`) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To support writing out the CLI configuration file the northbound API defines a +2 callbacks (:code:`cli_show` and :code:`cli_show_end`). Pointers to these +callbacks used to live side-by-side in a daemons :code:`struct frr_yang_module_info`, +with the daemons back-end configuration and operational state callbacks +(normally in a file named `_nb.c`). + +However, these 2 functionalities need to be split up now. The *frontend* config +writing callbacks (:code:`cli_show`) should now be linked into ``mgmtd`` while +the *backend* config and oper-state callbacks (e.g., :code:`create`, +:code:`modify`, etc) should continue to be linked into the daemon. + +So you will need to define 2 :code:`struct frr_yang_module_info` arrays. + +#. The existing array remains in the same place in the daemon, but with all the + :code:`cli_show` handlers removed. + +#. The removed :code:`cli_show` handlers should be added to a new + :code:`struct frr_yang_module_info` array. This second array should be + included in the same file that includes that actual function pointed to by + the the :code:`cli_show` callbacks (i.e., the file is compiled into + ``mgmtd``). + + This new :code:`struct frr_yang_module_info` array is the one to be included + in mgmtd in `mgmt_yang_modules` inside ``mgmtd/mgmt_main.c``. + +Back-End Client Connection +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In order for your daemon to communicate with mgmtd you need to initialize the +backend client library. You normally do this where you used to initialize your +CLI/VTY code. + +.. code-block:: c + + ... + struct event_loop *master; + + static struct mgmt_be_client *mgmt_be_client; + ... + + int main(int argc, char **argv) + { + ... + rip_init(); + rip_if_init(); + mgmt_be_client = mgmt_be_client_create("ripd", NULL, 0, master); + +Likewise the client should be cleaned up in the daemon cleanup routine. + +.. code-block:: c + + /* SIGINT handler. */ + static void sigint(void) + { + zlog_notice("Terminating on signal"); + ... + nb_oper_cancel_all_walks(); + mgmt_be_client_destroy(mgmt_be_client); + mgmt_be_client = NULL; + -Add Back-End XPATH mappings ---------------------------- +Back-End XPATH mappings +^^^^^^^^^^^^^^^^^^^^^^^ -In order for ``mgmtd`` to direct configuration to your daemon you need to add +In order for ``mgmtd`` to direct YANG modeled data to your daemon you should add some XPATH mappings to ``mgmtd/mgmt_be_adapter.c``. These XPATHs determine which -configuration changes get sent over the *back-end* interface to your daemon. +YANG modeled data (e.g., config changes) get sent over the *back-end* interface +to your daemon. There are 4 arrays to possibly update: configuration, +operational, notification, and RPC. You only need to add entries to the array +that you require mapping for. + +Additionally the back-end client can specify these XPATH mappings when it +first connects to mgmtd using it's initial ``SUBSCRIBE`` message. + +NOTE: the notif array (``be_client_notif_xpaths``), is a slightly different from +the other 3 types (config, oper and rpc) in that it maps xpaths the back-end +client wishes to *receive* notifications for, not the ones it may generate. +Normally a back-end client is generating notifications; however, mgmtd supports +back-end clients also "subscribing" to receive these notifications as well from +other back-end clients through notif_xpath maps. + +Config Map Example +"""""""""""""""""" +Below are the strings added for staticd config support: + +.. code-block:: c + + #if HAVE_STATICD + static const char *const staticd_xpaths[] = { + "/frr-vrf:lib", + "/frr-interface:lib", + "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd", + NULL, + }; + #endif + + static const char *const *be_client_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { + #ifdef HAVE_STATICD + [MGMTD_BE_CLIENT_ID_STATICD] = staticd_xpaths, + #endif + }; -Below are the strings added for staticd support: + +Operational Map Example +""""""""""""""""""""""" +Below are the strings added for zebra operational state support (note zebra is +not conditionalized b/c it should always be present): .. code-block:: c - static const struct mgmt_be_xpath_map_init mgmt_xpath_map_init[] = { - { - .xpath_regexp = "/frr-vrf:lib/*", - .subscr_info = - { - #if HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = - MGMT_SUBSCR_VALIDATE_CFG | - MGMT_SUBSCR_NOTIFY_CFG, - #endif - }, - }, - ... - { - .xpath_regexp = - "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/*", - .subscr_info = - { - #if HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = - MGMT_SUBSCR_VALIDATE_CFG | - MGMT_SUBSCR_NOTIFY_CFG, - #endif - }, - }, - }; - - #if HAVE_STATICD - static struct mgmt_be_client_xpath staticd_xpaths[] = { - { - .xpath = "/frr-vrf:lib/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, - ... - { - .xpath = - "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, - }; - #endif - - static struct mgmt_be_client_xpath_map - mgmt_client_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { - #ifdef HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = {staticd_xpaths, - array_size(staticd_xpaths)}, - #endif - }; + static const char *const zebra_oper_xpaths[] = { + "/frr-interface:lib/interface", + "/frr-vrf:lib/vrf/frr-zebra:zebra", + "/frr-zebra:zebra", + NULL, + }; + + static const char *const *be_client_oper_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { + [MGMTD_BE_CLIENT_ID_ZEBRA] = zebra_oper_xpaths, + }; + + +RPC Map Example +""""""""""""""" +Below is the string added for ripd RPC support: + +.. code-block:: c + + static const char *const ripd_rpc_xpaths[] = { + "/frr-ripd", + NULL, + }; + + static const char *const *be_client_rpc_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { + #ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = ripd_rpc_xpaths, + #endif + }; + + +Notification Map Example +"""""""""""""""""""""""" +There are no current back-end daemons that wish to receive other back-end +notifications so the array is empty. This may change in the future, and of +course any back-end daemon can utilize the connect (``BeSubscribeReq``) messages +as well. MGMTD Internals -^^^^^^^^^^^^^^^ +--------------- This section will describe the internal functioning of ``mgmtd``, for now a couple diagrams are included to aide in source code perusal. -The client side of a CLI change +The client side of a CLI configuration change .. figure:: ../figures/cli-change-client.svg :align: center -The server (mgmtd) side of a CLI change +The server (mgmtd) side of a CLI configuration change .. figure:: ../figures/cli-change-mgmtd.svg :align: center + + +The client and server sides of oper-state query + +.. figure:: ../figures/cli-oper-state.svg + :align: center diff --git a/doc/developer/northbound/_sidebar.rst b/doc/developer/northbound/_sidebar.rst deleted file mode 100644 index f2bca0bc05d3..000000000000 --- a/doc/developer/northbound/_sidebar.rst +++ /dev/null @@ -1,15 +0,0 @@ -Northbound: -~~~~~~~~~~~ - -- [[Architecture]] -- [[Transactional CLI]] -- [[Retrofitting Configuration Commands]] -- [[Operational data, RPCs and Notifications]] -- [[Plugins - ConfD]] -- [[Plugins: Sysrepo]] -- [[Plugins - Writing Your Own]] -- [[YANG module translator]] -- [[Advanced topics]] -- [[YANG tools]] -- [[Demos]] -- [[Links]] diff --git a/doc/developer/northbound/advanced-topics.rst b/doc/developer/northbound/advanced-topics.rst index bee29a95a929..eb756026e08a 100644 --- a/doc/developer/northbound/advanced-topics.rst +++ b/doc/developer/northbound/advanced-topics.rst @@ -1,11 +1,18 @@ +Advanced Topics +=============== + +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 1 + Auto-generated CLI commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to have less code to maintain, it should be possible to write a tool that auto-generates CLI commands based on the FRR YANG models. As a matter of fact, there are already a number of NETCONF-based CLIs that do -exactly that (e.g. `Clixon `__, -ConfD’s CLI). +exactly that (e.g. `Clixon `__). The problem however is that there isn’t an exact one-to-one mapping between the existing CLI commands and the corresponding YANG nodes from @@ -19,11 +26,6 @@ command for each YANG leaf, (leaf-)list and presence-container. The ripd’s ``timers basic`` command, for instance, would become three different commands, which would be undesirable. - This Tail-f’s® - `document `__ - shows how to customize ConfD auto-generated CLI commands using YANG - annotations. - The good news is that *libyang* allows users to create plugins to implement their own YANG extensions, which can be used to implement CLI annotations. If done properly, a CLI generator can save FRR developers @@ -34,13 +36,16 @@ CLI on a separate program The flexible design of the northbound architecture opens the door to move the CLI to a separate program in the long-term future. Some -advantages of doing so would be: \* Treat the CLI as just another -northbound client, instead of having CLI commands embedded in the -binaries of all FRR daemons. \* Improved robustness: bugs in CLI -commands (e.g. null-pointer dereferences) or in the CLI code itself -wouldn’t affect the FRR daemons. \* Foster innovation by allowing other -CLI programs to be implemented, possibly using higher level programming -languages. +advantages of doing so would be: + +* Treat the CLI as just another northbound client, instead of having CLI + commands embedded in the binaries of all FRR daemons. + +* Improved robustness: bugs in CLI commands (e.g. null-pointer dereferences) or + in the CLI code itself wouldn’t affect the FRR daemons. + +* Foster innovation by allowing other CLI programs to be implemented, possibly + using higher level programming languages. The problem, however, is that the northbound retrofitting process will convert only the CLI configuration commands and EXEC commands in a first @@ -65,8 +70,8 @@ Example of how this feature could be provided in the CLI: ``commit confirmed [minutes <1-60>]``. The ability to do confirmed commits should also be exposed in the northbound API so that the northbound plugins can also take advantage of it (in the case of the -Sysrepo and ConfD plugins, confirmed commits are implemented externally -in the *netopeer2-server* and *confd* daemons, respectively). +Sysrepo plugin, confirmed commit is implemented externally in the +*netopeer2-server* daemon). Proposed feature: enable/disable configuration commands/sections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -232,40 +237,42 @@ vtysh support As explained in the [[Transactional CLI]] page, all commands introduced by the transactional CLI are not yet available in *vtysh*. This needs to be addressed in the short term future. Some challenges for doing that -work include: \* How to display configurations (running, candidates and -rollbacks) in a more clever way? The implementation of the -``show running-config`` command in *vtysh* is not something that should -be followed as an example. A better idea would be to fetch the desired -configuration from all daemons (encoded in JSON for example), merge them -all into a single ``lyd_node`` variable and then display the combined -configurations from this variable (the configuration merges would -transparently take care of combining the shared configuration objects). -In order to be able to manipulate the JSON configurations, *vtysh* will -need to load the YANG modules from all daemons at startup (this might -have a minimal impact on startup time). The only issue with this -approach is that the ``cli_show()`` callbacks from all daemons are -embedded in their binaries and thus not accessible externally. It might -be necessary to compile these callbacks on a separate shared library so -that they are accessible to *vtysh* too. Other than that, displaying the -combined configurations in the JSON/XML formats should be -straightforward. \* With the current design, transaction IDs are -per-daemon and not global across all FRR daemons. This means that the -same transaction ID can represent different transactions on different -daemons. Given this observation, how to implement the -``rollback configuration`` command in *vtysh*? The easy solution would -be to add a ``daemon WORD`` argument to specify the context of the -rollback, but per-daemon rollbacks would certainly be confusing and -convoluted to end users. A better idea would be to attack the root of -the problem: change configuration transactions to be global instead of -being per-daemon. This involves a bigger change in the northbound -architecture, and would have implications on how transactions are stored -in the SQL database (daemon-specific and shared configuration objects -would need to have their own tables or columns). \* Loading -configuration files in the JSON or XML formats will be tricky, as -*vtysh* will need to know which sections of the configuration should be -sent to which daemons. *vtysh* will either need to fetch the YANG -modules implemented by all daemons at runtime or obtain this information -at compile-time somehow. +work include: + +* How to display configurations (running, candidates and rollbacks) in a more + clever way? The implementation of the ``show running-config`` command in + *vtysh* is not something that should be followed as an example. A better idea + would be to fetch the desired configuration from all daemons (encoded in JSON + for example), merge them all into a single ``lyd_node`` variable and then + display the combined configurations from this variable (the configuration + merges would transparently take care of combining the shared configuration + objects). In order to be able to manipulate the JSON configurations, *vtysh* + will need to load the YANG modules from all daemons at startup (this might + have a minimal impact on startup time). The only issue with this approach is + that the ``cli_show()`` callbacks from all daemons are embedded in their + binaries and thus not accessible externally. It might be necessary to compile + these callbacks on a separate shared library so that they are accessible to + *vtysh* too. Other than that, displaying the combined configurations in the + JSON/XML formats should be straightforward. + +* With the current design, transaction IDs are per-daemon and not global across + all FRR daemons. This means that the same transaction ID can represent + different transactions on different daemons. Given this observation, how to + implement the ``rollback configuration`` command in *vtysh*? The easy solution + would be to add a ``daemon WORD`` argument to specify the context of the + rollback, but per-daemon rollbacks would certainly be confusing and convoluted + to end users. A better idea would be to attack the root of the problem: change + configuration transactions to be global instead of being per-daemon. This + involves a bigger change in the northbound architecture, and would have + implications on how transactions are stored in the SQL database + (daemon-specific and shared configuration objects would need to have their own + tables or columns). + +* Loading configuration files in the JSON or XML formats will be tricky, as + *vtysh* will need to know which sections of the configuration should be sent + to which daemons. *vtysh* will either need to fetch the YANG modules + implemented by all daemons at runtime or obtain this information at + compile-time somehow. Detecting type mismatches at compile-time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/developer/northbound/architecture.rst b/doc/developer/northbound/architecture.rst index f551ce9e2fe5..4e84f1d6a49d 100644 --- a/doc/developer/northbound/architecture.rst +++ b/doc/developer/northbound/architecture.rst @@ -1,3 +1,6 @@ +Architecture +============ + Introduction ------------ @@ -24,13 +27,14 @@ configuration changes regardless of where they came from. This model-driven design ensures feature parity across all management interfaces supported by FRR. -Quoting RFC 7950: > YANG is a language originally designed to model data -for the NETCONF protocol. A YANG module defines hierarchies of data that -can be used for NETCONF-based operations, including configuration, state -data, RPCs, and notifications. This allows a complete description of all -data sent between a NETCONF client and server. Although out of scope for -this specification, YANG can also be used with protocols other than -NETCONF. +Quoting :rfc:`7950`: + + YANG is a language originally designed to model data for the NETCONF + protocol. A YANG module defines hierarchies of data that can be used for + NETCONF-based operations, including configuration, state data, RPCs, and + notifications. This allows a complete description of all data sent between a + NETCONF client and server. Although out of scope for this specification, + YANG can also be used with protocols other than NETCONF. While the YANG and NETCONF specifications are tightly coupled with one another, both are independent to a certain extent and are evolving @@ -41,30 +45,34 @@ and `CoAP `__. In addition to being management-protocol independent, some other -advantages of using YANG in FRR are listed below: \* Have a formal -contract between FRR and application developers (management clients). A -management client that has access to the FRR YANG models knows about all -existing configuration options available for use. This information can -be used to auto-generate user-friendly interfaces like Web-UIs, custom -CLIs and even code bindings for several different programming languages. -Using `PyangBind `__, for -example, it’s possible to generate Python class hierarchies from YANG -models and use these classes to instantiate objects that mirror the -structure of the YANG modules and can be serialized/deserialized using -different encoding formats. \* Support different encoding formats for -instance data. Currently only JSON and XML are supported, but -`GPB `__ and -`CBOR `__ are other viable options in the long term. -Additional encoding formats can be implemented in the *libyang* library -for optimal performance, or externally by translating data to/from one -of the supported formats (with a performance penalty). \* Have a formal -mechanism to introduce backward-incompatible changes based on `semantic -versioning `__ (not part of the -YANG standard, which allows backward-compatible module updates only). \* -Provide seamless support to the industry-standard NETCONF/RESTCONF -protocols as alternative management APIs. If FRR configuration/state -data is modeled using YANG, supporting YANG-based protocols like NETCONF -and RESTCONF is much easier. +advantages of using YANG in FRR are listed below: + +* Have a formal contract between FRR and application developers (management + clients). A management client that has access to the FRR YANG models knows + about all existing configuration options available for use. This information + can be used to auto-generate user-friendly interfaces like Web-UIs, custom + CLIs and even code bindings for several different programming languages. Using + `PyangBind `__, for example, it’s + possible to generate Python class hierarchies from YANG models and use these + classes to instantiate objects that mirror the structure of the YANG modules + and can be serialized/deserialized using different encoding formats. + +* Support different encoding formats for instance data. Currently only JSON and + XML are supported, but `GPB + `__ and `CBOR + `__ are other viable options in the long term. Additional + encoding formats can be implemented in the *libyang* library for optimal + performance, or externally by translating data to/from one of the supported + formats (with a performance penalty). + +* Have a formal mechanism to introduce backward-incompatible changes based on + `semantic versioning `__ (not part of + the YANG standard, which allows backward-compatible module updates only). + +* Provide seamless support to the industry-standard NETCONF/RESTCONF protocols + as alternative management APIs. If FRR configuration/state data is modeled + using YANG, supporting YANG-based protocols like NETCONF and RESTCONF is much + easier. As important as shifting to a model-driven management paradigm, the new northbound architecture also introduces the concept of configuration @@ -98,29 +106,27 @@ scripts that send CLI commands and parse the text output (which usually doesn’t have any structure) using screen scraping and regular expressions. -+-----------------------------------------+ -| |space-1.jpg| | -+=========================================+ -| *Figure 1: old northbound architecture* | -+-----------------------------------------+ +.. figure:: images/arch-before.png + :alt: diagram of northbound architecture prior to nbapi conversion + + Old northbound architecture The new northbound architectures, on the other hand, features a multitude of different management APIs, all of them connected to the northbound layer of the FRR daemons. By default, only the CLI interface is compiled built-in in the FRR daemons. The other management interfaces are provided as optional plugins and need to be loaded during the daemon -initialization (e.g. *zebra -M confd*). This design makes it possible to +initialization (e.g. *zebra -M grpc*). This design makes it possible to integrate FRR with different NETCONF solutions without introducing vendor lock-in. The [[Plugins - Writing Your Own]] page explains how to write custom northbound plugins that can be tailored to all needs (e.g. support custom transport protocols, different data encoding formats, fine-grained access control, etc). -+-----------------------------------------+ -| |space-1.jpg| | -+=========================================+ -| *Figure 2: new northbound architecture* | -+-----------------------------------------+ +.. figure:: images/arch-after.png + :alt: diagram of northbound architecture after nbapi conversion + + New northbound architecture Figure 3 shows the internal view of the FRR northbound architecture. In this image we can see that northbound layer is an abstract entity @@ -133,11 +139,10 @@ plugins that can be maintained separately. The northbound plugins, in turn, have their own APIs to communicate with external management clients. -+---------------------------------------------------------+ -| |space-1.jpg| | -+=========================================================+ -| *Figure 3: new northbound architecture - internal view* | -+---------------------------------------------------------+ +.. figure:: images/nb-layer.png + :alt: diagram of northbound architecture internals + + New northbound architecture - internal view Initially the CLI (and all of its commands) will be maintained inside the FRR daemons. In the long term, however, the goal is to move the CLI @@ -210,29 +215,29 @@ definitive solution to support standard models or not. Northbound Architecture ----------------------- -+-----------------------------------------------+ -| |space-1.jpg| | -+===============================================+ -| *Figure 4: libyang’s lys_node data structure* | -+-----------------------------------------------+ - -+-----------------------------------------------+ -| |space-1.jpg| | -+===============================================+ -| *Figure 5: libyang’s lyd_node data structure* | -+-----------------------------------------------+ - -+---------------------------------------------+ -| |space-1.jpg| | -+=============================================+ -| *Figure 6: libyang’s ly_ctx data structure* | -+---------------------------------------------+ - -+----------------------------------------+ -| |space-1.jpg| | -+========================================+ -| *Figure 7: configuration transactions* | -+----------------------------------------+ +.. figure:: images/lys-node.png + :alt: diagram of libyanbg's lys_node data structure + + ``libyang's`` lys_node data structure + + +.. figure:: images/lyd-node.png + :alt: diagram of libyanbg's lyd_node data structure + + ``libyang's`` lyd_node data structure + + +.. figure:: images/ly-ctx.png + :alt: diagram of libyanbg's ly_ctx data structure + + ``libyang's`` ly_ctx data structure + + +.. figure:: images/transactions.png + :alt: diagram showing how configuration transactions work + + Configuration transactions + Testing ------- @@ -241,21 +246,23 @@ The new northbound adds the libyang library as a new mandatory dependency for FRR. To obtain and install this library, follow the steps below: -:: +.. code-block:: console + + git clone https://github.com/CESNET/libyang + cd libyang + git checkout devel + mkdir build ; cd build + cmake -DENABLE_LYD_PRIV=ON .. + make + sudo make install - $ git clone https://github.com/CESNET/libyang - $ cd libyang - $ git checkout devel - $ mkdir build ; cd build - $ cmake -DENABLE_LYD_PRIV=ON .. - $ make - $ sudo make install -.. +.. note:: - NOTE: first make sure to install the libyang + first make sure to install the libyang `requirements `__. + FRR needs libyang from version 0.16.7 or newer, which is maintained in the ``devel`` branch. libyang 0.15.x is maintained in the ``master`` branch and doesn’t contain one small feature used by FRR (the @@ -273,11 +280,3 @@ commands. The ``debug northbound`` command can be used to see which northbound callbacks are called in response to the ``commit`` command. For reference, the [[Demos]] page shows a small demonstration of the transactional CLI in action and what it’s capable of. - -.. |space-1.jpg| image:: https://s22.postimg.cc/se52j8awh/arch-before.png -.. |space-1.jpg| image:: https://s22.postimg.cc/fziaiwboh/arch-after.png -.. |space-1.jpg| image:: https://s22.postimg.cc/qmc3ocmep/nb-layer.png -.. |space-1.jpg| image:: https://s22.postimg.cc/z4ljsodht/lys_node.png -.. |space-1.jpg| image:: https://s22.postimg.cc/6eynw1h7l/lyd_node.png -.. |space-1.jpg| image:: https://s22.postimg.cc/5cohdhiyp/ly_ctx.png -.. |space-1.jpg| image:: https://s22.postimg.cc/8waf3bgjl/transactions.png diff --git a/doc/developer/northbound/demos.rst b/doc/developer/northbound/demos.rst index 21ab43a49b60..7c5ae0c229ad 100644 --- a/doc/developer/northbound/demos.rst +++ b/doc/developer/northbound/demos.rst @@ -1,25 +1,10 @@ +Demos +===== + Transactional CLI ----------------- This short demo shows some of the capabilities of the new transactional -CLI: |asciicast| - -ConfD + NETCONF + Cisco YDK ---------------------------- - -This is a very simple demo of *ripd* being configured by a python -script. The script uses NETCONF to communicate with *ripd*, which has -the ConfD plugin loaded. The most interesting part, however, is the fact -that the python script is not using handcrafted XML payloads to -configure *ripd*. Instead, the script is using python bindings generated -using Cisco’s YANG Development Kit (YDK). - -- Script used in the demo: - https://gist.github.com/rwestphal/defa9bd1ccf216ab082d4711ae402f95 - -|asciicast| +CLI: -.. |asciicast| image:: https://asciinema.org/a/jL0BS5HfP2kS6N1HfgsZvfZk1.png - :target: https://asciinema.org/a/jL0BS5HfP2kS6N1HfgsZvfZk1 -.. |asciicast| image:: https://asciinema.org/a/VfMElNxsjLcdvV7484E6ChxWv.png - :target: https://asciinema.org/a/VfMElNxsjLcdvV7484E6ChxWv +|asciicast1| diff --git a/doc/developer/northbound/images/arch-after.png b/doc/developer/northbound/images/arch-after.png new file mode 100644 index 000000000000..01e6ae63646c Binary files /dev/null and b/doc/developer/northbound/images/arch-after.png differ diff --git a/doc/developer/northbound/images/arch-before.png b/doc/developer/northbound/images/arch-before.png new file mode 100644 index 000000000000..ab2bb0deb215 Binary files /dev/null and b/doc/developer/northbound/images/arch-before.png differ diff --git a/doc/developer/northbound/images/ly-ctx.png b/doc/developer/northbound/images/ly-ctx.png new file mode 100644 index 000000000000..4d4e138c73a1 Binary files /dev/null and b/doc/developer/northbound/images/ly-ctx.png differ diff --git a/doc/developer/northbound/images/lyd-node.png b/doc/developer/northbound/images/lyd-node.png new file mode 100644 index 000000000000..4ba2b48b71b9 Binary files /dev/null and b/doc/developer/northbound/images/lyd-node.png differ diff --git a/doc/developer/northbound/images/lys-node.png b/doc/developer/northbound/images/lys-node.png new file mode 100644 index 000000000000..e9e46e7f6483 Binary files /dev/null and b/doc/developer/northbound/images/lys-node.png differ diff --git a/doc/developer/northbound/images/nb-layer.png b/doc/developer/northbound/images/nb-layer.png new file mode 100644 index 000000000000..4aa1fd6bffe0 Binary files /dev/null and b/doc/developer/northbound/images/nb-layer.png differ diff --git a/doc/developer/northbound/images/transactions.png b/doc/developer/northbound/images/transactions.png new file mode 100644 index 000000000000..d18faf44782c Binary files /dev/null and b/doc/developer/northbound/images/transactions.png differ diff --git a/doc/developer/northbound/links.rst b/doc/developer/northbound/links.rst index e80374c57b15..e8fb3272381a 100644 --- a/doc/developer/northbound/links.rst +++ b/doc/developer/northbound/links.rst @@ -1,3 +1,6 @@ +Links +===== + RFCs ~~~~ @@ -192,14 +195,6 @@ pyangbind - GitHub page: https://github.com/robshakir/pyangbind - Documentation: http://pynms.io/pyangbind/ -ConfD -^^^^^ - -- Official webpage (for ConfD Basic): - http://www.tail-f.com/confd-basic/ -- Training Videos: http://www.tail-f.com/confd-training-videos/ -- Forum: http://discuss.tail-f.com/ - Sysrepo ^^^^^^^ diff --git a/doc/developer/northbound/northbound.rst b/doc/developer/northbound/northbound.rst index c5e30f16ca75..c5f4e2f7e671 100644 --- a/doc/developer/northbound/northbound.rst +++ b/doc/developer/northbound/northbound.rst @@ -7,15 +7,15 @@ Northbound API .. toctree:: :maxdepth: 2 - advanced-topics architecture + transactional-cli + retrofitting-configuration-commands + operational-data-rpcs-and-notifications + advanced-topics + yang-tools + yang-module-translator demos links - operational-data-rpcs-and-notifications plugins-sysrepo ppr-basic-test-topology ppr-mpls-basic-test-topology - retrofitting-configuration-commands - transactional-cli - yang-module-translator - yang-tools diff --git a/doc/developer/northbound/operational-data-rpcs-and-notifications.rst b/doc/developer/northbound/operational-data-rpcs-and-notifications.rst index 554bc17c80e0..07f92c2ca0d8 100644 --- a/doc/developer/northbound/operational-data-rpcs-and-notifications.rst +++ b/doc/developer/northbound/operational-data-rpcs-and-notifications.rst @@ -1,11 +1,19 @@ +Operational Data, RPCs and Notifications +======================================== + +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 1 + Operational data ~~~~~~~~~~~~~~~~ Writing API-agnostic code for YANG-modeled operational data is -challenging. ConfD and Sysrepo, for instance, have completely different -APIs to fetch operational data. So how can we write API-agnostic -callbacks that can be used by both the ConfD and Sysrepo plugins, and -any other northbound client that might be written in the future? +challenging. Sysrepo, for instance, has completely different API to +fetch operational data. So how can we write API-agnostic callbacks +that can be used by both the Sysrepo plugin, and any other northbound +client that might be written in the future? As an additional requirement, the callbacks must be designed in a way that makes in-place XPath filtering possible. As an example, a @@ -86,27 +94,18 @@ in the northbound architecture: */ void *(*lookup_entry)(struct yang_list_keys *keys); -These callbacks were designed to provide maximum flexibility, and borrow -a lot of ideas from the ConfD API. Each callback does one and only one -task, they are indivisible primitives that can be combined in several -different ways to iterate over operational data. The extra flexibility -certainly has a performance cost, but it’s the price to pay if we want -to expose FRR operational data using several different management -interfaces (e.g. NETCONF via either ConfD or Sysrepo+Netopeer2). In the +These callbacks were designed to provide maximum flexibility. Each +callback does one and only one task, they are indivisible primitives +that can be combined in several different ways to iterate over operational +data. The extra flexibility certainly has a performance cost, but it’s the +price to pay if we want to expose FRR operational data using several +different management interfaces (e.g. Sysrepo+Netopeer2). In the future it might be possible to introduce optional callbacks that do things like returning multiple objects at once. They would provide enhanced performance when iterating over large lists, but their use would be limited by the northbound plugins that can be integrated with them. - NOTE: using the northbound callbacks as a base, the ConfD plugin can - provide up to 100 objects between each round trip between FRR and the - *confd* daemon. Preliminary tests showed FRR taking ~7 seconds - (asynchronously, without blocking the main pthread) to return a RIP - table containing 100k routes to a NETCONF client connected to *confd* - (JSON was used as the encoding format). Work needs to be done to find - the bottlenecks and optimize this operation. - The [[Plugins - Writing Your Own]] page explains how the northbound plugins can fetch operational data using the aforementioned northbound callbacks, and how in-place XPath filtering can be implemented. @@ -330,10 +329,12 @@ CLI can take too long, potentially long enough to the point of triggering some protocol timeouts and bringing sessions down. To avoid this kind of problem, northbound clients are encouraged to do -one of the following: \* Create a separate pthread for handling requests -to fetch operational data. \* Iterate over YANG lists and leaf-lists -asynchronously, returning a maximum number of elements per time instead -of returning all elements in one shot. +one of the following: + +* Create a separate pthread for handling requests to fetch operational data. + +* Iterate over YANG lists and leaf-lists asynchronously, returning a maximum + number of elements per time instead of returning all elements in one shot. In order to handle both cases correctly, the ``get_next`` callbacks need to use locks to prevent the YANG lists from being modified while they @@ -341,10 +342,10 @@ are being iterated over. If that is not done, the list entry returned by this callback can become a dangling pointer when used in another callback. -Currently the ConfD and Sysrepo plugins run only in the main pthread. -The plan in the short-term is to introduce a separate pthread only for -handling operational data, and use the main pthread only for handling -configuration changes, RPCs and notifications. +Currently the Sysrepo plugin runs only in the main pthread. The plan in the +short-term is to introduce a separate pthread only for handling operational +data, and use the main pthread only for handling configuration changes, +RPCs and notifications. RPCs and Actions ~~~~~~~~~~~~~~~~ @@ -386,8 +387,8 @@ some EXEC-level commands using YANG so that their functionality is exposed to other management interfaces other than the CLI. As an example, if the ``clear bgp`` command is modeled using a YANG RPC, and a corresponding ``rpc`` callback is written, then it should be possible to -clear BGP neighbors using NETCONF and RESTCONF with that RPC (the ConfD -and Sysrepo plugins have full support for YANG RPCs and actions). +clear BGP neighbors using NETCONF and RESTCONF with that RPC (the Sysrepo +plugin has full support for YANG RPCs and actions). Here’s an example of a very simple RPC modeled using YANG: @@ -558,8 +559,7 @@ Now sending the *authentication-failure* YANG notification should be as simple as calling the above function and provide the appropriate interface name. The notification will be processed by all northbound plugins that subscribed a callback to the ``nb_notification_send`` hook. -The ConfD and Sysrepo plugins, for instance, use this hook to relay the -notifications to the *confd*/*sysrepod* daemons, which can generate -NETCONF notifications to subscribed clients. When no northbound plugin -is loaded, ``nb_notification_send()`` doesn’t do anything and the -notifications are ignored. +The Sysrepo plugin, for instance, uses this hook to relay the notifications +to the *sysrepod* daemon, which can generate NETCONF notifications to subscribed +clients. When no northbound plugin is loaded, ``nb_notification_send()`` doesn’t +do anything and the notifications are ignored. diff --git a/doc/developer/northbound/plugins-sysrepo.rst b/doc/developer/northbound/plugins-sysrepo.rst index 186c3a0177d1..f4df68ce3c5a 100644 --- a/doc/developer/northbound/plugins-sysrepo.rst +++ b/doc/developer/northbound/plugins-sysrepo.rst @@ -1,137 +1,193 @@ +Plugins Sysrepo +=============== + Installation ------------ Required dependencies ^^^^^^^^^^^^^^^^^^^^^ +Install FRR build required dependencies, check `Building FRR +`_ document for specific platform required packages. +Below are debian systems required packages: -:: +.. code-block:: console - # apt-get install git cmake build-essential bison flex libpcre3-dev libev-dev \ - libavl-dev libprotobuf-c-dev protobuf-c-compiler libcmocka0 \ - libcmocka-dev doxygen libssl-dev libssl-dev libssh-dev + sudo apt-get install git autoconf automake libtool make \ + libprotobuf-c-dev protobuf-c-compiler build-essential \ + python3-dev python3-pytest python3-sphinx libjson-c-dev \ + libelf-dev libreadline-dev cmake libcap-dev bison flex \ + pkg-config texinfo gdb libgrpc-dev python3-grpc-tools libpcre2-dev libyang ^^^^^^^ -:: +.. note:: - # apt-get install libyang0.16 libyang-dev + FRR requires version 2.1.128 or newer, in this document we will + be compiling and installing libyang version 2.1.148. -Sysrepo -^^^^^^^ +.. code-block:: console -:: + git clone https://github.com/CESNET/libyang.git + cd libyang + git checkout v2.1.148 + mkdir build; cd build + cmake --install-prefix /usr \ + -DCMAKE_BUILD_TYPE:String="Release" .. + make + sudo make install - $ git clone https://github.com/sysrepo/sysrepo.git - $ cd sysrepo/ - $ mkdir build; cd build - $ cmake -DCMAKE_BUILD_TYPE=Release -DGEN_LANGUAGE_BINDINGS=OFF .. && make - # make install +Sysrepo +^^^^^^^ -libnetconf2 -^^^^^^^^^^^ +.. note:: -:: + The following code block assumes you have installed libyang v2.1.148, if you have + libyang v2.1.128 change sysrepo version to 2.2.105. - $ git clone https://github.com/CESNET/libnetconf2.git - $ cd libnetconf2/ - $ mkdir build; cd build - $ cmake .. && make - # make install +.. code-block:: console -netopeer2 -^^^^^^^^^ + git clone https://github.com/sysrepo/sysrepo.git + cd sysrepo/ + git checkout v2.2.150 + mkdir build; cd build + cmake --install-prefix /usr \ + -DCMAKE_BUILD_TYPE:String="Release" .. + make + sudo make install -:: +Verify that sysrepo is installed correctly: - $ git clone https://github.com/CESNET/Netopeer2.git - $ cd Netopeer2 - $ cd server - $ mkdir build; cd build - $ cmake .. && make - # make install +.. code-block:: console -**Note:** If ``make install`` fails as it can’t find -``libsysrepo.so.0.7``, then run ``ldconfig`` and try again as it might -not have updated the lib search path + sudo sysrepoctl -l FRR ^^^ -Build and install FRR using the ``--enable-sysrepo`` configure-time -option. +Follow the steps of `Building FRR +`_ + + +Make sure to use ``--enable-sysrepo`` configure-time option while building FRR. + +Below is an example of frr configure-time options, your options +might vary, however in order to allow sysrepo plugin you have +to keep ``--enable-sysrepo`` option: + +.. code-block:: console + + ./bootstrap.sh + ./configure \ + --localstatedir=/var/opt/frr \ + --sbindir=/usr/lib/frr \ + --sysconfdir=/etc/frr \ + --enable-multipath=64 \ + --enable-user=frr \ + --enable-group=frr \ + --enable-vty-group=frrvty \ + --enable-configfile-mask=0640 \ + --enable-logfile-mask=0640 \ + --enable-fpm \ + --enable-sysrepo \ + --with-pkg-git-version \ + --with-pkg-extra-version=-MyOwnFRRVersion + make + make check + sudo make install + Initialization -------------- -Install the FRR YANG modules in the Sysrepo datastore: +Install FRR YANG modules in Sysrepo datastore: -:: +.. code-block:: console - # sysrepoctl --install /usr/local/share/yang/ietf-interfaces@2018-01-09.yang - # sysrepoctl --install /usr/local/share/yang/frr-vrf.yang - # sysrepoctl --install /usr/local/share/yang/frr-interface.yang - # sysrepoctl --install /usr/local/share/yang/frr-route-types.yang - # sysrepoctl --install /usr/local/share/yang/frr-filter.yang - # sysrepoctl --install /usr/local/share/yang/frr-route-map.yang - # sysrepoctl --install /usr/local/share/yang/frr-isisd.yang - # sysrepoctl --install /usr/local/share/yang/frr-ripd.yang - # sysrepoctl --install /usr/local/share/yang/frr-ripngd.yang - # sysrepoctl -c frr-vrf --owner frr --group frr - # sysrepoctl -c frr-interface --owner frr --group frr - # sysrepoctl -c frr-route-types --owner frr --group frr - # sysrepoctl -c frr-filter --owner frr --group frr - # sysrepoctl -c frr-route-map --owner frr --group frr - # sysrepoctl -c frr-isisd --owner frr --group frr - # sysrepoctl -c frr-ripd --owner frr --group frr - # sysrepoctl -c frr-ripngd --owner frr --group frr + cd frr/yang/ + sudo sysrepoctl -i ./ietf/ietf-interfaces.yang -o frr -g frr + sudo sysrepoctl -i frr-vrf.yang -o frr -g frr + sudo sysrepoctl -i frr-interface.yang -o frr -g frr + sudo sysrepoctl -i frr-route-types.yang -o frr -g frr + sudo sysrepoctl -i frr-filter.yang -o frr -g frr + sudo sysrepoctl -i frr-route-map.yang -o frr -g frr + sudo sysrepoctl -i frr-isisd.yang -o frr -g frr + sudo sysrepoctl -i frr-bfdd.yang -o frr -g frr + sudo sysrepoctl -i ./ietf/ietf-routing-types.yang -o frr -g frr + sudo sysrepoctl -i frr-nexthop.yang -o frr -g frr + sudo sysrepoctl -i frr-if-rmap.yang -o frr -g frr + sudo sysrepoctl -i frr-ripd.yang -o frr -g frr + sudo sysrepoctl -i frr-ripngd.yang -o frr -g frr + sudo sysrepoctl -i frr-affinity-map.yang -o frr -g frr + sudo sysrepoctl -i ./ietf/frr-deviations-ietf-interfaces.yang -o frr -g frr -Start netopeer2-server: -:: +Start FRR daemons with sysrepo plugin: - # netopeer2-server -d & +.. code-block:: console -Start the FRR daemons with the sysrepo module: + sudo /usr/lib/frr/isisd -M sysrepo --log stdout -:: - - # isisd -M sysrepo --log=stdout +Any daemon running with ``-M sysrepo`` will subscribe to its frr yang moduels +on sysrepo and you be able to configure it by editing module configuration on sysrepo. Managing the configuration -------------------------- -The following NETCONF scripts can be used to show and edit the FRR -configuration: -https://github.com/rzalamena/ietf-hackathon-brazil-201907/tree/master/netconf-scripts +Testing +^^^^^^^ -Example: +To test FRR intergartion with sysrepo, ``sysrepocfg`` tool can be used +to edit frr configuration on sysrepo -:: +Example: - # ./netconf-edit.py 127.0.0.1 - # ./netconf-get-config.py 127.0.0.1 - testnetlevel-1 +Edit sysrepo running datastore configuration for the desiged frr module: -.. +.. code-block:: console - NOTE: the ncclient library needs to be installed first: - ``apt install -y python3-ncclient`` + sudo sysrepocfg -E nano -d running -m frr-isisd -f json -The *sysrepocfg* tool can also be used to show/edit the FRR -configuration. Example: +Paste the following json configuration: -:: +.. code-block:: console - # sysrepocfg --format=json --import=frr-isisd.json --datastore=running frr-isisd - # sysrepocfg --format=json --export --datastore=running frr-isisd { "frr-isisd:isis": { "instance": [ { "area-tag": "testnet", + "vrf": "default", "is-type": "level-1" } ] } } + +Exit and save config to the same file. + +After that, this configuration should get reflected to vtysh: + +.. code-block:: console + + show run + Building configuration... + + Current configuration: + ! + frr version 9.2-dev-MyOwnFRRVersion + frr defaults traditional + hostname bullseye + ! + router isis testnet + is-type level-1 + exit + ! + end + +NETCONF +^^^^^^^ + +To manage sysrepo configuration through netconf +you can use `netopeer2 `_ as a netfconf server that can +be easily integrated with sysrepo. diff --git a/doc/developer/northbound/ppr-basic-test-topology.rst b/doc/developer/northbound/ppr-basic-test-topology.rst index 582c76c059dc..4929c9b28570 100644 --- a/doc/developer/northbound/ppr-basic-test-topology.rst +++ b/doc/developer/northbound/ppr-basic-test-topology.rst @@ -1,15 +1,10 @@ -Table of Contents -~~~~~~~~~~~~~~~~~ +IS-IS PPR Basic +=============== -- `Software <#software>`__ -- `Topology <#topology>`__ -- `Configuration <#configuration>`__ - - - `CLI <#configuration-cli>`__ - - `YANG <#configuration-yang>`__ - -- `Verification - Control Plane <#verification-cplane>`__ -- `Verification - Forwarding Plane <#verification-fplane>`__ +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 2 Software ~~~~~~~~ @@ -1258,7 +1253,7 @@ Using the ``show isis ppr`` command, verify that all routers installed the PPR-IDs for the paths they are part of. Example: Router RT11 -''''''''''' +^^^^^^^^^^^ :: diff --git a/doc/developer/northbound/ppr-mpls-basic-test-topology.rst b/doc/developer/northbound/ppr-mpls-basic-test-topology.rst index cedb795da997..aceec5fa2f8a 100644 --- a/doc/developer/northbound/ppr-mpls-basic-test-topology.rst +++ b/doc/developer/northbound/ppr-mpls-basic-test-topology.rst @@ -1,15 +1,10 @@ -Table of Contents -~~~~~~~~~~~~~~~~~ +IS-IS PPR Basic MPLS +==================== -- `Software <#software>`__ -- `Topology <#topology>`__ -- `Configuration <#configuration>`__ - - - `CLI <#configuration-cli>`__ - - `YANG <#configuration-yang>`__ - -- `Verification - Control Plane <#verification-cplane>`__ -- `Verification - Forwarding Plane <#verification-fplane>`__ +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 2 Software ~~~~~~~~ diff --git a/doc/developer/northbound/retrofitting-configuration-commands.rst b/doc/developer/northbound/retrofitting-configuration-commands.rst index c13332bf1fb5..d328be950650 100644 --- a/doc/developer/northbound/retrofitting-configuration-commands.rst +++ b/doc/developer/northbound/retrofitting-configuration-commands.rst @@ -1,24 +1,16 @@ -Table of Contents ------------------ -- `Introduction <#introduction>`__ -- `Retrofitting process <#retrofitting-process>`__ +.. _nb-retrofit: - - `Step 1: writing a YANG module <#step1>`__ - - `Step 2: generate skeleton northbound callbacks <#step2>`__ - - `Step 3: update the frr_yang_module_info array of all relevant - daemons <#step3>`__ - - `Step 4: implement the northbound configuration - callbacks <#step4>`__ - - `Step 5: rewrite the CLI commands as dumb wrappers around the - northbound callbacks <#step5>`__ - - `Step 6: implement the ``cli_show`` callbacks <#step6>`__ - - `Step 7: consolidation <#step7>`__ +Retrofitting Configuration Commands +=================================== -- `Final Considerations <#final-considerations>`__ +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 2 -Introduction ------------- +Retrofitting process +-------------------- This page explains how to convert existing CLI configuration commands to the new northbound model. This documentation is meant to be the primary @@ -26,9 +18,6 @@ reference for developers working on the northbound retrofitting process. We’ll show several examples taken from the ripd northbound conversion to illustrate some concepts described herein. -Retrofitting process --------------------- - Step 1: writing a YANG module ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -49,34 +38,41 @@ possible to facilitate the process of writing module translators using the [[YANG module translator]]. As an example, the frr-ripd YANG module incorporated several parts of the IETF RIP YANG module. The repositories below contain big collections of YANG models that might be used as a -reference: \* https://github.com/YangModels/yang \* -https://github.com/openconfig/public +reference: + +* https://github.com/YangModels/yang + +* https://github.com/openconfig/public When writing a YANG module, it’s highly recommended to follow the guidelines from `RFC 6087 `__. In general, most commands should be modeled fairly easy. Here are a few -guidelines specific to authors of FRR YANG models: \* Use -presence-containers or lists to model commands that change the CLI node -(e.g. ``router rip``, ``interface eth0``). This way, if the -presence-container or list entry is removed, all configuration options -below them are removed automatically (exactly like the CLI behaves when -a configuration object is removed using a *no* command). This -recommendation is orthogonal to the `YANG authoring guidelines for -OpenConfig -models `__ -where the use of presence containers is discouraged. OpenConfig YANG -models however were not designed to replicate the behavior of legacy CLI -commands. \* When using YANG lists, be careful to identify what should -be the key leaves. In the ``offset-list WORD (0-16) IFNAME`` -command, for example, both the direction (````) and the -interface name should be the keys of the list. This can be only known by -analyzing the data structures used to store the commands. \* For -clarity, use non-presence containers to group leaves that are associated -to the same configuration command (as we’ll see later, this also -facilitate the process of writing ``cli_show`` callbacks). \* YANG -leaves of type *enumeration* should define explicitly the value of each -*enum* option based on the value used in the FRR source code. \* Default -values should be taken from the source code whenever they exist. +guidelines specific to authors of FRR YANG models: + +* Use presence-containers or lists to model commands that change the CLI node + (e.g. ``router rip``, ``interface eth0``). This way, if the presence-container + or list entry is removed, all configuration options below them are removed + automatically (exactly like the CLI behaves when a configuration object is + removed using a *no* command). This recommendation is orthogonal to the `YANG + authoring guidelines for OpenConfig models + `__ + where the use of presence containers is discouraged. OpenConfig YANG models + however were not designed to replicate the behavior of legacy CLI commands. + +* When using YANG lists, be careful to identify what should be the key leaves. + In the ``offset-list WORD (0-16) IFNAME`` command, for example, both + the direction (````) and the interface name should be the keys of the + list. This can be only known by analyzing the data structures used to store + the commands. + +* For clarity, use non-presence containers to group leaves that are associated + to the same configuration command (as we’ll see later, this also facilitate + the process of writing ``cli_show`` callbacks). + +* YANG leaves of type *enumeration* should define explicitly the value of each + *enum* option based on the value used in the FRR source code. + +* Default values should be taken from the source code whenever they exist. Some commands are more difficult to model and demand the use of more advanced YANG constructs like *choice*, *when* and *must* statements. @@ -88,7 +84,7 @@ possible. As we’ll see later, not all constraints can be expressed using the YANG language and sometimes we’ll need to resort to code-level validation in the northbound callbacks. - Tip: the [[YANG tools]] page details several tools and commands that + Tip: the :doc:`yang-tools` page details several tools and commands that might be useful when writing a YANG module, like validating YANG files, indenting YANG files, validating instance data, etc. @@ -745,15 +741,17 @@ Configuration options are edited individually ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Several CLI commands edit multiple configuration options at the same -time. Some examples taken from ripd: \* -``timers basic (5-2147483647) (5-2147483647) (5-2147483647)`` - -*/frr-ripd:ripd/instance/timers/flush-interval* - -*/frr-ripd:ripd/instance/timers/holddown-interval* - -*/frr-ripd:ripd/instance/timers/update-interval* \* -``distance (1-255) A.B.C.D/M [WORD]`` - -*/frr-ripd:ripd/instance/distance/source/prefix* - -*/frr-ripd:ripd/instance/distance/source/distance* - -*/frr-ripd:ripd/instance/distance/source/access-list* +time. Some examples taken from ripd: + +* ``timers basic (5-2147483647) (5-2147483647) (5-2147483647)`` + * */frr-ripd:ripd/instance/timers/flush-interval* + * */frr-ripd:ripd/instance/timers/holddown-interval* + * */frr-ripd:ripd/instance/timers/update-interval* + +* ``distance (1-255) A.B.C.D/M [WORD]`` + * */frr-ripd:ripd/instance/distance/source/prefix* + * */frr-ripd:ripd/instance/distance/source/distance* + * */frr-ripd:ripd/instance/distance/source/access-list* In the new northbound model, there’s one or more separate callbacks for each configuration option. This usually has implications when converting @@ -984,34 +982,30 @@ future. For libfrr commands, it’s not possible to centralize all commands in a single file because the *extract.pl* script from *vtysh* treats commands differently depending on the file in which they are defined (e.g. DEFUNs -from *lib/routemap.c* are installed using the ``VTYSH_RMAP`` constant, +from *lib/routemap.c* are installed using the ``VTYSH_RMAP_SHOW`` constant, which identifies the daemons that support route-maps). In this case, the CLI commands should be rewritten but maintained in the same file. Since all CLI configuration commands from FRR will need to be rewritten, this is an excellent opportunity to rework this part of the code to make the commands easier to maintain and extend. These are the three main -recommendations: 1. Always use DEFPY instead of DEFUN to improve code -readability. 2. Always try to join multiple DEFUNs into a single DEFPY -whenever possible. As an example, there’s no need to have both -``distance (1-255) A.B.C.D/M`` and ``distance (1-255) A.B.C.D/M WORD`` -when a single ``distance (1-255) A.B.C.D/M [WORD]`` would suffice. 3. -When necessary, create a separate DEFPY for ``no`` commands so that part -of the configuration command can be made optional for convenience. -Example: -``no timers basic [(5-2147483647) (5-2147483647) (5-2147483647)]``. In -this example, everything after ``no timers basic`` is ignored by FRR, so -it makes sense to accept ``no timers basic`` as a valid command. But it -also makes sense to accept all parameters -(``no timers basic (5-2147483647) (5-2147483647) (5-2147483647)``) to -make it easier to remove the command just by prefixing a “no” to it. +recommendations: + +#. Always use DEFPY instead of DEFUN to improve code readability +#. Always try to join multiple DEFUNs into a single DEFPY whenever possible. As + an example, there’s no need to have both ``distance (1-255) A.B.C.D/M`` and + ``distance (1-255) A.B.C.D/M WORD`` when a single ``distance (1-255) + A.B.C.D/M [WORD]`` would suffice. +#. When making a negative form of a command, put ``[no]`` in the positive form + and use ``![...]`` to mark portions of the command that should be optional + only in the ``no`` version. To rewrite a CLI command as a dumb wrapper around the northbound callbacks, use the ``nb_cli_cfg_change()`` function. This function accepts as a parameter an array of ``cli_config_change`` structures that specify the changes that need to performed on the candidate configuration. Here’s the declaration of this structure (taken from the -*lib/northbound_cli.h* file): +``lib/northbound_cli.h`` file): .. code:: c @@ -1024,7 +1018,7 @@ configuration. Here’s the declaration of this structure (taken from the /* * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or - * NB_OP_DELETE). + * NB_OP_DESTROY). */ enum nb_operation operation; @@ -1053,16 +1047,23 @@ changing the candidate configuration. the northbound callbacks are not involved). Other important details to keep in mind while rewriting the CLI -commands: \* ``nb_cli_cfg_change()`` returns CLI errors codes -(e.g. ``CMD_SUCCESS``, ``CMD_WARNING``), so the return value of this -function can be used as the return value of CLI commands. \* Calls to -``VTY_PUSH_CONTEXT`` and ``VTY_PUSH_CONTEXT_SUB`` should be converted to -calls to ``VTY_PUSH_XPATH``. Similarly, the following macros aren’t -necessary anymore and can be removed: ``VTY_DECLVAR_CONTEXT``, -``VTY_DECLVAR_CONTEXT_SUB``, ``VTY_GET_CONTEXT`` and -``VTY_CHECK_CONTEXT``. The ``nb_cli_cfg_change()`` functions uses the -``VTY_CHECK_XPATH`` macro to check if the data node being edited still -exists before doing anything else. +commands: + +* ``nb_cli_cfg_change()`` returns CLI errors codes (e.g. ``CMD_SUCCESS``, + ``CMD_WARNING``), so the return value of this function can be used as the + return value of CLI commands. + +* Calls to ``VTY_PUSH_CONTEXT`` and ``VTY_PUSH_CONTEXT_SUB`` should be converted + to calls to ``VTY_PUSH_XPATH``. Similarly, the following macros aren’t + necessary anymore and can be removed: + + * ``VTY_DECLVAR_CONTEXT`` + * ``VTY_DECLVAR_CONTEXT_SUB`` + * ``VTY_GET_CONTEXT`` + * ``VTY_CHECK_CONTEXT``. + + The ``nb_cli_cfg_change()`` functions uses the ``VTY_CHECK_XPATH`` macro to + check if the data node being edited still exists before doing anything else. The examples below provide additional details about how the conversion should be done. @@ -1224,7 +1225,7 @@ This example shows how to create a list entry: }, { .xpath = "./access-list", - .operation = acl ? NB_OP_MODIFY : NB_OP_DELETE, + .operation = acl ? NB_OP_MODIFY : NB_OP_DESTROY, .value = acl, }, }; @@ -1261,7 +1262,7 @@ When deleting a list entry, all non-key leaves can be ignored: struct cli_config_change changes[] = { { .xpath = ".", - .operation = NB_OP_DELETE, + .operation = NB_OP_DESTROY, }, }; @@ -1804,10 +1805,13 @@ Implementation of the ``cli_show`` callback: } This is the most complex ``cli_show`` callback we have in ripd. Its -complexity comes from the following: \* The -``ip rip authentication mode ...`` command changes two YANG leaves at -the same time. \* Part of the command should be hidden when the -``show_defaults`` parameter is set to false. +complexity comes from the following: + +* The ``ip rip authentication mode ...`` command changes two YANG leaves at the + same time. + +* Part of the command should be hidden when the ``show_defaults`` parameter is + set to false. This is the behavior we want to implement: @@ -1857,25 +1861,33 @@ As mentioned in the fourth step, the northbound retrofitting process can happen gradually over time, since both “old” and “new” commands can coexist without problems. Once all commands from a given daemon were converted, we can proceed to the consolidation step, which consists of -the following: \* Remove the vty configuration lock, which is enabled by -default in all daemons. Now multiple users should be able to edit the -configuration concurrently, using either shared or private candidate -configurations. \* Reference commit: -`57dccdb1 `__. -\* Stop using the qobj infrastructure to keep track of configuration -objects. This is not necessary anymore, the northbound uses a similar -mechanism to keep track of YANG data nodes in the candidate -configuration. \* Reference commit: -`4e6d63ce `__. -\* Make the daemon SIGHUP handler re-read the configuration file (and -ensure it’s not doing anything other than that). \* Reference commit: -`5e57edb4 `__. +the following: + +* Remove the vty configuration lock, which is enabled by default in all daemons. + Now multiple users should be able to edit the configuration concurrently, + using either shared or private candidate configurations. + +* Reference commit: `57dccdb1 + `__. + +* Stop using the qobj infrastructure to keep track of configuration objects. + This is not necessary anymore, the northbound uses a similar mechanism to keep + track of YANG data nodes in the candidate configuration. + +* Reference commit: `4e6d63ce + `__. + +* Make the daemon SIGHUP handler re-read the configuration file (and ensure it’s + not doing anything other than that). + +* Reference commit: `5e57edb4 + `__. Final Considerations -------------------- Testing -^^^^^^^ +~~~~~~~ Converting CLI commands to the new northbound model can be a complicated task for beginners, but the more commands one converts, the easier it @@ -1888,7 +1900,7 @@ to use valgrind and static code analyzers to catch other types of problems like memory leaks. Amount of work -^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~ The output below gives a rough estimate of the total number of configuration commands that need to be converted per daemon: diff --git a/doc/developer/northbound/transactional-cli.rst b/doc/developer/northbound/transactional-cli.rst index 439bb6afceb1..5c495d3a89db 100644 --- a/doc/developer/northbound/transactional-cli.rst +++ b/doc/developer/northbound/transactional-cli.rst @@ -1,25 +1,10 @@ -Table of Contents ------------------ - -- `Introduction <#introduction>`__ -- `Configuration modes <#config-modes>`__ -- `New commands <#retrofitting-process>`__ - - - `commit check <#cmd1>`__ - - `commit <#cmd2>`__ - - `discard <#cmd3>`__ - - `configuration database max-transactions <#cmd4>`__ - - `configuration load <#cmd5>`__ - - `rollback configuration <#cmd6>`__ - - `show configuration candidate <#cmd7>`__ - - `show configuration compare <#cmd8>`__ - - `show configuration running <#cmd9>`__ - - `show configuration transaction <#cmd10>`__ - - `show yang module <#cmd11>`__ - - `show yang module-translator <#cmd12>`__ - - `update <#cmd13>`__ - - `yang module-translator load <#cmd14>`__ - - `yang module-translator unload <#cmd15>`__ +Transactional CLI +================= + +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 1 Introduction ~~~~~~~~~~~~ @@ -70,18 +55,21 @@ Configuration modes ~~~~~~~~~~~~~~~~~~~ When using the transactional CLI (``--tcli``), FRR supports three -different forms of the ``configure`` command: \* ``configure terminal``: -in this mode, a single candidate configuration is shared by all users. -This means that one user might delete a configuration object that’s -being edited by another user, in which case the CLI will detect and -report the problem. If one user issues the ``commit`` command, all -changes done by all users are committed. \* ``configure private``: users -have a private candidate configuration that is edited separately from -the other users. The ``commit`` command commits only the changes done by -the user. \* ``configure exclusive``: similar to ``configure private``, -but also locks the running configuration to prevent other users from -changing it. The configuration lock is released when the user exits the -configuration mode. +different forms of the ``configure`` command: + +* ``configure terminal``: in this mode, a single candidate configuration is + shared by all users. This means that one user might delete a configuration + object that’s being edited by another user, in which case the CLI will detect + and report the problem. If one user issues the ``commit`` command, all changes + done by all users are committed. + +* ``configure private``: users have a private candidate configuration that is + edited separately from the other users. The ``commit`` command commits only + the changes done by the user. + +* ``configure exclusive``: similar to ``configure private``, but also locks the + running configuration to prevent other users from changing it. The + configuration lock is released when the user exits the configuration mode. When using ``configure terminal`` or ``configure private``, the candidate configuration being edited might become outdated if another @@ -112,12 +100,14 @@ Check if the candidate configuration is valid or not. Commit the changes done in the candidate configuration into the running configuration. -Options: \* ``force``: commit even if the candidate configuration is -outdated. It’s usually a better option to use the ``update`` command -instead. \* ``comment LINE...``: assign a comment to the configuration -transaction. This comment is displayed when viewing the recorded -transactions in the output of the ``show configuration transaction`` -command. +Options: + +* ``force``: commit even if the candidate configuration is outdated. It’s + usually a better option to use the ``update`` command instead. + +* ``comment LINE...``: assign a comment to the configuration transaction. This + comment is displayed when viewing the recorded transactions in the output of + the ``show configuration transaction`` command. ``discard`` ''''''''''' @@ -140,10 +130,13 @@ respectively. It’s also possible to load a configuration from a previous transaction by specifying the desired transaction ID (``(1-4294967296)``). -Options: \* ``translate WORD``: translate the JSON/XML configuration -file using the YANG module translator. \* ``replace``: replace the -candidate by the loaded configuration. The default is to merge the -loaded configuration into the candidate configuration. +Options: + +* ``translate WORD``: translate the JSON/XML configuration file using the YANG + module translator. + +* ``replace``: replace the candidate by the loaded configuration. The default is + to merge the loaded configuration into the candidate configuration. ``rollback configuration (1-4294967296)`` ''''''''''''''''''''''''''''''''''''''''' @@ -156,39 +149,42 @@ identified by its transaction ID (``(1-4294967296)``). Show the candidate configuration. -Options: \* ``json``: show the configuration in the JSON format. \* -``xml``: show the configuration in the XML format. \* -``translate WORD``: translate the JSON/XML output using the YANG module -translator. \* ``with-defaults``: show default values that are hidden by -default. \* ``changes``: show only the changes done in the candidate -configuration. +Options: + +* ``json``: show the configuration in the JSON format. +* ``xml``: show the configuration in the XML format. +* ``translate WORD``: translate the JSON/XML output using the YANG module translator. +* ``with-defaults``: show default values that are hidden by default. +* ``changes``: show only the changes done in the candidate configuration. ``show configuration compare [ [translate WORD]]`` '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Show the difference between two different configurations. -Options: \* ``json``: show the configuration differences in the JSON -format. \* ``xml``: show the configuration differences in the XML -format. \* ``translate WORD``: translate the JSON/XML output using the -YANG module translator. +Options: + +* ``json``: show the configuration differences in the JSON format. +* ``xml``: show the configuration differences in the XML format. +* ``translate WORD``: translate the JSON/XML output using the YANG module translator. ``show configuration running [ [translate WORD]] [with-defaults]`` '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Show the running configuration. -Options: \* ``json``: show the configuration in the JSON format. \* -``xml``: show the configuration in the XML format. \* -``translate WORD``: translate the JSON/XML output using the YANG module -translator. \* ``with-defaults``: show default values that are hidden by -default. +Options: - NOTE: ``show configuration running`` shows only the running - configuration as known by the northbound layer. Configuration - commands not converted to the new northbound model will not be - displayed. To show the full running configuration, the legacy - ``show running-config`` command must be used. +* ``json``: show the configuration in the JSON format. +* ``xml``: show the configuration in the XML format. +* ``translate WORD``: translate the JSON/XML output using the YANG module translator. +* ``with-defaults``: show default values that are hidden by default. + +NOTE: ``show configuration running`` shows only the running +configuration as known by the northbound layer. Configuration +commands not converted to the new northbound model will not be +displayed. To show the full running configuration, the legacy +``show running-config`` command must be used. ``show configuration transaction [(1-4294967296) [ [translate WORD]] [changes]]`` ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -199,12 +195,13 @@ configuration associated to the previously committed transaction. When a transaction ID is not given, show all recorded transactions in the rollback log. -Options: \* ``json``: show the configuration in the JSON format. \* -``xml``: show the configuration in the XML format. \* -``translate WORD``: translate the JSON/XML output using the YANG module -translator. \* ``with-defaults``: show default values that are hidden by -default. \* ``changes``: show changes compared to the previous -transaction. +Options: + +* ``json``: show the configuration in the JSON format. +* ``xml``: show the configuration in the XML format. +* ``translate WORD``: translate the JSON/XML output using the YANG module translator. +* ``with-defaults``: show default values that are hidden by default. +* ``changes``: show changes compared to the previous transaction. ``show yang module [module-translator WORD] [WORD ]`` '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -212,11 +209,14 @@ transaction. When a YANG module is not given, show all loaded YANG modules. Otherwise, show detailed information about the given module. -Options: \* ``module-translator WORD``: change the context to modules -loaded by the specified YANG module translator. \* ``summary``: display -summary information about the module. \* ``tree``: display module in the -tree (RFC 8340) format. \* ``yang``: display module in the YANG format. -\* ``yin``: display module in the YIN format. +Options: + +* ``module-translator WORD``: change the context to modules loaded by the + specified YANG module translator. +* ``summary``: display summary information about the module. +* ``tree``: display module in the tree (RFC 8340) format. +* ``yang``: display module in the YANG format. +* ``yin``: display module in the YIN format. ``show yang module-translator`` ''''''''''''''''''''''''''''''' diff --git a/doc/developer/northbound/yang-module-translator.rst b/doc/developer/northbound/yang-module-translator.rst index aa527ce6b272..17ae160f079b 100644 --- a/doc/developer/northbound/yang-module-translator.rst +++ b/doc/developer/northbound/yang-module-translator.rst @@ -1,11 +1,10 @@ -Table of Contents ------------------ +YANG Module Translation +======================= -- `Introduction <#introduction>`__ -- `Deviation Modules <#deviation-modules>`__ -- `Translation Tables <#translation-tables>`__ -- `CLI Demonstration <#cli-demonstration>`__ -- `Implementation Details <#implementation-details>`__ +.. contents:: Table of contents + :local: + :backlinks: entry + :depth: 1 Introduction ------------ @@ -421,15 +420,20 @@ this shortcoming and make it possible to create more powerful YANG module translators. YANG module translators can be evaluated based on the following metrics: -\* Translation potential: is it possible to make complex translations, -taking several variables into account? \* Complexity: measure of how -easy or hard it is to write a module translator. \* Speed: measure of -how fast the translation can be achieved. Translation speed is of -fundamental importance, especially for operational data. \* Robustness: -can the translator be checked for inconsistencies at load time? A module -translator based on scripts wouldn’t fare well on this metric. \* -Round-trip conversions: can the translated data be translated back to -the original format without information loss? + +* Translation potential: is it possible to make complex translations, taking + several variables into account? + +* Complexity: measure of how easy or hard it is to write a module translator. + +* Speed: measure of how fast the translation can be achieved. Translation speed + is of fundamental importance, especially for operational data. + +* Robustness: can the translator be checked for inconsistencies at load time? A + module translator based on scripts wouldn’t fare well on this metric. + +* Round-trip conversions: can the translated data be translated back to the + original format without information loss? CLI Demonstration ----------------- diff --git a/doc/developer/northbound/yang-tools.rst b/doc/developer/northbound/yang-tools.rst index 4eb1a2fb2cb4..fb5a2872457b 100644 --- a/doc/developer/northbound/yang-tools.rst +++ b/doc/developer/northbound/yang-tools.rst @@ -1,3 +1,9 @@ +Yang Tools +========== + +Here's some information about various tools for working with yang +models. + yanglint cheat sheet ~~~~~~~~~~~~~~~~~~~~ @@ -77,17 +83,19 @@ Indent a YANG file: --keep-comments -f yang --yang-canonical \ module.yang -o module.yang -Generate skeleton instance data: \* XML: +Generate skeleton instance data: -.. code:: sh +* XML: + + .. code:: sh $ pyang -p \ -f sample-xml-skeleton --sample-xml-skeleton-defaults \ module.yang [augmented-module1.yang ...] -o module.xml -- JSON: +* JSON: -.. code:: sh + .. code:: sh $ pyang -p \ -f jsonxsl module.yang -o module.xsl diff --git a/doc/developer/ospf-ls-retrans.rst b/doc/developer/ospf-ls-retrans.rst new file mode 100644 index 000000000000..230d7a1c5d95 --- /dev/null +++ b/doc/developer/ospf-ls-retrans.rst @@ -0,0 +1,69 @@ +OSPF Neighor Retransmission List +================================ + +Overview +-------- + +OSPF neighbor link-state retransmission lists are implemented using +both a sparse Link State Database (LSDB) and a doubly-linked list. +Rather than previous per-neighbor periodic timer, a per-neighbor +timer is set to the expiration time of the next scheduled LSA +retransmission. + +Sparse Link State Database (LSDB) +--------------------------------- + +When an explicit or implied acknowledgment is recieved from a +neighbor in 2-way state or higher, the acknowledge LSA must be +removed from the neighbor's link state retransmission list. In order +to do this efficiently, a sparse LSDB is utilized. LSDB entries also +include a pointer to the corresponding list entry so that it may be +efficiently removed from the doubly-linked list. + +The sparse LSDB is implemented using the OSPF functions is +ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route +tables (lib/table.[c,h]). What is unique of the LS Retransmission +list LSDB is that each entry also has a pointer into the doubly-linked +list to facilitate fast deletions. + +Doubly-Linked List +------------------ + +In addition to the sparse LSDB, LSAs on a neighbor LS retransmission +list are also maintained in a linked-list order chronologically +with the LSA scheduled for the next retransmission at the head of +the list. + +The doubly-link list is implemented using the dlist macros in +lib/typesafe.h. + +LSA LS Retransmission List Addition +------------------------------------ + +When an LSA is added to a neighbor retransmission list, it is +added to both the sparse LSDB and the doubly-linked list with a pointer +in the LSDB route-table node to the list entry. The LSA is added to +the tail of the list with the expiration time set to the current time +with the retransmission interval added. If the neighbor retransmission +timer is not set, it is set to expire at the time of the newly added +LSA. + +LSA LS Retransmission List Deletion +----------------------------------- + +When an LSA is deleted from a neighbor retransmission list, it is +deleted from eboth the sparse LSDB and the doubly-linked list with the +pointer the LSDB route-table node used to efficiently delete the entry +from the list. If the LSA at the head of the list was removed, then +the neighbor retransmission timer is reset to the expiration of the +LSA at the head of the list or canceled if the list is empty. + +Neighbor LS Retransmission List Expiration +------------------------------------------ + +When the neighbor retransmission timer expires, the LSA at the top of +list and any in a configured window (e.g., 50 milliseconds) are +retransmitted. The LSAs that have been retransmitted are removed from +the list and readded to the tail of the list with a new expiration time +which is retransmit-interval seconds in the future. + diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst index a5164d552a18..da4802533c03 100644 --- a/doc/developer/ospf.rst +++ b/doc/developer/ospf.rst @@ -8,5 +8,7 @@ OSPFD :maxdepth: 2 ospf-api + ospf-ls-retrans ospf-sr + cspf diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c2c3b7e7e1eb..4109057ee5e5 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -68,6 +68,8 @@ buster.) +----------------+-------------------+-----------------------------------------+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) | +----------------+-------------------+-----------------------------------------+ + | pkg.frr.grpc | pkg.frr.nogrpc | builds with grpc support (default: no) | + +----------------+-------------------+-----------------------------------------+ * the ``-uc -us`` options to disable signing the packages with your GPG key diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index d88f449926b3..8037873461a5 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24. ############### FRRouting (FRR) configure options ################# # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_babeld: %global with_babeld 1 } + %{!?with_bfdd: %global with_bfdd 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_cumulus: %global with_cumulus 0 } + %{!?with_eigrpd: %global with_eigrpd 1 } + %{!?with_fpm: %global with_fpm 1 } + %{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 } %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_pam: %global with_pam 0 } + %{!?with_pbrd: %global with_pbrd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_pim6d: %global with_pim6d 1 } - %{!?with_rpki: %global with_rpki 0 } + %{!?with_vrrpd: %global with_vrrpd 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_pathd: %global with_pathd 1 } + %{!?with_grpc: %global with_grpc 0 } 8. Build the RPM:: diff --git a/doc/developer/process-architecture.rst b/doc/developer/process-architecture.rst index 06ee6a3c37ca..85126cab3040 100644 --- a/doc/developer/process-architecture.rst +++ b/doc/developer/process-architecture.rst @@ -87,7 +87,7 @@ are given by integer macros in :file:`frrevent.h` and are: ``EVENT_EXECUTE`` Just before a task is run its type is changed to this. This is used to show - ``X`` as the type in the output of :clicmd:`show thread cpu`. + ``X`` as the type in the output of :clicmd:`show event cpu`. The programmer never has to work with these types explicitly. Each type of task is created and queued via special-purpose functions (actually macros, but @@ -238,16 +238,16 @@ proceeding. In addition, the existing commands to show statistics and other information for tasks within the event driven model have been expanded to handle multiple -pthreads; running :clicmd:`show thread cpu` will display the usual event +pthreads; running :clicmd:`show event cpu` will display the usual event breakdown, but it will do so for each pthread running in the program. For example, :ref:`bgpd` runs a dedicated I/O pthread and shows the following -output for :clicmd:`show thread cpu`: +output for :clicmd:`show event cpu`: :: - frr# show thread cpu + frr# show event cpu - Thread statistics for bgpd: + Event statistics for bgpd: Showing statistics for pthread main ------------------------------------ diff --git a/doc/developer/rcu.rst b/doc/developer/rcu.rst index 4fd56587ae85..2335e8faed1a 100644 --- a/doc/developer/rcu.rst +++ b/doc/developer/rcu.rst @@ -232,6 +232,15 @@ Internals that case, either all of the library's threads must be registered for RCU, or the code must instead pass a (non-RCU) copy of the data to the library. +.. c:function:: int frr_pthread_non_controlled_startup(pthread_t thread, const char *name, const char *os_name) + + If a pthread is started outside the control of normal pthreads in frr + then frr_pthread_non_controlled_startup should be called. This will + properly setup both the pthread with rcu usage as well as some data + structures pertaining to the name of the pthread. This is especially + important if the pthread created ends up calling back into FRR and + one of the various zlog_XXX functions is called. + .. c:function:: void rcu_shutdown(void) Stop the RCU sweeper thread and make sure all cleanup has finished. diff --git a/doc/developer/requirements.txt b/doc/developer/requirements.txt new file mode 100644 index 000000000000..483a4e9600bd --- /dev/null +++ b/doc/developer/requirements.txt @@ -0,0 +1 @@ +sphinx_rtd_theme diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst index 202f0036f82f..7a4331449020 100644 --- a/doc/developer/scripting.rst +++ b/doc/developer/scripting.rst @@ -488,12 +488,6 @@ match *exactly*. In the above example, we defined encoders/decoders for a value of ``struct prefix *``, but not ``struct prefix`` or ``const struct prefix *``. -``const`` values are a special case. We want to use them in our Lua scripts -but not modify them, so creating a decoder for them would be meaningless. -But we still need a decoder for the type of value so that the compiler will be -satisfied. -For that, use ``lua_decode_noop``: - .. code-block:: diff #define DECODE_ARGS_WITH_STATE(L, value) \ diff --git a/doc/developer/static-linking.rst b/doc/developer/static-linking.rst index 5342fbfbf673..e9bb9281f874 100644 --- a/doc/developer/static-linking.rst +++ b/doc/developer/static-linking.rst @@ -44,7 +44,7 @@ when building libyang statically. The resultant cmake command is:: cmake -DENABLE_STATIC=ON -DENABLE_LYD_PRIV=ON \ - -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + --install-prefix /usr \ -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \ -DCMAKE_BUILD_TYPE:String="Release" .. diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index f052956c5431..652ee4e1af6a 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -5,12 +5,14 @@ dev_RSTFILES = \ doc/developer/bgp-typecodes.rst \ doc/developer/bgpd.rst \ + doc/developer/bmp.rst \ doc/developer/building-frr-for-alpine.rst \ doc/developer/building-frr-for-archlinux.rst \ doc/developer/building-frr-for-centos6.rst \ doc/developer/building-frr-for-centos7.rst \ doc/developer/building-frr-for-debian8.rst \ doc/developer/building-frr-for-debian9.rst \ + doc/developer/building-frr-for-debian12.rst \ doc/developer/building-frr-for-fedora.rst \ doc/developer/building-frr-for-freebsd10.rst \ doc/developer/building-frr-for-freebsd11.rst \ diff --git a/doc/developer/topotests-markers.rst b/doc/developer/topotests-markers.rst index 9f92412595bd..670bf0d255d0 100644 --- a/doc/developer/topotests-markers.rst +++ b/doc/developer/topotests-markers.rst @@ -12,6 +12,7 @@ systems, all tests must be marked with at least one of the following markers: * eigrpd * isisd * ldpd +* mgmtd * nhrpd * ospf6d * ospfd @@ -64,12 +65,12 @@ Adding a single marker: import pytest ... - + # add after imports, before defining classes or functions: pytestmark = pytest.mark.bfdd - + ... - + def test_using_bfdd(): @@ -79,16 +80,16 @@ Adding multiple markers: import pytest ... - + # add after imports, before defining classes or functions: pytestmark = [ pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.ospf6d ] - + ... - + def test_using_bgpd_ospfd_ospf6d(): diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 87edad40bb58..52c0361a025e 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -8,14 +8,15 @@ Topotests is a suite of topology tests for FRR built on top of micronet. Installation and Setup ---------------------- -Topotests run under python3. Additionally, for ExaBGP (which is used -in some of the BGP tests) an older python2 version (and the python2 -version of ``pip``) must be installed. +Topotests run under python3. -Tested with Ubuntu 20.04,Ubuntu 18.04, and Debian 11. +Tested with Ubuntu 22.04,Ubuntu 20.04, and Debian 12. -Instructions are the same for all setups (i.e. ExaBGP is only used for -BGP tests). +Python protobuf version < 4 is required b/c python protobuf >= 4 requires a +protoc >= 3.19, and older package versions are shipped by in the above distros. + +Instructions are the same for all setups. However, ExaBGP is only used for +BGP tests. Tshark is only required if you enable any packet captures on test runs. @@ -35,15 +36,24 @@ Installing Topotest Requirements tshark \ valgrind python3 -m pip install wheel - python3 -m pip install 'pytest>=6.2.4' - python3 -m pip install 'pytest-xdist>=2.3.0' + python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0' python3 -m pip install 'scapy>=2.4.5' python3 -m pip install xmltodict - # Use python2 pip to install older ExaBGP - python2 -m pip install 'exabgp<4.0.0' + python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311 useradd -d /var/run/exabgp/ -s /bin/false exabgp - # To enable the gRPC topotest install: +The version of protobuf package that is installed on your system will determine +which versions of the python protobuf packages you need to install. + +.. code:: shell + + # - Either - For protobuf version <= 3.12 + python3 -m pip install 'protobuf<4' + + # - OR- for protobuf version >= 3.21 + python3 -m pip install 'protobuf>=4' + + # To enable the gRPC topotest also install: python3 -m pip install grpcio grpcio-tools @@ -116,9 +126,9 @@ If you prefer to manually build FRR, then use the following suggested config: ./configure \ --prefix=/usr \ - --localstatedir=/var/run/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --enable-vtysh \ --enable-pimd \ --enable-pim6d \ @@ -230,8 +240,8 @@ the number of the test we are interested in along with ``--errmsg`` option. ~/frr/tests/topotests# ./analyze.py -Ar run-save -T0 --errmsg bgp_multiview_topo1/test_bgp_multiview_topo1.py::test_bgp_converge: AssertionError: BGP did not converge: - IPv4 Unicast Summary (VIEW 1): - BGP router identifier 172.30.1.1, local AS number 100 vrf-id -1 + IPv4 Unicast Summary: + BGP router identifier 172.30.1.1, local AS number 100 VIEW 1 vrf-id -1 BGP table version 1 RIB entries 1, using 184 bytes of memory Peers 3, using 2169 KiB of memory @@ -266,8 +276,8 @@ select the first failed test case. > assert False, "BGP did not converge:\n%s" % bgpStatus E AssertionError: BGP did not converge: E - E IPv4 Unicast Summary (VIEW 1): - E BGP router identifier 172.30.1.1, local AS number 100 vrf-id -1 + E IPv4 Unicast Summary: + E BGP router identifier 172.30.1.1, local AS number 100 VIEW 1 vrf-id -1 [...] E Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc E 172.16.1.1 4 65001 0 0 0 0 0 never Connect 0 N/A @@ -386,8 +396,9 @@ for ``master`` branch: ./bootstrap.sh ./configure \ --enable-address-sanitizer \ - --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ - --localstatedir=/var/run/frr \ + --prefix=/usr/lib/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ --with-moduledir=/usr/lib/frr/modules \ --enable-multipath=0 --enable-rtadv \ @@ -400,6 +411,14 @@ for ``master`` branch: and create ``frr`` user and ``frrvty`` group as shown above. +Newer versions of Address Sanitizers require a sysctl to be changed +to allow for the tests to be successfully run. This is also true +for Undefined behavior Sanitizers as well as Memory Sanitizer. + +.. code:: shell + + sysctl vm.mmap_rnd_bits=28 + Debugging Topotest Failures ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -470,10 +489,10 @@ One can live view daemon or the frr logs in separate windows using the For each capture a window is opened displaying a live summary of the captured packets. Additionally, the entire packet stream is captured in a pcap file in -the tests log directory e.g.,:: +the tests log directory e.g., -When using a unified log file `frr.log` one substitutes `frr` for the daemon -name in the ``--logd`` CLI option, e.g., +When using a unified log file ``frr.log`` one substitutes ``frr`` for the +daemon name in the ``--logd`` CLI option, e.g., .. code:: shell @@ -559,6 +578,8 @@ Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``. sudo -E pytest --vtysh=rt1,rt2 all-protocol-startup +.. _debug_with_gdb: + Debugging with GDB """""""""""""""""" @@ -583,6 +604,12 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router --gdb-breakpoints=nb_config_diff \ all-protocol-startup +Finally, for Emacs users, you can specify ``--gdb-use-emacs``. When specified +the first router and daemon to be launched in gdb will be launched and run with +Emacs gdb functionality by using `emacsclient --eval` commands. This provides an +IDE debugging experience for Emacs users. This functionality works best when +using password-less sudo. + Reporting Memleaks with FRR Memory Statistics """"""""""""""""""""""""""""""""""""""""""""" @@ -617,6 +644,8 @@ allocations upon exit. To enable also reporting of memory leaks to a specific location, define an environment variable ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.: +:: + export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_" For tests that support the TOPOTESTS_CHECK_MEMLEAK environment variable, this @@ -629,16 +658,26 @@ Detecting Memleaks with Valgrind """""""""""""""""""""""""""""""" Topotest can automatically launch all daemons with ``valgrind`` to check for -memleaks. This is enabled by specifying 1 or 2 CLI arguments. -``--valgrind-memleaks`` will enable general memleak detection, and -``--valgrind-extra`` enables extra functionality including generating a -suppression file. The suppression file ``tools/valgrind.supp`` is used when -memleak detection is enabled. +memleaks. This is enabled by specifying 1 to 3 CLI arguments. +``--valgrind-memleaks`` enables memleak detection. ``--valgrind-extra`` enables +extra functionality including generating a suppression file. The suppression +file ``tools/valgrind.supp`` is used when memleak detection is enabled. Finally, +``--valgrind-leak-kinds=KINDS`` can be used to modify what types of links are +reported. This corresponds to valgrind's ``--show-link-kinds`` arg. The value is +either ``all`` or a comma-separated list of types: +``definite,indirect,possible,reachable``. The default is ``definite,possible``. .. code:: shell sudo -E pytest --valgrind-memleaks all-protocol-startup +.. note:: GDB can be used in conjection with valgrind. + + When you enable ``--valgrind-memleaks`` and you also launch various daemons + under GDB (debug_with_gdb_) topotest will connect the two utilities using + ``--vgdb-error=0`` and attaching to a ``vgdb`` process. This is very + useful for debugging bugs with use of uninitialized errors, et al. + Collecting Performance Data using perf(1) """"""""""""""""""""""""""""""""""""""""" @@ -660,6 +699,106 @@ during the config_timing test. To specify different arguments for ``perf record``, one can use the ``--perf-options`` this will replace the ``-g`` used by default. +Running Daemons under RR Debug (``rr record``) +"""""""""""""""""""""""""""""""""""""""""""""" + +Topotest can automatically launch any daemon under ``rr(1)`` to collect +execution state. The daemon is run in the foreground with ``rr record``. + +The execution state will be saved in the router specific directory +(in a `rr` subdir that rr creates) under the test's run directoy. + +Here's an example of collecting ``rr`` execution state from ``mgmtd`` on router +``r1`` during the ``config_timing`` test. + +.. code:: console + + $ sudo -E pytest --rr-routers=r1 --rr-daemons=mgmtd config_timing + ... + $ find /tmp/topotests/ -name '*perf.data*' + /tmp/topotests/config_timing.test_config_timing/r1/perf.data + +To specify additional arguments for ``rr record``, one can use the +``--rr-options``. + +.. _code_coverage: + +Code coverage +""""""""""""" +Code coverage reporting requires installation of the ``gcov`` and ``lcov`` +packages. + +Code coverage can automatically be gathered for any topotest run. To support +this FRR must first be compiled with the ``--enable-gcov`` configure option. +This will cause *.gnco files to be created during the build. When topotests are +run the statistics are generated and stored in *.gcda files. Topotest +infrastructure will gather these files, capture the information into a +``coverage.info`` ``lcov`` file and also report the coverage summary. + +To enable code coverage support pass the ``--cov-topotest`` argument to pytest. +If you build your FRR in a directory outside of the FRR source directory you +will also need to pass the ``--cov-frr-build-dir`` argument specifying the build +directory location. + +During the topotest run the *.gcda files are generated into a ``gcda`` +sub-directory of the top-level run directory (i.e., normally +``/tmp/topotests/gcda``). These files will then be copied at the end of the +topotest run into the FRR build directory where the ``gcov`` and ``lcov`` +utilities expect to find them. This is done to deal with the various different +file ownership and permissions. + +At the end of the run ``lcov`` will be run to capture all of the coverage data +into a ``coverage.info`` file. This file will be located in the top-level run +directory (i.e., normally ``/tmp/topotests/coverage.info``). + +The ``coverage.info`` file can then be used to generate coverage reports or file +markup (e.g., using the ``genhtml`` utility) or enable markup within your +IDE/editor if supported (e.g., the emacs ``cov-mode`` package) + +NOTE: the *.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do +not remove them they will aggregate data across multiple topotest runs. + +How to reproduce failed Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generally tests fail but recreating the test failure reliably is not necessarily +easy, or it happens once every 10 runs locally. Here are some generic strategies +that are employed to allow for the test to be reproduced reliably + +.. code:: console + + cd + ln -s test_the_test_name.py test_a.py + ln -s test_the_test_name.py test_b.py + +This allows you to run multiple copies of the same test with one full test run. +Additionally if you need to modify the test you don't need to recopy everything +to make it work. By adding multiple copies of the same occassionally failing test +you raise the odds of it failing again. Additionally you have easily accessible +good and bad runs to compare. + +.. code:: console + + sudo -E python3 -m pytest -n --dist=loadfile + +Choose a n value that is greater than the number of cpu's avalaible on the system. +This changes the timing and may or may not make it more likely that the test fails. +Be aware, though, that this changes memory requirements as well as may make other +tests fail more often as well. You should choose values that do not cause the system +to go into swap usage. + +.. code:: console + + stress -n + +By filling up cpu's with programs that do nothing you also change the timing again and +may cause the problem to happen more often. + +There is no magic bullet here. You as a developer might have to experiment with different +values and different combinations of the above to cause the problem to happen more often. +These are just the tools that we know of at this point in time. + + .. _topotests_docker: Running Tests with Docker @@ -1201,6 +1340,15 @@ Example: router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF) +or using unified config (specifying which daemons to run is optional): + +.. code:: py + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)), [ + TopoRouter.RD_ZEBRA + TopoRouter.RD_MGMTD, + TopoRouter.RD_BGP]) - The topology definition or build function diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 5199d42db312..a6bdec1e5bcf 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -167,28 +167,26 @@ as early as possible, i.e. the first 2-week window. For reference, the expected release schedule according to the above is: +---------+------------+------------+------------+ -| Release | 2023-07-04 | 2023-10-31 | 2024-02-27 | +| Release | 2024-03-12 | 2024-07-02 | 2024-11-05 | +---------+------------+------------+------------+ -| RC | 2023-06-20 | 2023-10-17 | 2024-02-13 | +| RC | 2024-02-27 | 2024-06-18 | 2024-10-22 | +---------+------------+------------+------------+ -| dev/X.Y | 2023-06-06 | 2023-10-03 | 2024-01-30 | +| dev/X.Y | 2024-02-13 | 2024-06-04 | 2024-10-08 | +---------+------------+------------+------------+ -| freeze | 2023-05-23 | 2023-09-19 | 2024-01-16 | +| freeze | 2024-01-30 | 2024-05-21 | 2024-09-24 | +---------+------------+------------+------------+ Here is the hint on how to get the dates easily: .. code-block:: console - ~$ # Last freeze date was 2023-09-19 - ~$ date +%F --date='2023-09-19 +119 days' # Next freeze date - 2024-01-16 - ~$ date +%F --date='2024-01-16 +14 days' # Next dev/X.Y date - 2024-01-30 - ~$ date +%F --date='2024-01-30 +14 days' # Next RC date - 2024-02-13 - ~$ date +%F --date='2024-02-13 +14 days' # Next Release date - 2024-02-27 + ~$ # Release date is 2023-11-07 (First Tuesday each March/July/November) + ~$ date +%F --date='2023-11-07 -42 days' # Next freeze date + 2023-09-26 + ~$ date +%F --date='2023-11-07 -28 days' # Next dev/X.Y date + 2023-10-10 + ~$ date +%F --date='2023-11-07 -14 days' # Next RC date + 2023-10-24 Each release is managed by one or more volunteer release managers from the FRR community. These release managers are expected to handle the branch for a period @@ -819,6 +817,7 @@ The project provides multiple tools to allow you to correctly style your code as painlessly as possible, primarily built around ``clang-format``. clang-format + In the project root there is a :file:`.clang-format` configuration file which can be used with the ``clang-format`` source formatter tool from the LLVM project. Most of the time, this is the easiest and smartest tool to @@ -877,6 +876,8 @@ clang-format checkpatch.sh checkpatch.pl + .. seealso:: :ref:`checkpatch` + In the Linux kernel source tree there is a Perl script used to check incoming patches for style errors. FRR uses a shell script front end and an adapted version of the perl script for the same purpose. These scripts can @@ -1305,6 +1306,16 @@ MemorySanitizer to ``configure``. +UndefinedSanitizer + Similar to AddressSanitizer, this tool provides runtime instrumentation for + detecting use of undefined behavior in C. Testing your own code with this + tool before submission is encouraged. You can enable it by passing:: + + --enable-undefined-sanitizer + + to ``configure``. If you run FRR with this you will probably also have + to set ``sudo sysctl vm.mmap_rnd_bits=28`` + All of the above tools are available in the Clang/LLVM toolchain since 3.4. AddressSanitizer and ThreadSanitizer are available in recent versions of GCC, but are no longer actively maintained. MemorySanitizer is not available in GCC. @@ -1314,6 +1325,14 @@ but are no longer actively maintained. MemorySanitizer is not available in GCC. The different Sanitizers are mostly incompatible with each other. Please refer to GCC/LLVM documentation for details. +.. note:: + + The different sanitizers also require setting + + sysctl vm.mmap_rnd_bits=28 + + in order to work properly. + frr-format plugin This is a GCC plugin provided with FRR that does extended type checks for ``%pFX``-style printfrr extensions. To use this plugin, @@ -1353,12 +1372,12 @@ Coverity static analysis errors prior to submission using the be installed. For example, this can be accomplished on Ubuntu with the ``sudo apt-get install clang-tools`` command. Then, touch the files you want scanned and invoke the ``scan-build`` command. For example:: - + cd ~/GitHub/frr touch ospfd/ospf_flood.c ospfd/ospf_vty.c ospfd/ospf_opaque.c cd build scan-build make -j32 - + The results of the scan including any static analysis errors will appear inline. Additionally, there will a directory in the /tmp containing the Coverity reports (e.g., scan-build-2023-06-09-120100-473730-1). diff --git a/doc/developer/zebra.rst b/doc/developer/zebra.rst index 5f039758a5ee..482df96267a3 100644 --- a/doc/developer/zebra.rst +++ b/doc/developer/zebra.rst @@ -159,229 +159,22 @@ Past Versions Zebra Protocol Commands ----------------------- -+------------------------------------+-------+ -| Command | Value | -+====================================+=======+ -| ZEBRA_INTERFACE_ADD | 0 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_DELETE | 1 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_ADDRESS_ADD | 2 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_ADDRESS_DELETE | 3 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_UP | 4 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_DOWN | 5 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_SET_MASTER | 6 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_SET_PROTODOWN | 7 | -+------------------------------------+-------+ -| ZEBRA_ROUTE_ADD | 8 | -+------------------------------------+-------+ -| ZEBRA_ROUTE_DELETE | 9 | -+------------------------------------+-------+ -| ZEBRA_ROUTE_NOTIFY_OWNER | 10 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ADD | 11 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DELETE | 12 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DEFAULT_ADD | 13 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_DEFAULT_DELETE | 14 | -+------------------------------------+-------+ -| ZEBRA_ROUTER_ID_ADD | 15 | -+------------------------------------+-------+ -| ZEBRA_ROUTER_ID_DELETE | 16 | -+------------------------------------+-------+ -| ZEBRA_ROUTER_ID_UPDATE | 17 | -+------------------------------------+-------+ -| ZEBRA_HELLO | 18 | -+------------------------------------+-------+ -| ZEBRA_CAPABILITIES | 19 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_REGISTER | 20 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_UNREGISTER | 21 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_UPDATE | 22 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_NBR_ADDRESS_ADD | 23 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_NBR_ADDRESS_DELETE | 24 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_BFD_DEST_UPDATE | 25 | -+------------------------------------+-------+ -| ZEBRA_IMPORT_ROUTE_REGISTER | 26 | -+------------------------------------+-------+ -| ZEBRA_IMPORT_ROUTE_UNREGISTER | 27 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_REGISTER | 29 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_DEREGISTER | 30 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_UPDATE | 31 | -+------------------------------------+-------+ -| ZEBRA_BFD_DEST_REPLAY | 32 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ROUTE_ADD | 33 | -+------------------------------------+-------+ -| ZEBRA_REDISTRIBUTE_ROUTE_DEL | 34 | -+------------------------------------+-------+ -| ZEBRA_VRF_UNREGISTER | 35 | -+------------------------------------+-------+ -| ZEBRA_VRF_ADD | 36 | -+------------------------------------+-------+ -| ZEBRA_VRF_DELETE | 37 | -+------------------------------------+-------+ -| ZEBRA_VRF_LABEL | 38 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_VRF_UPDATE | 39 | -+------------------------------------+-------+ -| ZEBRA_BFD_CLIENT_REGISTER | 40 | -+------------------------------------+-------+ -| ZEBRA_BFD_CLIENT_DEREGISTER | 41 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_ENABLE_RADV | 42 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_DISABLE_RADV | 43 | -+------------------------------------+-------+ -| ZEBRA_NEXTHOP_LOOKUP_MRIB | 44 | -+------------------------------------+-------+ -| ZEBRA_INTERFACE_LINK_PARAMS | 45 | -+------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_ADD | 46 | -+------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_DELETE | 47 | -+------------------------------------+-------+ -| ZEBRA_MPLS_LABELS_REPLACE | 48 | -+------------------------------------+-------+ -| ZEBRA_IPMR_ROUTE_STATS | 49 | -+------------------------------------+-------+ -| ZEBRA_LABEL_MANAGER_CONNECT | 50 | -+------------------------------------+-------+ -| ZEBRA_LABEL_MANAGER_CONNECT_ASYNC | 51 | -+------------------------------------+-------+ -| ZEBRA_GET_LABEL_CHUNK | 52 | -+------------------------------------+-------+ -| ZEBRA_RELEASE_LABEL_CHUNK | 53 | -+------------------------------------+-------+ -| ZEBRA_FEC_REGISTER | 54 | -+------------------------------------+-------+ -| ZEBRA_FEC_UNREGISTER | 55 | -+------------------------------------+-------+ -| ZEBRA_FEC_UPDATE | 56 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_DEFAULT_GW | 57 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_SVI_MACIP | 58 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_SUBNET | 59 | -+------------------------------------+-------+ -| ZEBRA_ADVERTISE_ALL_VNI | 60 | -+------------------------------------+-------+ -| ZEBRA_LOCAL_ES_ADD | 61 | -+------------------------------------+-------+ -| ZEBRA_LOCAL_ES_DEL | 62 | -+------------------------------------+-------+ -| ZEBRA_VNI_ADD | 63 | -+------------------------------------+-------+ -| ZEBRA_VNI_DEL | 64 | -+------------------------------------+-------+ -| ZEBRA_L3VNI_ADD | 65 | -+------------------------------------+-------+ -| ZEBRA_L3VNI_DEL | 66 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_VTEP_ADD | 67 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_VTEP_DEL | 68 | -+------------------------------------+-------+ -| ZEBRA_MACIP_ADD | 69 | -+------------------------------------+-------+ -| ZEBRA_MACIP_DEL | 70 | -+------------------------------------+-------+ -| ZEBRA_IP_PREFIX_ROUTE_ADD | 71 | -+------------------------------------+-------+ -| ZEBRA_IP_PREFIX_ROUTE_DEL | 72 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_MACIP_ADD | 73 | -+------------------------------------+-------+ -| ZEBRA_REMOTE_MACIP_DEL | 74 | -+------------------------------------+-------+ -| ZEBRA_DUPLICATE_ADDR_DETECTION | 75 | -+------------------------------------+-------+ -| ZEBRA_PW_ADD | 76 | -+------------------------------------+-------+ -| ZEBRA_PW_DELETE | 77 | -+------------------------------------+-------+ -| ZEBRA_PW_SET | 78 | -+------------------------------------+-------+ -| ZEBRA_PW_UNSET | 79 | -+------------------------------------+-------+ -| ZEBRA_PW_STATUS_UPDATE | 80 | -+------------------------------------+-------+ -| ZEBRA_RULE_ADD | 81 | -+------------------------------------+-------+ -| ZEBRA_RULE_DELETE | 82 | -+------------------------------------+-------+ -| ZEBRA_RULE_NOTIFY_OWNER | 83 | -+------------------------------------+-------+ -| ZEBRA_TABLE_MANAGER_CONNECT | 84 | -+------------------------------------+-------+ -| ZEBRA_GET_TABLE_CHUNK | 85 | -+------------------------------------+-------+ -| ZEBRA_RELEASE_TABLE_CHUNK | 86 | -+------------------------------------+-------+ -| ZEBRA_IPSET_CREATE | 87 | -+------------------------------------+-------+ -| ZEBRA_IPSET_DESTROY | 88 | -+------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_ADD | 89 | -+------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_DELETE | 90 | -+------------------------------------+-------+ -| ZEBRA_IPSET_NOTIFY_OWNER | 91 | -+------------------------------------+-------+ -| ZEBRA_IPSET_ENTRY_NOTIFY_OWNER | 92 | -+------------------------------------+-------+ -| ZEBRA_IPTABLE_ADD | 93 | -+------------------------------------+-------+ -| ZEBRA_IPTABLE_DELETE | 94 | -+------------------------------------+-------+ -| ZEBRA_IPTABLE_NOTIFY_OWNER | 95 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_FLOOD_CONTROL | 96 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_SG_ADD | 97 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_SG_DEL | 98 | -+------------------------------------+-------+ -| ZEBRA_VXLAN_SG_REPLAY | 99 | -+------------------------------------+-------+ -| ZEBRA_MLAG_PROCESS_UP | 100 | -+------------------------------------+-------+ -| ZEBRA_MLAG_PROCESS_DOWN | 101 | -+------------------------------------+-------+ -| ZEBRA_MLAG_CLIENT_REGISTER | 102 | -+------------------------------------+-------+ -| ZEBRA_MLAG_CLIENT_UNREGISTER | 103 | -+------------------------------------+-------+ -| ZEBRA_MLAG_FORWARD_MSG | 104 | -+------------------------------------+-------+ -| ZEBRA_ERROR | 105 | -+------------------------------------+-------+ -| ZEBRA_CLIENT_CAPABILITIES | 106 | -+------------------------------------+-------+ -| ZEBRA_OPAQUE_MESSAGE | 107 | -+------------------------------------+-------+ -| ZEBRA_OPAQUE_REGISTER | 108 | -+------------------------------------+-------+ -| ZEBRA_OPAQUE_UNREGISTER | 109 | -+------------------------------------+-------+ -| ZEBRA_NEIGH_DISCOVER | 110 | -+------------------------------------+-------+ +The definitions of zebra protocol commands can be found at ``lib/zclient.h``. + + +Zebra Dataplane +=============== + +The zebra dataplane subsystem provides a framework for FIB +programming. Zebra uses the dataplane to program the local kernel as +it makes changes to objects such as IP routes, MPLS LSPs, and +interface IP addresses. The dataplane runs in its own pthread, in +order to off-load work from the main zebra pthread. + +The zebra dataplane API is versioned; the version number must be +updated along with API changes. Plugins can test the current version +number and confirm that they are compatible with the current version. + Dataplane batching ================== diff --git a/doc/figures/cli-oper-state.drawio b/doc/figures/cli-oper-state.drawio new file mode 100644 index 000000000000..4b86b58f7c7c --- /dev/null +++ b/doc/figures/cli-oper-state.drawio @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/figures/cli-oper-state.svg b/doc/figures/cli-oper-state.svg new file mode 100644 index 000000000000..bda7d7be8e49 --- /dev/null +++ b/doc/figures/cli-oper-state.svg @@ -0,0 +1,3 @@ + + +
Frontend CLI (mgmtd)
Frontend CLI (mgmtd)
MGMTD
MGMTD
xpath
xpath
txn
txn
clients (bitmask)
clients (bitmask)
fe_adapter_handle_get_tree
fe_adapter_handle_get_tree
be_adapter_handle_get_tree
mgmt_txn_notify_tree_data_reply
------------------------------------
merge tree data
when all clients respond or timeout
be_adapter_handle_get_tree...
mgmt_txn_send_get_tree_oper
mgmt_txn_send_get_tree_oper
mgmt_be_send_native
mgmt_be_send_native
socket connection
FE adapter -> FE client
MGMT_MSG_CODE_TREE_DATA
struct mgmt_msg_tree_data
socket connection...
txn_get_tree_data_done
fe_adapter_send_tree_data
txn_get_tree_data_done...
session->get_tree_notify
session->get_tree_notify
vty_mgmt_resume_response
vty_mgmt_resume_response
vty_mgmt_get_tree_result_notified
displays result
vty_mgmt_get_tree_result_notified...
clients (bitmask)
clients (bitmask)
mgmt_be_interested_clients
mgmt_be_interested_clients
vty_mgmt_send_get_tree_req
vty_mgmt_send_get_tree_req
socket connection
FE client -> FE adapter
MGMT_MSG_CODE_GET_TREE
struct mgmt_msg_get_tree
socket connection...
mgmt_fe_send_get_tree_req
mgmt_fe_send_get_tree_req
xpath
xpath
fe_adapter_handle_native_msg
fe_adapter_handle_native_msg
"show mgmt get-data-tree WORD$path [json|xml]"
"show mgmt get-data-tree WORD...
EVENT: VTYSH_READ
EVENT: VTYSH_READ
VTYSH
VTYSH
mgmt_create_txn
mgmt_create_txn
mgmt_txn_req_alloc
mgmt_txn_req_alloc
txn_req
MGMTD_TXN_PROC_GETTREE
txn_req...
for each of the clients
in bitmask
for ea...
be_client_send_native_msg
be_client_send_native_msg
be_adapter_handle_native_msg
be_adapter_handle_native_msg
socket connection
BE client -> BE adapter
MGMT_MSG_CODE_TREE_DATA
struct mgmt_msg_tree_data
socket connection...
be_client_send_native_msg
be_client_send_native_msg
Backend Client (ospfd, staticd, ...)
Backend Client (ospfd, staticd, ...)
(1) build oper state tree
struct mgmt_msg_tree_data
(1) build oper state tree...
(2)
(2)
be_client_handle_get_tree
be_client_handle_get_tree
nb_oper_data_iterate
nb_oper_data_iterate
be_client_handle_native_msg
be_client_handle_native_msg
be_client_send_native_msg
be_client_send_native_msg
for each of the
queried BE clients
for ea...
socket connection
BE adapter -> BE client
MGMT_MSG_CODE_GET_TREE
struct mgmt_msg_get_tree
socket connection...
fe_client_handle_native_msg
fe_client_handle_native_msg
socket async
socket async
timer/event async
timer/event async
function sync
function sync
mgmt_fe_adapter.c
mgmt_fe_adapter.c
mgmt_txn.c
mgmt_txn.c
mgmt_be_adapter.c
mgmt_be_adapter.c
z
z
Text is not SVG - cannot display
\ No newline at end of file diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst index e335ed120bde..3f1091620730 100644 --- a/doc/manpages/bfd-options.rst +++ b/doc/manpages/bfd-options.rst @@ -1,10 +1,33 @@ -BFD SOCKET ----------- +BFD +--- -The following option controls the BFD daemon control socket location. +The following options controls the BFD daemon auxiliary sockets. -.. option:: --bfdctl bfd-control-socket +.. option:: --dplaneaddr :
[<:port>] - Opens the BFD daemon control socket located at the pointed location. + Configure the distributed BFD data plane listening socket bind address. - (default: |INSTALL_PREFIX_STATE|/bfdd.sock) + One would expect the data plane to run in the same machine as FRR, so + the suggested configuration would be: + + ``--dplaneaddr unix:/var/run/frr/bfdd_dplane.sock`` + + Or using IPv4: + + ``--dplaneaddr ipv4:127.0.0.1`` + + Or using IPv6: + + ``--dplaneaddr ipv6:[::1]`` + + It is also possible to specify a port (for IPv4/IPv6 only): + + ``--dplaneaddr ipv6:[::1]:50701`` + + (if omitted the default port is ``50700``). + + It is also possible to operate in client mode (instead of listening for + connections). To connect to a data plane server append the letter 'c' to + the protocol, example: + + ``--dplaneaddr ipv4c:127.0.0.1`` diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py index 73dea094ae9f..995885b22039 100644 --- a/doc/manpages/conf.py +++ b/doc/manpages/conf.py @@ -91,7 +91,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index debc7f188909..000000000000 --- a/doc/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -sphinx==4.0.2 diff --git a/doc/user/.readthedocs.yaml b/doc/user/.readthedocs.yaml new file mode 100644 index 000000000000..ba5698c1d50e --- /dev/null +++ b/doc/user/.readthedocs.yaml @@ -0,0 +1,15 @@ +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +python: + install: + - requirements: doc/user/requirements.txt +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/user/conf.py diff --git a/doc/user/overview.rst b/doc/user/about.rst similarity index 94% rename from doc/user/overview.rst rename to doc/user/about.rst index a1cb0cc5793e..ba80a324d3bb 100644 --- a/doc/user/overview.rst +++ b/doc/user/about.rst @@ -1,47 +1,8 @@ .. _overview: -******** -Overview -******** - -`FRR`_ is a fully featured, high performance, free software IP routing suite. - -FRR implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and -more (see :ref:`feature-matrix`), as well as many of their extensions. - -FRR is a high performance suite written primarily in C. It can easily handle -full Internet routing tables and is suitable for use on hardware ranging from -cheap SBCs to commercial grade routers. It is actively used in production by -hundreds of companies, universities, research labs and governments. - -FRR is distributed under GPLv2, with development modeled after the Linux -kernel. Anyone may contribute features, bug fixes, tools, documentation -updates, or anything else. - -FRR is a fork of `Quagga `_. - -.. _how-to-get-frr: - -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - -Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/ -& https://rpm.frrouting.org/ respectively. - -For instructions on installing from source, refer to the -`developer documentation `_. - - -.. _about-frr: - +********* About FRR -========= +********* FRR provides IP routing services. Its role in a networking stack is to exchange routing information with other routers, make routing and policy decisions, and @@ -55,11 +16,8 @@ light L2 functionality as well, but this is mostly left to the platform. This makes it suitable for deployments ranging from small home networks with static routes to Internet exchanges running full Internet tables. -FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. -Feature support varies by platform; see the :ref:`feature-matrix`. - System Requirements -------------------- +=================== System resources needed by FRR are highly dependent on workload. Routing software performance is particularly susceptible to external factors such as: @@ -86,8 +44,8 @@ information with peers about how to forward packets. Forwarding plane performance largely depends on choice of NIC / ASIC. -System Architecture -------------------- +Architecture +============ .. index:: pair: architecture; FRR @@ -146,9 +104,8 @@ routing stack. .. _supported-platforms: -Supported Platforms -------------------- - +Platform Support +================ Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not too difficult as platform dependent code should be mostly limited to the @@ -366,6 +323,8 @@ BGP :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.` - :rfc:`5668` :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.` +- :rfc:`5701` + :t:`IPv6 Address Specific BGP Extended Community Attribute. Y. Rekhter. 2009.` - :rfc:`6286` :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.` - :rfc:`6472` @@ -428,6 +387,8 @@ BGP :t:`Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages. A. Azimov, E. Bogomazov, R. Bush, K. Patel, K. Sriram. May 2022.` - :rfc:`9384` :t:`A BGP Cease NOTIFICATION Subcode for Bidirectional Forwarding Detection (BFD). J. Haas. March 2023.` +- :rfc:`9494` + :t:`Long-Lived Graceful Restart for BGP. J. Uttaro, E. Chen, B. Decraene, J. Scudder. November 2023.` OSPF ---- diff --git a/doc/user/babeld.rst b/doc/user/babeld.rst index bda0045a603a..b7b7c1fcb43f 100644 --- a/doc/user/babeld.rst +++ b/doc/user/babeld.rst @@ -26,8 +26,7 @@ The *zebra* daemon must be running before *babeld* is invoked. Also, if *zebra* is restarted then *babeld* must be too. -Configuration of *babeld* is done in its configuration file -:file:`babeld.conf`. +.. include:: config-include.rst .. _babel-configuration: diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 337cfff9378f..5fdd1887fa32 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -11,45 +11,22 @@ The following sections discuss commands common to all the routing daemons. Config Commands =============== - - - - -In a config file, you can write the debugging options, a vty's password, +In the config file, you can write the debugging options, a vty's password, routing daemon configurations, a log file name, and so forth. This information forms the initial command set for a routing beast as it is starting. -Config files are generally found in |INSTALL_PREFIX_ETC|. +.. _config-file: -Config Methods --------------- - -There are two ways of configuring FRR. +Integrated Config File +---------------------- -Traditionally each of the daemons had its own config file. The daemon name plus -``.conf`` was the default config file name. For example, zebra's default config -file was :file:`zebra.conf`. This method is deprecated. - -Because of the amount of config files this creates, and the tendency of one -daemon to rely on others for certain functionality, most deployments now use -"integrated" configuration. In this setup all configuration goes into a single -file, typically :file:`/etc/frr/frr.conf`. When starting up FRR using an init -script or systemd, ``vtysh`` is invoked to read the config file and send the -appropriate portions to only the daemons interested in them. Running -configuration updates are persisted back to this single file using ``vtysh``. -This is the recommended method. To use this method, add the following line to -:file:`/etc/frr/vtysh.conf`: - -.. code-block:: frr - - service integrated-vtysh-config - -If you installed from source or used a package, this is probably already -present. - -If desired, you can specify a config file using the :option:`-f` or -:option:`--config_file` options when starting a daemon. +FRR uses a single configuration file located in |INSTALL_PREFIX_ETC|/frr.conf. +When FRR is started using an init script or ``systemd``, ``vtysh`` is invoked to +read the config file and send the appropriate portions to only the daemons +interested in them. Running configuration updates are persisted back to this +single file using ``vtysh`` as well. +.. include:: prior-config-files.rst .. _basic-config-commands: @@ -92,9 +69,6 @@ Basic Config Commands of some routine in FRR mistakenly blocking/hogging the processing loop and should be reported as a FRR bug. - The default limit is 5 seconds (i.e. 5000), but this can be changed by the - deprecated ``--enable-time-check=...`` compile-time option. - This command has no effect if :clicmd:`service cputime-stats` is disabled. .. clicmd:: service walltime-warning (1-4294967295) @@ -106,9 +80,6 @@ Basic Config Commands provide an immediate sign that FRR is not operating correctly due to externally caused starvation.) - The default limit is 5 seconds as above, including the same deprecated - ``--enable-time-check=...`` compile-time option. - .. clicmd:: log trap LEVEL These commands are deprecated and are present only for historical @@ -158,6 +129,20 @@ Basic Config Commands deprecated ``log trap`` command) will be used. The ``no`` form of the command disables logging to a file. +.. clicmd:: log daemon DAEMON file [FILENAME [LEVEL]] + + Configure file logging for a single FRR daemon. If you want to log + into a file, please specify ``filename`` as in this example: + + :: + + log daemon bgpd file /var/log/frr/bgpd.log informational + + If the optional second argument specifying the logging level is not present, + the default logging level (typically debugging, but can be changed using the + deprecated ``log trap`` command) will be used. The ``no`` form of the command + disables logging to a file for a single FRR daemon. + .. clicmd:: log syslog [LEVEL] Enable logging output to syslog. If the optional second argument specifying @@ -221,7 +206,7 @@ Basic Config Commands enabled log destinations. The note that logging includes full command lines, including passwords. If the daemon startup option `--command-log-always` is used to start the daemon then this command is turned on by default - and cannot be turned off and the [no] form of the command is dissallowed. + and cannot be turned off and the [no] form of the command is disallowed. .. clicmd:: log filtered-file [FILENAME [LEVEL]] @@ -679,25 +664,29 @@ Terminal Mode Commands .. _common-show-commands: -.. clicmd:: show thread cpu [r|w|t|e|x] +.. clicmd:: show event cpu [r|w|t|e|x] This command displays system run statistics for all the different event types. If no options is specified all different run types are displayed together. Additionally you can ask to look at (r)ead, (w)rite, (t)imer, - (e)vent and e(x)ecute thread event types. If you have compiled with - disable-cpu-time then this command will not show up. + (e)vent and e(x)ecute thread event types. -.. clicmd:: show thread poll +.. clicmd:: show event poll This command displays FRR's poll data. It allows a glimpse into how we are setting each individual fd for the poll command at that point in time. -.. clicmd:: show thread timers +.. clicmd:: show event timers This command displays FRR's timer data for timers that will pop in the future. +.. clicmd:: show configuration running [ [translate WORD]] [with-defaults] DAEMON + + This command displays the northbound/YANG configuration data for a + daemon in text/vty, json, or xml format. + .. clicmd:: show yang operational-data XPATH [{format |translate TRANSLATOR|with-config}] DAEMON Display the YANG operational data starting from XPATH. The default @@ -780,7 +769,7 @@ These options apply to all |PACKAGE_NAME| daemons. .. option:: --command-log-always Cause the daemon to always log commands entered to the specified log file. - This also makes the `no log commands` command dissallowed. Enabling this + This also makes the `no log commands` command disallowed. Enabling this is suggested if you have need to track what the operator is doing on this router. diff --git a/doc/user/basics.rst b/doc/user/basics.rst new file mode 100644 index 000000000000..4504e9893c41 --- /dev/null +++ b/doc/user/basics.rst @@ -0,0 +1,23 @@ +.. _basics: + +###### +Basics +###### + +.. toctree:: + :maxdepth: 2 + + basic + extlog + vtysh + grpc + filter + routemap + affinitymap + ipv6 + kernel + snmp + scripting + nexthop_groups + + diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 6c57822510a5..4c142cfbbb06 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -1,12 +1,19 @@ .. _bfd: -********************************** -Bidirectional Forwarding Detection -********************************** +*** +BFD +*** -:abbr:`BFD (Bidirectional Forwarding Detection)` stands for -Bidirectional Forwarding Detection and it is described and extended by -the following RFCs: +:abbr:`BFD (Bidirectional Forwarding Detection)` is: + + a protocol intended to detect faults in the bidirectional path between two + forwarding engines, including interfaces, data link(s), and to the extent + possible the forwarding engines themselves, with potentially very low + latency. + + -- :rfc:`5880` + +It is described and extended by the following RFCs: * :rfc:`5880` * :rfc:`5881` @@ -27,6 +34,8 @@ This document will focus on the later implementation: *bfdd*. Starting BFD ============ +.. include:: config-include.rst + *bfdd* default configuration file is :file:`bfdd.conf`. *bfdd* searches the current directory first then |INSTALL_PREFIX_ETC|/bfdd.conf. All of *bfdd*'s command must be configured in :file:`bfdd.conf`. @@ -36,21 +45,6 @@ may also be specified (:ref:`common-invocation-options`). .. program:: bfdd -.. option:: --bfdctl - - Set the BFD daemon control socket location. If using a non-default - socket location:: - - /usr/lib/frr/bfdd --bfdctl /tmp/bfdd.sock - - - The default UNIX socket location is: - - #define BFDD_CONTROL_SOCKET "|INSTALL_PREFIX_STATE|/bfdd.sock" - - This option overrides the location addition that the -N option provides - to the bfdd.sock - .. option:: --dplaneaddr :
[<:port>] Configure the distributed BFD data plane listening socket bind address. @@ -72,7 +66,7 @@ may also be specified (:ref:`common-invocation-options`). --dplaneaddr ipv6:[::1]:50701 - (if ommited the default port is ``50700``). + (if omitted the default port is ``50700``). It is also possible to operate in client mode (instead of listening for connections). To connect to a data plane server append the letter 'c' to diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index ba6c16056084..a569a9af2889 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -14,10 +14,7 @@ interdomain routing protocol. BGP-4 is described in :rfc:`1771` and updated by Starting BGP ============ -The default configuration file of *bgpd* is :file:`bgpd.conf`. *bgpd* searches -the current directory first, followed by |INSTALL_PREFIX_ETC|/bgpd.conf. All of -*bgpd*'s commands must be configured in :file:`bgpd.conf` when the integrated -config is not being used. +.. include:: config-include.rst *bgpd* specific invocation options are described below. Common options may also be specified (:ref:`common-invocation-options`). @@ -95,6 +92,12 @@ be specified (:ref:`common-invocation-options`). the operator has turned off communication to zebra and is running bgpd as a complete standalone process. +.. option:: -K, --graceful_restart + + Bgpd will use this option to denote either a planned FRR graceful + restart or a bgpd-only graceful restart, and this will drive the BGP + GR restarting router procedures. + LABEL MANAGER ------------- @@ -428,6 +431,11 @@ Route Selection Disabled by default. +.. clicmd:: bgp bestpath med missing-as-worst + + If the paths MED value is missing and this command is configured + then treat it as the worse possible value that it can be. + .. clicmd:: maximum-paths (1-128) Sets the maximum-paths value used for ecmp calculations for this @@ -461,6 +469,15 @@ Administrative Distance Metrics Sets the administrative distance for a particular route. + If the system has a static route configured from the kernel, it has a + distance of 0. In some cases, it might be useful to override the route + from the FRR. E.g.: Kernel has a statically configured default route, + and you received another default route from the BGP and want to install + it to be preferred over the static route. In such a case, you MUST set + a higher distance from the kernel. + + .. seealso:: :ref:`administrative-distance` + .. _bgp-requires-policy: Require policy on EBGP @@ -485,8 +502,8 @@ Require policy on EBGP exit1# show bgp summary - IPv4 Unicast Summary (VRF default): - BGP router identifier 10.10.10.1, local AS number 65001 vrf-id 0 + IPv4 Unicast Summary: + BGP router identifier 10.10.10.1, local AS number 65001 VRF default vrf-id 0 BGP table version 4 RIB entries 7, using 1344 bytes of memory Peers 2, using 43 KiB of memory @@ -518,6 +535,27 @@ Reject routes with AS_SET or AS_CONFED_SET types This command enables rejection of incoming and outgoing routes having AS_SET or AS_CONFED_SET type. +Enforce first AS +---------------- + +.. clicmd:: bgp enforce-first-as + + To configure a router to deny an update received from an external BGP (eBGP) + peer that does not list its autonomous system number at the beginning of + the `AS_PATH` in the incoming update, use the ``bgp enforce-first-as`` command + in router configuration mode. + + In order to exclude an arbitrary neighbor from this enforcement, use the + command ``no neighbor NAME enforce-first-as``. And vice-versa if a global + enforcement is disabled, you can override this behavior per neighbor too. + + Default: enabled. + +.. note:: + + If you have a peering to RS (Route-Server), most likely you MUST disable the + first AS enforcement. + Suppress duplicate updates -------------------------- @@ -557,26 +595,52 @@ Route Flap Dampening .. clicmd:: bgp dampening (1-45) (1-20000) (1-50000) (1-255) - This command enables BGP route-flap dampening and specifies dampening parameters. + This command enables (with optionally specified dampening parameters) or + disables route-flap dampening for all routes of a BGP instance. + +.. clicmd:: neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]] + + This command enables (with optionally specified dampening parameters) or + disables route-flap dampening for all routes learned from a BGP peer. + +.. clicmd:: neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]] + + This command enables (with optionally specified dampening parameters) or + disables route-flap dampening for all routes learned from peers of a peer + group. half-life - Half-life time for the penalty + Half-life time for the penalty in minutes (default value: 15). reuse-threshold - Value to start reusing a route + Value to start reusing a route (default value: 750). suppress-threshold - Value to start suppressing a route + Value to start suppressing a route (default value: 2000). max-suppress - Maximum duration to suppress a stable route + Maximum duration to suppress a stable route in minutes (default value: + 60). The route-flap damping algorithm is compatible with :rfc:`2439`. The use of - this command is not recommended nowadays. + these commands is not recommended nowadays. At the moment, route-flap dampening is not working per VRF and is working only for IPv4 unicast and multicast. + With different parameter sets configurable for BGP instances, peer groups and + peers, the active dampening profile for a route is chosen on the fly, + allowing for various changes in configuration (i.e. peer group memberships) + during runtime. The parameter sets are taking precedence in the following + order: + + 1. Peer + 2. Peer group + 3. BGP instance + + The negating commands do not allow to exclude a peer/peer group from a peer + group/BGP instances configuration. + .. seealso:: https://www.ripe.net/publications/docs/ripe-378 @@ -1022,6 +1086,52 @@ Default global mode is helper and default peer per mode is inherit from global. If per peer mode is configured, the GR mode of this particular peer will override the global mode. +.. _bgp-GR-config-mode-cmd: + +BGP GR Config Mode Commands +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: bgp graceful-restart + + This command will enable BGP graceful restart functionality for all BGP instances. + +.. clicmd:: bgp graceful-restart-disable + + This command will disable both the functionality graceful restart and helper + mode for all BGP instances + +.. clicmd:: bgp graceful-restart select-defer-time (0-3600) + + This is command, will set deferral time to value specified. + +.. clicmd:: bgp graceful-restart rib-stale-time (1-3600) + + This is command, will set the time for which stale routes are kept in RIB. + +.. clicmd:: bgp graceful-restart restart-time (0-4095) + + Set the time to wait to delete stale routes before a BGP open message + is received. + + Using with Long-lived Graceful Restart capability, this is recommended + setting this timer to 0 and control stale routes with + ``bgp long-lived-graceful-restart stale-time``. + + Default value is 120. + +.. clicmd:: bgp graceful-restart stalepath-time (1-4095) + + This is command, will set the max time (in seconds) to hold onto + restarting peer's stale paths. + + It also controls Enhanced Route-Refresh timer. + + If this command is configured and the router does not receive a Route-Refresh EoRR + message, the router removes the stale routes from the BGP table after the timer + expires. The stale path timer is started when the router receives a Route-Refresh + BoRR message + + .. _bgp-GR-global-mode-cmd: BGP GR Global Mode Commands @@ -1032,7 +1142,7 @@ BGP GR Global Mode Commands This command will enable BGP graceful restart functionality at the global level. -.. clicmd:: bgp graceful-restart disable +.. clicmd:: bgp graceful-restart-disable This command will disable both the functionality graceful restart and helper mode. @@ -1300,9 +1410,37 @@ section for the specific AF to redistribute into. Protocol availability for redistribution is determined by BGP AF; for example, you cannot redistribute OSPFv3 into ``address-family ipv4 unicast`` as OSPFv3 supports IPv6. -.. clicmd:: redistribute [metric (0-4294967295)] [route-map WORD] +.. clicmd:: redistribute [metric (0-4294967295)] [route-map WORD] + + Redistribute routes from other protocols into BGP. + + Note - When redistributing a static route, or any better Admin Distance route, + into BGP for which the same path is learned dynamically from another BGP + speaker, if the redistribute path is more preferred from a BGP Best Path + standpoint than the dynamically learned path, then BGP will not export + the best path to Zebra(RIB) for installation into the routing table, + unless BGP receives the path before the static route is created. + +.. clicmd:: redistribute (1-65535)] [metric (0-4294967295)] [route-map WORD] -Redistribute routes from other protocols into BGP. + Redistribute routes from a routing table ID into BGP. There are two + techniques for redistribution: + + - Standard Table Redistribution ``table (1-65535)``: + - Routes from the specified routing table ID are imported into the + default routing table using the ``ip import-table ID`` command. + - These routes are identified by the protocol type "T[ID]" when + displayed with ``show (ip|ipv6) route``. + - The ``redistribute table ID`` command then integrates these routes + into BGP. + + - Direct Table Redistribution ``table-direct (1-65535)``: + - This method directly imports routes from the designated routing table + ID into BGP, omitting the step of adding to the default routing table. + - This method is especially relevant when the specified table ID is + checked against routing by appending the appropriate `ip rules`. + +Redistribute routes from a routing table number into BGP. .. clicmd:: redistribute vnc-direct @@ -1423,6 +1561,27 @@ Defining Peers peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. +.. clicmd:: neighbor PEER remote-as auto + + The neighbor's ASN is detected automatically from the OPEN message. + +.. clicmd:: neighbor PEER oad + + Mark a peer belonging to the One Administrative Domain. + + Some networks span more than one autonomous system and require more + flexibility in the propagation of path attributes.It is worth noting that + these multi-AS networks have a common or single administrative entity. + These networks are said to belong to One Administrative Domain (OAD). + It is desirable to carry IBGP-only attributes across EBGP peerings when + the peers belong to an OAD. + + Enabling this peering sub-type will allow the propagation of non-transitive + attributes across EBGP peerings (e.g. local-preference). Make sure to + turn this peering type on for all peers in the OAD. + + Disabled by default. + .. clicmd:: bgp listen range peer-group PGNAME Accept connections from any peers in the specified prefix. Configuration @@ -1495,6 +1654,25 @@ Configuring Peers value is carried encoded as uint32. To enable backward compatibility we need to disable IEEE floating-point encoding option per-peer. +.. clicmd:: neighbor PEER extended-link-bandwidth + + By default bandwidth in extended communities is carried encoded as IEEE + floating-point format, and is limited to maximum of 25 Gbps. + + Enabling this parameter, you can use the bandwidth of to 4294967295 Mbps. + + This is disabled by default. + +.. clicmd:: neighbor PEER enforce-first-as + + Discard updates received from the specified (eBGP) peer if the AS_PATH + attribute does not contain the PEER's ASN as the first AS_PATH segment. + + You can enable or disable this enforcement globally too using + ``bgp enforce-first-as`` command. + + Default: enabled. + .. clicmd:: neighbor PEER extended-optional-parameters Force Extended Optional Parameters Length format to be used for OPEN messages. @@ -1525,11 +1703,14 @@ Configuring Peers IPv4 session addresses, see the ``neighbor PEER update-source`` command below. -.. clicmd:: neighbor PEER interface remote-as +.. clicmd:: neighbor PEER interface remote-as Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The session will be established via IPv6 link locals. Use ``internal`` for iBGP - and ``external`` for eBGP sessions, or specify an ASN if you wish. + and ``external`` for eBGP sessions, or specify an ASN if you wish. Finally + this connection type is meant for point to point connections. If you are + on an ethernet segment and attempt to use this with more than one bgp + neighbor, only one neighbor will come up, due to how this feature works. .. clicmd:: neighbor PEER next-hop-self [force] @@ -1548,10 +1729,12 @@ Configuring Peers .. clicmd:: neighbor PEER update-source - Specify the IPv4 source address to use for the :abbr:`BGP` session to this - neighbour, may be specified as either an IPv4 address directly or as an + Specify the IPv4 or IPv6 source address to use for the :abbr:`BGP` session to this + neighbour, may be specified as either an IP address directly or as an interface name (in which case the *zebra* daemon MUST be running in order - for *bgpd* to be able to retrieve interface state). + for *bgpd* to be able to retrieve interface state). When there are multiple + addresses on the choosen IFNAME then BGP will use the address that matches + the most number of bits in comparison to the destination peer address. .. code-block:: frr @@ -1594,7 +1777,18 @@ Configuring Peers modifying the `net.core.optmem_max` sysctl to a larger value to avoid out of memory errors from the linux kernel. -.. clicmd:: neighbor PEER send-community +.. clicmd:: neighbor PEER send-community + + Send the communities to the peer. + + Default: enabled. + +.. clicmd:: neighbor PEER send-community extended rpki + + Send the extended RPKI communities to the peer. RPKI extended community + can be send only to iBGP and eBGP-OAD peers. + + Default: enabled. .. clicmd:: neighbor PEER weight WEIGHT @@ -1689,6 +1883,17 @@ Configuring Peers Do not accept additional paths from this neighbor. +.. clicmd:: neighbor addpath-rx-paths-limit (1-65535) + + Limit the maximum number of paths a BGP speaker can receive from a peer, optimizing + the transmission of BGP routes by selectively relaying pertinent routes instead of + the entire set. + + If this command is configured, the sender will only send the number of paths specified + in PATHS-LIMIT capability. + + To exchange this limit, both peers must support the PATHS-LIMIT capability. + .. clicmd:: neighbor PEER ttl-security hops NUMBER This command enforces Generalized TTL Security Mechanism (GTSM), as @@ -1704,6 +1909,28 @@ Configuring Peers turning on this command will allow BGP to install v4 routes with v6 nexthops if you do not have v4 configured on interfaces. +.. clicmd:: neighbor PEER capability dynamic + + Allow BGP to negotiate the Dynamic Capability with its peers. + + Dynamic Capability defines a new BGP message (CAPABILITY) that can be used + to set/unset BGP capabilities without bringing down a BGP session. + + This includes changing graceful-restart (LLGR also) timers, + enabling/disabling add-path, and other supported capabilities. + +.. clicmd:: neighbor PEER capability fqdn + + Allow BGP to negotiate the FQDN Capability with its peers. + + FQDN Capability defines a new BGP message (CAPABILITY) allowing the + use of peer's name and domain name. + + This capability is activated by default. The ``no neighbor PEER capability + fqdn`` avoid negotiation of that capability. This is useful for peers who + are not supporting this capability or supporting BGP Capabilities + Negotiation RFC 2842. + .. clicmd:: neighbor accept-own Enable handling of self-originated VPN routes containing ``accept-own`` community. @@ -1825,6 +2052,13 @@ Configuring Peers outputs. It's easier to troubleshoot if you have a number of BGP peers and a number of routes to check. +.. clicmd:: bgp default dynamic-capability + + This command enables dynamic capability advertisement by default + for all the neighbors. + + For ``datacenter`` profile, this is enabled by default. + .. clicmd:: bgp default software-version-capability This command enables software version capability advertisement by default @@ -1834,8 +2068,8 @@ Configuring Peers .. code-block:: frr - IPv4 Unicast Summary (VRF default): - BGP router identifier 10.0.0.6, local AS number 65001 vrf-id 0 + IPv4 Unicast Summary: + BGP router identifier 10.0.0.6, local AS number 65001 VRF default vrf-id 0 BGP table version 12 RIB entries 23, using 4600 bytes of memory Peers 3, using 2174 KiB of memory @@ -2033,7 +2267,6 @@ Capability Negotiation .. clicmd:: neighbor PEER strict-capability-match - Strictly compares remote capabilities and local capabilities. If capabilities are different, send Unsupported Capability error then reset connection. @@ -2960,7 +3193,33 @@ address-family: Specifies the route-target list to be attached to a route (export) or the route-target list to match against (import) when exporting/importing between - the current unicast VRF and VPN. + the current unicast VRF and VPN. The `rt vpn export RTLIST` command is not + mandatory and can be replaced or completed by the `set extcommunity rt` + command in the route-map attached with the `route-map vpn export`. The below + configuration illustrates how the route target is selected based on the + prefixes, and not solely on vrf criterium: + + .. code-block:: frr + + access-list acl1 permit 192.0.2.0/24 + access-list acl2 permit 192.0.3.0/24 + route-map rmap permit 10 + match address acl1 + set extcommunity rt 65001:10 + ! + route-map rmap permit 20 + match address acl1 + set extcommunity rt 65001:20 + ! + router bgp 65001 vrf vrf1 + ! + address-family ipv4 unicast + rd vpn export 65001:1 + import vpn + export vpn + rt vpn import 65001:1 + route-map vpn export rmap + The RTLIST is a space-separated list of route-targets, which are BGP extended community values as described in @@ -3058,6 +3317,31 @@ L3VPN SRv6 Specify the SRv6 locator to be used for SRv6 L3VPN. The Locator name must be set in zebra, but user can set it in any order. +L3VPN SRv6 SID reachability +--------------------------- + +In the context of IPv4 L3VPN over SRv6 specific usecase, 2001:db8:12::2 +is the peer IPv6 address of r2, and 2001:db8:2:2:: is the SRv6 SID +advertised by router r2 for prefix P. On r1, the SID reachability is +checked in order to install the prefix P. The below output indicates +that the 2001:db8:2:2:: prefix is valid. + + +.. code-block:: frr + + r1# show bgp nexthop detail + Current BGP nexthop cache: + 2001:db8:2:2:: valid [IGP metric 0], #paths 4 + gate 2001:db8:12::2, if eth0 + Last update: Tue Nov 14 10:36:28 2023 + Paths: + 1/1 192.168.2.0/24 VRF vrf10 flags 0x4018 + 1/3 192.168.2.0/24 RD 65002:10 VRF default flags 0x418 + 2001:db8:12::2 valid [IGP metric 0], #paths 0, peer 2001:db8:12::2 + if eth0 + Last update: Tue Nov 14 10:36:26 2023 + Paths: + General configuration ^^^^^^^^^^^^^^^^^^^^^ @@ -3348,7 +3632,7 @@ The import filtering described in item (2) is constrained just to Type-2 The EVPN MAC-VRF Site-of-Origin can be configured using a single CLI command under ``address-family l2vpn evpn`` of the EVPN underlay BGP instance. -.. clicmd:: [no] mac-vrf soo +.. clicmd:: mac-vrf soo Example configuration: @@ -3494,7 +3778,7 @@ route maybe fragmented. The number of EVIs per-EAD route can be configured via the following BGP command - -.. clicmd:: [no] ead-es-frag evi-limit (1-1000) +.. clicmd:: ead-es-frag evi-limit (1-1000) Sample Configuration ^^^^^^^^^^^^^^^^^^^^^ @@ -3672,7 +3956,7 @@ When default route is present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2.1/3 *> 192.0.2.1/32 10.10.10.1 0 0 1 i *> 192.0.2.5/32 10.10.10.1 0 0 1 i - Displayed 4 routes and 4 total paths + Displayed 4 routes and 4 total paths Router2# show ip bgp neighbors 10.10.20.3 !--- Output suppressed. @@ -3720,7 +4004,7 @@ When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2 *> 192.0.2.1/32 10.10.10.1 0 0 1 i *> 192.0.2.5/32 10.10.10.1 0 0 1 i - Displayed 3 routes and 3 total paths + Displayed 3 routes and 3 total paths Router2# show ip bgp neighbors 10.10.20.3 @@ -3789,12 +4073,20 @@ Debugging information on BGP events such as peer connection / disconnection, session establishment / teardown, and capability negotiation. -.. clicmd:: debug bgp updates +.. clicmd:: debug bgp updates [detail] Enable or disable debugging for BGP updates. This provides information on BGP UPDATE messages transmitted and received between local and remote instances. + If ``detail`` is specified, the output will include the full BGP UPDATE with + detailed information such as attribute length, withdraw length, and more. + +.. clicmd:: debug bgp updates [ [prefix-list WORD]] + + Enable or disable debugging for BGP updates. Optionally, you can specify + a prefix-list to filter the updates for an arbitrary neighbor. + .. clicmd:: debug bgp keepalives Enable or disable debugging for BGP keepalives. This provides information on @@ -3866,6 +4158,10 @@ The following are available in the top level *enable* mode: Clear all peers. +.. clicmd:: clear bgp ipv4|ipv6 ASNUM + + Clear peers with the AS number in plain or dotted format. + .. clicmd:: clear bgp ipv4|ipv6 \* Clear all peers with this address-family activated. @@ -3895,6 +4191,26 @@ The following are available in the top level *enable* mode: Clear BGP message statistics for a specified peer or for all peers, optionally filtered by activated address-family and sub-address-family. +.. clicmd:: clear bgp [ipv4|ipv6] [unicast] PEER|\* capabilities + + Clear specific BGP capabilities for a specified peer or for all peers. This + includes such capabilities like FQDN capability, that can't be controlled by + any other configuration knob. + + For example, if you want to change the FQDN, you MUST reset the BGP session + in order to send a new FQDN capability to the peer. This command allows you + to resend FQDN capability without resetting the session. + + .. code-block:: frr + + hostname bgp-new.example.com + clear bgp 10.10.10.1 capabilities + +.. note:: + + Changing the hostname is possible only when connected to the specific daemon. + If you change the hostname via ``vtysh``, it won't be changed. + The following are available in the ``router bgp`` mode: .. clicmd:: write-quanta (1-64) @@ -4018,8 +4334,8 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. exit1# show ip bgp summary wide - IPv4 Unicast Summary (VRF default): - BGP router identifier 192.168.100.1, local AS number 65534 vrf-id 0 + IPv4 Unicast Summary: + BGP router identifier 192.168.100.1, local AS number 65534 VRF default vrf-id 0 BGP table version 3 RIB entries 5, using 920 bytes of memory Peers 1, using 27 KiB of memory @@ -4313,7 +4629,7 @@ incoming/outgoing directions. Origin incomplete, metric 0, weight 32768, valid, sourced, bestpath-from-AS Local, best (First path received) Last update: Wed May 8 12:54:41 2023 - Displayed 2 routes and 2 total paths + Displayed 2 routes and 2 total paths .. code-block:: frr @@ -4338,7 +4654,7 @@ incoming/outgoing directions. Origin incomplete, metric 0, weight 32768, valid, sourced, bestpath-from-AS Local, best (First path received) Last update: Wed May 8 12:45:01 2023 - Displayed 2 routes and 2 total paths + Displayed 2 routes and 2 total paths Instance vrf3: @@ -4363,7 +4679,7 @@ incoming/outgoing directions. Extended Community: RT:65000:1009 ET:8 Rmac:00:02:00:00:00:58 Last update: Fri May 8 02:41:55 2023 - Displayed 2 routes and 2 total paths + Displayed 2 routes and 2 total paths .. code-block:: frr @@ -4391,7 +4707,7 @@ incoming/outgoing directions. Extended Community: RT:65000:1009 ET:8 Rmac:00:02:00:00:00:58 Last update: Fri May 8 02:23:55 2023 - Displayed 2 routes and 2 total paths + Displayed 2 routes and 2 total paths .. _bgp-display-routes-by-community: @@ -4677,8 +4993,8 @@ setting. .. clicmd:: bgp session-dscp (0-63) -This command allows bgp to control, at a global level, the TCP dscp values -in the TCP header. +This command allows the BGP daemon to control, at a global level, the DSCP value +used in outgoing packets for each BGP connection. .. _bgp-suppress-fib: diff --git a/doc/user/bmp.rst b/doc/user/bmp.rst index 1983995c1fdb..14d0849b3410 100644 --- a/doc/user/bmp.rst +++ b/doc/user/bmp.rst @@ -23,6 +23,8 @@ The `BMP` implementation in FRR has the following properties: - 3: count of **prefixes** with loop in cluster id - 4: count of **prefixes** with loop in AS-path - 5: count of **prefixes** with loop in originator + - 7: count of **routes** in adj-rib-in + - 8: count of **routes** in Loc-RIB - 11: count of updates subjected to :rfc:`7607` "treat as withdrawal" handling due to errors - 65531: *experimental* count of prefixes rejected due to invalid next-hop @@ -36,8 +38,8 @@ The `BMP` implementation in FRR has the following properties: successfully. OPEN messages for failed sessions cannot currently be mirrored. -- **route monitoring** is available for IPv4 and IPv6 AFIs, unicast and - multicast SAFIs. Other SAFIs (VPN, Labeled-Unicast, Flowspec, etc.) are not +- **route monitoring** is available for IPv4 and IPv6 AFIs, unicast, multicast, + EVPN and VPN SAFIs. Other SAFIs (VPN, Labeled-Unicast, Flowspec, etc.) are not currently supported. - monitoring peers that have BGP **add-path** enabled on the session will @@ -146,10 +148,15 @@ associated with a particular ``bmp targets``: Send BMP Statistics (counter) messages at the specified interval (in milliseconds.) -.. clicmd:: bmp monitor AFI SAFI +.. clicmd:: bmp stats send-experimental + + Send BMP Statistics (counter) messages whose code is defined as + experimental (in the [65531-65534] range). + +.. clicmd:: bmp monitor AFI SAFI Perform Route Monitoring for the specified AFI and SAFI. Only IPv4 and - IPv6 are currently valid for AFI. SAFI valid values are currently + IPv6 are currently valid for AFI. SAFI valid values are currently unicast, multicast, evpn and vpn. Other AFI/SAFI combinations may be added in the future. diff --git a/doc/user/conf.py b/doc/user/conf.py index 728f9c936486..236a90e9026b 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -18,6 +18,8 @@ import pygments import sphinx from sphinx.highlighting import lexers +from sphinx.domains.std import GenericObject +from docutils.parsers.rst import directives # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -52,18 +54,28 @@ master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" + +# RTD configuration + +# Set canonical URL from the Read the Docs Domain +html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") + +# Tell Jinja2 templates the build is running on Read the Docs +if os.environ.get("READTHEDOCS", "") == "True": + html_context["READTHEDOCS"] = True + # ----------------------------------------------------------------------------- @@ -94,7 +106,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): @@ -287,7 +299,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR User Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR User Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +327,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR User Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR User Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +342,7 @@ ( master_doc, "frr", - u"FRR User Manual", + "FRR User Manual", author, "FRR", "One line description of project.", @@ -358,6 +370,7 @@ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() + # Parse version string into int array def vparse(s): a = [] @@ -372,11 +385,54 @@ def vparse(s): return a[:3] -# custom extensions here +class ClicmdDirective(GenericObject): + """ + Directive for documenting CLI commands. + + The xref string, if no option is provided, will be the verbatim command + string. If the :daemon: option is provided, then it's + "() )". + + Options: + :daemon: - specify the daemon this command belongs to. Useful for + disambiguating multiple definitions of the same command. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + option_spec = { + **GenericObject.option_spec, + "daemon": directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + daemon = self.options["daemon"] if "daemon" in self.options else "" + prefix = f"({daemon}) " if daemon else "" + return prefix + name + + def run(self): + daemon = self.options["daemon"] if "daemon" in self.options else "" + if daemon: + self.indextemplate = f"pair: ({daemon}) %s; configuration command" + else: + self.indextemplate = f"pair: %s; configuration command" + + nodes = super().run() + + return nodes + + def setup(app): - # object type for FRR CLI commands, can be extended to document parent CLI - # node later on - app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") + # Override the directive that was just created for us + if int(sphinx.__version__.split(".")[0]) >= 2: + app.add_object_type("clicmd", "clicmd", objname="CLI command") + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) + else: + app.add_object_type( + "clicmd", "clicmd", indextemplate="pair: %s; configuration command" + ) # I dont care how stupid this is if "add_js_file" in dir(app): @@ -389,7 +445,6 @@ def setup(app): else: app.add_stylesheet("overrides.css") - # load Pygments lexer for FRR config syntax # # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we diff --git a/doc/user/config-include.rst b/doc/user/config-include.rst new file mode 100644 index 000000000000..3a341513b48b --- /dev/null +++ b/doc/user/config-include.rst @@ -0,0 +1,12 @@ +.. +.. January 12 2024, Christian Hopps +.. +.. Copyright (c) 2024, LabN Consulting, L.L.C. +.. +.. + +Configuration for the daemon should be saved in the FRR integrated configuration +file located in |INSTALL_PREFIX_ETC|/frr.conf, see :ref:`config-file` for more +information on system configuration. + +.. include:: prior-config-files.rst diff --git a/doc/user/eigrpd.rst b/doc/user/eigrpd.rst index fa157c465900..58a2957ad051 100644 --- a/doc/user/eigrpd.rst +++ b/doc/user/eigrpd.rst @@ -24,21 +24,17 @@ known topology. Starting and Stopping eigrpd ============================ -The default configuration file name of *eigrpd*'s is :file:`eigrpd.conf`. When -invocation *eigrpd* searches directory |INSTALL_PREFIX_ETC|. If -:file:`eigrpd.conf` is not there next search current directory. If an -integrated config is specified configuration is written into :file:`frr.conf`. +.. include:: config-include.rst -The EIGRP protocol requires interface information maintained by *zebra* daemon. -So running *zebra* is mandatory to run *eigrpd*. Thus minimum sequence for -running EIGRP is: +If starting daemons by hand then please note, the EIGRP protocol requires +interface information maintained by *zebra* daemon. So running *zebra* is +mandatory to run *eigrpd*. Thus minimum sequence for running EIGRP is: :: # zebra -d # eigrpd -d - Please note that *zebra* must be invoked before *eigrpd*. To stop *eigrpd*, please use:: diff --git a/doc/user/index.rst b/doc/user/index.rst index 4789677a9a04..d3b632a8debb 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -1,80 +1,31 @@ FRRouting User Guide ==================== -############ -Introduction -############ +FRR is a fully featured, high performance, free software IP routing suite. It +implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and +more (see :ref:`feature-matrix`), as well as many of their extensions. It can +handle full Internet routing tables and is suitable for use on hardware ranging +from cheap SBCs to commercial grade routers, and is actively used in production +by hundreds of companies, universities, research labs and governments. -.. _introduction: -.. toctree:: - :maxdepth: 2 - - overview - installation - setup - -###### -Basics -###### +FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. +Feature support varies by platform; see the :ref:`feature-matrix`. -.. _basics: -.. toctree:: - :maxdepth: 2 +FRR is distributed under GPLv2, with development modeled after the Linux +kernel. Anyone may contribute features, bug fixes, tools, documentation +updates, or anything else. - basic - extlog - vtysh - grpc - filter - routemap - affinitymap - ipv6 - kernel - snmp - scripting - nexthop_groups -.. modules +FRR is a fork of `Quagga `_. -######### -Protocols -######### - -.. _protocols: .. toctree:: :maxdepth: 2 - zebra - bfd - bgp - babeld - fabricd - ldpd - eigrpd - evpn - isisd - nhrpd - ospfd - ospf6d - pathd - pim - pimv6 - pbr - ripd - ripngd - sharp - static - vnc - vrrp - bmp - watchfrr - mgmtd - -######## -Appendix -######## + introduction + basics + protocols -.. _appendix: .. toctree:: + :caption: Appendix :maxdepth: 2 bugs diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 8e8fb246086b..4d2017c0f8e5 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -3,22 +3,25 @@ single: Installing FRR single: Building FRR -.. _installation: - Installation ============ -This section covers the basics of building, installing and setting up FRR. +This section covers the basics of building, installing and setting up +FRR. +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. From Packages ------------- -The project publishes packages for Red Hat, Centos, Debian and Ubuntu on the -`GitHub releases `_. page. External -contributors offer packages for many other platforms including \*BSD, Alpine, -Gentoo, Docker, and others. There is currently no documentation on how to use -those but we hope to add it soon. +Up-to-date Debian & Redhat packages are available at +https://deb.frrouting.org/ & https://rpm.frrouting.org/ respectively. + +Several distributions also provide packages for FRR. Check your +distribution's repositories to find out if a suitable version is +available. + From Snapcraft -------------- @@ -29,12 +32,12 @@ universal Snap images, available at https://snapcraft.io/frr. From Source ----------- -Building FRR from source is the best way to ensure you have the latest features -and bug fixes. Details for each supported platform, including dependency -package listings, permissions, and other gotchas, are in the `developer's -documentation -`_. This -section provides a brief overview on the process. +Building FRR from source is the best way to ensure you have the latest +features and bug fixes. Details for each supported platform, including +dependency package listings, permissions, and other gotchas, are in the +`developer's documentation +`_. +This section provides a brief overview on the process. Getting the Source @@ -234,10 +237,9 @@ options from the list below. assigned to the realm. See the tc man page. This option is currently not compatible with the usage of nexthop groups in the linux kernel itself. -.. option:: --disable-irdp +.. option:: --enable-irdp - Disable IRDP server support. This is enabled by default if we have - both `struct in_pktinfo` and `struct icmphdr` available to us. + Enable IRDP server support. This is deprecated. .. option:: --disable-rtadv @@ -275,6 +277,10 @@ options from the list below. Build with FPM module support. +.. option:: --enable-fpm-listener + + Build a small fpm listener for testing. + .. option:: --with-service-timeout=X Set timeout value for FRR service. The time of restarting or reloading FRR @@ -310,13 +316,6 @@ options from the list below. make these arrays at build time. Additionally if this parameter is not passed in FRR will default to 16 ECMP. -.. option:: --enable-shell-access - - Turn on the ability of FRR to access some shell options( telnet/ssh/bash/etc. ) - from vtysh itself. This option is considered extremely unsecure and should only - be considered for usage if you really really know what you are doing. This - option is deprecated and will be removed on Feb 1, 2024. - .. option:: --enable-gcov Code coverage reports from gcov require adjustments to the C and LD flags. @@ -330,11 +329,6 @@ options from the list below. Build with configuration rollback support. Requires SQLite3. -.. option:: --enable-confd= - - Build the ConfD northbound plugin. Look for the libconfd libs and headers - in `dir`. - .. option:: --enable-sysrepo Build the Sysrepo northbound plugin. @@ -351,20 +345,6 @@ options from the list below. Use libpam for PAM support in vtysh. -.. option:: --enable-time-check XXX - - This option is deprecated as it was replaced by the - :clicmd:`service cputime-stats` CLI command, which may be adjusted at - runtime rather than being a compile-time setting. See there for further - detail. - -.. option:: --disable-cpu-time - - This option is deprecated as it was replaced by the - :clicmd:`service cputime-warning NNN` CLI command, which may be adjusted at - runtime rather than being a compile-time setting. See there for further - detail. - .. option:: --enable-pcreposix Turn on the usage of PCRE Posix libs for regex functionality. @@ -408,13 +388,20 @@ options to the configuration script. .. option:: --sysconfdir - Look for configuration files in `dir` [`prefix`/etc]. Note that sample - configuration files will be installed here. + Look for configuration files in `dir`/frr [`prefix`/etc]. Note that sample + configuration files will be installed here. Should be ``/etc`` unless + your platform splits package configuration locations. .. option:: --localstatedir - Configure zebra to use `dir` for local state files, such as pid files and - unix sockets. + Configure base directory for local state. Indirectly controls + ``--runstatedir``. Should be ``/var`` in most cases. + +.. option:: --runstatedir + + Configure FRR to use `dir`/frr for local state files, such as pid files and + unix sockets. Should be ``/var/run`` (default through ``--localstatedir``) + or ``/run`` in most cases. .. option:: --with-scriptdir @@ -438,7 +425,12 @@ options to the configuration script. Python dependency, documentation and tests ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -FRR's documentation and basic unit tests heavily use code written in Python. +FRR uses Python for these components: + +* configuration reloading (see :ref:`FRR-RELOAD ` for details), +* documentation, +* unit tests. + Additionally, FRR ships Python extensions written in C which are used during its build process. @@ -593,9 +585,9 @@ the options you chose: ./configure \ --prefix=/usr \ - --localstatedir=/var/run/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --enable-pimd \ --enable-watchfrr \ ... diff --git a/doc/user/introduction.rst b/doc/user/introduction.rst new file mode 100644 index 000000000000..89866b9c2921 --- /dev/null +++ b/doc/user/introduction.rst @@ -0,0 +1,13 @@ +.. _introduction: + +############ +Introduction +############ + +.. toctree:: + :maxdepth: 2 + + about + installation + setup + diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 63c921330bbc..3a0f277bf0cf 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -22,8 +22,7 @@ interface information from *zebra* in order to function. Therefore *zebra* must be running before invoking *isisd*. Also, if *zebra* is restarted then *isisd* must be too. -Like other daemons, *isisd* configuration is done in :abbr:`ISIS` specific -configuration file :file:`isisd.conf`. +.. include:: config-include.rst .. _isis-router: @@ -124,7 +123,7 @@ ISIS Timer Set LSP refresh interval in seconds, globally, for an area (level-1) or a domain (level-2). -.. clicmd:: max-lsp-lifetime [level-1 | level-2] (360-65535) +.. clicmd:: max-lsp-lifetime [level-1 | level-2] (350-65535) Set LSP maximum LSP lifetime in seconds, globally, for an area (level-1) or a domain (level-2). @@ -225,17 +224,17 @@ ISIS interface Add padding to IS-IS hello packets during adjacency formation only. -.. clicmd:: isis hello-interval (1-600) [level-1 | level-2] +.. clicmd:: isis hello-interval [level-1 | level-2] (1-600) Set Hello interval in seconds globally, for an area (level-1) or a domain (level-2). -.. clicmd:: isis hello-multiplier (2-100) [level-1 | level-2] +.. clicmd:: isis hello-multiplier [level-1 | level-2] (2-100) Set multiplier for Hello holding time globally, for an area (level-1) or a domain (level-2). -.. clicmd:: isis metric [(0-255) | (0-16777215)] [level-1 | level-2] +.. clicmd:: isis metric [level-1 | level-2] [(0-255) | (0-16777215)] Set default metric value globally, for an area (level-1) or a domain (level-2). Max value depend if metric support narrow or wide value (see @@ -302,7 +301,7 @@ Showing ISIS information Show summary information about ISIS. -.. clicmd:: show isis hostname +.. clicmd:: show isis [vrf ] hostname Show information about ISIS node. @@ -321,17 +320,17 @@ Showing ISIS information Show the ISIS database globally, for a specific LSP id without or with details. -.. clicmd:: show isis topology [level-1|level-2] [algorithm (128-255)] +.. clicmd:: show isis [vrf ] topology [level-1|level-2] [algorithm [(128-255)]] Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. clicmd:: show isis route [level-1|level-2] [prefix-sid|backup] [algorithm (128-255)] +.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid] [backup] [algorithm [(128-255)]] Show the ISIS routing table, as determined by the most recent SPF calculation. -.. clicmd:: show isis fast-reroute summary [level-1|level-2] +.. clicmd:: show isis [vrf ] fast-reroute summary [level-1|level-2] Show information about the number of prefixes having LFA protection, and network-wide LFA coverage. @@ -436,7 +435,7 @@ Known limitations: clear the Node flag that is set by default for Prefix-SIDs associated to loopback addresses. This option is necessary to configure Anycast-SIDs. -.. clicmd:: show isis segment-routing node [algorithm (128-255)] +.. clicmd:: show isis segment-routing node [algorithm [(128-255)]] Show detailed information about all learned Segment Routing Nodes. @@ -463,10 +462,14 @@ To do so, it defines a set of Flex-Algo Definitions (FAD) which have the following characteristics: - a numeric identifier (ID) between 128 and 255 inclusive + - a set of constraints (basically, include or exclude a certain given set of links, designated by a admin-group) + - the calculation type (only the `Shortest-Path-First` is currently supported) + - the metric type (only the IGP inherited metric type is currently supported) + - some additional flags (not supported for the moment). A subset of routers advertises the Flex-Algo Definitions (FAD) to the other @@ -476,13 +479,18 @@ rules: - If a locally configured FAD is not advertised to the area, the router does not participate in the particular flex algorithm. + - If a given flex algorithm is running, the participation in this particular flex algorithm stops when its advertisements are over. + - A router includes its own FAD in the election process if and only if it is advertised to the other routers. + - If only one router advertises the FAD, the FAD is elected. + - If several FADs are advertised with different priorities, the one with the highest priority value is selected. + - If there are multiple advertisements of the FAD with the same highest priority, the FAD of the router with the highest IS-IS system-ID is selected. @@ -498,15 +506,11 @@ which flex algorithm they must use for a given packet. The following commands configure Flex-Algo at the 'router isis' configuration level. Segment-Routing prefixes must be configured for the Flex-Algo. -.. clicmd:: flexible-algorithm (128-255) +.. clicmd:: flex-algo (128-255) Add a Flex-Algo Definition (FAD) and enter the FAD configuration level. The algorithm ID value is in the range of 128 to 255 inclusive. -.. clicmd:: no flexible-algorithm (128-255) - - Unconfigure a Flex-Algo Definition. - .. clicmd:: affinity-map NAME bit-position (0-255) Add the specified 'affinity-map'. Affinity-map definitions are used in @@ -518,7 +522,7 @@ level. Segment-Routing prefixes must be configured for the Flex-Algo. admin-group 'bit-position' is set 1, else it is set to 0. The following commands configure Flex-Algo at the 'router isis' and -'flexible-algorithm (128-255)' configuration level. +'flex-algo (128-255)' configuration level. .. clicmd:: advertise-definition @@ -635,26 +639,14 @@ Debugging ISIS IS-IS Adjacency related packets. -.. clicmd:: debug isis checksum-errors - - IS-IS LSP checksum errors. - .. clicmd:: debug isis events IS-IS Events. -.. clicmd:: debug isis local-updates - - IS-IS local update packets. - .. clicmd:: debug isis packet-dump IS-IS packet dump. -.. clicmd:: debug isis protocol-errors - - IS-IS LSP protocol errors. - .. clicmd:: debug isis route-events IS-IS Route related events. @@ -664,11 +656,8 @@ Debugging ISIS IS-IS CSNP/PSNP packets. .. clicmd:: debug isis spf-events -.. clicmd:: debug isis spf-statistics -.. clicmd:: debug isis spf-triggers - IS-IS Shortest Path First Events, Timing and Statistic Data and triggering - events. + IS-IS Shortest Path First Events. .. clicmd:: debug isis update-packets @@ -847,7 +836,7 @@ A simple vrf example: ! interface eth0 vrf RED - ip router isis FOO vrf RED + ip router isis FOO isis network point-to-point isis circuit-type level-2-only ! diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index 682443a45667..7a000a49c450 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -32,9 +32,7 @@ options (:ref:`common-invocation-options`). The *zebra* daemon must be running before *ldpd* is invoked. -Configuration of *ldpd* is done in its configuration file -:file:`ldpd.conf`. - +.. include:: config-include.rst .. _understanding-ldp: @@ -150,7 +148,7 @@ LDP Configuration configured password. PASSWORD is a clear text password wit its digest sent through the network. -.. clicmd:: neighbor A.B.C.D holdtime HOLDTIME +.. clicmd:: neighbor A.B.C.D session holdtime HOLDTIME The following command located under MPLS router node configures the holdtime value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive diff --git a/doc/user/mgmtd.rst b/doc/user/mgmtd.rst index 737eb57c85bc..8b197bb99bdd 100644 --- a/doc/user/mgmtd.rst +++ b/doc/user/mgmtd.rst @@ -97,6 +97,8 @@ Following are some of the management operations supported: - Currently committing configurations from Candidate to Running database is only allowed, and not vice versa. +Front-End Native Protobuf API +""""""""""""""""""""""""""""" The exact set of message-based APIs are represented as Google Protobuf messages and can be found in the following file distributed with FRR codebase. @@ -104,6 +106,14 @@ messages and can be found in the following file distributed with FRR codebase. lib/mgmt.proto +Front-End Native (non-protobuf) API +""""""""""""""""""""""""""""""""""" +Additionally there exists a "native" API that does not utilize ``protobuf``s +this native API and the front-end messages and structures it supports are +documented in the header file ``lib/mgmt_msg_native.h``. + +Connecting to MGMTd +""""""""""""""""""" The MGMT daemon implements a MGMT Frontend Server that opens a UNIX socket-based IPC channel on the following path to listen for incoming connections from all possible Frontend clients: @@ -124,7 +134,9 @@ specification of this library can be found at: lib/mgmt_fe_client.h -Following is a list of message types supported on the MGMT Frontend Interface: +Following is a list of protobuf message types supported on the MGMT Frontend +Interface: + - SESSION_REQ - SESSION_REPLY - LOCK_DB_REQ @@ -139,8 +151,21 @@ Following is a list of message types supported on the MGMT Frontend Interface: - COMMIT_CONFIG_REPLY - GET_DATA_REQ - GET_DATA_REPLY - - REGISTER_NOTIFY_REQ - - DATA_NOTIFY_REQ + +Following is a list of native messages types supported by the MGMTd Front-End +API: + + - ERROR (receive) - received in response to any sent native message. + - TREE_DATA (receive) - returned data from a datastore + - GET_DATA (send) - get a tree of data + - NOTIFY (receive) - a notification received from mgmtd + - EDIT (send) - edit configuration datastore + - EDIT_REPLY (receive) - reply for an edit operation + - RPC (send) - sending (invoking) an RPC. + - RPC_REPLY (receive) - reply from invoking an RPC + - NOTIFY_SELECT (send) - specify the sub-set of notifications the front-end + wishes to receive, rather than the default of receiving all. + Please refer to the MGMT Frontend Client Developers Reference and Guide (coming soon) for more details. @@ -356,7 +381,7 @@ MGMT Show commands Currenlty supported values for 'candidate' and 'running' only ('operational' shall be supported in future soon). -.. clicmd:: show mgmt database-contents [candidate|operation|running] [xpath WORD] [file WORD] json|xml +.. clicmd:: show mgmt datastore-contents [candidate|operation|running] [xpath WORD] [file WORD] json|xml This command dumps the subtree pointed by the xpath in JSON or XML format. If filepath is not present then the tree will be printed on the shell. @@ -371,22 +396,22 @@ MGMT Daemon debug commands The following debug commands enable debugging within the management daemon: -.. clicmd:: [no] debug mgmt backend +.. clicmd:: debug mgmt backend Enable[/Disable] debugging messages related to backend operations within the management daemon. -.. clicmd:: [no] debug mgmt datastore +.. clicmd:: debug mgmt datastore Enable[/Disable] debugging messages related to YANG datastore operations within the management daemon. -.. clicmd:: [no] debug mgmt frontend +.. clicmd:: debug mgmt frontend Enable[/Disable] debugging messages related to frontend operations within the management daemon. -.. clicmd:: [no] debug mgmt transaction +.. clicmd:: debug mgmt transaction Enable[/Disable] debugging messages related to transactions within the management daemon. @@ -398,12 +423,12 @@ MGMT Client debug commands The following debug commands enable debugging within the management front and backend clients: -.. clicmd:: [no] debug mgmt client backend +.. clicmd:: debug mgmt client backend Enable[/Disable] debugging messages related to backend operations inside the backend mgmtd clients. -.. clicmd:: [no] debug mgmt client frontend +.. clicmd:: debug mgmt client frontend Enable[/Disable] debugging messages related to frontend operations inside the frontend mgmtd clients. diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index 54527a0c9a85..648d56d9c18a 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -84,6 +84,12 @@ Configuring NHRP registration requests are sent. By default registrations are sent every one third of the holdtime. +.. clicmd:: ip nhrp authentication PASSWORD + + Enables Cisco style authentication on NHRP packets. This embeds the + plaintext password to the outgoing NHRP packets. + Maximum length of the password is 8 characters. + .. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local Map an IP address of a station to the station's NBMA address. diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 2f4c956ffd90..ea41ba53b370 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -9,8 +9,13 @@ described in :rfc:`2740`. .. _ospf6-router: -OSPF6 router -============ +Configuring OSPF6 +***************** + +.. include:: config-include.rst + +Configuration Commands +====================== .. clicmd:: router ospf6 [vrf NAME] @@ -312,10 +317,135 @@ OSPF6 interface Sets interface's Inf-Trans-Delay. Default value is 1. -.. clicmd:: ipv6 ospf6 network (broadcast|point-to-point) +.. clicmd:: ipv6 ospf6 network (broadcast|point-to-point|point-to-multipoint) Set explicitly network type for specified interface. + The only functional difference between ``point-to-point`` (PtP) and + ``point-to-multipoint`` (PtMP) mode is the packet addressing for database + flooding and updates. PtP will use multicast packets while PtMP will + unicast them. Apart from this, + :clicmd:`ipv6 ospf6 p2p-p2mp connected-prefixes ` has a + different default for PtP and PtMP. There are no other differences, in + particular FRR does not impose a limit of one neighbor in PtP mode. + + FRR does not support NBMA mode for IPv6 and likely never will, as NBMA is + considered deprecated for IPv6. Refer to `this IETF OSPF working group + discussion + `_ + for context. + +OSPF6 point-to-point and point-to-multipoint operation +====================================================== + +OSPFv3, by default, operates in broadcast mode where it elects a DR and BDR +for each network segment. This can be changed to point-to-point (PtP) / +point-to-multipoint (PtMP) mode by configuration. The actual physical +interface characteristics do not matter for this setting, all interfaces can +be configured for all modes. However, routers must be configured for the same +mode to form adjacencies. + +The main advantages of PtP/PtMP mode are: + +- no DR/BDR election +- adjacencies can be suppressed in a pairwise manner for any two routers, e.g. + to represent the underlying topology if it isn't a true full mesh +- distinct costs can be set for each pair of routers and direction + +The main downside is less efficient flooding on networks with a large number +of OSPFv3 routers. + +.. warning:: + + All options in this section should be considered "advanced" configuration + options. Inconsistent or nonsensical combinations can easily result in a + non-functional setup. + +.. clicmd:: ipv6 ospf6 p2p-p2mp disable-multicast-hello + + Disables sending normal multicast hellos when in PtP/PtMP mode. Some + vendors do this automatically for PtMP mode while others have a separate + ``no-broadcast`` option matching this. + + If this setting is used, you must issue + :clicmd:`ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)` for each + neighbor to send unicast hello packets. + +.. clicmd:: ipv6 ospf6 p2p-p2mp config-neighbors-only + + Only form adjacencies with neighbors that are explicitly configured with + the :clicmd:`ipv6 ospf6 neighbor X:X::X:X` command. Hellos from other + routers are ignored. + + .. warning:: + + This setting is not intended to provide any security benefit. Do not + run OSPFv3 over untrusted links without additional security measures + (e.g. IPsec.) + +.. clicmd:: ipv6 ospf6 p2p-p2mp connected-prefixes + + For global/ULA prefixes configured on this interfaces, do (not) advertise + the full prefix to the area. Regardless of this setting, the router's own + address, as a /128 host route with the "LA" (Local Address) bit set, will + always be advertised. + + The default is to include connected prefixes for PtP mode and exclude them + for PtMP mode. Since these prefixes will cover other router's addresses, + these addresses can become unreachable if the link is partitioned if the + other router does not advertise the address as a /128. However, conversely, + if all routers have this flag set, the overall prefix will not be advertised + anywhere. End hosts on this link will therefore be unreachable (and + blackholing best-practices for non-existing prefixes apply.) It may be + preferable to have only one router announce the connected prefix. + + The Link LSA (which is not propagated into the area) always includes all + prefixes on the interface. This setting only affects the Router LSA that + is visible to all routers in the area. + + .. note:: + + Before interacting with this setting, consider either not configuring + any global/ULA IPv6 address on the interface, or directly configuring a + /128 if needed. OSPFv3 relies exclusively on link-local addresses to do + its signaling and there is absolutely no reason to configure global/ULA + addresses as far as OSPFv3 is concerned. + +.. clicmd:: ipv6 ospf6 neighbor X:X::X:X + + Explicitly configure a neighbor by its link-local address on this interface. + This statement has no effect other than allowing an adjacency when + :clicmd:`ipv6 ospf6 p2p-p2mp config-neighbors-only` is set. This command + does **not** cause unicast hellos to be sent. + + Only link-local addresses can be used to establish explicit neighbors. + When using this command, you should probably assign static IPv6 link-local + addresses to all routers on this link. It would technically be possible to + use the neighbor's Router ID (IPv4 address) here to ease working with + changing link-local addresses but this is not planned as a feature at the + time of writing. Global/ULA IPv6 addresses cannot be supported here due to + the way OSPFv3 works. + +.. clicmd:: ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535) + + Send unicast hellos to this neighbor at the specified interval (in seconds.) + The interval is only used while there is no adjacency with this neighbor. + As soon as an adjacency is formed, the interface's + :clicmd:`ipv6 ospf6 hello-interval HELLOINTERVAL` value is used. + (``hello-interval`` must be the same on all routers on this link.) + + :rfc:`2328` recommends a "much larger" value than ``hello-interval`` for + this setting, but this is a legacy of ATM and X.25 networks and nowadays you + should probably just use the same value as for ``hello-interval``. + +.. clicmd:: ipv6 ospf6 neighbor X:X::X:X cost (1-65535) + + Use a distinct cost for paths traversing this neighbor. The default is + to use the interface's cost value (which may be automatically calculated + based on link bandwidth.) Note that costs are directional in OSPF and the + reverse direction must be set on the other router. + + OSPF6 route-map =============== @@ -364,11 +494,11 @@ Graceful Restart Configure Graceful Restart (RFC 5187) helper support. - By default, helper support is disabled for all neighbours. + By default, helper support is disabled for all neighbors. This config enables/disables helper support on this router - for all neighbours. + for all neighbors. To enable/disable helper support for a specific - neighbour, the router-id (A.B.C.D) has to be specified. + neighbor, the router-id (A.B.C.D) has to be specified. .. clicmd:: graceful-restart helper strict-lsa-checking diff --git a/doc/user/ospf_fundamentals.rst b/doc/user/ospf_fundamentals.rst index c56605912179..3032d2771ee8 100644 --- a/doc/user/ospf_fundamentals.rst +++ b/doc/user/ospf_fundamentals.rst @@ -12,7 +12,7 @@ OSPF Fundamentals :term:`distance-vector` protocols, such as :abbr:`RIP` or :abbr:`BGP`, where routers describe available `paths` (i.e. routes) to each other, in :term:`link-state` protocols routers instead describe the state of their links -to their immediate neighbouring routers. +to their immediate neighboring routers. .. index:: single: Link State Announcement @@ -127,7 +127,7 @@ LSA Flooding """""""""""" OSPF defines several related mechanisms, used to manage synchronisation of -:abbr:`LSDB` s between neighbours as neighbours form adjacencies and the +:abbr:`LSDB` s between neighbors as neighbors form adjacencies and the propagation, or `flooding` of new or updated :abbr:`LSA` s. @@ -259,7 +259,7 @@ called `intra-area routes`. LSA is originated for such a link. Stub - A link with no adjacent neighbours, or a host route. + A link with no adjacent neighbors, or a host route. - Link ID and Data @@ -339,8 +339,8 @@ The example below shows two :abbr:`LSA` s, both originated by the same router of different LSA types. The first LSA being the router LSA describing 192.168.0.49's links: 2 links -to multi-access networks with fully-adjacent neighbours (i.e. Transit -links) and 1 being a Stub link (no adjacent neighbours). +to multi-access networks with fully-adjacent neighbors (i.e. Transit +links) and 1 being a Stub link (no adjacent neighbors). The second LSA being a Network LSA, for which 192.168.0.49 is the :abbr:`DR`, listing the Router IDs of 4 routers on that network which diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index d61522b051f2..b80adba7f046 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -28,12 +28,17 @@ Configuring OSPF Enable the OSPF API server. This is required to use ``ospfclient``. +.. option:: -l, --apiserver_addr
+ + Specify the local IPv4 address to which to bind the OSPF API server socket. + If unspecified, connections are accepted to any address. Specification of + 127.0.0.1 can be used to limit socket access to local applications. + *ospfd* must acquire interface information from *zebra* in order to function. Therefore *zebra* must be running before invoking *ospfd*. Also, if *zebra* is restarted then *ospfd* must be too. -Like other daemons, *ospfd* configuration is done in :abbr:`OSPF` specific -configuration file :file:`ospfd.conf` when the integrated config is not used. +.. include:: config-include.rst .. _ospf-multi-instance: @@ -240,6 +245,17 @@ To start OSPF process you have to specify the OSPF router. This configuration setting MUST be consistent across all routers within the OSPF domain. +.. clicmd:: neighbor A.B.C.D [poll-interval (1-65535)] [priority (0-255)] + + + Configures OSPF neighbors for non-broadcast multi-access (NBMA) networks + and point-to-multipoint non-broadcast networks. The `poll-interval` + specifies the rate for sending hello packets to neighbors that are not + active. When the configured neighbor is discovered, hello packets will be + sent at the rate of the hello-interval. The default `poll-interval` is 60 + seconds. The `priority` is used to for the Designated Router (DR) election + on non-broadcast multi-access networks. + .. clicmd:: network A.B.C.D/M area A.B.C.D .. clicmd:: network A.B.C.D/M area (0-4294967295) @@ -581,7 +597,7 @@ Interfaces Note that OSPF MD5 authentication requires that time never go backwards (correct time is NOT important, only that it never goes backwards), even across resets, if ospfd is to be able to promptly reestablish adjacencies - with its neighbours after restarts/reboots. The host should have system time + with its neighbors after restarts/reboots. The host should have system time be set at boot from an external or non-volatile source (e.g. battery backed clock, NTP, etc.) or else the system clock should be periodically saved to non-volatile storage and restored at boot if MD5 authentication is to be @@ -613,7 +629,7 @@ Interfaces Note that OSPF HMAC cryptographic authentication requires that time never go backwards (correct time is NOT important, only that it never goes backwards), even across resets, if ospfd is to be able to promptly reestablish adjacencies - with its neighbours after restarts/reboots. The host should have system time + with its neighbors after restarts/reboots. The host should have system time be set at boot from an external or non-volatile source (e.g. battery backed clock, NTP, etc.) or else the system clock should be periodically saved to non-volatile storage and restored at boot if HMAC cryptographic authentication is to be @@ -680,7 +696,7 @@ Interfaces it's recommended to set the hello delay and hello interval with the same values. The default value is 10 seconds. -.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint [delay-reflood]|point-to-point [dmvpn]) +.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint [delay-reflood|non-broadcast]|point-to-point [dmvpn]) When configuring a point-to-point network on an interface and the interface has a /32 address associated with then OSPF will treat the interface @@ -692,6 +708,13 @@ Interfaces point-to-point, but the HUB will be a point-to-multipoint. To make this topology work, specify the optional 'dmvpn' parameter at the spoke. + When the network is configured as point-to-multipoint and `non-broadcast` + is specified, the network doesn't support broadcast or multicast delivery + and neighbors cannot be discovered from OSPF hello received from the + OSPFAllRouters (224.0.0.5). Rather, they must be explicitly configured + using the :clicmd:`neighbor A.B.C.D` configuration command as they are + on non-broadcast networks. + When the network is configured as point-to-multipoint and `delay-reflood` is specified, LSAs received on the interface from neighbors on the interface will not be flooded back out on the interface immediately. @@ -715,7 +738,17 @@ Interfaces retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] +.. clicmd:: ip ospf retransmit-window (20-1000) + + + Set number of milliseconds in the window for neighbor LSA retransmission. + When a neighbor Link State (LS) retransmission timer expires, LSAs scheduled + to be retransmitted within the number of milliseconds configured are + retransmitted to the neighbor. Any expiring after the window will be + retransmitted the next time the neighbor LS retransmission timer expires. + The default is 50 milliseconds. + + .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] Set number of seconds for InfTransDelay value. LSAs' age should be @@ -740,6 +773,32 @@ Interfaces optional IPv4 address is specified, the prefix suppression will apply to the OSPF interface associated with the specified interface address. +.. clicmd:: ip ospf neighbor-filter NAME [A.B.C.D] + + Configure an IP prefix-list to use to filter packets received from + OSPF neighbors on the OSPF interface. The prefix-list should include rules + to permit or deny OSPF neighbors by IP source address. This is useful for + multi-access interfaces where adjacencies with only a subset of the + reachable neighbors are desired. Applications include testing partially + meshed topologies, OSPF Denial of Sevice (DoS) mitigation, and avoidance + of adjacencies with OSPF neighbors not meeting traffic engineering criteria. + + Example: + +.. code-block:: frr + + ! + ! Prefix-list to block neighbor with source address 10.1.0.2 + ! + ip prefix-list nbr-filter seq 10 deny 10.1.0.2/32 + ip prefix-list nbr-filter seq 200 permit any + ! + ! Configure the neighbor filter prefix-list on interface eth0 + ! + interface eth0 + ip ospf neighbor-filter nbr-filter + ! + .. clicmd:: ip ospf area (A.B.C.D|(0-4294967295)) @@ -839,11 +898,11 @@ Graceful Restart Configure Graceful Restart (RFC 3623) helper support. - By default, helper support is disabled for all neighbours. + By default, helper support is disabled for all neighbors. This config enables/disables helper support on this router - for all neighbours. + for all neighbors. To enable/disable helper support for a specific - neighbour, the router-id (A.B.C.D) has to be specified. + neighbor, the router-id (A.B.C.D) has to be specified. .. clicmd:: graceful-restart helper strict-lsa-checking @@ -853,7 +912,7 @@ Graceful Restart affects the restarting router. By default 'strict-lsa-checking' is enabled" -.. clicmd:: graceful-restart helper supported-grace-time +.. clicmd:: graceful-restart helper supported-grace-time (10-1800) Supports as HELPER for configured grace period. @@ -938,7 +997,7 @@ Showing Information User can get that information as JSON format when ``json`` keyword at the end of cli is presented. -.. clicmd:: show ip ospf graceful-restart helper [detail] [json] +.. clicmd:: show ip ospf [{(1-65535)|vrf }] graceful-restart helper [detail] [json] Displays the Graceful Restart Helper details including helper config changes. @@ -1083,7 +1142,7 @@ Router Information respectively the PCE IP address, Autonomous System (AS) numbers of controlled domains, neighbor ASs, flag and scope. For flag and scope, please refer to :rfc`5088` for the BITPATTERN recognition. Multiple 'pce neighbor' - command could be specified in order to specify all PCE neighbours. + command could be specified in order to specify all PCE neighbors. .. clicmd:: show ip ospf router-info diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst index ec107fbe4725..2519ac491228 100644 --- a/doc/user/pathd.rst +++ b/doc/user/pathd.rst @@ -327,7 +327,7 @@ Configuration Commands Delete or specify a bandwidth constraint for a dynamic candidate path. -.. clicmd:: metric [bound] METRIC VALUE [required] +.. clicmd:: metric [bound] METRIC VALUE [required] [computed] Delete or specify a metric constraint for a dynamic candidate path. @@ -475,6 +475,9 @@ Configuration Commands Specify the maximum SID depth in a PCC definition. +.. clicmd:: no msd [(1-32)] + + Default the maximum SID depth to 4. .. clicmd:: peer WORD [precedence (1-255)] @@ -531,7 +534,7 @@ retrieved via PCEP a random number based name is generated. Display PCC information. -.. clicmd:: show sr-te pcep session [NAME] +.. clicmd:: show sr-te pcep session [NAME] [json] Display the information of a PCEP session, if not name is specified all the sessions will be displayed. diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 83abfa220eee..6ea153cc35a8 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -15,11 +15,7 @@ the default Linux kernel dataplane provider. Starting PBR ============ -Default configuration file for *pbrd* is :file:`pbrd.conf`. The typical -location of :file:`pbrd.conf` is |INSTALL_PREFIX_ETC|/pbrd.conf. - -If FRR is using integrated config, then :file:`pbrd.conf` need not be -present and the :file:`frr.conf` is read instead. +.. include:: config-include.rst .. program:: pbrd @@ -267,7 +263,7 @@ specified in the rule are also applied to the packet. this action, so this field will be ignored unless another dataplane provider is used. -.. clicmd:: show pbr map [NAME] [detail|json] +.. clicmd:: show pbr map [NAME] [detail] [json] Display pbr maps either all or by ``NAME``. If ``detail`` is set, it will give information about each rule's unique internal ID and some extra diff --git a/doc/user/pim.rst b/doc/user/pim.rst index d70c3c0e64e9..5701560bd68c 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -23,12 +23,11 @@ network for optimizing forwarding of overlay BUM traffic. Starting and Stopping pimd ========================== -The default configuration file name of *pimd*'s is :file:`pimd.conf`. When -invoked *pimd* searches directory |INSTALL_PREFIX_ETC|. If -:file:`pimd.conf` is not there then next search current directory. +.. include:: config-include.rst -*pimd* requires zebra for proper operation. Additionally *pimd* depends on -routing properly setup and working in the network that it is working on. +If starting daemons by hand then please note, *pimd* requires zebra for proper +operation. Additionally *pimd* depends on routing properly setup and working in +the network that it is working on. :: @@ -56,16 +55,23 @@ Certain signals have special meanings to *pimd*. *pimd* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ip pim rp A.B.C.D A.B.C.D/M +PIM Routers +----------- + +.. clicmd:: router pim [vrf NAME] + + Configure global PIM protocol + +.. clicmd:: rp A.B.C.D A.B.C.D/M In order to use pim, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pim network must agree on these values. The first ip address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -75,41 +81,41 @@ Certain signals have special meanings to *pimd*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + vrf aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-accept-list PLIST +.. clicmd:: register-accept-list PLIST When pim receives a register packet the source of the packet will be compared to the prefix-list specified, PLIST, and if a permit is received normal processing continues. If a deny is returned for the source address of the register packet a register stop message is sent to the source. -.. clicmd:: ip pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim block. -.. clicmd:: ip pim ecmp +.. clicmd:: ecmp If pim has the a choice of ECMP nexthops for a particular RPF, pim will cause S,G flows to be spread out amongst the nexthops. If this command is not specified then the first nexthop found will be used. This command is vrf - aware, to configure for a vrf, enter the vrf submode. + aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ecmp rebalance +.. clicmd:: ecmp rebalance If pim is using ECMP and an interface goes down, cause pim to rebalance all S,G flows across the remaining nexthops. If this command is not configured pim only modifies those S,G flows that were using the interface that went - down. This command is vrf aware, to configure for a vrf, enter the vrf - submode. + down. This command is vrf aware, to configure for a vrf, specify the vrf in + the router pim block. -.. clicmd:: ip pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -117,39 +123,45 @@ Certain signals have special meanings to *pimd*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ip pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim send-v6-secondary +.. clicmd:: send-v6-secondary When sending pim hello packets tell pim to send any v6 secondary addresses on the interface. This information is used to allow pim to use v6 nexthops in it's decision for RPF lookup. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ssm prefix-list WORD +.. clicmd:: ssm prefix-list WORD Specify a range of group addresses via a prefix-list that forces pim to - never do SM over. This command is vrf aware, to configure for a vrf, enter - the vrf submode. + never do SM over. This command is vrf aware, to configure for a vrf, specify + the vrf in the router pim block. + +Global Multicast +---------------- + +These commands are valid at the top-level of the configuration (or also per +vrf where indicated), instead of under the 'router pim' submode. .. clicmd:: ip multicast rpf-lookup-mode WORD @@ -212,7 +224,7 @@ is in a vrf, enter the interface command with the vrf keyword at the end. messages. This is enabled by default. 'no' form of this command is used to restrict processing of unicast bsm messages on this interface. -.. clicmd:: ip pim drpriority (1-4294967295) +.. clicmd:: ip pim drpriority (0-4294967295) Set the DR Priority for the interface. This command is useful to allow the user to influence what node becomes the DR for a lan segment. @@ -243,9 +255,17 @@ is in a vrf, enter the interface command with the vrf keyword at the end. Tell pim to receive IGMP reports and Query on this interface. The default version is v3. This command is useful on a LHR. -.. clicmd:: ip igmp join A.B.C.D [A.B.C.D] +.. clicmd:: ip igmp join-group A.B.C.D [A.B.C.D] + + Join multicast group or source-group on an interface. This will result in + an IGMP join happening through a local socket so that IGMP reports will be + sent on this interface. It may also have the side effect of the kernel + forwarding multicast traffic to the socket unnessarily. - Join multicast group or source-group on an interface. +.. clicmd:: ip igmp static-group A.B.C.D [A.B.C.D] + + Add a static multicast group or source-group on an interface. This will behave + as if there is a receiver on this interface without any IGMP reports. .. clicmd:: ip igmp query-interval (1-65535) @@ -334,12 +354,16 @@ MSDP can be setup in different ways: .. note:: - MSDP default peer and SA filtering is not implemented. + MSDP default peer is not implemented. + +Commands available for MSDP +--------------------------- +.. note:: -Commands available for MSDP: + MSDP configuration is available under 'router pim'. -.. clicmd:: ip msdp timers (1-65535) (1-65535) [(1-65535)] +.. clicmd:: msdp timers (1-65535) (1-65535) [(1-65535)] Configure global MSDP timers. @@ -355,19 +379,39 @@ Commands available for MSDP: configures the interval between connection attempts. The default value is 30 seconds. -.. clicmd:: ip msdp mesh-group WORD member A.B.C.D +.. clicmd:: msdp mesh-group WORD member A.B.C.D Create or update a mesh group to include the specified MSDP peer. -.. clicmd:: ip msdp mesh-group WORD source A.B.C.D +.. clicmd:: msdp mesh-group WORD source A.B.C.D Create or update a mesh group to set the source address used to connect to peers. -.. clicmd:: ip msdp peer A.B.C.D source A.B.C.D +.. clicmd:: msdp peer A.B.C.D source A.B.C.D Create a regular MSDP session with peer using the specified source address. +.. clicmd:: msdp peer A.B.C.D sa-filter ACL_NAME + + Configure incoming or outgoing SA filtering rule. + + .. note:: + + The filtering will only take effect starting from the command + application. + +.. clicmd:: msdp peer A.B.C.D password WORD + + Use MD5 authentication to connect with the remote peer. + + .. note:: + + The authentication will only take effect when starting a new + connection. + + To apply it immediately call `clear ip msdp peer A.B.C.D`. + .. _show-pim-information: @@ -386,15 +430,9 @@ cause great confusion. .. clicmd:: show ip igmp [vrf NAME] join [json] - Display IGMP static join information for a specific vrf. - -.. index:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] -.. clicmd:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] + Display IGMP static join information. - Display IGMP static join information for all the vrfs present. - -.. index:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] -.. clicmd:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] +.. clicmd:: show ip igmp [vrf NAME] groups [INTERFACE [GROUP]] [detail] [json] Display IGMP groups information. @@ -577,11 +615,11 @@ cause great confusion. Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ip pim bsrp-info +.. clicmd:: show ip pim bsrp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. -.. clicmd:: show ip pim bsm-database +.. clicmd:: show ip pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. @@ -697,6 +735,13 @@ Clear commands reset various variables. removes the next hop tracking for the bsr and resets the upstreams for the dynamically learnt RPs. +.. clicmd:: clear ip msdp peer A.B.C.D + + Reset MSDP peer connection. + + Use this command to set/unset MD5 authentication. + + PIM EVPN configuration ====================== To use PIM in the underlay for overlay BUM forwarding associate a multicast @@ -735,8 +780,9 @@ Sample configuration ! You may want to enable ssmpingd for troubleshooting ! See http://www.venaas.no/multicast/ssmping/ ! - ip ssmpingd 1.1.1.1 - ip ssmpingd 2.2.2.2 + router pim + ssmpingd 1.1.1.1 + ssmpingd 2.2.2.2 ! HINTS: ! - Enable "ip pim ssm" on the interface directly attached to the @@ -751,4 +797,3 @@ Sample configuration interface eth0 ip pim ssm ip igmp - diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index 856939038ff0..edf7a82015da 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -15,12 +15,11 @@ do S,G mrouting. Starting and Stopping pim6d =========================== -The default configuration file name of *pim6d*'s is :file:`pim6d.conf`. When -invoked *pim6d* searches directory |INSTALL_PREFIX_ETC|. If -:file:`pim6d.conf` is not there then next search current directory. +.. include:: config-include.rst -*pim6d* requires zebra for proper operation. Additionally *pim6d* depends on -routing properly setup and working in the network that it is working on. +If starting daemons by hand then please note, *pim6d* requires zebra for proper +operation. Additionally *pim6d* depends on routing properly setup and working in +the network that it is working on. :: @@ -48,21 +47,28 @@ Certain signals have special meanings to *pim6d*. *pim6d* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M +PIMv6 Router +------------ + +.. clicmd:: router pim6 [vrf NAME] + + Configure the global PIMv6 protocol + +.. clicmd:: rp X:X::X:X Y:Y::Y:Y/M In order to use pimv6, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pimv6 network must agree on these values. The first ipv6 address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD +.. clicmd:: rp X:X::X:X prefix-list WORD This CLI helps in configuring RP address for a range of groups specified by the prefix-list. -.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -72,19 +78,19 @@ Certain signals have special meanings to *pim6d*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + vrf aware, to configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim6 block. -.. clicmd:: ipv6 pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -92,28 +98,28 @@ Certain signals have special meanings to *pim6d*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ipv6 pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 ssmpingd [X:X::X:X] +.. clicmd:: ssmpingd [X:X::X:X] Enable ipv6 ssmpingd configuration. A network level management tool to check whether one can receive multicast packets via SSM from host. @@ -136,7 +142,7 @@ is in a vrf, enter the interface command with the vrf keyword at the end. command will not do anything if you do not have the underlying ability of a mlag implementation. -.. clicmd:: ipv6 pim drpriority (1-4294967295) +.. clicmd:: ipv6 pim drpriority (0-4294967295) Set the DR Priority for the interface. This command is useful to allow the user to influence what node becomes the DR for a lan segment. @@ -389,11 +395,11 @@ General multicast routing state Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ipv6 pim bsrp-info +.. clicmd:: show ipv6 pim bsrp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. -.. clicmd:: show ipv6 pim bsm-database +.. clicmd:: show ipv6 pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. @@ -418,7 +424,7 @@ Clear commands reset various variables. .. clicmd:: clear ipv6 pim [vrf NAME] interface traffic - When this command is issued, resets the information about the + When this command is issued, resets the information about the number of PIM protocol packets sent/received on an interface. .. clicmd:: clear ipv6 pim oil @@ -495,7 +501,7 @@ the config was written out. .. clicmd:: debug mld trace [detail] - This traces mld code and how it is running. + This traces mld code and how it is running. .. clicmd:: debug pimv6 bsm diff --git a/doc/user/prior-config-files.rst b/doc/user/prior-config-files.rst new file mode 100644 index 000000000000..a01b6888596d --- /dev/null +++ b/doc/user/prior-config-files.rst @@ -0,0 +1,23 @@ +.. +.. January 12 2024, Christian Hopps +.. +.. Copyright (c) 2024, LabN Consulting, L.L.C. +.. +.. + +Prior versions of FRR supported reading and writing per-daemon config files; +however, with the introduction of the centralized management daemon ``mgmtd`` +this could no longer be supported. + +In order to allow for an orderly transition from per-daemon config files to the +integrated config file, FRR daemons will continue to try and **read** their +specific per-daemon configuration file as before. Additionally the config can +still be loaded directly using the ``-f`` or ``--config-file`` CLI options; +however, these files will **not** be updated when the configuration is written +(e.g., with the ``write mem`` command). + +.. warning:: + + Per-daemon files will **no longer** be updated when the user issues a ``write + memory`` command. Therefore these per-daemon config files should only be used + as a mechanism for transitioning to the integrated config, and then removed. diff --git a/doc/user/protocols.rst b/doc/user/protocols.rst new file mode 100644 index 000000000000..e571cd66fc84 --- /dev/null +++ b/doc/user/protocols.rst @@ -0,0 +1,35 @@ +.. _protocols: + +######### +Protocols +######### + +.. toctree:: + :maxdepth: 2 + + zebra + bfd + bgp + babeld + fabricd + ldpd + eigrpd + evpn + isisd + nhrpd + ospfd + ospf6d + pathd + pim + pimv6 + pbr + ripd + ripngd + sharp + static + vnc + vrrp + bmp + watchfrr + mgmtd + diff --git a/doc/user/requirements.txt b/doc/user/requirements.txt new file mode 100644 index 000000000000..483a4e9600bd --- /dev/null +++ b/doc/user/requirements.txt @@ -0,0 +1 @@ +sphinx_rtd_theme diff --git a/doc/user/ripd.rst b/doc/user/ripd.rst index f9c772430221..ea13dc92df16 100644 --- a/doc/user/ripd.rst +++ b/doc/user/ripd.rst @@ -21,15 +21,15 @@ version 1 as described in RFC1058. Starting and Stopping ripd ========================== -The default configuration file name of *ripd*'s is :file:`ripd.conf`. When -invocation *ripd* searches directory |INSTALL_PREFIX_ETC|. If :file:`ripd.conf` -is not there next search current directory. +.. include:: config-include.rst RIP uses UDP port 520 to send and receive RIP packets. So the user must have the capability to bind the port, generally this means that the user must have -superuser privileges. RIP protocol requires interface information maintained by -*zebra* daemon. So running *zebra* is mandatory to run *ripd*. Thus minimum -sequence for running RIP is like below: +superuser privileges. + +If starting daemons by hand then please note, RIP protocol requires interface +information maintained by *zebra* daemon. So running *zebra* is mandatory to run +*ripd*. Thus minimum sequence for running RIP is like below: :: diff --git a/doc/user/ripngd.rst b/doc/user/ripngd.rst index 1e78294f3226..f55ee3944570 100644 --- a/doc/user/ripngd.rst +++ b/doc/user/ripngd.rst @@ -12,6 +12,8 @@ reincarnation of the RIP protocol. Invoking ripngd =============== +.. include:: config-include.rst + There are no `ripngd` specific invocation options. Common options can be specified (:ref:`common-invocation-options`). @@ -134,7 +136,7 @@ functionality. range is very large for compatibility with other protocols. For RIPng, valid metric values are from 1 to 16. -.. clicmd:: set tag (1-4294967295) +.. clicmd:: set tag Set a tag on the matched route. diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 3d43e74744d1..1d2f4e352f38 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -176,18 +176,19 @@ Route Map Match Command Matches the specified `metric`. -.. clicmd:: match tag TAG +.. clicmd:: match tag - Matches the specified tag value associated with the route. This tag value - can be in the range of (1-4294967295). + Matches the specified tag (or untagged) value associated with the route. .. clicmd:: match local-preference METRIC Matches the specified `local-preference`. -.. clicmd:: match community COMMUNITY_LIST +.. clicmd:: match community COMMUNITY_LIST [] - Matches the specified `community_list` + Matches the specified `community_list`. ``exact-match`` specifies to + do the exact matching of the communities, while ``any`` - can match any + community specified in COMMUNITY_LIST. .. clicmd:: match peer IPV4_ADDR @@ -239,9 +240,10 @@ Route Map Set Command .. program:: configure -.. clicmd:: set tag TAG +.. clicmd:: set tag + + Set a tag on the matched route. - Set a tag on the matched route. This tag value can be from (1-4294967295). Additionally if you have compiled with the :option:`--enable-realms` configure option. Tag values from (1-255) are sent to the Linux kernel as a realm value. Then route policy can be applied. See the tc man page. As @@ -378,13 +380,13 @@ Route Map Exit Action Command .. clicmd:: on-match next -.. clicmd:: continue - Proceed on to the next entry in the route-map. -.. clicmd:: on-match goto N +.. clicmd:: continue (1-65535) -.. clicmd:: continue N + Proceed to the specified sequence in the route-map. + +.. clicmd:: on-match goto N Proceed processing the route-map at the first entry whose order is >= N diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index 40535362475b..98f9b103cdf9 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -62,8 +62,9 @@ otherwise ``bgpd`` daemon won't startup. This command enables the RPKI configuration mode. Most commands that start with *rpki* can only be used in this mode. - When it is used in a telnet session, leaving of this mode cause rpki to be - initialized. + This command is available either in *configure node* for default *vrf* or + in *vrf node* for specific *vrf*. When it is used in a telnet session, + leaving of this mode cause rpki to be initialized. Executing this command alone does not activate prefix validation. You need to configure at least one reachable cache server. See section @@ -90,6 +91,9 @@ Examples of the error:: router(config)# rpki % [BGP] Unknown command: rpki + router(config-vrf)# rpki + % [BGP] Unknown command: rpki + Note that the RPKI commands will be available in vtysh when running ``find rpki`` regardless of whether the module is loaded. @@ -98,7 +102,14 @@ Note that the RPKI commands will be available in vtysh when running Configuring RPKI/RTR Cache Servers ---------------------------------- -The following commands are independent of a specific cache server. +RPKI/RTR can be configured independently, either in configure node, or in *vrf* +sub context. If configured in configure node, the core *bgp* instance of default +*vrf* is impacted by the configuration. + +Each RPKI/RTR context is mapped to a *vrf* and can be made up of a specific list +of cache-servers, and specific settings. + +The following commands are available for independent of a specific cache server. .. clicmd:: rpki polling_period (1-3600) @@ -120,19 +131,13 @@ The following commands are independent of a specific cache server. The default value is 600 seconds. -.. clicmd:: rpki cache (A.B.C.D|WORD) PORT [SSH_USERNAME] [SSH_PRIVKEY_PATH] [KNOWN_HOSTS_PATH] [source A.B.C.D] preference (1-255) +.. clicmd:: rpki cache tcp HOST PORT [source A.B.C.D] preference (1-255) + Add a TCP cache server to the socket. - Add a cache server to the socket. By default, the connection between router - and cache server is based on plain TCP. Protecting the connection between - router and cache server by SSH is optional. Deleting a socket removes the - associated cache server and terminates the existing connection. +.. clicmd:: rpki cache ssh HOST PORT SSH_USERNAME SSH_PRIVKEY_PATH [KNOWN_HOSTS_PATH] [source A.B.C.D] preference (1-255) - A.B.C.D|WORD - Address of the cache server. - - PORT - Port number to connect to the cache server + Add a SSH cache server to the socket. SSH_USERNAME SSH username to establish an SSH connection to the cache server. @@ -148,7 +153,6 @@ The following commands are independent of a specific cache server. source A.B.C.D Source address of the RPKI connection to access cache server. - .. _validating-bgp-updates: Validating BGP Updates @@ -166,7 +170,7 @@ Validating BGP Updates .. code-block:: frr ! Allow for invalid routes in route selection process - route bgp 60001 + route bgp 65001 ! ! Set local preference of invalid prefixes to 10 route-map rpki permit 10 @@ -200,35 +204,42 @@ Debugging Displaying RPKI --------------- -.. clicmd:: show rpki prefix [(1-4294967295)] [json] +.. clicmd:: show rpki configuration [vrf NAME] [json] + + Display RPKI configuration state including timers values. + +.. clicmd:: show rpki prefix [ASN] [vrf NAME] [json] Display validated prefixes received from the cache servers filtered - by the specified prefix. + by the specified prefix. The AS number space has been increased + to allow the choice of using AS 0 because RFC-7607 specifically + calls out the usage of 0 in a special case. -.. clicmd:: show rpki as-number ASN [json] +.. clicmd:: show rpki as-number ASN [vrf NAME] [json] Display validated prefixes received from the cache servers filtered - by ASN. + by ASN. The usage of AS 0 is allowed because RFC-76067 specifically + calls out the usage of 0 in a special case. -.. clicmd:: show rpki prefix-table [json] +.. clicmd:: show rpki prefix-table [vrf NAME] [json] Display all validated prefix to origin AS mappings/records which have been received from the cache servers and stored in the router. Based on this data, the router validates BGP Updates. -.. clicmd:: show rpki cache-server [json] +.. clicmd:: show rpki cache-server [vrf NAME] [json] Display all configured cache servers, whether active or not. -.. clicmd:: show rpki cache-connection [json] +.. clicmd:: show rpki cache-connection [vrf NAME] [json] Display all cache connections, and show which is connected or not. -.. clicmd:: show bgp [afi] [safi] rpki +.. clicmd:: show bgp [vrf NAME] [afi] [safi] rpki Display for the specified prefix or address the bgp paths that match the given rpki state. -.. clicmd:: show bgp [afi] [safi] rpki +.. clicmd:: show bgp [vrf NAME] [afi] [safi] rpki Display all prefixes that match the given rpki state. @@ -244,25 +255,52 @@ RPKI Configuration Example debug bgp keepalives debug rpki ! + vrf VRF1 + rpki + rpki polling_period 1000 + rpki timeout 10 + ! SSH Example: + rpki cache ssh example.com 22 rtr-ssh ./ssh_key/id_rsa preference 1 + ! TCP Example: + rpki cache tcp rpki-validator.realmv6.org 8282 preference 2 + exit + ! + exit-vrf + ! rpki rpki polling_period 1000 rpki timeout 10 ! SSH Example: - rpki cache example.com source 141.22.28.223 22 rtr-ssh ./ssh_key/id_rsa ./ssh_key/id_rsa.pub preference 1 + rpki cache ssh example.com source 198.51.100.223 22 rtr-ssh ./ssh_key/id_rsa preference 1 ! TCP Example: - rpki cache rpki-validator.realmv6.org 8282 preference 2 + rpki cache tcp rpki-validator.realmv6.org 8282 preference 2 exit ! - router bgp 60001 - bgp router-id 141.22.28.223 - network 192.168.0.0/16 - neighbor 123.123.123.0 remote-as 60002 - neighbor 123.123.123.0 route-map rpki in - neighbor 123.123.123.0 update-source 141.22.28.223 + router bgp 65001 + bgp router-id 198.51.100.223 + neighbor 203.0.113.1 remote-as 65002 + neighbor 203.0.113.1 update-source 198.51.100.223 + address-family ipv4 + network 192.0.2.0/24 + neighbor 203.0.113.1 route-map rpki in + exit-address-family + ! + address-family ipv6 + neighbor 203.0.113.1 activate + neighbor 203.0.113.1 route-map rpki in + exit-address-family + ! + router bgp 65001 vrf VRF1 + bgp router-id 198.51.100.223 + neighbor 203.0.113.1 remote-as 65002 + address-family ipv4 + network 192.0.2.0/24 + neighbor 203.0.113.1 route-map rpki in + exit-address-family ! address-family ipv6 - neighbor 123.123.123.0 activate - neighbor 123.123.123.0 route-map rpki in + neighbor 203.0.113.1 activate + neighbor 203.0.113.1 route-map rpki in exit-address-family ! route-map rpki permit 10 diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 3e73a599edec..2be38a31df69 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -13,11 +13,7 @@ labs. Starting SHARP ============== -Default configuration file for *sharpd* is :file:`sharpd.conf`. The typical -location of :file:`sharpd.conf` is |INSTALL_PREFIX_ETC|/sharpd.conf. - -If the user is using integrated config, then :file:`sharpd.conf` need not be -present and the :file:`frr.conf` is read instead. +.. include:: config-include.rst .. program:: sharpd @@ -67,6 +63,11 @@ keyword. At present, no sharp commands will be preserved in the config. Install a label into the kernel that causes the specified vrf NAME table to be used for pop and forward operations when the specified label is seen. +.. clicmd:: sharp watch [vrf VRF_NAME] neighbor + + Instruct zebra to notify sharpd about neighbor events in the specified vrf. + If no vrf is specified then assume default. + .. clicmd:: sharp watch |import [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is diff --git a/doc/user/snmp.rst b/doc/user/snmp.rst index 0bf3565b2e2e..3c2d11a6a732 100644 --- a/doc/user/snmp.rst +++ b/doc/user/snmp.rst @@ -126,54 +126,121 @@ An example below is how to query SNMP for BGP: $ # Information about the peers (bgp4V2PeerTable): $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.2 ... - .1.3.6.1.3.5.1.1.2.1.1.1.4.192.168.10.124 = Gauge32: 0 - .1.3.6.1.3.5.1.1.2.1.1.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 0 - .1.3.6.1.3.5.1.1.2.1.2.1.4.192.168.10.124 = INTEGER: 1 - .1.3.6.1.3.5.1.1.2.1.2.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 - .1.3.6.1.3.5.1.1.2.1.3.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11 - .1.3.6.1.3.5.1.1.2.1.3.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 01 - .1.3.6.1.3.5.1.1.2.1.4.1.4.192.168.10.124 = INTEGER: 1 - .1.3.6.1.3.5.1.1.2.1.4.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 - .1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 7C - .1.3.6.1.3.5.1.1.2.1.5.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 02 - .1.3.6.1.3.5.1.1.2.1.6.1.4.192.168.10.124 = Gauge32: 179 - .1.3.6.1.3.5.1.1.2.1.6.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 179 - .1.3.6.1.3.5.1.1.2.1.7.1.4.192.168.10.124 = Gauge32: 65002 - .1.3.6.1.3.5.1.1.2.1.7.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65002 - .1.3.6.1.3.5.1.1.2.1.8.1.4.192.168.10.124 = Hex-STRING: C0 A8 0A 11 - .1.3.6.1.3.5.1.1.2.1.8.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C0 A8 0A 11 - .1.3.6.1.3.5.1.1.2.1.9.1.4.192.168.10.124 = Gauge32: 41894 - .1.3.6.1.3.5.1.1.2.1.9.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 39960 - .1.3.6.1.3.5.1.1.2.1.10.1.4.192.168.10.124 = Gauge32: 65001 - .1.3.6.1.3.5.1.1.2.1.10.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65001 - .1.3.6.1.3.5.1.1.2.1.11.1.4.192.168.10.124 = Hex-STRING: C8 C8 C8 CA - .1.3.6.1.3.5.1.1.2.1.11.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C8 C8 C8 CA - .1.3.6.1.3.5.1.1.2.1.12.1.4.192.168.10.124 = INTEGER: 2 - .1.3.6.1.3.5.1.1.2.1.12.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 - .1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.10.124 = INTEGER: 6 - .1.3.6.1.3.5.1.1.2.1.13.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 6 + .1.3.6.1.3.5.1.1.2.1.1.1.1.192.168.10.124 = Gauge32: 0 + .1.3.6.1.3.5.1.1.2.1.1.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 0 + .1.3.6.1.3.5.1.1.2.1.2.1.1.192.168.10.124 = INTEGER: 1 + .1.3.6.1.3.5.1.1.2.1.2.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.3.1.1.192.168.10.124 = Hex-STRING: C0 A8 0A 11 + .1.3.6.1.3.5.1.1.2.1.3.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 01 + .1.3.6.1.3.5.1.1.2.1.4.1.1.192.168.10.124 = INTEGER: 1 + .1.3.6.1.3.5.1.1.2.1.4.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.5.1.1.192.168.10.124 = Hex-STRING: C0 A8 0A 7C + .1.3.6.1.3.5.1.1.2.1.5.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 2A 02 47 80 0A BC 00 00 00 00 00 00 00 00 00 02 + .1.3.6.1.3.5.1.1.2.1.6.1.1.192.168.10.124 = Gauge32: 179 + .1.3.6.1.3.5.1.1.2.1.6.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 179 + .1.3.6.1.3.5.1.1.2.1.7.1.1.192.168.10.124 = Gauge32: 65002 + .1.3.6.1.3.5.1.1.2.1.7.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65002 + .1.3.6.1.3.5.1.1.2.1.8.1.1.192.168.10.124 = Hex-STRING: C0 A8 0A 11 + .1.3.6.1.3.5.1.1.2.1.8.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C0 A8 0A 11 + .1.3.6.1.3.5.1.1.2.1.9.1.1.192.168.10.124 = Gauge32: 41894 + .1.3.6.1.3.5.1.1.2.1.9.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 39960 + .1.3.6.1.3.5.1.1.2.1.10.1.1.192.168.10.124 = Gauge32: 65001 + .1.3.6.1.3.5.1.1.2.1.10.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 65001 + .1.3.6.1.3.5.1.1.2.1.11.1.1.192.168.10.124 = Hex-STRING: C8 C8 C8 CA + .1.3.6.1.3.5.1.1.2.1.11.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: C8 C8 C8 CA + .1.3.6.1.3.5.1.1.2.1.12.1.1.192.168.10.124 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.12.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 2 + .1.3.6.1.3.5.1.1.2.1.13.1.1.192.168.10.124 = INTEGER: 6 + .1.3.6.1.3.5.1.1.2.1.13.1.2.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = INTEGER: 6 $ # Information about the BGP table (bgp4V2NlriTable): $ snmpwalk -c public -v2c -On -Ln localhost .1.3.6.1.3.5.1.1.9 ... - .1.3.6.1.3.5.1.1.9.1.22.1.4.10.0.2.0.24.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.10.10.100.0.24.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.1.32.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.2.32.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.172.16.31.3.32.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.0.0.24.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.1.0.24.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.1.4.192.168.10.0.24.192.168.10.124 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.22.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Gauge32: 1 - .1.3.6.1.3.5.1.1.9.1.24.1.4.10.0.2.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.10.10.100.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.1.32.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.2.32.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.172.16.31.3.32.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.0.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.1.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.1.4.192.168.10.0.24.192.168.10.124 = Hex-STRING: 02 01 FD E9 - .1.3.6.1.3.5.1.1.9.1.24.2.16.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.0.64.42.2.71.128.10.188.0.0.0.0.0.0.0.0.0.2 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.1.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.1.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.1.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.1.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.2.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.2.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.2.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 2 + .1.3.6.1.3.5.1.1.9.1.2.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 2 + .1.3.6.1.3.5.1.1.9.1.3.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.3.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.3.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.3.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.4.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.4.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.4.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 2 + .1.3.6.1.3.5.1.1.9.1.4.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 2 + .1.3.6.1.3.5.1.1.9.1.5.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Hex-STRING: 0A 00 00 00 + .1.3.6.1.3.5.1.1.9.1.5.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Hex-STRING: 0A 00 00 02 + .1.3.6.1.3.5.1.1.9.1.5.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: 20 01 0D B8 00 00 00 00 00 00 00 00 00 00 00 01 + .1.3.6.1.3.5.1.1.9.1.5.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: 20 01 0D B8 00 01 00 00 00 00 00 00 00 00 00 00 + .1.3.6.1.3.5.1.1.9.1.6.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 31 + .1.3.6.1.3.5.1.1.9.1.6.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 32 + .1.3.6.1.3.5.1.1.9.1.6.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 128 + .1.3.6.1.3.5.1.1.9.1.6.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 56 + .1.3.6.1.3.5.1.1.9.1.7.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.7.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.7.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.7.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.8.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.8.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.8.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.8.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 3 + .1.3.6.1.3.5.1.1.9.1.9.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.9.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 3 + .1.3.6.1.3.5.1.1.9.1.10.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.10.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.10.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 4 + .1.3.6.1.3.5.1.1.9.1.10.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 4 + .1.3.6.1.3.5.1.1.9.1.11.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Hex-STRING: C0 A8 0C 01 + .1.3.6.1.3.5.1.1.9.1.11.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Hex-STRING: C0 A8 0C 01 + .1.3.6.1.3.5.1.1.9.1.11.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: FE 80 00 00 00 00 00 00 30 39 84 FF FE 9A 24 2B + .1.3.6.1.3.5.1.1.9.1.11.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: FE 80 00 00 00 00 00 00 30 39 84 FF FE 9A 24 2B + .1.3.6.1.3.5.1.1.9.1.14.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 0 + .1.3.6.1.3.5.1.1.9.1.14.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 0 + .1.3.6.1.3.5.1.1.9.1.14.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 0 + .1.3.6.1.3.5.1.1.9.1.14.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 0 + .1.3.6.1.3.5.1.1.9.1.15.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.15.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.15.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.15.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + .1.3.6.1.3.5.1.1.9.1.16.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.16.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.16.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + .1.3.6.1.3.5.1.1.9.1.16.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 1 + 1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 1 + 1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 2 + 1.3.6.1.3.5.1.1.9.1.17.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 1 + 1.3.6.1.3.5.1.1.9.1.17.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 2 + 1.3.6.1.3.5.1.1.9.1.18.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.18.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.18.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.18.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.19.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.19.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.19.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.19.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = INTEGER: 0 + 1.3.6.1.3.5.1.1.9.1.20.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 0 + 1.3.6.1.3.5.1.1.9.1.20.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 0 + 1.3.6.1.3.5.1.1.9.1.20.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + 1.3.6.1.3.5.1.1.9.1.20.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 0 + 1.3.6.1.3.5.1.1.9.1.21.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Hex-STRING: 00 00 00 00 + 1.3.6.1.3.5.1.1.9.1.21.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Hex-STRING: 00 00 00 00 + 1.3.6.1.3.5.1.1.9.1.21.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: 00 00 00 00 + 1.3.6.1.3.5.1.1.9.1.21.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: 00 00 00 00 + 1.3.6.1.3.5.1.1.9.1.22.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Gauge32: 1 + 1.3.6.1.3.5.1.1.9.1.22.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.22.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Gauge32: 1 + .1.3.6.1.3.5.1.1.9.1.24.1.1.1.1.10.0.0.0.31.1.192.168.12.1.1 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.1.1.1.10.0.0.2.32.1.192.168.12.1.1 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: 02 01 FD E9 + .1.3.6.1.3.5.1.1.9.1.24.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1.1 = Hex-STRING: 02 01 FD E9 + The AgentX protocol can be transported over a Unix socket or using TCP or UDP. It usually defaults to a Unix socket and depends on how NetSNMP was built. If diff --git a/doc/user/snmptrap.rst b/doc/user/snmptrap.rst index 7e306b743dd1..52b1904665df 100644 --- a/doc/user/snmptrap.rst +++ b/doc/user/snmptrap.rst @@ -4,8 +4,9 @@ Handling SNMP Traps To handle snmp traps make sure your snmp setup of frr works correctly as described in the frr documentation in :ref:`snmp-support`. -The BGP4 mib will send traps on peer up/down events. These should be visible in -your snmp logs with a message similar to: +BGP handles both :rfc:`4273` and [Draft-IETF-idr-bgp4-mibv2-11]_ MIBs. +The BGP4 MIBs will send traps on peer up/down events. These should be +visible in your snmp logs with a message similar to: :: @@ -199,3 +200,24 @@ a siren, have your display flash, etc., be creative ;). # mail the notification echo "$MAIL" | mail -s "$SUBJECT" $EMAILADDR + +.. _traps-mib-selection: + +Traps Mib Selection in BGP +-------------------------- + +Both :rfc:`4273` and [Draft-IETF-idr-bgp4-mibv2-11]_ MIBs define traps for +dealing with up/down events and state transition. The user has the +possibility to select the MIB he wants to receive traps from: + +.. clicmd:: bgp snmp traps + +By default, only rfc4273 traps are enabled and sent. + +.. [Draft-IETF-idr-bgp4-mibv2-11] + +The :rfc:`4382` also defines traps to inform when an L3VPN network changes +the operational status of its VRF interface. The user can choose to suppress +those traps or not. + +.. clicmd:: bgp snmp traps rfc4382 diff --git a/doc/user/static.rst b/doc/user/static.rst index d405276573df..922c71a073a7 100644 --- a/doc/user/static.rst +++ b/doc/user/static.rst @@ -12,21 +12,13 @@ of static routes. Starting STATIC =============== -Default configuration file for *staticd* is :file:`staticd.conf`. The typical -location of :file:`staticd.conf` is |INSTALL_PREFIX_ETC|/staticd.conf. - -If the user is using integrated config, then :file:`staticd.conf` need not be -present and the :file:`frr.conf` is read instead. - -If the user has not fully upgraded to using the staticd.conf and still has -a non-integrated config with zebra.conf holding the static routes, *staticd* -will read in the :file:`zebrad.conf` as a backup. - .. program:: staticd :abbr:`STATIC` supports all the common FRR daemon start options which are documented elsewhere. +.. include:: config-include.rst + .. _static-route-commands: Static Route Commands diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 4879f7f7ef3c..395ce305fe94 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -29,7 +29,7 @@ user_RSTFILES = \ doc/user/ospf6d.rst \ doc/user/ospfd.rst \ doc/user/ospf_fundamentals.rst \ - doc/user/overview.rst \ + doc/user/about.rst \ doc/user/packet-dumps.rst \ doc/user/pathd.rst \ doc/user/pim.rst \ diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst index ef3aebeafa08..d99fc23ef5be 100644 --- a/doc/user/vrrp.rst +++ b/doc/user/vrrp.rst @@ -24,11 +24,7 @@ protocol. Starting VRRP ============= -The configuration file for *vrrpd* is :file:`vrrpd.conf`. The typical location -of :file:`vrrpd.conf` is |INSTALL_PREFIX_ETC|/vrrpd.conf. - -If using integrated config, then :file:`vrrpd.conf` need not be present and -:file:`frr.conf` is read instead. +.. include:: config-include.rst .. program:: vrrpd diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst index adbdf3451a3a..9722231d3330 100644 --- a/doc/user/vtysh.rst +++ b/doc/user/vtysh.rst @@ -131,14 +131,14 @@ could be made SGID (set group ID) to the |INSTALL_VTY_GROUP| group. at all. -.. _integrated-configuration-mode: +.. _integrated-configuration-file: -Integrated configuration mode +Integrated configuration file ============================= -Integrated configuration mode uses a single configuration file, -:file:`frr.conf`, for all daemons. This replaces the individual files like -:file:`zebra.conf` or :file:`bgpd.conf`. +FRR uses a single configuration file, :file:`frr.conf`, for all daemons. This +replaces the individual files like :file:`zebra.conf` or :file:`bgpd.conf` used +in previous versions of the software. :file:`frr.conf` is located in |INSTALL_PREFIX_ETC|. All daemons check for the existence of this file at startup, and if it exists will not load their diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 8b2d727f3667..900d2fd34305 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -50,7 +50,8 @@ Besides the common invocation options (:ref:`common-invocation-options`), the When *Zebra* starts with this option, the VRF backend is based on Linux network namespaces. That implies that all network namespaces discovered by ZEBRA will create an associated VRF. The other daemons will operate on the VRF - VRF defined by *Zebra*, as usual. + VRF defined by *Zebra*, as usual. If this option is specified when running + *Zebra*, one must also specify the same option for *mgmtd*. .. seealso:: :ref:`zebra-vrf` @@ -177,16 +178,15 @@ Standard Commands work on non-linux systems at all. 'enable' and 'disable' will respectively turn on and off mpls on the given interface. -.. clicmd:: multicast +.. clicmd:: multicast Enable or disable multicast flag for the interface. -.. clicmd:: bandwidth (1-10000000) +.. clicmd:: bandwidth (1-1000000) - - Set bandwidth value of the interface in kilobits/sec. This is for + Set bandwidth value of the interface in Megabits/sec. This is for calculating OSPF cost. This command does not affect the actual device configuration. @@ -213,20 +213,14 @@ Link Parameters Commands .. clicmd:: link-params + Enter into the link parameters sub node. This command activates the link + parameters and allows to configure routing information that could be used + as part of Traffic Engineering on this interface. MPLS-TE must be enabled at + the OSPF (:ref:`ospf-traffic-engineering`) or ISIS + (:ref:`isis-traffic-engineering`) router level in complement to this. To + disable link parameters, use the ``no`` version of this command. - Enter into the link parameters sub node. At least 'enable' must be - set to activate the link parameters, and consequently routing - information that could be used as part of Traffic Engineering on - this interface. MPLS-TE must be enable at the OSPF - (:ref:`ospf-traffic-engineering`) or ISIS - (:ref:`isis-traffic-engineering`) router level in complement to - this. - - Under link parameter statement, the following commands set the different TE values: - -.. clicmd:: enable - - Enable link parameters for this interface. +Under link parameter statement, the following commands set the different TE values: .. clicmd:: metric (0-4294967295) @@ -252,7 +246,7 @@ Link Parameters Commands as specified in RFC3630 (OSPF) or RFC5305 (ISIS). Admin-group is also known as Resource Class/Color in the OSPF protocol. -.. clicmd:: [no] affinity AFFINITY-MAP-NAME +.. clicmd:: affinity AFFINITY-MAP-NAME This commands configures the Traffic Engineering Admin-Group of the interface using the affinity-map definitions (:ref:`affinity-map`). @@ -263,7 +257,7 @@ Link Parameters Commands ``admin-grp`` and ``affinity`` commands provide two ways of setting admin-groups. They cannot be both set on the same interface. -.. clicmd:: [no] affinity-mode [extended|standard|both] +.. clicmd:: affinity-mode [extended|standard|both] This commands configures which admin-group format is set by the affinity command. ``extended`` Admin-Group is the default and uses the RFC7308 format. @@ -374,6 +368,8 @@ outgoing interface Resolve PBR nexthop via ip neigh tracking +.. _administrative-distance: + Administrative Distance ======================= @@ -420,16 +416,34 @@ the same distances that other routing suites have chosen. +------------+-----------+ An admin distance of 255 indicates to Zebra that the route should not be -installed into the Data Plane. Additionally routes with an admin distance +installed into the Data Plane. Additionally routes with an admin distance of 255 will not be redistributed. Zebra does treat Kernel routes as special case for the purposes of Admin -Distance. Upon learning about a route that is not originated by FRR -we read the metric value as a uint32_t. The top byte of the value +Distance. Upon learning about a route that is not originated by FRR +we read the metric value as a uint32_t. The top byte of the value is interpreted as the Administrative Distance and the low three bytes -are read in as the metric. This special case is to facilitate VRF +are read in as the metric. This special case is to facilitate VRF default routes. +.. code-block:: shell + + $ # Set administrative distance to 255 for Zebra + $ ip route add 192.0.2.0/24 metric $(( 2**32 - 2**24 )) dev lo + $ vtysh -c 'show ip route 192.0.2.0/24 json' | jq '."192.0.2.0/24"[] | (.distance, .metric)' + 255 + 0 + $ # Set administrative distance to 192 for Zebra + $ ip route add 192.0.2.0/24 metric $(( 2**31 + 2**30 )) dev lo + $ vtysh -c 'show ip route 192.0.2.0/24 json' | jq '."192.0.2.0/24"[] | (.distance, .metric)' + 192 + 0 + $ # Set administrative distance to 128, and metric 100 for Zebra + $ ip route add 192.0.2.0/24 metric $(( 2**31 + 100 )) dev lo + $ vtysh -c 'show ip route 192.0.2.0/24 json' | jq '."192.0.2.0/24"[] | (.distance, .metric)' + 128 + 100 + Route Replace Semantics ======================= @@ -763,6 +777,44 @@ presence of the entry. 21 Static 10.125.0.2 IPv4 Explicit Null +MPLS label chunks +----------------- + +MPLS label chunks are handled in the zebra label manager service, +which ensures a same label value or label chunk can not be used by +multiple CP routing daemons at the same time. + +Label requests originate from CP routing daemons, and are resolved +over the default MPLS range (16-1048575). There are two kind of +requests: +- Static label requests request an exact label value or range. For +instance, segment routing label blocks requests originating from +IS-IS are part of it. +- Dynamic label requests only need a range of label values. The +'bgp l3vpn export auto' command uses such requests. + +Allocated label chunks table can be dumped using the command + +.. clicmd:: show debugging label-table [json] + +:: + + zebra# show debugging label-table + Proto ospf: [300/350] + Proto srte: [500/500] + Proto isis: [1200/1300] + Proto ospf: [20000/21000] + Proto isis: [22000/23000] + +.. clicmd:: mpls label dynamic-block (16-1048575) (16-1048575) + + Define a range of labels where dynamic label requests will + allocate label chunks from. This command guarantees that + static label values outside that range will not conflict + with the dynamic label requests. When the dynamic-block + range is configured, static label requests that match that + range are not accepted. + .. _zebra-srv6: Segment-Routing IPv6 @@ -780,6 +832,35 @@ FRR's cli or frr.conf or zebra.conf. This section shows how to configure SRv6 on FRR. Of course SRv6 can be used as standalone, and this section also helps that case. +.. clicmd:: show segment-routing srv6 manager [json] + + This command dumps the SRv6 information configured on zebra, including + the encapsulation parameters (e.g., the IPv6 source address used for + the encapsulated packets). + + Example:: + + router# sh segment-routing srv6 manager + Parameters: + Encapsulation: + Source Address: + Configured: fc00:0:1::1 + + + To get the same information in json format, you can use the ``json`` keyword:: + + rose-srv6# sh segment-routing srv6 manager json + { + "parameters":{ + "encapsulation":{ + "sourceAddress":{ + "configured":"fc00:0:1::1" + } + } + } + } + + .. clicmd:: show segment-routing srv6 locator [json] This command dump SRv6-locator configured on zebra. SRv6-locator is used @@ -940,6 +1021,98 @@ and this section also helps that case. ! ... +.. clicmd:: format NAME + + Specify the SID allocation schema for the SIDs allocated from this locator. Currently, + FRR supports supports the following allocation schemas: + + - `usid-f3216` + - `uncompressed` + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# locators + router(config-srv6-locators)# locator loc1 + router(config-srv6-locator)# prefix fc00:0:1::/48 + router(config-srv6-locator)# format usid-f3216 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 + format usid-f3216 + ! + ... + +.. clicmd:: encapsulation + + Configure parameters for SRv6 encapsulation. + +.. clicmd:: source-address X:X::X:X + + Configure the source address of the outer encapsulating IPv6 header. + +.. clicmd:: formats + + Configure SRv6 SID formats. + +.. clicmd:: format NAME + + Configure SRv6 SID format. + +.. clicmd:: compressed usid + + Enable SRv6 uSID compression and configure SRv6 uSID compression parameters. + +.. clicmd:: local-id-block start START + + Configure the start value for the Local ID Block (LIB). + +.. clicmd:: local-id-block explicit start START end END + + Configure the start/end values for the Explicit LIB (ELIB). + +.. clicmd:: wide-local-id-block start START end END + + Configure the start/end values for the Wide LIB (W-LIB). + +.. clicmd:: wide-local-id-block explicit start START + + Configure the start value for the Explicit Wide LIB (EW-LIB). + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# formats + router(config-srv6-formats)# format usid-f3216 + router(config-srv6-format)# compressed usid + router(config-srv6-format-usid)# local-id-block start 0xD000 + router(config-srv6-format-usid)# local-id-block explicit start 0xF000 end 0xFDFF + router(config-srv6-format-usid)# wide-local-id-block start 0xFFF4 end 0xFFF5 + router(config-srv6-format-usid)# wide-local-id-block explicit start 0xFFF4 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + formats + format usid-f3216 + compressed usid + local-id-block start 0xD000 + local-id-block explicit start 0xF000 end 0xFDFF + wide-local-id-block start 0xFFF4 end 0xFFF5 + wide-local-id-block explicit start 0xFFF4 + ! + ... + .. _multicast-rib-commands: Multicast RIB Commands @@ -1267,6 +1440,9 @@ FPM Commands User FPM configurations: 1 User FPM disable requests: 0 +.. clicmd:: show fpm status [json] + + Show the FPM status. .. clicmd:: clear fpm counters @@ -1361,29 +1537,41 @@ To program the PBR rules as rte_flows you additionally need to configure zebra Terminal Mode Commands ============================ -.. clicmd:: show ip route +.. clicmd:: show [ip|ipv6] route Display current routes which zebra holds in its database. :: Router# show ip route - Codes: K - kernel route, C - connected, S - static, R - RIP, - B - BGP * - FIB route. - - K* 0.0.0.0/0 203.181.89.241 - S 0.0.0.0/0 203.181.89.1 - C* 127.0.0.0/8 lo - C* 203.181.89.240/28 eth0 + Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, + F - PBR, f - OpenFabric, t - Table-Direct, + > - selected route, * - FIB route, q - queued, r - rejected, b - backup + t - trapped, o - offload failure + K>* 0.0.0.0/0 [0/100] via 192.168.119.1, enp13s0, 00:30:22 + S> 4.5.6.7/32 [1/0] via 192.168.119.1 (recursive), weight 1, 00:30:22 + * via 192.168.119.1, enp13s0, weight 1, 00:30:22 + K>* 169.254.0.0/16 [0/1000] is directly connected, virbr2 linkdown, 00:30:22 + L>* 192.168.119.205/32 is directly connected, enp13s0, 00:30:22 -.. clicmd:: show ipv6 route .. clicmd:: show [ip|ipv6] route [PREFIX] [nexthop-group] Display detailed information about a route. If [nexthop-group] is included, it will display the nexthop group ID the route is using as well. +.. clicmd:: show [ip|ipv6] route summary + + Display summary information about routes received from each protocol. + This command displays the entries received from each route and as such + this total can be more than the actual number of FIB routes. Finally + due to the way that linux supports local and connected routes the FIB + total may not be exactly what is shown in the equivalent `ip route show` + command to see the state of the linux kernel. + .. clicmd:: show interface [NAME] [{vrf VRF|brief}] [json] .. clicmd:: show interface [NAME] [{vrf all|brief}] [json] @@ -1401,8 +1589,6 @@ zebra Terminal Mode Commands .. clicmd:: show ip prefix-list [NAME] -.. clicmd:: show route-map [NAME] - .. clicmd:: show ip protocol .. clicmd:: show ip forward diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 98e8407498d6..3f811455b394 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Create a basic stage set up to build APKs -FROM alpine:3.18 as alpine-builder +FROM alpine:3.20 as alpine-builder RUN apk add \ --update-cache \ abuild \ @@ -24,7 +24,7 @@ RUN cd /src/libyang \ && abuild -r -P /pkgs/apk # This stage builds a dist tarball from the source -FROM alpine:3.18 as source-builder +FROM alpine:3.20 as source-builder RUN mkdir -p /src/alpine /pkgs/apk COPY alpine/APKBUILD.in /src/alpine COPY --from=alpine-apk-builder-libyang /pkgs/apk/src /pkgs/apk @@ -33,8 +33,7 @@ RUN source /src/alpine/APKBUILD.in \ && apk add \ --no-cache \ --update-cache \ - $makedepends \ - && pip install pytest + $makedepends COPY . /src ARG PKGVER RUN cd /src \ @@ -58,7 +57,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:3.18 +FROM alpine:3.20 RUN mkdir -p /pkgs/apk COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD index 04e943fe48f7..d8cd4d918a53 100755 --- a/docker/alpine/libyang/APKBUILD +++ b/docker/alpine/libyang/APKBUILD @@ -1,7 +1,7 @@ # Contributor: Sören Tempel # Maintainer: Christian Franke pkgname=libyang -pkgver=2.1.80 +pkgver=2.1.128 pkgrel=0 pkgdesc="YANG data modelling language parser and toolkit" url="https://github.com/CESNET/libyang" @@ -11,6 +11,7 @@ makedepends="bison cmake cmocka-dev flex pcre2-dev" checkdepends="expect grep shunit2" subpackages="$pkgname-dev $pkgname-doc" source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz" +options="!check" # secfixes: # 1.0.215-r1: @@ -21,6 +22,7 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkg # - CVE-2021-28906 build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" if [ "$CBUILD" != "$CHOST" ]; then CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux" fi diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile index d136538c7d08..b317b0598d9f 100644 --- a/docker/debian/Dockerfile +++ b/docker/debian/Dockerfile @@ -24,5 +24,5 @@ RUN chown -R frr:frr /etc/frr /var/run/frr ENTRYPOINT ["/usr/bin/tini", "--"] # Default CMD starts watchfrr -COPY docker-start /usr/lib/frr/docker-start +COPY --chmod=0755 docker-start /usr/lib/frr/docker-start CMD ["/usr/lib/frr/docker-start"] diff --git a/docker/ubi8-minimal/Dockerfile b/docker/ubi8-minimal/Dockerfile index 53f8d2569723..14a5cddbec8e 100644 --- a/docker/ubi8-minimal/Dockerfile +++ b/docker/ubi8-minimal/Dockerfile @@ -10,6 +10,7 @@ ADD docker/ubi8-minimal/almalinux.repo /etc/yum.repos.d/almalinux.repo # and later reinstall it again: https://bugzilla.redhat.com/show_bug.cgi?id=1668185 RUN rpm --quiet -e --nodeps tzdata >/dev/null 2>&1 +# Keep the list of dependencies alphabetically sorted for easier maintenance RUN microdnf --disableplugin=subscription-manager --setopt=install_weak_deps=0 install \ autoconf \ automake \ @@ -29,6 +30,7 @@ RUN microdnf --disableplugin=subscription-manager --setopt=install_weak_deps=0 i pcre-devel \ pkgconfig \ platform-python-devel \ + protobuf-c-devel \ python3-devel \ python3-pytest \ python3-sphinx \ @@ -37,7 +39,6 @@ RUN microdnf --disableplugin=subscription-manager --setopt=install_weak_deps=0 i systemd-devel \ texinfo \ tzdata \ - protobuf-c-devel \ && microdnf --disableplugin=subscription-manager clean all RUN curl -sSL -o /tmp/libyang2.rpm https://ci1.netdef.org/artifact/LIBYANG-LIBYANG2/shared/build-181/RedHat-8-x86_64-Packages/libyang-2.1.80-1.el8.x86_64.rpm \ @@ -92,12 +93,14 @@ ADD docker/ubi8-minimal/almalinux.repo /etc/yum.repos.d/almalinux.repo RUN rpm --import https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-8 +# Keep the list of dependencies alphabetically sorted for easier maintenance RUN microdnf --disableplugin=subscription-manager --setopt=install_weak_deps=0 install \ c-ares \ initscripts \ net-snmp-agent-libs \ net-snmp-libs \ openssl \ + protobuf-c \ python3 \ shadow-utils \ systemd \ diff --git a/docker/ubuntu-ci/Dockerfile b/docker/ubuntu-ci/Dockerfile index 939a43e4ea85..5c4649dc325c 100644 --- a/docker/ubuntu-ci/Dockerfile +++ b/docker/ubuntu-ci/Dockerfile @@ -23,13 +23,17 @@ RUN apt update && apt upgrade -y && \ libreadline-dev \ libsnmp-dev \ libsqlite3-dev \ + lsb-release \ libtool \ + lcov \ make \ perl \ pkg-config \ python3-dev \ python3-sphinx \ + screen \ texinfo \ + tmux \ && \ # Protobuf build requirements apt-get install -y \ @@ -41,17 +45,24 @@ RUN apt update && apt upgrade -y && \ cmake \ libpcre2-dev \ && \ + # GRPC extra build requirements + apt-get install -y \ + libgrpc-dev \ + libgrpc++-dev \ + protobuf-compiler-grpc \ + && \ # Runtime/triage/testing requirements apt-get install -y \ curl \ gdb \ + kmod \ iproute2 \ iputils-ping \ liblua5.3-dev \ libssl-dev \ lua5.3 \ net-tools \ - python2 \ + python3 \ python3-pip \ snmp \ snmp-mibs-downloader \ @@ -66,17 +77,12 @@ RUN apt update && apt upgrade -y && \ wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/iana/IANA-IPPM-METRICS-REGISTRY-MIB -O /usr/share/snmp/mibs/iana/IANA-IPPM-METRICS-REGISTRY-MIB && \ wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/ietf/SNMPv2-PDU -O /usr/share/snmp/mibs/ietf/SNMPv2-PDU && \ wget https://raw.githubusercontent.com/FRRouting/frr-mibs/main/ietf/IPATM-IPMC-MIB -O /usr/share/snmp/mibs/ietf/IPATM-IPMC-MIB && \ - curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output /tmp/get-pip.py && \ - python2 /tmp/get-pip.py && \ - rm -f /tmp/get-pip.py && \ python3 -m pip install wheel && \ - python3 -m pip install pytest && \ - python3 -m pip install pytest-sugar && \ - python3 -m pip install pytest-xdist && \ - python3 -m pip install "scapy>=2.4.2" && \ + python3 -m pip install 'protobuf<4' grpcio grpcio-tools && \ + python3 -m pip install 'pytest>=6.2.4' 'pytest-xdist>=2.3.0' && \ + python3 -m pip install 'scapy>=2.4.5' && \ python3 -m pip install xmltodict && \ - python3 -m pip install grpcio grpcio-tools && \ - python2 -m pip install 'exabgp<4.0.0' + python3 -m pip install git+https://github.com/Exa-Networks/exabgp@0659057837cd6c6351579e9f0fa47e9fb7de7311 RUN groupadd -r -g 92 frr && \ groupadd -r -g 85 frrvty && \ @@ -87,18 +93,14 @@ RUN groupadd -r -g 92 frr && \ echo 'frr ALL = NOPASSWD: ALL' | tee /etc/sudoers.d/frr && \ mkdir -p /home/frr && chown frr.frr /home/frr -USER frr:frr +# Install FRR built packages +RUN mkdir -p /etc/apt/keyrings && \ + curl -s -o /etc/apt/keyrings/frrouting.gpg https://deb.frrouting.org/frr/keys.gpg && \ + echo deb '[signed-by=/etc/apt/keyrings/frrouting.gpg]' https://deb.frrouting.org/frr \ + $(lsb_release -s -c) "frr-stable" > /etc/apt/sources.list.d/frr.list && \ + apt-get update && apt-get install -y librtr-dev libyang2-dev libyang2-tools -# build and install libyang2 -RUN cd && pwd && ls -al && \ - git clone https://github.com/CESNET/libyang.git && \ - cd libyang && \ - git checkout v2.1.80 && \ - mkdir build; cd build && \ - cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ - -DCMAKE_BUILD_TYPE:String="Release" .. && \ - make -j $(nproc) && \ - sudo make install +USER frr:frr COPY --chown=frr:frr . /home/frr/frr/ @@ -106,14 +108,19 @@ RUN cd ~/frr && \ ./bootstrap.sh && \ ./configure \ --prefix=/usr \ - --localstatedir=/var/run/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ + --enable-gcov \ + --enable-dev-build \ + --enable-mgmtd-test-be-client \ + --enable-rpki \ --enable-sharpd \ --enable-multipath=64 \ --enable-user=frr \ --enable-group=frr \ --enable-config-rollbacks \ + --enable-grpc \ --enable-vty-group=frrvty \ --enable-snmp=agentx \ --enable-scripting \ diff --git a/docker/ubuntu-ci/docker-start b/docker/ubuntu-ci/docker-start index 9a45c722f1b8..c383ea8ee929 100755 --- a/docker/ubuntu-ci/docker-start +++ b/docker/ubuntu-ci/docker-start @@ -1,8 +1,5 @@ #!/bin/bash - if [ $(uname -a | grep -ci Ubuntu) -ge 1 ]; then - #for topotests under ubuntu host - sudo modprobe mpls-router mpls-iptunnel - sudo /etc/init.d/openvswitch-switch start + sudo modprobe mpls-router mpls-iptunnel vrf fi while true ; do sleep 365d ; done diff --git a/docker/ubuntu20-ci/README.md b/docker/ubuntu20-ci/README.md index 536f8e2e3590..6c0ff447dcec 100644 --- a/docker/ubuntu20-ci/README.md +++ b/docker/ubuntu20-ci/README.md @@ -11,13 +11,13 @@ docker build -t frr-ubuntu20:latest --build-arg=UBUNTU_VERSION=20.04 -f docker/u # Running Full Topotest ``` -docker run --init -it --privileged --name frr -v /lib/modules:/lib/modules frr-ubuntu22:latest bash -c 'cd ~/frr/tests/topotests ; sudo pytest -nauto --dist=loadfile' +docker run --init -it --privileged --name frr-ubuntu20 -v /lib/modules:/lib/modules frr-ubuntu20:latest bash -c 'cd ~/frr/tests/topotests ; sudo pytest -nauto --dist=loadfile' ``` # Extract results from the above run into `run-results` dir and analyze ``` -tests/topotest/analyze.py -C frr -Ar run-results +tests/topotests/analyze.py -C frr-ubuntu20 -Ar run-results ``` # Running @@ -41,13 +41,13 @@ docker exec -it frr-ubuntu20 bash # topotest -- when Host O/S is Ubuntu only ``` -docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' +docker exec frr-ubuntu20 bash -c 'cd ~/frr/tests/topotests/ospf_topo1 ; sudo pytest test_ospf_topo1.py' ``` # stop & remove container ``` -docker stop frr-ubuntu20 ; docker rm frr-ubuntu18 +docker stop frr-ubuntu20 ; docker rm frr-ubuntu20 ``` # remove image diff --git a/docker/ubuntu22-ci/README.md b/docker/ubuntu22-ci/README.md index 403abbf5bbe0..617192eb71b2 100644 --- a/docker/ubuntu22-ci/README.md +++ b/docker/ubuntu22-ci/README.md @@ -8,46 +8,55 @@ This builds an ubuntu 22.04 container for dev / test docker build -t frr-ubuntu22:latest -f docker/ubuntu-ci/Dockerfile . ``` -# Running Full Topotest +# Run ``` -docker run --init -it --privileged --name frr -v /lib/modules:/lib/modules frr-ubuntu22:latest bash -c 'cd ~/frr/tests/topotests ; sudo pytest -nauto --dist=loadfile' +docker run -d --init --privileged --name frr-ubuntu22 --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu22:latest +``` + +# Running full topotest (container stops at end) + +``` +docker run --init -it --privileged --name frr-ubuntu22 \ + -v /lib/modules:/lib/modules frr-ubuntu22:latest \ + bash -c 'cd /home/frr/frr/tests/topotests; sudo pytest -nauto --dist=loadfile' ``` # Extract results from the above run into `run-results` dir and analyze ``` -tests/topotest/analyze.py -C frr -Ar run-results +tests/topotests/analyze.py -C frr-ubuntu22 -Ar run-results ``` -# Running +# Extract coverage from a stopped container into host FRR source tree ``` -docker run -d --init --privileged --name frr --mount type=bind,source=/lib/modules,target=/lib/modules frr-ubuntu22:latest +docker export frr-ubuntu22 | tar --strip=3 --wildcards -vx '*.gc??' +lcov -b $(pwd) --capture --directory . --output-file=coverage.info ``` # make check ``` -docker exec frr bash -c 'cd ~/frr ; make check' +docker exec frr-ubuntu22 bash -c 'cd ~/frr ; make check' ``` # interactive bash ``` -docker exec -it frr bash +docker exec -it frr-ubuntu22 bash ``` -# topotest -- when Host O/S is Ubuntu only +# Run a specific topotest ``` -docker exec frr bash -c 'cd ~/frr/tests/topotests/ospf-topo1 ; sudo pytest test_ospf_topo1.py' +docker exec frr-ubuntu22 bash -c 'cd ~/frr/tests/topotests ; sudo pytest ospf_topo1/test_ospf_topo1.py' ``` # stop & remove container ``` -docker stop frr ; docker rm frr +docker stop frr-ubuntu22 ; docker rm frr-ubuntu22 ``` # remove image diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c index 213834afc8f7..eaede73fb3a3 100644 --- a/eigrpd/eigrp_cli.c +++ b/eigrpd/eigrp_cli.c @@ -69,8 +69,8 @@ DEFPY_YANG( void eigrp_cli_show_header(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *asn = yang_dnode_get_string(dnode, "./asn"); - const char *vrf = yang_dnode_get_string(dnode, "./vrf"); + const char *asn = yang_dnode_get_string(dnode, "asn"); + const char *vrf = yang_dnode_get_string(dnode, "vrf"); vty_out(vty, "router eigrp %s", asn); if (strcmp(vrf, VRF_DEFAULT_NAME)) @@ -131,12 +131,14 @@ DEFPY_YANG( "Suppress routing updates on an interface\n" "Interface to suppress on\n") { + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./passive-interface[.='%s']", ifname); + if (no) - nb_cli_enqueue_change(vty, "./passive-interface", - NB_OP_DESTROY, ifname); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); else - nb_cli_enqueue_change(vty, "./passive-interface", - NB_OP_CREATE, ifname); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -323,18 +325,18 @@ void eigrp_cli_show_metrics(struct vty *vty, const struct lyd_node *dnode, { const char *k1, *k2, *k3, *k4, *k5, *k6; - k1 = yang_dnode_exists(dnode, "./K1") ? - yang_dnode_get_string(dnode, "./K1") : "0"; - k2 = yang_dnode_exists(dnode, "./K2") ? - yang_dnode_get_string(dnode, "./K2") : "0"; - k3 = yang_dnode_exists(dnode, "./K3") ? - yang_dnode_get_string(dnode, "./K3") : "0"; - k4 = yang_dnode_exists(dnode, "./K4") ? - yang_dnode_get_string(dnode, "./K4") : "0"; - k5 = yang_dnode_exists(dnode, "./K5") ? - yang_dnode_get_string(dnode, "./K5") : "0"; - k6 = yang_dnode_exists(dnode, "./K6") ? - yang_dnode_get_string(dnode, "./K6") : "0"; + k1 = yang_dnode_exists(dnode, "K1") ? + yang_dnode_get_string(dnode, "K1") : "0"; + k2 = yang_dnode_exists(dnode, "K2") ? + yang_dnode_get_string(dnode, "K2") : "0"; + k3 = yang_dnode_exists(dnode, "K3") ? + yang_dnode_get_string(dnode, "K3") : "0"; + k4 = yang_dnode_exists(dnode, "K4") ? + yang_dnode_get_string(dnode, "K4") : "0"; + k5 = yang_dnode_exists(dnode, "K5") ? + yang_dnode_get_string(dnode, "K5") : "0"; + k6 = yang_dnode_exists(dnode, "K6") ? + yang_dnode_get_string(dnode, "K6") : "0"; vty_out(vty, " metric weights %s %s %s %s %s", k1, k2, k3, k4, k5); @@ -354,12 +356,14 @@ DEFPY_YANG( "Enable routing on an IP network\n" "EIGRP network prefix\n") { + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./network[.='%s']", prefix_str); + if (no) - nb_cli_enqueue_change(vty, "./network", NB_OP_DESTROY, - prefix_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); else - nb_cli_enqueue_change(vty, "./network", NB_OP_CREATE, - prefix_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -383,12 +387,14 @@ DEFPY_YANG( "Specify a neighbor router\n" "Neighbor address\n") { + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./neighbor[.='%s']", addr_str); + if (no) - nb_cli_enqueue_change(vty, "./neighbor", NB_OP_DESTROY, - addr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); else - nb_cli_enqueue_change(vty, "./neighbor", NB_OP_CREATE, - addr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -401,6 +407,117 @@ void eigrp_cli_show_neighbor(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " neighbor %s\n", prefix); } +/* + * XPath: /frr-eigrpd:eigrpd/instance/distribute-list + */ +DEFPY_YANG (eigrp_distribute_list, + eigrp_distribute_list_cmd, + "distribute-list ACCESSLIST4_NAME$name $dir [WORD$ifname]", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/access-list", + ifname ? ifname : "", dir); + /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */ + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG (eigrp_distribute_list_prefix, + eigrp_distribute_list_prefix_cmd, + "distribute-list prefix PREFIXLIST4_NAME$name $dir [WORD$ifname]", + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/prefix-list", + ifname ? ifname : "", dir); + /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */ + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG (eigrp_no_distribute_list, + eigrp_no_distribute_list_cmd, + "no distribute-list [ACCESSLIST4_NAME$name] $dir [WORD$ifname]", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + const struct lyd_node *value_node; + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/access-list", + ifname ? ifname : "", dir); + /* + * See if the user has specified specific list so check it exists. + * + * NOTE: Other FRR CLI commands do not do this sort of verification and + * there may be an official decision not to. + */ + if (name) { + value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s", + VTY_CURR_XPATH, xpath); + if (!value_node || strcmp(name, lyd_get_value(value_node))) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG (eigrp_no_distribute_list_prefix, + eigrp_no_distribute_list_prefix_cmd, + "no distribute-list prefix [PREFIXLIST4_NAME$name] $dir [WORD$ifname]", + NO_STR + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + const struct lyd_node *value_node; + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/prefix-list", + ifname ? ifname : "", dir); + /* + * See if the user has specified specific list so check it exists. + * + * NOTE: Other FRR CLI commands do not do this sort of verification and + * there may be an official decision not to. + */ + if (name) { + value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s", + VTY_CURR_XPATH, xpath); + if (!value_node || strcmp(name, lyd_get_value(value_node))) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + /* * XPath: /frr-eigrpd:eigrpd/instance/redistribute * XPath: /frr-eigrpd:eigrpd/instance/redistribute/route-map @@ -456,19 +573,19 @@ DEFPY_YANG( void eigrp_cli_show_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *proto = yang_dnode_get_string(dnode, "./protocol"); + const char *proto = yang_dnode_get_string(dnode, "protocol"); const char *bw, *delay, *load, *mtu, *rlbt; - bw = yang_dnode_exists(dnode, "./metrics/bandwidth") ? - yang_dnode_get_string(dnode, "./metrics/bandwidth") : NULL; - delay = yang_dnode_exists(dnode, "./metrics/delay") ? - yang_dnode_get_string(dnode, "./metrics/delay") : NULL; - rlbt = yang_dnode_exists(dnode, "./metrics/reliability") ? - yang_dnode_get_string(dnode, "./metrics/reliability") : NULL; - load = yang_dnode_exists(dnode, "./metrics/load") ? - yang_dnode_get_string(dnode, "./metrics/load") : NULL; - mtu = yang_dnode_exists(dnode, "./metrics/mtu") ? - yang_dnode_get_string(dnode, "./metrics/mtu") : NULL; + bw = yang_dnode_exists(dnode, "metrics/bandwidth") ? + yang_dnode_get_string(dnode, "metrics/bandwidth") : NULL; + delay = yang_dnode_exists(dnode, "metrics/delay") ? + yang_dnode_get_string(dnode, "metrics/delay") : NULL; + rlbt = yang_dnode_exists(dnode, "metrics/reliability") ? + yang_dnode_get_string(dnode, "metrics/reliability") : NULL; + load = yang_dnode_exists(dnode, "metrics/load") ? + yang_dnode_get_string(dnode, "metrics/load") : NULL; + mtu = yang_dnode_exists(dnode, "metrics/mtu") ? + yang_dnode_get_string(dnode, "metrics/mtu") : NULL; vty_out(vty, " redistribute %s", proto); if (bw || rlbt || delay || load || mtu) @@ -658,8 +775,9 @@ DEFPY_YANG( as_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath); - nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str); + snprintf(xpath_auth, sizeof(xpath_auth), + "%s/summarize-addresses[.='%s']", xpath, prefix_str); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -681,8 +799,9 @@ DEFPY_YANG( as_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath); - nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str); + snprintf(xpath_auth, sizeof(xpath_auth), + "%s/summarize-addresses[.='%s']", xpath, prefix_str); + nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -693,7 +812,7 @@ void eigrp_cli_show_summarize_address(struct vty *vty, { const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); - uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); + uint16_t asn = yang_dnode_get_uint16(instance, "asn"); const char *summarize_address = yang_dnode_get_string(dnode, NULL); vty_out(vty, " ip summary-address eigrp %d %s\n", asn, @@ -759,7 +878,7 @@ void eigrp_cli_show_authentication(struct vty *vty, { const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); - uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); + uint16_t asn = yang_dnode_get_uint16(instance, "asn"); const char *crypt = yang_dnode_get_string(dnode, NULL); vty_out(vty, " ip authentication mode eigrp %d %s\n", asn, crypt); @@ -819,7 +938,7 @@ void eigrp_cli_show_keychain(struct vty *vty, const struct lyd_node *dnode, { const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); - uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); + uint16_t asn = yang_dnode_get_uint16(instance, "asn"); const char *keychain = yang_dnode_get_string(dnode, NULL); vty_out(vty, " ip authentication key-chain eigrp %d %s\n", asn, @@ -875,6 +994,10 @@ eigrp_cli_init(void) install_element(EIGRP_NODE, &no_eigrp_metric_weights_cmd); install_element(EIGRP_NODE, &eigrp_network_cmd); install_element(EIGRP_NODE, &eigrp_neighbor_cmd); + install_element(EIGRP_NODE, &eigrp_distribute_list_cmd); + install_element(EIGRP_NODE, &eigrp_distribute_list_prefix_cmd); + install_element(EIGRP_NODE, &eigrp_no_distribute_list_cmd); + install_element(EIGRP_NODE, &eigrp_no_distribute_list_prefix_cmd); install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd); vrf_cmd_init(NULL); diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h index 607719d4f136..05fbae32af55 100644 --- a/eigrpd/eigrp_const.h +++ b/eigrpd/eigrp_const.h @@ -61,9 +61,6 @@ /* IP TTL for EIGRP protocol. */ #define EIGRP_IP_TTL 1 -/* VTY port number. */ -#define EIGRP_VTY_PORT 2613 - /* Default configuration file name for eigrp. */ #define EIGRP_DEFAULT_CONFIG "eigrpd.conf" diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index 2381977dbaef..fb8f47e7234b 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -43,8 +43,7 @@ #include "eigrpd/eigrp_types.h" #include "eigrpd/eigrp_metric.h" -DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF, "EIGRP interface"); -DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF, "EIGRP interface"); struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, struct prefix *p) @@ -110,7 +109,7 @@ int eigrp_if_delete_hook(struct interface *ifp) eigrp_fifo_free(ei->obuf); - XFREE(MTYPE_EIGRP_IF_INFO, ifp->info); + XFREE(MTYPE_EIGRP_IF, ifp->info); return 0; } @@ -203,8 +202,10 @@ struct list *eigrp_iflist; void eigrp_if_init(void) { - if_zapi_callbacks(eigrp_ifp_create, eigrp_ifp_up, - eigrp_ifp_down, eigrp_ifp_destroy); + hook_register_prio(if_real, 0, eigrp_ifp_create); + hook_register_prio(if_up, 0, eigrp_ifp_up); + hook_register_prio(if_down, 0, eigrp_ifp_down); + hook_register_prio(if_unreal, 0, eigrp_ifp_destroy); /* Initialize Zebra interface data structure. */ // hook_register_prio(if_add, 0, eigrp_if_new); hook_register_prio(if_del, 0, eigrp_if_delete_hook); diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 6d7443b7914e..319ac925337b 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -36,6 +36,7 @@ #include "distribute.h" #include "libfrr.h" #include "routemap.h" +#include "libagentx.h" //#include "if_rmap.h" #include "eigrpd/eigrp_structs.h" @@ -94,6 +95,9 @@ static void sighup(void) static void sigint(void) { zlog_notice("Terminating on signal"); + + keychain_terminate(); + eigrp_terminate(); exit(0); @@ -130,18 +134,24 @@ static const struct frr_yang_module_info *const eigrpd_yang_modules[] = { &frr_interface_info, &frr_route_map_info, &frr_vrf_info, + &ietf_key_chain_info, + &ietf_key_chain_deviation_info, }; -FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(eigrpd, EIGRP, + .vty_port = EIGRP_VTY_PORT, + .proghelp = "Implementation of the EIGRP routing protocol.", - .proghelp = "Implementation of the EIGRP routing protocol.", + .signals = eigrp_signals, + .n_signals = array_size(eigrp_signals), - .signals = eigrp_signals, - .n_signals = array_size(eigrp_signals), + .privs = &eigrpd_privs, - .privs = &eigrpd_privs, .yang_modules = eigrpd_yang_modules, - .n_yang_modules = array_size(eigrpd_yang_modules), + .yang_modules = eigrpd_yang_modules, + .n_yang_modules = array_size(eigrpd_yang_modules), ); +/* clang-format on */ /* EIGRPd main routine. */ int main(int argc, char **argv, char **envp) @@ -169,9 +179,11 @@ int main(int argc, char **argv, char **envp) /* EIGRP master init. */ eigrp_master_init(); + eigrp_om->master = frr_init(); master = eigrp_om->master; + libagentx_init(); eigrp_error_init(); eigrp_vrf_init(); vrf_init(NULL, NULL, NULL, NULL); diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index ef567fe4ef63..5ca5a18a974e 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -233,13 +233,11 @@ static void eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p, struct interface *ifp) { struct eigrp_interface *ei; - struct listnode *cnode; struct connected *co; /* if interface prefix is match specified prefix, then create socket and join multicast group. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) { - + frr_each (if_connected, ifp->connected, co) { if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY)) continue; diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c index f50abb7e48ca..4aeb635c05c3 100644 --- a/eigrpd/eigrp_northbound.c +++ b/eigrpd/eigrp_northbound.c @@ -14,6 +14,7 @@ #include "lib/table.h" #include "lib/vrf.h" #include "lib/zclient.h" +#include "lib/distribute.h" #include "eigrp_structs.h" #include "eigrpd.h" @@ -28,18 +29,18 @@ static void redistribute_get_metrics(const struct lyd_node *dnode, { memset(em, 0, sizeof(*em)); - if (yang_dnode_exists(dnode, "./bandwidth")) - em->bandwidth = yang_dnode_get_uint32(dnode, "./bandwidth"); - if (yang_dnode_exists(dnode, "./delay")) - em->delay = yang_dnode_get_uint32(dnode, "./delay"); + if (yang_dnode_exists(dnode, "bandwidth")) + em->bandwidth = yang_dnode_get_uint32(dnode, "bandwidth"); + if (yang_dnode_exists(dnode, "delay")) + em->delay = yang_dnode_get_uint32(dnode, "delay"); #if 0 /* TODO: How does MTU work? */ - if (yang_dnode_exists(dnode, "./mtu")) - em->mtu[0] = yang_dnode_get_uint32(dnode, "./mtu"); + if (yang_dnode_exists(dnode, "mtu")) + em->mtu[0] = yang_dnode_get_uint32(dnode, "mtu"); #endif - if (yang_dnode_exists(dnode, "./load")) - em->load = yang_dnode_get_uint32(dnode, "./load"); - if (yang_dnode_exists(dnode, "./reliability")) - em->reliability = yang_dnode_get_uint32(dnode, "./reliability"); + if (yang_dnode_exists(dnode, "load")) + em->load = yang_dnode_get_uint32(dnode, "load"); + if (yang_dnode_exists(dnode, "reliability")) + em->reliability = yang_dnode_get_uint32(dnode, "reliability"); } static struct eigrp_interface *eigrp_interface_lookup(const struct eigrp *eigrp, @@ -73,7 +74,7 @@ static int eigrpd_instance_create(struct nb_cb_create_args *args) /* NOTHING */ break; case NB_EV_PREPARE: - vrf = yang_dnode_get_string(args->dnode, "./vrf"); + vrf = yang_dnode_get_string(args->dnode, "vrf"); pVrf = vrf_lookup_by_name(vrf); if (pVrf) @@ -81,7 +82,7 @@ static int eigrpd_instance_create(struct nb_cb_create_args *args) else vrfid = VRF_DEFAULT; - eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "./asn"), + eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "asn"), vrfid); args->resource->ptr = eigrp; break; @@ -701,6 +702,22 @@ static int eigrpd_instance_neighbor_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: /frr-eigrpd:eigrpd/instance/distribute-list + */ +static int eigrpd_instance_distribute_list_create(struct nb_cb_create_args *args) +{ + struct eigrp *eigrp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + eigrp = nb_running_get_entry(args->dnode, NULL, true); + group_distribute_list_create_helper(args, eigrp->distribute_ctx); + + return NB_OK; +} + /* * XPath: /frr-eigrpd:eigrpd/instance/redistribute */ @@ -715,7 +732,7 @@ static int eigrpd_instance_redistribute_create(struct nb_cb_create_args *args) switch (args->event) { case NB_EV_VALIDATE: - proto = yang_dnode_get_enum(args->dnode, "./protocol"); + proto = yang_dnode_get_enum(args->dnode, "protocol"); vrfname = yang_dnode_get_string(args->dnode, "../vrf"); pVrf = vrf_lookup_by_name(vrfname); @@ -733,7 +750,7 @@ static int eigrpd_instance_redistribute_create(struct nb_cb_create_args *args) break; case NB_EV_APPLY: eigrp = nb_running_get_entry(args->dnode, NULL, true); - proto = yang_dnode_get_enum(args->dnode, "./protocol"); + proto = yang_dnode_get_enum(args->dnode, "protocol"); redistribute_get_metrics(args->dnode, &metrics); eigrp_redistribute_set(eigrp, proto, metrics); break; @@ -755,7 +772,7 @@ static int eigrpd_instance_redistribute_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: eigrp = nb_running_get_entry(args->dnode, NULL, true); - proto = yang_dnode_get_enum(args->dnode, "./protocol"); + proto = yang_dnode_get_enum(args->dnode, "protocol"); eigrp_redistribute_unset(eigrp, proto); break; } @@ -1120,7 +1137,7 @@ static int lib_interface_eigrp_instance_create(struct nb_cb_create_args *args) break; } - eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "./asn"), + eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "asn"), ifp->vrf->vrf_id); eif = eigrp_interface_lookup(eigrp, ifp->name); if (eif == NULL) @@ -1132,7 +1149,7 @@ static int lib_interface_eigrp_instance_create(struct nb_cb_create_args *args) break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "./asn"), + eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "asn"), ifp->vrf->vrf_id); eif = eigrp_interface_lookup(eigrp, ifp->name); if (eif == NULL) @@ -1402,6 +1419,45 @@ const struct frr_yang_module_info frr_eigrpd_info = { .cli_show = eigrp_cli_show_neighbor, } }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/distribute-list", + .cbs = { + .create = eigrpd_instance_distribute_list_create, + .destroy = group_distribute_list_destroy, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/distribute-list/in/access-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + .cli_show = group_distribute_list_ipv4_cli_show, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/distribute-list/out/access-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + .cli_show = group_distribute_list_ipv4_cli_show, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/distribute-list/in/prefix-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + .cli_show = group_distribute_list_ipv4_cli_show, + } + }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/distribute-list/out/prefix-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + .cli_show = group_distribute_list_ipv4_cli_show, + } + }, { .xpath = "/frr-eigrpd:eigrpd/instance/redistribute", .cbs = { diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index 84f27d01677e..420cb6cb414c 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -1107,60 +1107,14 @@ ALIAS(no_set_tag, no_set_tag_val_cmd, "no set tag (0-65535)", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\n") -DEFUN (eigrp_distribute_list, - eigrp_distribute_list_cmd, - "distribute-list [prefix] ACCESSLIST_NAME [WORD]", - "Filter networks in routing updates\n" - "Specify a prefix\n" - "Access-list name\n" - "Filter incoming routing updates\n" - "Filter outgoing routing updates\n" - "Interface name\n") -{ - const char *ifname = NULL; - int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0; - - if (argv[argc - 1]->type == VARIABLE_TKN) - ifname = argv[argc - 1]->arg; - - return distribute_list_parser(prefix, true, argv[2 + prefix]->text, - argv[1 + prefix]->arg, ifname); -} - -DEFUN (eigrp_no_distribute_list, - eigrp_no_distribute_list_cmd, - "no distribute-list [prefix] ACCESSLIST_NAME [WORD]", - NO_STR - "Filter networks in routing updates\n" - "Specify a prefix\n" - "Access-list name\n" - "Filter incoming routing updates\n" - "Filter outgoing routing updates\n" - "Interface name\n") -{ - const char *ifname = NULL; - int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; - - if (argv[argc - 1]->type == VARIABLE_TKN) - ifname = argv[argc - 1]->arg; - - return distribute_list_no_parser(vty, prefix, true, - argv[3 + prefix]->text, - argv[2 + prefix]->arg, ifname); -} - - /* Route-map init */ -void eigrp_route_map_init() +void eigrp_route_map_init(void) { route_map_init(); route_map_init_vty(); route_map_add_hook(eigrp_route_map_update); route_map_delete_hook(eigrp_route_map_update); - install_element(EIGRP_NODE, &eigrp_distribute_list_cmd); - install_element(EIGRP_NODE, &eigrp_no_distribute_list_cmd); - /*route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_interface_cmd);*/ /*route_map_install_match (&route_match_ip_next_hop_cmd); diff --git a/eigrpd/eigrp_routemap.h b/eigrpd/eigrp_routemap.h index c471679619d5..c797d10882bb 100644 --- a/eigrpd/eigrp_routemap.h +++ b/eigrpd/eigrp_routemap.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * eigrp_routemap.h * diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index a5cecb9c1615..a0eff683dbc9 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -98,9 +98,7 @@ static zclient_handler *const eigrp_handlers[] = { void eigrp_zebra_init(void) { - struct zclient_options opt = {.receive_notify = false}; - - zclient = zclient_new(master, &opt, eigrp_handlers, + zclient = zclient_new(master, &zclient_options_default, eigrp_handlers, array_size(eigrp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs); diff --git a/fpm/fpm.h b/fpm/fpm.h index b08310f675be..70c0df57157e 100644 --- a/fpm/fpm.h +++ b/fpm/fpm.h @@ -62,11 +62,6 @@ */ #define FPM_DEFAULT_IP (htonl (INADDR_LOOPBACK)) -/* - * default port for fpm connections - */ -#define FPM_DEFAULT_PORT 2620 - /* * Largest message that can be sent to or received from the FPM. */ diff --git a/fpm/fpm.proto b/fpm/fpm.proto index 9f0917feae53..beaa5d635cd5 100644 --- a/fpm/fpm.proto +++ b/fpm/fpm.proto @@ -6,6 +6,9 @@ // // @author Avneesh Sachdev // +// Portions: +// Copyright (C) 2024 Carmine Scarpitta (for SRv6) +// // Permission to use, copy, modify, and/or distribute this software // for any purpose with or without fee is hereby granted, provided // that the above copyright notice and this permission notice appear @@ -72,6 +75,141 @@ message AddRoute { required int32 metric = 8; repeated Nexthop nexthops = 9; + + /* Source Address of outer encapsulating IPv6 header */ + optional qpb.Ipv6Address srv6_encap_source_address = 10; + /* SRv6 SID for VPN use cases */ + optional qpb.Ipv6Address srv6_vpn_sid = 11; +} + +/* SID Format - as per RFC 8986 section #3.1 */ +message SRv6SIDFormat +{ + /* Locator block length */ + required uint32 locator_block_length = 1; + /* Locator node length */ + required uint32 locator_node_length = 2; + /* Function length */ + required uint32 function_length = 3; + /* Argument length */ + required uint32 argument_length = 4; +} + +/* SRv6 Local SID */ +message SRv6LocalSID +{ + /* SRv6 SID value */ + required qpb.Ipv6Address sid = 1; + + /* SID Format - as per RFC 8986 section #3.1 */ + optional SRv6SIDFormat sid_format = 2; + + /* SRv6 Endpoint Behavior associated with the SID */ + oneof end_behavior + { + /* Endpoint */ + End end = 3; + /* Endpoint with L3 cross-connect */ + EndX end_x = 4; + /* Endpoint with specific IPv6 table lookup */ + EndT end_t = 5; + /* Endpoint with decapsulation and IPv6 cross-connect */ + EndDX6 end_dx6 = 7; + /* Endpoint with decapsulation and IPv4 cross-connect */ + EndDX4 end_dx4 = 8; + /* Endpoint with decapsulation and specific IPv6 table lookup */ + EndDT6 end_dt6 = 9; + /* Endpoint with decapsulation and specific IPv4 table lookup */ + EndDT4 end_dt4 = 10; + /* Endpoint with decapsulation and specific IP table lookup */ + EndDT46 end_dt46 = 11; + /* Endpoint behavior with NEXT-CSID, PSP and USD flavors */ + UN un = 12; + /* End.X behavior with NEXT-CSID, PSP and USD flavors */ + UA ua = 13; + /* End.DT6 behavior with NEXT-CSID flavor */ + UDT6 udt6 = 14; + /* End.DT4 behavior with NEXT-CSID flavor */ + UDT4 udt4 = 15; + /* End.DT46 behavior with NEXT-CSID flavor */ + UDT46 udt46 = 16; + } + + /* Endpoint */ + message End + { + } + + /* Endpoint with L3 cross-connect */ + message EndX + { + required Nexthop nexthop = 1; + } + + /* Endpoint with specific IPv6 table lookup */ + message EndT + { + required uint32 vrf_id = 1; + } + + /* Endpoint with decapsulation and IPv6 cross-connect */ + message EndDX6 + { + required Nexthop nexthop = 1; + } + + /* Endpoint with decapsulation and IPv4 cross-connect */ + message EndDX4 + { + required Nexthop nexthop = 1; + } + + /* Endpoint with decapsulation and specific IPv6 table lookup */ + message EndDT6 + { + required uint32 vrf_id = 1; + } + + /* Endpoint with decapsulation and specific IPv4 table lookup */ + message EndDT4 + { + required uint32 vrf_id = 1; + } + + /* Endpoint with decapsulation and specific IP table lookup */ + message EndDT46 + { + required uint32 vrf_id = 1; + } + + /* Endpoint behavior with NEXT-CSID, PSP and USD flavors */ + message UN + { + } + + /* End.X behavior with NEXT-CSID, PSP and USD flavors */ + message UA + { + required Nexthop nexthop = 1; + } + + /* End.DT6 behavior with NEXT-CSID flavor */ + message UDT6 + { + required uint32 vrf_id = 1; + } + + /* End.DT4 behavior with NEXT-CSID flavor */ + message UDT4 + { + required uint32 vrf_id = 1; + } + + /* End.DT46 behavior with NEXT-CSID flavor */ + message UDT46 + { + required uint32 vrf_id = 1; + } } // @@ -82,10 +220,17 @@ message Message { UNKNOWN_MSG = 0; ADD_ROUTE = 1; DELETE_ROUTE = 2; + /* Install an SRv6 Local SID */ + ADD_SRV6_LOCALSID = 3; + /* Remove an SRv6 Local SID */ + DELETE_SRV6_LOCALSID = 4; }; optional Type type = 1; optional AddRoute add_route = 2; optional DeleteRoute delete_route = 3; + + /* SRv6 Local SID */ + optional SRv6LocalSID srv6_localsid = 4; } diff --git a/fpm/fpm_pb.c b/fpm/fpm_pb.c index e4c9395a84a6..0e8f618c4d3c 100644 --- a/fpm/fpm_pb.c +++ b/fpm/fpm_pb.c @@ -10,3 +10,8 @@ /* * Main file for the fpm_pb library. */ + +#include "config.h" +#include "xref.h" + +XREF_SETUP(); diff --git a/fpm/fpm_pb.h b/fpm/fpm_pb.h index 7e39054d1925..23d7e43993be 100644 --- a/fpm/fpm_pb.h +++ b/fpm/fpm_pb.h @@ -5,6 +5,9 @@ * @copyright Copyright (C) 2016 Sproute Networks, Inc. * * @author Avneesh Sachdev + * + * Portions: + * Copyright (C) 2024 Carmine Scarpitta (for SRv6) */ /* @@ -15,6 +18,7 @@ #define _FPM_PB_H #include "lib/route_types.h" +#include "lib/vrf.h" #include "qpb/qpb.h" #include "fpm/fpm.pb-c.h" @@ -42,4 +46,400 @@ static inline Fpm__RouteKey *fpm__route_key__create(qpb_allocator_t *allocator, return key; } +/* + * fpm__nexthop__create + */ +#define fpm_nexthop_create fpm__nexthop__create +static inline Fpm__Nexthop * +fpm__nexthop__create(qpb_allocator_t *allocator, struct nexthop *nh) +{ + Fpm__Nexthop *nexthop; + uint8_t family; + + nexthop = QPB_ALLOC(allocator, typeof(*nexthop)); + if (!nexthop) + return NULL; + + fpm__nexthop__init(nexthop); + + if (nh->type == NEXTHOP_TYPE_IPV4 || + nh->type == NEXTHOP_TYPE_IPV4_IFINDEX) + family = AF_INET; + else if (nh->type == NEXTHOP_TYPE_IPV6 || + nh->type == NEXTHOP_TYPE_IPV6_IFINDEX) + family = AF_INET6; + else + return NULL; + + nexthop->if_id = qpb__if_identifier__create(allocator, nh->ifindex); + if (!nexthop->if_id) + return NULL; + + nexthop->address = qpb__l3_address__create(allocator, &nh->gate, family); + if (!nexthop->address) + return NULL; + + + return nexthop; +} + +/* + * fpm__nexthop__get + * + * Read out information from a protobuf nexthop structure. + */ +#define fpm_nexthop_get fpm__nexthop__get +static inline int fpm__nexthop__get(const Fpm__Nexthop *nh, + struct nexthop *nexthop) +{ + struct in_addr ipv4; + struct in6_addr ipv6; + uint32_t ifindex; + char *ifname; + + if (!nh) + return 0; + + if (!qpb_if_identifier_get(nh->if_id, &ifindex, &ifname)) + return 0; + + if (nh->address) { + if (nh->address->v4) { + memset(&ipv4, 0, sizeof(ipv4)); + if (!qpb__ipv4_address__get(nh->address->v4, &ipv4)) + return 0; + + nexthop->vrf_id = VRF_DEFAULT; + nexthop->type = NEXTHOP_TYPE_IPV4; + nexthop->gate.ipv4 = ipv4; + if (ifindex) { + nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; + nexthop->ifindex = ifindex; + } + return 1; + } + + if (nh->address->v6) { + memset(&ipv6, 0, sizeof(ipv6)); + if (!qpb__ipv6_address__get(nh->address->v6, &ipv6)) + return 0; + nexthop->vrf_id = VRF_DEFAULT; + nexthop->type = NEXTHOP_TYPE_IPV6; + nexthop->gate.ipv6 = ipv6; + if (ifindex) { + nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX; + nexthop->ifindex = ifindex; + } + return 1; + } + } + + return 0; +} + +/* + * fpm__srv6_sid_format__create + */ +#define fpm_srv6_sid_format_create fpm__srv6_sid_format__create +static inline Fpm__SRv6SIDFormat * +fpm__srv6_sid_format__create(qpb_allocator_t *allocator, + uint8_t locator_block_length, + uint8_t locator_node_length, + uint8_t function_length, uint8_t argument_length) +{ + Fpm__SRv6SIDFormat *sid_format; + + sid_format = QPB_ALLOC(allocator, typeof(*sid_format)); + if (!sid_format) + return NULL; + fpm__srv6_sidformat__init(sid_format); + + sid_format->locator_block_length = locator_block_length; + sid_format->locator_node_length = locator_node_length; + sid_format->function_length = function_length; + sid_format->argument_length = argument_length; + + return sid_format; +} + +/* + * fpm__srv6_local_sid_end_behavior__create + */ +#define fpm_srv6_local_sid_end_behavior_create \ + fpm__srv6_local_sid_end_behavior__create +static inline Fpm__SRv6LocalSID__End * +fpm__srv6_local_sid_end_behavior__create(qpb_allocator_t *allocator) +{ + Fpm__SRv6LocalSID__End *end; + + end = QPB_ALLOC(allocator, typeof(*end)); + if (!end) + return NULL; + + fpm__srv6_local_sid__end__init(end); + + return end; +} + +/* + * fpm__srv6_local_sid_end_x_behavior__create + */ +#define fpm_srv6_local_sid_end_x_behavior_create \ + fpm__srv6_local_sid_end_x_behavior__create +static inline Fpm__SRv6LocalSID__EndX * +fpm__srv6_local_sid_end_x_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__EndX *end_x; + + end_x = QPB_ALLOC(allocator, typeof(*end_x)); + if (!end_x) + return NULL; + + fpm__srv6_local_sid__end_x__init(end_x); + + end_x->nexthop = fpm_nexthop_create(allocator, nexthop); + + return end_x; +} + +/* + * fpm__srv6_local_sid_end_t_behavior__create + */ +#define fpm_srv6_local_sid_end_t_behavior_create \ + fpm__srv6_local_sid_end_t_behavior__create +static inline Fpm__SRv6LocalSID__EndT * +fpm__srv6_local_sid_end_t_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndT *end_t; + + end_t = QPB_ALLOC(allocator, typeof(*end_t)); + if (!end_t) + return NULL; + + fpm__srv6_local_sid__end_t__init(end_t); + + end_t->vrf_id = vrf_id; + + return end_t; +} + +/* + * fpm__srv6_local_sid_end_dx6_behavior__create + */ +#define fpm_srv6_local_sid_end_dx6_behavior_create \ + fpm__srv6_local_sid_end_dx6_behavior__create +static inline Fpm__SRv6LocalSID__EndDX6 * +fpm__srv6_local_sid_end_dx6_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__EndDX6 *end_dx6; + + end_dx6 = QPB_ALLOC(allocator, typeof(*end_dx6)); + if (!end_dx6) + return NULL; + + fpm__srv6_local_sid__end_dx6__init(end_dx6); + + end_dx6->nexthop = fpm_nexthop_create(allocator, nexthop); + + return end_dx6; +} + +/* + * fpm__srv6_local_sid_end_dx4_behavior__create + */ +#define fpm_srv6_local_sid_end_dx4_behavior_create \ + fpm__srv6_local_sid_end_dx4_behavior__create +static inline Fpm__SRv6LocalSID__EndDX4 * +fpm__srv6_local_sid_end_dx4_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__EndDX4 *end_dx4; + + end_dx4 = QPB_ALLOC(allocator, typeof(*end_dx4)); + if (!end_dx4) + return NULL; + + fpm__srv6_local_sid__end_dx4__init(end_dx4); + + end_dx4->nexthop = fpm_nexthop_create(allocator, nexthop); + + return end_dx4; +} + +/* + * fpm__srv6_local_sid_end_dt6_behavior__create + */ +#define fpm_srv6_local_sid_end_dt6_behavior_create \ + fpm__srv6_local_sid_end_dt6_behavior__create +static inline Fpm__SRv6LocalSID__EndDT6 * +fpm__srv6_local_sid_end_dt6_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndDT6 *end_dt6; + + end_dt6 = QPB_ALLOC(allocator, typeof(*end_dt6)); + if (!end_dt6) + return NULL; + + fpm__srv6_local_sid__end_dt6__init(end_dt6); + + end_dt6->vrf_id = vrf_id; + + return end_dt6; +} + +/* + * fpm__srv6_local_sid_end_dt4_behavior__create + */ +#define fpm_srv6_local_sid_end_dt4_behavior_create \ + fpm__srv6_local_sid_end_dt4_behavior__create +static inline Fpm__SRv6LocalSID__EndDT4 * +fpm__srv6_local_sid_end_dt4_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndDT4 *end_dt4; + + end_dt4 = QPB_ALLOC(allocator, typeof(*end_dt4)); + if (!end_dt4) + return NULL; + + fpm__srv6_local_sid__end_dt4__init(end_dt4); + + end_dt4->vrf_id = vrf_id; + + return end_dt4; +} + +/* + * fpm__srv6_local_sid_end_dt46_behavior__create + */ +#define fpm_srv6_local_sid_end_dt46_behavior_create \ + fpm__srv6_local_sid_end_dt46_behavior__create +static inline Fpm__SRv6LocalSID__EndDT46 * +fpm__srv6_local_sid_end_dt46_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__EndDT46 *end_dt46; + + end_dt46 = QPB_ALLOC(allocator, typeof(*end_dt46)); + if (!end_dt46) + return NULL; + + fpm__srv6_local_sid__end_dt46__init(end_dt46); + + end_dt46->vrf_id = vrf_id; + + return end_dt46; +} + +/* + * fpm__srv6_local_sid_un_behavior__create + */ +#define fpm_srv6_local_sid_un_behavior_create \ + fpm__srv6_local_sid_un_behavior__create +static inline Fpm__SRv6LocalSID__UN * +fpm__srv6_local_sid_un_behavior__create(qpb_allocator_t *allocator) +{ + Fpm__SRv6LocalSID__UN *un; + + un = QPB_ALLOC(allocator, typeof(*un)); + if (!un) + return NULL; + + fpm__srv6_local_sid__un__init(un); + + return un; +} + +/* + * fpm__srv6_local_sid_ua_behavior__create + */ +#define fpm_srv6_local_sid_ua_behavior_create \ + fpm__srv6_local_sid_ua_behavior__create +static inline Fpm__SRv6LocalSID__UA * +fpm__srv6_local_sid_ua_behavior__create(qpb_allocator_t *allocator, + struct nexthop *nexthop) +{ + Fpm__SRv6LocalSID__UA *ua; + + ua = QPB_ALLOC(allocator, typeof(*ua)); + if (!ua) + return NULL; + + fpm__srv6_local_sid__ua__init(ua); + + ua->nexthop = fpm_nexthop_create(allocator, nexthop); + + return ua; +} + +/* + * fpm__srv6_local_sid_udt6_behavior__create + */ +#define fpm_srv6_local_sid_udt6_behavior_create \ + fpm__srv6_local_sid_udt6_behavior__create +static inline Fpm__SRv6LocalSID__UDT6 * +fpm__srv6_local_sid_udt6_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__UDT6 *udt6; + + udt6 = QPB_ALLOC(allocator, typeof(*udt6)); + if (!udt6) + return NULL; + + fpm__srv6_local_sid__udt6__init(udt6); + + udt6->vrf_id = vrf_id; + + return udt6; +} + +/* + * fpm__srv6_local_sid_udt4_behavior__create + */ +#define fpm_srv6_local_sid_udt4_behavior_create \ + fpm__srv6_local_sid_udt4_behavior__create +static inline Fpm__SRv6LocalSID__UDT4 * +fpm__srv6_local_sid_udt4_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__UDT4 *udt4; + + udt4 = QPB_ALLOC(allocator, typeof(*udt4)); + if (!udt4) + return NULL; + + fpm__srv6_local_sid__udt4__init(udt4); + + udt4->vrf_id = vrf_id; + + return udt4; +} + +/* + * fpm__srv6_local_sid_udt46_behavior__create + */ +#define fpm_srv6_local_sid_udt46_behavior_create \ + fpm__srv6_local_sid_udt46_behavior__create +static inline Fpm__SRv6LocalSID__UDT46 * +fpm__srv6_local_sid_udt46_behavior__create(qpb_allocator_t *allocator, + vrf_id_t vrf_id) +{ + Fpm__SRv6LocalSID__UDT46 *udt46; + + udt46 = QPB_ALLOC(allocator, typeof(*udt46)); + if (!udt46) + return NULL; + + fpm__srv6_local_sid__udt46__init(udt46); + + udt46->vrf_id = vrf_id; + + return udt46; +} + #endif diff --git a/gdb/lib.txt b/gdb/lib.txt index 5d22321b6291..435ec7eda7bc 100644 --- a/gdb/lib.txt +++ b/gdb/lib.txt @@ -306,8 +306,9 @@ define mq_walk end set $mg = $mg->next end +end -document mg_walk +document mq_walk Walk the memory data structures to show what is holding memory. Arguments: @@ -315,3 +316,49 @@ Arguments: sure where to start pass it mg_first, which is a global DS for all memory allocated in FRR end + +define __darr_meta + set $_ = ((struct darr_metadata *)$arg0) - 1 +end +document __darr_meta +Store a pointer to the struct darr_metadata in $_ for the given dynamic array. + +Argument: a pointer to a darr dynamic array. +Returns: pointer to the struct darr_metadata in $_. +end + +define darr_meta + __darr_meta $arg0 + p *$_ +end +document darr_meta +Print the struct darr_metadata for the given dynamic array. Store the value +in $_ as well. + +Argument: a pointer to a darr dynamic array. +Returns: pointer to the struct darr_metadata in $_. +end + +define darr_len + __darr_meta $arg0 + set $_ = $_->len + p $_ +end +document darr_len +Print the length of the given dynamic array, and store in $_. + +Argument: a pointer to a darr dynamic array. +Returns: length of the array. +end + +define darr_cap + __darr_meta $arg0 + set $_ = $_->cap + p $_ +end +document darr_len +Print the capacity of the given dynamic array, and store in $_. + +Argument: a pointer to a darr dynamic array. +Returns: capacity of the array. +end diff --git a/grpc/frrgrpc_pb.c b/grpc/frrgrpc_pb.c new file mode 100644 index 000000000000..938d777534e3 --- /dev/null +++ b/grpc/frrgrpc_pb.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: ISC +/* + * libfrrgrpc_pb library stub source + */ + +#include "config.h" +#include "xref.h" + +XREF_SETUP(); diff --git a/grpc/subdir.am b/grpc/subdir.am index 06b37f91d611..a464edc9303b 100644 --- a/grpc/subdir.am +++ b/grpc/subdir.am @@ -10,6 +10,10 @@ nodist_grpc_libfrrgrpc_pb_la_SOURCES = \ grpc/frr-northbound.pb.cc \ grpc/frr-northbound.grpc.pb.cc \ # end + +grpc_libfrrgrpc_pb_la_SOURCES = \ + grpc/frrgrpc_pb.c \ + # end endif CLEANFILES += \ diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h new file mode 100644 index 000000000000..72393a8c1a6c --- /dev/null +++ b/include/linux/compiler_types.h @@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_COMPILER_TYPES_H +#define __LINUX_COMPILER_TYPES_H + +#ifndef __ASSEMBLY__ + +#ifdef __CHECKER__ +# define __user __attribute__((noderef, address_space(1))) +# define __kernel __attribute__((address_space(0))) +# define __safe __attribute__((safe)) +# define __force __attribute__((force)) +# define __nocast __attribute__((nocast)) +# define __iomem __attribute__((noderef, address_space(2))) +# define __must_hold(x) __attribute__((context(x,1,1))) +# define __acquires(x) __attribute__((context(x,0,1))) +# define __releases(x) __attribute__((context(x,1,0))) +# define __acquire(x) __context__(x,1) +# define __release(x) __context__(x,-1) +# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) +# define __percpu __attribute__((noderef, address_space(3))) +# define __rcu __attribute__((noderef, address_space(4))) +# define __private __attribute__((noderef)) +extern void __chk_user_ptr(const volatile void __user *); +extern void __chk_io_ptr(const volatile void __iomem *); +# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member)) +#else /* __CHECKER__ */ +# ifdef STRUCTLEAK_PLUGIN +# define __user __attribute__((user)) +# else +# define __user +# endif +# define __kernel +# define __safe +# define __force +# define __nocast +# define __iomem +# define __chk_user_ptr(x) (void)0 +# define __chk_io_ptr(x) (void)0 +# define __builtin_warning(x, y...) (1) +# define __must_hold(x) +# define __acquires(x) +# define __releases(x) +# define __acquire(x) (void)0 +# define __release(x) (void)0 +# define __cond_lock(x,c) (c) +# define __percpu +# define __rcu +# define __private +# define ACCESS_PRIVATE(p, member) ((p)->member) +#endif /* __CHECKER__ */ + +/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ +#define ___PASTE(a,b) a##b +#define __PASTE(a,b) ___PASTE(a,b) + +#ifdef __KERNEL__ + +/* Attributes */ +#include + +/* Compiler specific macros. */ +#ifdef __clang__ +#include +#elif defined(__INTEL_COMPILER) +#include +#elif defined(__GNUC__) +/* The above compilers also define __GNUC__, so order is important here. */ +#include +#else +#error "Unknown compiler" +#endif + +/* + * Some architectures need to provide custom definitions of macros provided + * by linux/compiler-*.h, and can do so using asm/compiler.h. We include that + * conditionally rather than using an asm-generic wrapper in order to avoid + * build failures if any C compilation, which will include this file via an + * -include argument in c_flags, occurs prior to the asm-generic wrappers being + * generated. + */ +#ifdef CONFIG_HAVE_ARCH_COMPILER_H +#include +#endif + +struct ftrace_branch_data { + const char *func; + const char *file; + unsigned line; + union { + struct { + unsigned long correct; + unsigned long incorrect; + }; + struct { + unsigned long miss; + unsigned long hit; + }; + unsigned long miss_hit[2]; + }; +}; + +struct ftrace_likely_data { + struct ftrace_branch_data data; + unsigned long constant; +}; + +#ifdef CONFIG_ENABLE_MUST_CHECK +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif + +#if defined(CC_USING_HOTPATCH) +#define notrace __attribute__((hotpatch(0, 0))) +#elif defined(CC_USING_PATCHABLE_FUNCTION_ENTRY) +#define notrace __attribute__((patchable_function_entry(0, 0))) +#else +#define notrace __attribute__((__no_instrument_function__)) +#endif + +/* + * it doesn't make sense on ARM (currently the only user of __naked) + * to trace naked functions because then mcount is called without + * stack and frame pointer being set up and there is no chance to + * restore the lr register to the value before mcount was called. + */ +#define __naked __attribute__((__naked__)) notrace + +#define __compiler_offsetof(a, b) __builtin_offsetof(a, b) + +/* + * Force always-inline if the user requests it so via the .config. + * Prefer gnu_inline, so that extern inline functions do not emit an + * externally visible function. This makes extern inline behave as per gnu89 + * semantics rather than c99. This prevents multiple symbol definition errors + * of extern inline functions at link time. + * A lot of inline functions can cause havoc with function tracing. + * Do not use __always_inline here, since currently it expands to inline again + * (which would break users of __always_inline). + */ +#if !defined(CONFIG_OPTIMIZE_INLINING) +#define inline inline __attribute__((__always_inline__)) __gnu_inline \ + __inline_maybe_unused notrace +#else +#define inline inline __gnu_inline \ + __inline_maybe_unused notrace +#endif + +/* + * gcc provides both __inline__ and __inline as alternate spellings of + * the inline keyword, though the latter is undocumented. New kernel + * code should only use the inline spelling, but some existing code + * uses __inline__. Since we #define inline above, to ensure + * __inline__ has the same semantics, we need this #define. + * + * However, the spelling __inline is strictly reserved for referring + * to the bare keyword. + */ +#define __inline__ inline + +/* + * GCC does not warn about unused static inline functions for -Wunused-function. + * Suppress the warning in clang as well by using __maybe_unused, but enable it + * for W=1 build. This will allow clang to find unused functions. Remove the + * __inline_maybe_unused entirely after fixing most of -Wunused-function warnings. + */ +#ifdef KBUILD_EXTRA_WARN1 +#define __inline_maybe_unused +#else +#define __inline_maybe_unused __maybe_unused +#endif + +/* + * Rather then using noinline to prevent stack consumption, use + * noinline_for_stack instead. For documentation reasons. + */ +#define noinline_for_stack noinline + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +/* + * The below symbols may be defined for one or more, but not ALL, of the above + * compilers. We don't consider that to be an error, so set them to nothing. + * For example, some of them are for compiler specific plugins. + */ +#ifndef __latent_entropy +# define __latent_entropy +#endif + +#ifndef __randomize_layout +# define __randomize_layout __designated_init +#endif + +#ifndef __no_randomize_layout +# define __no_randomize_layout +#endif + +#ifndef randomized_struct_fields_start +# define randomized_struct_fields_start +# define randomized_struct_fields_end +#endif + +#ifndef asm_volatile_goto +#define asm_volatile_goto(x...) asm goto(x) +#endif + +#ifdef CONFIG_CC_HAS_ASM_INLINE +#define asm_inline asm __inline +#else +#define asm_inline asm +#endif + +#ifndef __no_fgcse +# define __no_fgcse +#endif + +/* Are two types/vars the same type (ignoring qualifiers)? */ +#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) + +/* Is this type a native word size -- useful for atomic operations */ +#define __native_word(t) \ + (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \ + sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) + +/* Helpers for emitting diagnostics in pragmas. */ +#ifndef __diag +#define __diag(string) +#endif + +#ifndef __diag_GCC +#define __diag_GCC(version, severity, string) +#endif + +#define __diag_push() __diag(push) +#define __diag_pop() __diag(pop) + +#define __diag_ignore(compiler, version, option, comment) \ + __diag_ ## compiler(version, ignore, option) +#define __diag_warn(compiler, version, option, comment) \ + __diag_ ## compiler(version, warn, option) +#define __diag_error(compiler, version, option, comment) \ + __diag_ ## compiler(version, error, option) + +#endif /* __LINUX_COMPILER_TYPES_H */ diff --git a/include/linux/if.h b/include/linux/if.h new file mode 100644 index 000000000000..a8ccf6d171e9 --- /dev/null +++ b/include/linux/if.h @@ -0,0 +1,296 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Global definitions for the INET interface module. + * + * Version: @(#)if.h 1.0.2 04/18/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988 + * Ross Biro + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_H +#define _LINUX_IF_H + +#include /* for compatibility with glibc */ +#include /* for "__kernel_caddr_t" et al */ +#include /* for "struct sockaddr" et al */ +#include /* for "__user" et al */ + +#ifndef __KERNEL__ +#include /* for struct sockaddr. */ +#endif + +#if __UAPI_DEF_IF_IFNAMSIZ +#define IFNAMSIZ 16 +#endif /* __UAPI_DEF_IF_IFNAMSIZ */ +#define IFALIASZ 256 +#define ALTIFNAMSIZ 128 +#include + +/* For glibc compatibility. An empty enum does not compile. */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \ + __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 +/** + * enum net_device_flags - &struct net_device flags + * + * These are the &struct net_device flags, they can be set by drivers, the + * kernel and some can be triggered by userspace. Userspace can query and + * set these flags using userspace utilities but there is also a sysfs + * entry available for all dev flags which can be queried and set. These flags + * are shared for all types of net_devices. The sysfs entries are available + * via /sys/class/net//flags. Flags which can be toggled through sysfs + * are annotated below, note that only a few flags can be toggled and some + * other flags are always preserved from the original net_device flags + * even if you try to set them via sysfs. Flags which are always preserved + * are kept under the flag grouping @IFF_VOLATILE. Flags which are volatile + * are annotated below as such. + * + * You should have a pretty good reason to be extending these flags. + * + * @IFF_UP: interface is up. Can be toggled through sysfs. + * @IFF_BROADCAST: broadcast address valid. Volatile. + * @IFF_DEBUG: turn on debugging. Can be toggled through sysfs. + * @IFF_LOOPBACK: is a loopback net. Volatile. + * @IFF_POINTOPOINT: interface is has p-p link. Volatile. + * @IFF_NOTRAILERS: avoid use of trailers. Can be toggled through sysfs. + * Volatile. + * @IFF_RUNNING: interface RFC2863 OPER_UP. Volatile. + * @IFF_NOARP: no ARP protocol. Can be toggled through sysfs. Volatile. + * @IFF_PROMISC: receive all packets. Can be toggled through sysfs. + * @IFF_ALLMULTI: receive all multicast packets. Can be toggled through + * sysfs. + * @IFF_MASTER: master of a load balancer. Volatile. + * @IFF_SLAVE: slave of a load balancer. Volatile. + * @IFF_MULTICAST: Supports multicast. Can be toggled through sysfs. + * @IFF_PORTSEL: can set media type. Can be toggled through sysfs. + * @IFF_AUTOMEDIA: auto media select active. Can be toggled through sysfs. + * @IFF_DYNAMIC: dialup device with changing addresses. Can be toggled + * through sysfs. + * @IFF_LOWER_UP: driver signals L1 up. Volatile. + * @IFF_DORMANT: driver signals dormant. Volatile. + * @IFF_ECHO: echo sent packets. Volatile. + */ +enum net_device_flags { +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS + IFF_UP = 1<<0, /* sysfs */ + IFF_BROADCAST = 1<<1, /* volatile */ + IFF_DEBUG = 1<<2, /* sysfs */ + IFF_LOOPBACK = 1<<3, /* volatile */ + IFF_POINTOPOINT = 1<<4, /* volatile */ + IFF_NOTRAILERS = 1<<5, /* sysfs */ + IFF_RUNNING = 1<<6, /* volatile */ + IFF_NOARP = 1<<7, /* sysfs */ + IFF_PROMISC = 1<<8, /* sysfs */ + IFF_ALLMULTI = 1<<9, /* sysfs */ + IFF_MASTER = 1<<10, /* volatile */ + IFF_SLAVE = 1<<11, /* volatile */ + IFF_MULTICAST = 1<<12, /* sysfs */ + IFF_PORTSEL = 1<<13, /* sysfs */ + IFF_AUTOMEDIA = 1<<14, /* sysfs */ + IFF_DYNAMIC = 1<<15, /* sysfs */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO + IFF_LOWER_UP = 1<<16, /* volatile */ + IFF_DORMANT = 1<<17, /* volatile */ + IFF_ECHO = 1<<18, /* volatile */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ +}; +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ + +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS +#define IFF_UP IFF_UP +#define IFF_BROADCAST IFF_BROADCAST +#define IFF_DEBUG IFF_DEBUG +#define IFF_LOOPBACK IFF_LOOPBACK +#define IFF_POINTOPOINT IFF_POINTOPOINT +#define IFF_NOTRAILERS IFF_NOTRAILERS +#define IFF_RUNNING IFF_RUNNING +#define IFF_NOARP IFF_NOARP +#define IFF_PROMISC IFF_PROMISC +#define IFF_ALLMULTI IFF_ALLMULTI +#define IFF_MASTER IFF_MASTER +#define IFF_SLAVE IFF_SLAVE +#define IFF_MULTICAST IFF_MULTICAST +#define IFF_PORTSEL IFF_PORTSEL +#define IFF_AUTOMEDIA IFF_AUTOMEDIA +#define IFF_DYNAMIC IFF_DYNAMIC +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ + +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO +#define IFF_LOWER_UP IFF_LOWER_UP +#define IFF_DORMANT IFF_DORMANT +#define IFF_ECHO IFF_ECHO +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + +#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ + IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) + +#define IF_GET_IFACE 0x0001 /* for querying only */ +#define IF_GET_PROTO 0x0002 + +/* For definitions see hdlc.h */ +#define IF_IFACE_V35 0x1000 /* V.35 serial interface */ +#define IF_IFACE_V24 0x1001 /* V.24 serial interface */ +#define IF_IFACE_X21 0x1002 /* X.21 serial interface */ +#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */ +#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */ +#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */ +#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */ + +/* For definitions see hdlc.h */ +#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */ +#define IF_PROTO_PPP 0x2001 /* PPP protocol */ +#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */ +#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */ +#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */ +#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */ +#define IF_PROTO_X25 0x2006 /* X.25 */ +#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */ +#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */ +#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */ +#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */ +#define IF_PROTO_FR_ETH_PVC 0x200B +#define IF_PROTO_RAW 0x200C /* RAW Socket */ + +/* RFC 2863 operational status */ +enum { + IF_OPER_UNKNOWN, + IF_OPER_NOTPRESENT, + IF_OPER_DOWN, + IF_OPER_LOWERLAYERDOWN, + IF_OPER_TESTING, + IF_OPER_DORMANT, + IF_OPER_UP, +}; + +/* link modes */ +enum { + IF_LINK_MODE_DEFAULT, + IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */ +}; + +/* + * Device mapping structure. I'd just gone off and designed a + * beautiful scheme using only loadable modules with arguments + * for driver options and along come the PCMCIA people 8) + * + * Ah well. The get() side of this is good for WDSETUP, and it'll + * be handy for debugging things. The set side is fine for now and + * being very small might be worth keeping for clean configuration. + */ + +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFMAP +struct ifmap { + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + /* 3 bytes spare */ +}; +#endif /* __UAPI_DEF_IF_IFMAP */ + +struct if_settings { + unsigned int type; /* Type of physical device or protocol */ + unsigned int size; /* Size of the data allocated by the caller */ + union { + /* {atm/eth/dsl}_settings anyone ? */ + raw_hdlc_proto __user *raw_hdlc; + cisco_proto __user *cisco; + fr_proto __user *fr; + fr_proto_pvc __user *fr_pvc; + fr_proto_pvc_info __user *fr_pvc_info; + + /* interface settings */ + sync_serial_settings __user *sync; + te1_settings __user *te1; + } ifs_ifsu; +}; + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ + +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFREQ +struct ifreq { +#define IFHWADDRLEN 6 + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + void __user * ifru_data; + struct if_settings ifru_settings; + } ifr_ifru; +}; +#endif /* __UAPI_DEF_IF_IFREQ */ + +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_ivalue /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_map ifr_ifru.ifru_map /* device map */ +#define ifr_slave ifr_ifru.ifru_slave /* slave device */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ +#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ +#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ +#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */ +#define ifr_newname ifr_ifru.ifru_newname /* New name */ +#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/ + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ + +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFCONF +struct ifconf { + int ifc_len; /* size of buffer */ + union { + char __user *ifcu_buf; + struct ifreq __user *ifcu_req; + } ifc_ifcu; +}; +#endif /* __UAPI_DEF_IF_IFCONF */ + +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + +#endif /* _LINUX_IF_H */ diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h new file mode 100644 index 000000000000..8254c937c9f4 --- /dev/null +++ b/include/linux/libc-compat.h @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Compatibility interface for userspace libc header coordination: + * + * Define compatibility macros that are used to control the inclusion or + * exclusion of UAPI structures and definitions in coordination with another + * userspace C library. + * + * This header is intended to solve the problem of UAPI definitions that + * conflict with userspace definitions. If a UAPI header has such conflicting + * definitions then the solution is as follows: + * + * * Synchronize the UAPI header and the libc headers so either one can be + * used and such that the ABI is preserved. If this is not possible then + * no simple compatibility interface exists (you need to write translating + * wrappers and rename things) and you can't use this interface. + * + * Then follow this process: + * + * (a) Include libc-compat.h in the UAPI header. + * e.g. #include + * This include must be as early as possible. + * + * (b) In libc-compat.h add enough code to detect that the comflicting + * userspace libc header has been included first. + * + * (c) If the userspace libc header has been included first define a set of + * guard macros of the form __UAPI_DEF_FOO and set their values to 1, else + * set their values to 0. + * + * (d) Back in the UAPI header with the conflicting definitions, guard the + * definitions with: + * #if __UAPI_DEF_FOO + * ... + * #endif + * + * This fixes the situation where the linux headers are included *after* the + * libc headers. To fix the problem with the inclusion in the other order the + * userspace libc headers must be fixed like this: + * + * * For all definitions that conflict with kernel definitions wrap those + * defines in the following: + * #if !__UAPI_DEF_FOO + * ... + * #endif + * + * This prevents the redefinition of a construct already defined by the kernel. + */ +#ifndef _UAPI_LIBC_COMPAT_H +#define _UAPI_LIBC_COMPAT_H + +/* We have included glibc headers... */ +#if defined(__GLIBC__) + +/* Coordinate with glibc net/if.h header. */ +#if defined(_NET_IF_H) && defined(__USE_MISC) + +/* GLIBC headers included first so don't define anything + * that would already be defined. */ + +#define __UAPI_DEF_IF_IFCONF 0 +#define __UAPI_DEF_IF_IFMAP 0 +#define __UAPI_DEF_IF_IFNAMSIZ 0 +#define __UAPI_DEF_IF_IFREQ 0 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + +#else /* _NET_IF_H */ + +/* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ + +#define __UAPI_DEF_IF_IFCONF 1 +#define __UAPI_DEF_IF_IFMAP 1 +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#define __UAPI_DEF_IF_IFREQ 1 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 + +#endif /* _NET_IF_H */ + +/* Coordinate with glibc netinet/in.h header. */ +#if defined(_NETINET_IN_H) + +/* GLIBC headers included first so don't define anything + * that would already be defined. */ +#define __UAPI_DEF_IN_ADDR 0 +#define __UAPI_DEF_IN_IPPROTO 0 +#define __UAPI_DEF_IN_PKTINFO 0 +#define __UAPI_DEF_IP_MREQ 0 +#define __UAPI_DEF_SOCKADDR_IN 0 +#define __UAPI_DEF_IN_CLASS 0 + +#define __UAPI_DEF_IN6_ADDR 0 +/* The exception is the in6_addr macros which must be defined + * if the glibc code didn't define them. This guard matches + * the guard in glibc/inet/netinet/in.h which defines the + * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */ +#if defined(__USE_MISC) || defined (__USE_GNU) +#define __UAPI_DEF_IN6_ADDR_ALT 0 +#else +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#endif +#define __UAPI_DEF_SOCKADDR_IN6 0 +#define __UAPI_DEF_IPV6_MREQ 0 +#define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 +#define __UAPI_DEF_IN6_PKTINFO 0 +#define __UAPI_DEF_IP6_MTUINFO 0 + +#else + +/* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ +#define __UAPI_DEF_IN_ADDR 1 +#define __UAPI_DEF_IN_IPPROTO 1 +#define __UAPI_DEF_IN_PKTINFO 1 +#define __UAPI_DEF_IP_MREQ 1 +#define __UAPI_DEF_SOCKADDR_IN 1 +#define __UAPI_DEF_IN_CLASS 1 + +#define __UAPI_DEF_IN6_ADDR 1 +/* We unconditionally define the in6_addr macros and glibc must + * coordinate. */ +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#define __UAPI_DEF_SOCKADDR_IN6 1 +#define __UAPI_DEF_IPV6_MREQ 1 +#define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 +#define __UAPI_DEF_IN6_PKTINFO 1 +#define __UAPI_DEF_IP6_MTUINFO 1 + +#endif /* _NETINET_IN_H */ + +/* Coordinate with glibc netipx/ipx.h header. */ +#if defined(__NETIPX_IPX_H) + +#define __UAPI_DEF_SOCKADDR_IPX 0 +#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0 +#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0 +#define __UAPI_DEF_IPX_CONFIG_DATA 0 +#define __UAPI_DEF_IPX_ROUTE_DEF 0 + +#else /* defined(__NETIPX_IPX_H) */ + +#define __UAPI_DEF_SOCKADDR_IPX 1 +#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 +#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 +#define __UAPI_DEF_IPX_CONFIG_DATA 1 +#define __UAPI_DEF_IPX_ROUTE_DEF 1 + +#endif /* defined(__NETIPX_IPX_H) */ + +/* Definitions for xattr.h */ +#if defined(_SYS_XATTR_H) +#define __UAPI_DEF_XATTR 0 +#else +#define __UAPI_DEF_XATTR 1 +#endif + +/* If we did not see any headers from any supported C libraries, + * or we are being included in the kernel, then define everything + * that we need. Check for previous __UAPI_* definitions to give + * unsupported C libraries a way to opt out of any kernel definition. */ +#else /* !defined(__GLIBC__) */ + +/* Definitions for if.h */ +#ifndef __UAPI_DEF_IF_IFCONF +#define __UAPI_DEF_IF_IFCONF 1 +#endif +#ifndef __UAPI_DEF_IF_IFMAP +#define __UAPI_DEF_IF_IFMAP 1 +#endif +#ifndef __UAPI_DEF_IF_IFNAMSIZ +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#endif +#ifndef __UAPI_DEF_IF_IFREQ +#define __UAPI_DEF_IF_IFREQ 1 +#endif +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +#endif +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 +#endif + +/* Definitions for in.h */ +#ifndef __UAPI_DEF_IN_ADDR +#define __UAPI_DEF_IN_ADDR 1 +#endif +#ifndef __UAPI_DEF_IN_IPPROTO +#define __UAPI_DEF_IN_IPPROTO 1 +#endif +#ifndef __UAPI_DEF_IN_PKTINFO +#define __UAPI_DEF_IN_PKTINFO 1 +#endif +#ifndef __UAPI_DEF_IP_MREQ +#define __UAPI_DEF_IP_MREQ 1 +#endif +#ifndef __UAPI_DEF_SOCKADDR_IN +#define __UAPI_DEF_SOCKADDR_IN 1 +#endif +#ifndef __UAPI_DEF_IN_CLASS +#define __UAPI_DEF_IN_CLASS 1 +#endif + +/* Definitions for in6.h */ +#ifndef __UAPI_DEF_IN6_ADDR +#define __UAPI_DEF_IN6_ADDR 1 +#endif +#ifndef __UAPI_DEF_IN6_ADDR_ALT +#define __UAPI_DEF_IN6_ADDR_ALT 1 +#endif +#ifndef __UAPI_DEF_SOCKADDR_IN6 +#define __UAPI_DEF_SOCKADDR_IN6 1 +#endif +#ifndef __UAPI_DEF_IPV6_MREQ +#define __UAPI_DEF_IPV6_MREQ 1 +#endif +#ifndef __UAPI_DEF_IPPROTO_V6 +#define __UAPI_DEF_IPPROTO_V6 1 +#endif +#ifndef __UAPI_DEF_IPV6_OPTIONS +#define __UAPI_DEF_IPV6_OPTIONS 1 +#endif +#ifndef __UAPI_DEF_IN6_PKTINFO +#define __UAPI_DEF_IN6_PKTINFO 1 +#endif +#ifndef __UAPI_DEF_IP6_MTUINFO +#define __UAPI_DEF_IP6_MTUINFO 1 +#endif + +/* Definitions for ipx.h */ +#ifndef __UAPI_DEF_SOCKADDR_IPX +#define __UAPI_DEF_SOCKADDR_IPX 1 +#endif +#ifndef __UAPI_DEF_IPX_ROUTE_DEFINITION +#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 +#endif +#ifndef __UAPI_DEF_IPX_INTERFACE_DEFINITION +#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 +#endif +#ifndef __UAPI_DEF_IPX_CONFIG_DATA +#define __UAPI_DEF_IPX_CONFIG_DATA 1 +#endif +#ifndef __UAPI_DEF_IPX_ROUTE_DEF +#define __UAPI_DEF_IPX_ROUTE_DEF 1 +#endif + +/* Definitions for xattr.h */ +#ifndef __UAPI_DEF_XATTR +#define __UAPI_DEF_XATTR 1 +#endif + +#endif /* __GLIBC__ */ + +#endif /* _UAPI_LIBC_COMPAT_H */ diff --git a/include/linux/mroute.h b/include/linux/mroute.h deleted file mode 100644 index a0bfdcb53ee2..000000000000 --- a/include/linux/mroute.h +++ /dev/null @@ -1,193 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI__LINUX_MROUTE_H -#define _UAPI__LINUX_MROUTE_H - -#ifdef __LINUX__ -#include -#include -#endif -#include /* For struct in_addr. */ - -/* Based on the MROUTING 3.5 defines primarily to keep - * source compatibility with BSD. - * - * See the mrouted code for the original history. - * - * Protocol Independent Multicast (PIM) data structures included - * Carlos Picoto (cap@di.fc.ul.pt) - */ - -#define MRT_BASE 200 -#define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */ -#define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */ -#define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */ -#define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */ -#define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */ -#define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ -#define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ -#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ -#define MRT_PIM (MRT_BASE+8) /* enable PIM code */ -#define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */ -#define MRT_ADD_MFC_PROXY (MRT_BASE+10) /* Add a (*,*|G) mfc entry */ -#define MRT_DEL_MFC_PROXY (MRT_BASE+11) /* Del a (*,*|G) mfc entry */ -#define MRT_FLUSH (MRT_BASE+12) /* Flush all mfc entries and/or vifs */ -#define MRT_MAX (MRT_BASE+12) - -#ifndef SIOCGETVIFCNT -#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ -#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) -#define SIOCGETRPF (SIOCPROTOPRIVATE+2) -#endif - -#ifndef MAXVIFS -#define MAXVIFS 32 -#endif -/* MRT_FLUSH optional flags */ -#define MRT_FLUSH_MFC 1 /* Flush multicast entries */ -#define MRT_FLUSH_MFC_STATIC 2 /* Flush static multicast entries */ -#define MRT_FLUSH_VIFS 4 /* Flush multicast vifs */ -#define MRT_FLUSH_VIFS_STATIC 8 /* Flush static multicast vifs */ - -typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */ -typedef unsigned short vifi_t; -#define ALL_VIFS ((vifi_t)(-1)) - -/* Same idea as select */ - -#define VIFM_SET(n,m) ((m)|=(1<<(n))) -#define VIFM_CLR(n,m) ((m)&=~(1<<(n))) -#define VIFM_ISSET(n,m) ((m)&(1<<(n))) -#define VIFM_CLRALL(m) ((m)=0) -#define VIFM_COPY(mfrom,mto) ((mto)=(mfrom)) -#define VIFM_SAME(m1,m2) ((m1)==(m2)) - -/* Passed by mrouted for an MRT_ADD_VIF - again we use the - * mrouted 3.6 structures for compatibility - */ -struct vifctl { - vifi_t vifc_vifi; /* Index of VIF */ - unsigned char vifc_flags; /* VIFF_ flags */ - unsigned char vifc_threshold; /* ttl limit */ - unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ - union { - struct in_addr vifc_lcl_addr; /* Local interface address */ - int vifc_lcl_ifindex; /* Local interface index */ - }; - struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ -}; - -#define VIFF_TUNNEL 0x1 /* IPIP tunnel */ -#define VIFF_SRCRT 0x2 /* NI */ -#define VIFF_REGISTER 0x4 /* register vif */ -#define VIFF_USE_IFINDEX 0x8 /* use vifc_lcl_ifindex instead of - vifc_lcl_addr to find an interface */ - -/* Cache manipulation structures for mrouted and PIMd */ -struct mfcctl { - struct in_addr mfcc_origin; /* Origin of mcast */ - struct in_addr mfcc_mcastgrp; /* Group in question */ - vifi_t mfcc_parent; /* Where it arrived */ - unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */ - unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */ - unsigned int mfcc_byte_cnt; - unsigned int mfcc_wrong_if; - int mfcc_expire; -}; - -/* Group count retrieval for mrouted */ -struct sioc_sg_req { - struct in_addr src; - struct in_addr grp; - unsigned long pktcnt; - unsigned long bytecnt; - unsigned long wrong_if; -}; - -/* To get vif packet counts */ -struct sioc_vif_req { - vifi_t vifi; /* Which iface */ - unsigned long icount; /* In packets */ - unsigned long ocount; /* Out packets */ - unsigned long ibytes; /* In bytes */ - unsigned long obytes; /* Out bytes */ -}; - -/* This is the format the mroute daemon expects to see IGMP control - * data. Magically happens to be like an IP packet as per the original - */ -struct igmpmsg { - uint32_t unused1,unused2; - unsigned char im_msgtype; /* What is this */ - unsigned char im_mbz; /* Must be zero */ - unsigned char im_vif; /* Low 8 bits of Interface */ - unsigned char im_vif_hi; /* High 8 bits of Interface */ - struct in_addr im_src,im_dst; -}; - -/* ipmr netlink table attributes */ -enum { - IPMRA_TABLE_UNSPEC, - IPMRA_TABLE_ID, - IPMRA_TABLE_CACHE_RES_QUEUE_LEN, - IPMRA_TABLE_MROUTE_REG_VIF_NUM, - IPMRA_TABLE_MROUTE_DO_ASSERT, - IPMRA_TABLE_MROUTE_DO_PIM, - IPMRA_TABLE_VIFS, - IPMRA_TABLE_MROUTE_DO_WRVIFWHOLE, - __IPMRA_TABLE_MAX -}; -#define IPMRA_TABLE_MAX (__IPMRA_TABLE_MAX - 1) - -/* ipmr netlink vif attribute format - * [ IPMRA_TABLE_VIFS ] - nested attribute - * [ IPMRA_VIF ] - nested attribute - * [ IPMRA_VIFA_xxx ] - */ -enum { - IPMRA_VIF_UNSPEC, - IPMRA_VIF, - __IPMRA_VIF_MAX -}; -#define IPMRA_VIF_MAX (__IPMRA_VIF_MAX - 1) - -/* vif-specific attributes */ -enum { - IPMRA_VIFA_UNSPEC, - IPMRA_VIFA_IFINDEX, - IPMRA_VIFA_VIF_ID, - IPMRA_VIFA_FLAGS, - IPMRA_VIFA_BYTES_IN, - IPMRA_VIFA_BYTES_OUT, - IPMRA_VIFA_PACKETS_IN, - IPMRA_VIFA_PACKETS_OUT, - IPMRA_VIFA_LOCAL_ADDR, - IPMRA_VIFA_REMOTE_ADDR, - IPMRA_VIFA_PAD, - __IPMRA_VIFA_MAX -}; -#define IPMRA_VIFA_MAX (__IPMRA_VIFA_MAX - 1) - -/* ipmr netlink cache report attributes */ -enum { - IPMRA_CREPORT_UNSPEC, - IPMRA_CREPORT_MSGTYPE, - IPMRA_CREPORT_VIF_ID, - IPMRA_CREPORT_SRC_ADDR, - IPMRA_CREPORT_DST_ADDR, - IPMRA_CREPORT_PKT, - IPMRA_CREPORT_TABLE, - __IPMRA_CREPORT_MAX -}; -#define IPMRA_CREPORT_MAX (__IPMRA_CREPORT_MAX - 1) - -/* That's all usermode folks */ - -#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ - -/* Pseudo messages used by mrouted */ -#define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ -#define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ -#define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ -#define IGMPMSG_WRVIFWHOLE 4 /* For PIM Register and assert processing */ - -#endif /* _UAPI__LINUX_MROUTE_H */ diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h deleted file mode 100644 index 8c0640671a6e..000000000000 --- a/include/linux/mroute6.h +++ /dev/null @@ -1,164 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _UAPI__LINUX_MROUTE6_H -#define _UAPI__LINUX_MROUTE6_H - -#ifdef __LINUX__ -#include -#include -#include -#endif -#include /* For struct sockaddr_in6. */ - -/* - * Based on the MROUTING 3.5 defines primarily to keep - * source compatibility with BSD. - * - * See the pim6sd code for the original history. - * - * Protocol Independent Multicast (PIM) data structures included - * Carlos Picoto (cap@di.fc.ul.pt) - * - */ - -#define MRT6_BASE 200 -#define MRT6_INIT (MRT6_BASE) /* Activate the kernel mroute code */ -#define MRT6_DONE (MRT6_BASE+1) /* Shutdown the kernel mroute */ -#define MRT6_ADD_MIF (MRT6_BASE+2) /* Add a virtual interface */ -#define MRT6_DEL_MIF (MRT6_BASE+3) /* Delete a virtual interface */ -#define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */ -#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ -#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ -#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */ -#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */ -#define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */ -#define MRT6_ADD_MFC_PROXY (MRT6_BASE+10) /* Add a (*,*|G) mfc entry */ -#define MRT6_DEL_MFC_PROXY (MRT6_BASE+11) /* Del a (*,*|G) mfc entry */ -#define MRT6_FLUSH (MRT6_BASE+12) /* Flush all mfc entries and/or vifs */ -#define MRT6_MAX (MRT6_BASE+12) - -#ifndef SIOCGETMIFCNT_IN6 -#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ -#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) -#define SIOCGETRPF (SIOCPROTOPRIVATE+2) -#endif - -#ifndef MAXMIFS -#define MAXMIFS 32 -#endif -/* MRT6_FLUSH optional flags */ -#define MRT6_FLUSH_MFC 1 /* Flush multicast entries */ -#define MRT6_FLUSH_MFC_STATIC 2 /* Flush static multicast entries */ -#define MRT6_FLUSH_MIFS 4 /* Flushing multicast vifs */ -#define MRT6_FLUSH_MIFS_STATIC 8 /* Flush static multicast vifs */ - -typedef unsigned long mifbitmap_t; /* User mode code depends on this lot */ -typedef unsigned short mifi_t; -#define ALL_MIFS ((mifi_t)(-1)) - -#ifndef IF_SETSIZE -#define IF_SETSIZE 256 -#endif - -typedef uint32_t if_mask; -#define NIFBITS (sizeof(if_mask) * 8) /* bits per mask */ - -typedef struct if_set { - /* __KERNEL_DIV_ROUND_UP() */ - if_mask ifs_bits[(IF_SETSIZE + NIFBITS - 1) / NIFBITS]; -} if_set; - -#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS))) -#define IF_CLR(n, p) ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS))) -#define IF_ISSET(n, p) ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS))) -#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f))) -#define IF_ZERO(p) bzero(p, sizeof(*(p))) - -/* - * Passed by mrouted for an MRT_ADD_MIF - again we use the - * mrouted 3.6 structures for compatibility - */ - -struct mif6ctl { - mifi_t mif6c_mifi; /* Index of MIF */ - unsigned char mif6c_flags; /* MIFF_ flags */ - unsigned char vifc_threshold; /* ttl limit */ - __u16 mif6c_pifi; /* the index of the physical IF */ - unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ -}; - -#define MIFF_REGISTER 0x1 /* register vif */ - -/* - * Cache manipulation structures for mrouted and PIMd - */ - -struct mf6cctl { - struct sockaddr_in6 mf6cc_origin; /* Origin of mcast */ - struct sockaddr_in6 mf6cc_mcastgrp; /* Group in question */ - mifi_t mf6cc_parent; /* Where it arrived */ - struct if_set mf6cc_ifset; /* Where it is going */ -}; - -/* - * Group count retrieval for pim6sd - */ - -struct sioc_sg_req6 { - struct sockaddr_in6 src; - struct sockaddr_in6 grp; - unsigned long pktcnt; - unsigned long bytecnt; - unsigned long wrong_if; -}; - -/* - * To get vif packet counts - */ - -struct sioc_mif_req6 { - mifi_t mifi; /* Which iface */ - unsigned long icount; /* In packets */ - unsigned long ocount; /* Out packets */ - unsigned long ibytes; /* In bytes */ - unsigned long obytes; /* Out bytes */ -}; - -/* - * That's all usermode folks - */ - - - -/* - * Structure used to communicate from kernel to multicast router. - * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{} - * used for IPv4 implementation). This is because this structure will be passed via an - * IPv6 raw socket, on which an application will only receiver the payload i.e the data after - * the IPv6 header and all the extension headers. (See section 3 of RFC 3542) - */ - -struct mrt6msg { -#define MRT6MSG_NOCACHE 1 -#define MRT6MSG_WRONGMIF 2 -#define MRT6MSG_WHOLEPKT 3 /* used for use level encap */ -#define MRT6MSG_WRMIFWHOLE 4 /* For PIM Register and assert processing */ - __u8 im6_mbz; /* must be zero */ - __u8 im6_msgtype; /* what type of message */ - __u16 im6_mif; /* mif rec'd on */ - __u32 im6_pad; /* padding for 64 bit arch */ - struct in6_addr im6_src, im6_dst; -}; - -/* ip6mr netlink cache report attributes */ -enum { - IP6MRA_CREPORT_UNSPEC, - IP6MRA_CREPORT_MSGTYPE, - IP6MRA_CREPORT_MIF_ID, - IP6MRA_CREPORT_SRC_ADDR, - IP6MRA_CREPORT_DST_ADDR, - IP6MRA_CREPORT_PKT, - __IP6MRA_CREPORT_MAX -}; -#define IP6MRA_CREPORT_MAX (__IP6MRA_CREPORT_MAX - 1) - -#endif /* _UAPI__LINUX_MROUTE6_H */ diff --git a/include/subdir.am b/include/subdir.am index 4fa88a0afd51..bcf3ef7b9bf8 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -1,4 +1,7 @@ noinst_HEADERS += \ + include/linux/compiler_types.h \ + include/linux/libc-compat.h \ + include/linux/if.h \ include/linux/if_addr.h \ include/linux/if_bridge.h \ include/linux/if_link.h \ @@ -17,7 +20,5 @@ noinst_HEADERS += \ include/linux/seg6_hmac.h \ include/linux/seg6_iptunnel.h \ include/linux/seg6_local.h \ - include/linux/mroute.h \ - include/linux/mroute6.h \ include/linux/pkt_cls.h \ # end diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index cba1b91faef1..078280acf55d 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -231,11 +231,12 @@ static void isis_adj_route_switchover(struct isis_adjacency *adj) } } -void isis_adj_process_threeway(struct isis_adjacency *adj, +void isis_adj_process_threeway(struct isis_adjacency **padj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage) { enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN; + struct isis_adjacency *adj = *padj; if (tw_adj && !adj->circuit->disable_threeway_adj) { if (tw_adj->state == ISIS_THREEWAY_DOWN) { @@ -265,14 +266,13 @@ void isis_adj_process_threeway(struct isis_adjacency *adj, fabricd_initial_sync_hello(adj->circuit); if (next_tw_state == ISIS_THREEWAY_DOWN) { - isis_adj_state_change(&adj, ISIS_ADJ_DOWN, - "Neighbor restarted"); + isis_adj_state_change(padj, ISIS_ADJ_DOWN, "Neighbor restarted"); return; } if (next_tw_state == ISIS_THREEWAY_UP) { if (adj->adj_state != ISIS_ADJ_UP) { - isis_adj_state_change(&adj, ISIS_ADJ_UP, NULL); + isis_adj_state_change(padj, ISIS_ADJ_UP, NULL); adj->adj_usage = adj_usage; } } @@ -293,7 +293,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj) struct isis_dynhn *dyn; dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid); - if (dyn) + if (adj->circuit->area->dynhostname && dyn) return dyn->hostname; snprintfrr(buf, sizeof(buf), "%pSY", adj->sysid); @@ -358,12 +358,15 @@ void isis_adj_state_change(struct isis_adjacency **padj, * purposes */ adj->last_flap = time(NULL); adj->flaps++; - } else if (old_state == ISIS_ADJ_UP) { - circuit->adj_state_changes++; + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { listnode_delete( @@ -409,10 +412,13 @@ void isis_adj_state_change(struct isis_adjacency **padj, master, send_l2_csnp, circuit, 0, &circuit->t_send_csnp[1]); } - } else if (old_state == ISIS_ADJ_UP) { - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) @@ -687,7 +693,7 @@ void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json, default: continue; } - backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)" + backup = (sra->type == ISIS_SR_ADJ_BACKUP) ? " (backup)" : ""; json_object_string_add(adj_sid_json, "nexthop", @@ -726,13 +732,13 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, now = time(NULL); if (adj->last_upd) { if (adj->last_upd + adj->hold_time < now) - vty_out(vty, " Expiring"); + vty_out(vty, " Expiring "); else vty_out(vty, " %-9llu", (unsigned long long)adj->last_upd + adj->hold_time - now); } else - vty_out(vty, "- "); + vty_out(vty, " - "); vty_out(vty, "%-10pSY", adj->snpa); vty_out(vty, "\n"); } @@ -862,7 +868,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, default: continue; } - backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)" + backup = (sra->type == ISIS_SR_ADJ_BACKUP) ? " (backup)" : ""; vty_out(vty, " %s %s%s: %u\n", diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index dc181055fa98..0ad36e4c5f2a 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -74,12 +74,10 @@ struct isis_adjacency { struct nlpids nlpids; /* protocols spoken ... */ struct in_addr *ipv4_addresses; unsigned int ipv4_address_count; - struct in_addr router_address; struct in6_addr *ll_ipv6_addrs; /* Link local IPv6 neighbor address */ unsigned int ll_ipv6_count; struct in6_addr *global_ipv6_addrs; /* Global IPv6 neighbor address */ unsigned int global_ipv6_count; - struct in6_addr router_address6; uint8_t prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ int level; /* level (1 or 2) */ @@ -113,7 +111,7 @@ struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level, struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa, int level, struct isis_circuit *circuit); void isis_delete_adj(void *adj); -void isis_adj_process_threeway(struct isis_adjacency *adj, +void isis_adj_process_threeway(struct isis_adjacency **padj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage); DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)); diff --git a/isisd/isis_affinitymap.c b/isisd/isis_affinitymap.c index 41bad0a7d934..595091db2727 100644 --- a/isisd/isis_affinitymap.c +++ b/isisd/isis_affinitymap.c @@ -11,35 +11,6 @@ #ifndef FABRICD -static bool isis_affinity_map_check_use(const char *affmap_name) -{ - struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); - struct isis_area *area; - struct listnode *area_node, *fa_node; - struct flex_algo *fa; - struct affinity_map *map; - uint16_t pos; - - if (!isis) - return false; - - map = affinity_map_get(affmap_name); - pos = map->bit_position; - - for (ALL_LIST_ELEMENTS_RO(isis->area_list, area_node, area)) { - for (ALL_LIST_ELEMENTS_RO(area->flex_algos->flex_algos, fa_node, - fa)) { - if (admin_group_get(&fa->admin_group_exclude_any, - pos) || - admin_group_get(&fa->admin_group_include_any, - pos) || - admin_group_get(&fa->admin_group_include_all, pos)) - return true; - } - } - return false; -} - static void isis_affinity_map_update(const char *affmap_name, uint16_t old_pos, uint16_t new_pos) { @@ -90,7 +61,6 @@ void isis_affinity_map_init(void) { affinity_map_init(); - affinity_map_set_check_use_hook(isis_affinity_map_check_use); affinity_map_set_update_hook(isis_affinity_map_update); } diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 96d629124de2..47f51a754892 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -8,6 +8,9 @@ */ #include + +#include + #if ISIS_METHOD == ISIS_METHOD_BPF #include #include diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index ffa6ad3e402d..fa1ce3007f8a 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -198,8 +198,8 @@ void isis_circuit_del(struct isis_circuit *circuit) ldp_sync_info_free(&circuit->ldp_sync_info); circuit_mt_finish(circuit); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL1); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL2); list_delete(&circuit->ip_addrs); list_delete(&circuit->ipv6_link); @@ -489,7 +489,6 @@ static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp) void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) { - struct listnode *node, *nnode; struct connected *conn; if (if_is_broadcast(ifp)) { @@ -509,20 +508,18 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) circuit->circ_type = CIRCUIT_T_UNKNOWN; } - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) + frr_each (if_connected, ifp->connected, conn) isis_circuit_add_addr(circuit, conn); - } void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) { - struct listnode *node, *nnode; struct connected *conn; assert(circuit->interface == ifp); /* destroy addresses */ - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) + frr_each_safe (if_connected, ifp->connected, conn) isis_circuit_del_addr(circuit, conn); circuit->circ_type = CIRCUIT_T_UNKNOWN; @@ -1680,6 +1677,8 @@ void isis_circuit_init(void) #else if_cmd_init_default(); #endif - if_zapi_callbacks(isis_ifp_create, isis_ifp_up, - isis_ifp_down, isis_ifp_destroy); + hook_register_prio(if_real, 0, isis_ifp_create); + hook_register_prio(if_up, 0, isis_ifp_up); + hook_register_prio(if_down, 0, isis_ifp_down); + hook_register_prio(if_unreal, 0, isis_ifp_destroy); } diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 9718a457ede5..2b19cbba849d 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -85,13 +85,13 @@ void cli_show_router_isis(struct vty *vty, const struct lyd_node *dnode, { const char *vrf = NULL; - vrf = yang_dnode_get_string(dnode, "./vrf"); + vrf = yang_dnode_get_string(dnode, "vrf"); vty_out(vty, "!\n"); vty_out(vty, "router isis %s", - yang_dnode_get_string(dnode, "./area-tag")); + yang_dnode_get_string(dnode, "area-tag")); if (!strmatch(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, " vrf %s", yang_dnode_get_string(dnode, "./vrf")); + vty_out(vty, " vrf %s", yang_dnode_get_string(dnode, "vrf")); vty_out(vty, "\n"); } @@ -172,7 +172,7 @@ DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd, * If both ipv4 and ipv6 are off delete the interface isis container. */ if (strmatch(ip, "ipv6")) { - if (!yang_dnode_get_bool(dnode, "./ipv4-routing")) + if (!yang_dnode_get_bool(dnode, "ipv4-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_DESTROY, NULL); else @@ -180,7 +180,7 @@ DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd, "./frr-isisd:isis/ipv6-routing", NB_OP_MODIFY, "false"); } else { - if (!yang_dnode_get_bool(dnode, "./ipv6-routing")) + if (!yang_dnode_get_bool(dnode, "ipv6-routing")) nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_DESTROY, NULL); else @@ -280,16 +280,16 @@ void cli_show_ip_isis_bfd_monitoring(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - if (!yang_dnode_get_bool(dnode, "./enabled")) { + if (!yang_dnode_get_bool(dnode, "enabled")) { if (show_defaults) vty_out(vty, " no isis bfd\n"); } else { vty_out(vty, " isis bfd\n"); } - if (yang_dnode_exists(dnode, "./profile")) + if (yang_dnode_exists(dnode, "profile")) vty_out(vty, " isis bfd profile %s\n", - yang_dnode_get_string(dnode, "./profile")); + yang_dnode_get_string(dnode, "profile")); } /* @@ -300,8 +300,12 @@ DEFPY_YANG(net, net_cmd, "[no] net WORD", "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { - nb_cli_enqueue_change(vty, "./area-address", - no ? NB_OP_DESTROY : NB_OP_CREATE, net); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, XPATH_MAXLEN, "./area-address[.='%s']", net); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -588,9 +592,9 @@ void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode, const char *snp; vty_out(vty, " area-password %s %s", - yang_dnode_get_string(dnode, "./password-type"), - yang_dnode_get_string(dnode, "./password")); - snp = yang_dnode_get_string(dnode, "./authenticate-snp"); + yang_dnode_get_string(dnode, "password-type"), + yang_dnode_get_string(dnode, "password")); + snp = yang_dnode_get_string(dnode, "authenticate-snp"); if (!strmatch("none", snp)) vty_out(vty, " authenticate snp %s", snp); vty_out(vty, "\n"); @@ -638,9 +642,9 @@ void cli_show_isis_domain_pwd(struct vty *vty, const struct lyd_node *dnode, const char *snp; vty_out(vty, " domain-password %s %s", - yang_dnode_get_string(dnode, "./password-type"), - yang_dnode_get_string(dnode, "./password")); - snp = yang_dnode_get_string(dnode, "./authenticate-snp"); + yang_dnode_get_string(dnode, "password-type"), + yang_dnode_get_string(dnode, "password")); + snp = yang_dnode_get_string(dnode, "authenticate-snp"); if (!strmatch("none", snp)) vty_out(vty, " authenticate snp %s", snp); vty_out(vty, "\n"); @@ -861,17 +865,17 @@ void cli_show_isis_lsp_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *l1_refresh = - yang_dnode_get_string(dnode, "./level-1/refresh-interval"); + yang_dnode_get_string(dnode, "level-1/refresh-interval"); const char *l2_refresh = - yang_dnode_get_string(dnode, "./level-2/refresh-interval"); + yang_dnode_get_string(dnode, "level-2/refresh-interval"); const char *l1_lifetime = - yang_dnode_get_string(dnode, "./level-1/maximum-lifetime"); + yang_dnode_get_string(dnode, "level-1/maximum-lifetime"); const char *l2_lifetime = - yang_dnode_get_string(dnode, "./level-2/maximum-lifetime"); + yang_dnode_get_string(dnode, "level-2/maximum-lifetime"); const char *l1_gen = - yang_dnode_get_string(dnode, "./level-1/generation-interval"); + yang_dnode_get_string(dnode, "level-1/generation-interval"); const char *l2_gen = - yang_dnode_get_string(dnode, "./level-2/generation-interval"); + yang_dnode_get_string(dnode, "level-2/generation-interval"); if (strmatch(l1_refresh, l2_refresh) && strmatch(l1_lifetime, l2_lifetime) && strmatch(l1_gen, l2_gen)) vty_out(vty, @@ -980,8 +984,8 @@ void cli_show_isis_spf_min_interval(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " spf-interval %s\n", l1); @@ -1051,11 +1055,11 @@ void cli_show_isis_spf_ietf_backoff(struct vty *vty, { vty_out(vty, " spf-delay-ietf init-delay %s short-delay %s long-delay %s holddown %s time-to-learn %s\n", - yang_dnode_get_string(dnode, "./init-delay"), - yang_dnode_get_string(dnode, "./short-delay"), - yang_dnode_get_string(dnode, "./long-delay"), - yang_dnode_get_string(dnode, "./hold-down"), - yang_dnode_get_string(dnode, "./time-to-learn")); + yang_dnode_get_string(dnode, "init-delay"), + yang_dnode_get_string(dnode, "short-delay"), + yang_dnode_get_string(dnode, "long-delay"), + yang_dnode_get_string(dnode, "hold-down"), + yang_dnode_get_string(dnode, "time-to-learn")); } /* @@ -1364,15 +1368,15 @@ static void vty_print_def_origin(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " default-information originate %s %s", family, level); - if (yang_dnode_get_bool(dnode, "./always")) + if (yang_dnode_get_bool(dnode, "always")) vty_out(vty, " always"); - if (yang_dnode_exists(dnode, "./route-map")) + if (yang_dnode_exists(dnode, "route-map")) vty_out(vty, " route-map %s", - yang_dnode_get_string(dnode, "./route-map")); - if (show_defaults || !yang_dnode_is_default(dnode, "./metric")) + yang_dnode_get_string(dnode, "route-map")); + if (show_defaults || !yang_dnode_is_default(dnode, "metric")) vty_out(vty, " metric %s", - yang_dnode_get_string(dnode, "./metric")); + yang_dnode_get_string(dnode, "metric")); vty_out(vty, "\n"); } @@ -1381,7 +1385,7 @@ void cli_show_isis_def_origin_ipv4(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *level = yang_dnode_get_string(dnode, "./level"); + const char *level = yang_dnode_get_string(dnode, "level"); vty_print_def_origin(vty, dnode, "ipv4", level, show_defaults); } @@ -1390,7 +1394,7 @@ void cli_show_isis_def_origin_ipv6(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *level = yang_dnode_get_string(dnode, "./level"); + const char *level = yang_dnode_get_string(dnode, "level"); vty_print_def_origin(vty, dnode, "ipv6", level, show_defaults); } @@ -1505,22 +1509,22 @@ static void vty_print_redistribute(struct vty *vty, const struct lyd_node *dnode if (table) { level = yang_dnode_get_string(dnode, "../level"); - tableid = yang_dnode_get_uint16(dnode, "./table"); + tableid = yang_dnode_get_uint16(dnode, "table"); vty_out(vty, " redistribute %s table %d ", family, tableid); } else { - protocol = yang_dnode_get_string(dnode, "./protocol"); + protocol = yang_dnode_get_string(dnode, "protocol"); if (!table && strmatch(protocol, "table")) return; - level = yang_dnode_get_string(dnode, "./level"); + level = yang_dnode_get_string(dnode, "level"); vty_out(vty, " redistribute %s %s ", family, protocol); } vty_out(vty, "%s", level); - if (show_defaults || !yang_dnode_is_default(dnode, "./metric")) + if (show_defaults || !yang_dnode_is_default(dnode, "metric")) vty_out(vty, " metric %s", - yang_dnode_get_string(dnode, "%s", "./metric")); + yang_dnode_get_string(dnode, "%s", "metric")); - if (yang_dnode_exists(dnode, "./route-map")) - routemap = yang_dnode_get_string(dnode, "./route-map"); + if (yang_dnode_exists(dnode, "route-map")) + routemap = yang_dnode_get_string(dnode, "route-map"); if (routemap) vty_out(vty, " route-map %s", routemap); vty_out(vty, "\n"); @@ -1557,8 +1561,8 @@ void cli_show_isis_redistribute_ipv6_table(struct vty *vty, int cli_cmp_isis_redistribute_table(const struct lyd_node *dnode1, const struct lyd_node *dnode2) { - uint16_t table1 = yang_dnode_get_uint16(dnode1, "./table"); - uint16_t table2 = yang_dnode_get_uint16(dnode2, "./table"); + uint16_t table1 = yang_dnode_get_uint16(dnode1, "table"); + uint16_t table2 = yang_dnode_get_uint16(dnode2, "table"); return table1 - table2; } @@ -1619,7 +1623,7 @@ void cli_show_isis_mt_ipv4_multicast(struct vty *vty, bool show_defaults) { vty_out(vty, " topology ipv4-multicast"); - if (yang_dnode_get_bool(dnode, "./overload")) + if (yang_dnode_get_bool(dnode, "overload")) vty_out(vty, " overload"); vty_out(vty, "\n"); } @@ -1628,7 +1632,7 @@ void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv4-mgmt"); - if (yang_dnode_get_bool(dnode, "./overload")) + if (yang_dnode_get_bool(dnode, "overload")) vty_out(vty, " overload"); vty_out(vty, "\n"); } @@ -1638,7 +1642,7 @@ void cli_show_isis_mt_ipv6_unicast(struct vty *vty, bool show_defaults) { vty_out(vty, " topology ipv6-unicast"); - if (yang_dnode_get_bool(dnode, "./overload")) + if (yang_dnode_get_bool(dnode, "overload")) vty_out(vty, " overload"); vty_out(vty, "\n"); } @@ -1648,7 +1652,7 @@ void cli_show_isis_mt_ipv6_multicast(struct vty *vty, bool show_defaults) { vty_out(vty, " topology ipv6-multicast"); - if (yang_dnode_get_bool(dnode, "./overload")) + if (yang_dnode_get_bool(dnode, "overload")) vty_out(vty, " overload"); vty_out(vty, "\n"); } @@ -1657,7 +1661,7 @@ void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv6-mgmt"); - if (yang_dnode_get_bool(dnode, "./overload")) + if (yang_dnode_get_bool(dnode, "overload")) vty_out(vty, " overload"); vty_out(vty, "\n"); } @@ -1666,7 +1670,7 @@ void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv6-dstsrc"); - if (yang_dnode_get_bool(dnode, "./overload")) + if (yang_dnode_get_bool(dnode, "overload")) vty_out(vty, " overload"); vty_out(vty, "\n"); } @@ -1771,13 +1775,13 @@ void cli_show_isis_label_blocks(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " segment-routing global-block %s %s", - yang_dnode_get_string(dnode, "./srgb/lower-bound"), - yang_dnode_get_string(dnode, "./srgb/upper-bound")); - if (!yang_dnode_is_default(dnode, "./srlb/lower-bound") - || !yang_dnode_is_default(dnode, "./srlb/upper-bound")) + yang_dnode_get_string(dnode, "srgb/lower-bound"), + yang_dnode_get_string(dnode, "srgb/upper-bound")); + if (!yang_dnode_is_default(dnode, "srlb/lower-bound") + || !yang_dnode_is_default(dnode, "srlb/upper-bound")) vty_out(vty, " local-block %s %s", - yang_dnode_get_string(dnode, "./srlb/lower-bound"), - yang_dnode_get_string(dnode, "./srlb/upper-bound")); + yang_dnode_get_string(dnode, "srlb/lower-bound"), + yang_dnode_get_string(dnode, "srlb/upper-bound")); vty_out(vty, "\n"); } @@ -1899,11 +1903,11 @@ void cli_show_isis_prefix_sid(struct vty *vty, const struct lyd_node *dnode, const char *sid_value; bool n_flag_clear; - prefix = yang_dnode_get_string(dnode, "./prefix"); - lh_behavior = yang_dnode_get_string(dnode, "./last-hop-behavior"); - sid_value_type = yang_dnode_get_string(dnode, "./sid-value-type"); - sid_value = yang_dnode_get_string(dnode, "./sid-value"); - n_flag_clear = yang_dnode_get_bool(dnode, "./n-flag-clear"); + prefix = yang_dnode_get_string(dnode, "prefix"); + lh_behavior = yang_dnode_get_string(dnode, "last-hop-behavior"); + sid_value_type = yang_dnode_get_string(dnode, "sid-value-type"); + sid_value = yang_dnode_get_string(dnode, "sid-value"); + n_flag_clear = yang_dnode_get_bool(dnode, "n-flag-clear"); vty_out(vty, " segment-routing prefix %s", prefix); if (strmatch(sid_value_type, "absolute")) @@ -2013,12 +2017,12 @@ void cli_show_isis_prefix_sid_algorithm(struct vty *vty, bool n_flag_clear; uint32_t algorithm; - prefix = yang_dnode_get_string(dnode, "./prefix"); - sid_value_type = yang_dnode_get_string(dnode, "./sid-value-type"); - sid_value = yang_dnode_get_string(dnode, "./sid-value"); - algorithm = yang_dnode_get_uint32(dnode, "./algo"); - lh_behavior = yang_dnode_get_string(dnode, "./last-hop-behavior"); - n_flag_clear = yang_dnode_get_bool(dnode, "./n-flag-clear"); + prefix = yang_dnode_get_string(dnode, "prefix"); + sid_value_type = yang_dnode_get_string(dnode, "sid-value-type"); + sid_value = yang_dnode_get_string(dnode, "sid-value"); + algorithm = yang_dnode_get_uint32(dnode, "algo"); + lh_behavior = yang_dnode_get_string(dnode, "last-hop-behavior"); + n_flag_clear = yang_dnode_get_bool(dnode, "n-flag-clear"); vty_out(vty, " segment-routing prefix %s", prefix); vty_out(vty, " algorithm %u", algorithm); @@ -2220,22 +2224,22 @@ void cli_show_isis_srv6_node_msd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " node-msd\n"); - if (yang_dnode_get_uint8(dnode, "./max-segs-left") != + if (yang_dnode_get_uint8(dnode, "max-segs-left") != yang_get_default_uint8("%s/msd/node-msd/max-segs-left", ISIS_SRV6)) vty_out(vty, " max-segs-left %u\n", - yang_dnode_get_uint8(dnode, "./max-segs-left")); - if (yang_dnode_get_uint8(dnode, "./max-end-pop") != + yang_dnode_get_uint8(dnode, "max-segs-left")); + if (yang_dnode_get_uint8(dnode, "max-end-pop") != yang_get_default_uint8("%s/msd/node-msd/max-end-pop", ISIS_SRV6)) vty_out(vty, " max-end-pop %u\n", - yang_dnode_get_uint8(dnode, "./max-end-pop")); - if (yang_dnode_get_uint8(dnode, "./max-h-encaps") != + yang_dnode_get_uint8(dnode, "max-end-pop")); + if (yang_dnode_get_uint8(dnode, "max-h-encaps") != yang_get_default_uint8("%s/msd/node-msd/max-h-encaps", ISIS_SRV6)) vty_out(vty, " max-h-encaps %u\n", - yang_dnode_get_uint8(dnode, "./max-h-encaps")); - if (yang_dnode_get_uint8(dnode, "./max-end-d") != + yang_dnode_get_uint8(dnode, "max-h-encaps")); + if (yang_dnode_get_uint8(dnode, "max-end-d") != yang_get_default_uint8("%s/msd/node-msd/max-end-d", ISIS_SRV6)) vty_out(vty, " max-end-d %u\n", - yang_dnode_get_uint8(dnode, "./max-end-d")); + yang_dnode_get_uint8(dnode, "max-end-d")); } /* @@ -2381,8 +2385,8 @@ void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, bool show_defaults) { vty_out(vty, " fast-reroute lfa tiebreaker %s index %s %s\n", - yang_dnode_get_string(dnode, "./type"), - yang_dnode_get_string(dnode, "./index"), + yang_dnode_get_string(dnode, "type"), + yang_dnode_get_string(dnode, "index"), dnode->parent->parent->schema->name); } @@ -2554,8 +2558,8 @@ void cli_show_ip_isis_password(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " isis password %s %s\n", - yang_dnode_get_string(dnode, "./password-type"), - yang_dnode_get_string(dnode, "./password")); + yang_dnode_get_string(dnode, "password-type"), + yang_dnode_get_string(dnode, "password")); } /* @@ -2601,8 +2605,8 @@ DEFPY_YANG(no_isis_metric, no_isis_metric_cmd, void cli_show_ip_isis_metric(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " isis metric %s\n", l1); @@ -2660,8 +2664,8 @@ void cli_show_ip_isis_hello_interval(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " isis hello-interval %s\n", l1); @@ -2718,8 +2722,8 @@ DEFPY_YANG(no_isis_hello_multiplier, no_isis_hello_multiplier_cmd, void cli_show_ip_isis_hello_multi(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " isis hello-multiplier %s\n", l1); @@ -2837,8 +2841,8 @@ void cli_show_ip_isis_csnp_interval(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " isis csnp-interval %s\n", l1); @@ -2896,8 +2900,8 @@ void cli_show_ip_isis_psnp_interval(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " isis psnp-interval %s\n", l1); @@ -3054,12 +3058,16 @@ void cli_show_ip_isis_circ_type(struct vty *vty, const struct lyd_node *dnode, } static int ag_change(struct vty *vty, int argc, struct cmd_token **argv, - const char *xpath, bool no, int start_idx) + const char *xpath_base, bool no, int start_idx) { - for (int i = start_idx; i < argc; i++) + char xpath[XPATH_MAXLEN]; + + for (int i = start_idx; i < argc; i++) { + snprintf(xpath, XPATH_MAXLEN, "%s[.='%s']", xpath_base, + argv[i]->arg); nb_cli_enqueue_change(vty, xpath, - no ? NB_OP_DESTROY : NB_OP_CREATE, - argv[i]->arg); + no ? NB_OP_DESTROY : NB_OP_CREATE, NULL); + } return nb_cli_apply_changes(vty, NULL); } @@ -3140,8 +3148,8 @@ DEFPY_YANG(no_isis_priority, no_isis_priority_cmd, void cli_show_ip_isis_priority(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *l1 = yang_dnode_get_string(dnode, "./level-1"); - const char *l2 = yang_dnode_get_string(dnode, "./level-2"); + const char *l1 = yang_dnode_get_string(dnode, "level-1"); + const char *l2 = yang_dnode_get_string(dnode, "level-2"); if (strmatch(l1, l2)) vty_out(vty, " isis priority %s\n", l1); @@ -3162,8 +3170,8 @@ void cli_show_ip_isis_frr(struct vty *vty, const struct lyd_node *dnode, bool l1_link_fallback, l2_link_fallback; /* Classic LFA */ - l1_enabled = yang_dnode_get_bool(dnode, "./level-1/lfa/enable"); - l2_enabled = yang_dnode_get_bool(dnode, "./level-2/lfa/enable"); + l1_enabled = yang_dnode_get_bool(dnode, "level-1/lfa/enable"); + l2_enabled = yang_dnode_get_bool(dnode, "level-2/lfa/enable"); if (l1_enabled || l2_enabled) { if (l1_enabled == l2_enabled) { @@ -3180,8 +3188,8 @@ void cli_show_ip_isis_frr(struct vty *vty, const struct lyd_node *dnode, } /* Remote LFA */ - l1_enabled = yang_dnode_get_bool(dnode, "./level-1/remote-lfa/enable"); - l2_enabled = yang_dnode_get_bool(dnode, "./level-2/remote-lfa/enable"); + l1_enabled = yang_dnode_get_bool(dnode, "level-1/remote-lfa/enable"); + l2_enabled = yang_dnode_get_bool(dnode, "level-2/remote-lfa/enable"); if (l1_enabled || l2_enabled) { if (l1_enabled == l2_enabled) { @@ -3199,16 +3207,16 @@ void cli_show_ip_isis_frr(struct vty *vty, const struct lyd_node *dnode, } /* TI-LFA */ - l1_enabled = yang_dnode_get_bool(dnode, "./level-1/ti-lfa/enable"); - l2_enabled = yang_dnode_get_bool(dnode, "./level-2/ti-lfa/enable"); + l1_enabled = yang_dnode_get_bool(dnode, "level-1/ti-lfa/enable"); + l2_enabled = yang_dnode_get_bool(dnode, "level-2/ti-lfa/enable"); l1_node_protection = - yang_dnode_get_bool(dnode, "./level-1/ti-lfa/node-protection"); + yang_dnode_get_bool(dnode, "level-1/ti-lfa/node-protection"); l2_node_protection = - yang_dnode_get_bool(dnode, "./level-2/ti-lfa/node-protection"); + yang_dnode_get_bool(dnode, "level-2/ti-lfa/node-protection"); l1_link_fallback = - yang_dnode_get_bool(dnode, "./level-1/ti-lfa/link-fallback"); + yang_dnode_get_bool(dnode, "level-1/ti-lfa/link-fallback"); l2_link_fallback = - yang_dnode_get_bool(dnode, "./level-2/ti-lfa/link-fallback"); + yang_dnode_get_bool(dnode, "level-2/ti-lfa/link-fallback"); if (l1_enabled || l2_enabled) { @@ -3302,31 +3310,27 @@ DEFPY(isis_lfa_exclude_interface, isis_lfa_exclude_interface_cmd, "Exclude an interface from computation\n" "Interface name\n") { + char xpath[XPATH_MAXLEN]; + if (!level || strmatch(level, "level-1")) { - if (no) { - nb_cli_enqueue_change( - vty, - "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface", - NB_OP_DESTROY, ifname); - } else { - nb_cli_enqueue_change( - vty, - "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface", - NB_OP_CREATE, ifname); - } + snprintf(xpath, sizeof(xpath), + "./frr-isisd:isis/fast-reroute/level-1/lfa/exclude-interface[.='%s']", + ifname); + + if (no) + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); } if (!level || strmatch(level, "level-2")) { - if (no) { - nb_cli_enqueue_change( - vty, - "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface", - NB_OP_DESTROY, ifname); - } else { - nb_cli_enqueue_change( - vty, - "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface", - NB_OP_CREATE, ifname); - } + snprintf(xpath, sizeof(xpath), + "./frr-isisd:isis/fast-reroute/level-2/lfa/exclude-interface[.='%s']", + ifname); + + if (no) + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); } return nb_cli_apply_changes(vty, NULL); @@ -3874,24 +3878,24 @@ void cli_show_isis_flex_algo(struct vty *vty, const struct lyd_node *dnode, uint32_t priority; char type_str[10]; - algorithm = yang_dnode_get_uint32(dnode, "./flex-algo"); + algorithm = yang_dnode_get_uint32(dnode, "flex-algo"); vty_out(vty, " flex-algo %u\n", algorithm); - if (yang_dnode_exists(dnode, "./advertise-definition")) + if (yang_dnode_exists(dnode, "advertise-definition")) vty_out(vty, " advertise-definition\n"); - if (yang_dnode_exists(dnode, "./dplane-sr-mpls")) + if (yang_dnode_exists(dnode, "dplane-sr-mpls")) vty_out(vty, " dataplane sr-mpls\n"); - if (yang_dnode_exists(dnode, "./dplane-srv6")) + if (yang_dnode_exists(dnode, "dplane-srv6")) vty_out(vty, " dataplane srv6\n"); - if (yang_dnode_exists(dnode, "./dplane-ip")) + if (yang_dnode_exists(dnode, "dplane-ip")) vty_out(vty, " dataplane ip\n"); - if (yang_dnode_exists(dnode, "./prefix-metric")) + if (yang_dnode_exists(dnode, "prefix-metric")) vty_out(vty, " prefix-metric\n"); - if (yang_dnode_exists(dnode, "./metric-type")) { - metric_type = yang_dnode_get_enum(dnode, "./metric-type"); + if (yang_dnode_exists(dnode, "metric-type")) { + metric_type = yang_dnode_get_enum(dnode, "metric-type"); if (metric_type != MT_IGP) { flex_algo_metric_type_print(type_str, sizeof(type_str), metric_type); @@ -3899,8 +3903,8 @@ void cli_show_isis_flex_algo(struct vty *vty, const struct lyd_node *dnode, } } - if (yang_dnode_exists(dnode, "./priority")) { - priority = yang_dnode_get_uint32(dnode, "./priority"); + if (yang_dnode_exists(dnode, "priority")) { + priority = yang_dnode_get_uint32(dnode, "priority"); if (priority != FLEX_ALGO_PRIO_DEFAULT) vty_out(vty, " priority %u\n", priority); } diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 32231a079f1a..5574bbc50fca 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -83,6 +83,7 @@ static void circuit_commence_level(struct isis_circuit *circuit, int level) send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY); circuit->u.bc.lan_neighs[level - 1] = list_new(); + circuit->u.bc.adjdb[level - 1] = list_new(); } } @@ -108,6 +109,10 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level) circuit->u.bc.is_dr[idx] = 0; if (circuit->u.bc.lan_neighs[idx] != NULL) list_delete(&circuit->u.bc.lan_neighs[idx]); + if (circuit->u.bc.adjdb[idx]) { + circuit->u.bc.adjdb[idx]->del = isis_delete_adj; + list_delete(&circuit->u.bc.adjdb[idx]); + } } return; diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 6f21f4cea2cc..887f27eec5d9 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -238,10 +238,10 @@ void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level) * * @param nodes List of SPF nodes */ -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level) +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level) { - hash_clean(circuit->lfa_excluded_ifaces[level - 1], - lfa_excl_interface_hash_free); + hash_clean_and_free(&circuit->lfa_excluded_ifaces[level - 1], + lfa_excl_interface_hash_free); } /** @@ -916,9 +916,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc, adj = isis_adj_find(spftree_pc->area, spftree_pc->level, vertex->N.id); - if (adj - && isis_sr_adj_sid_find(adj, spftree_pc->family, - ISIS_SR_LAN_BACKUP)) { + if (adj && isis_sr_adj_sid_find(adj, spftree_pc->family, + ISIS_SR_ADJ_BACKUP)) { if (IS_DEBUG_LFA) zlog_debug( "ISIS-LFA: %s %s already covered by node protection", @@ -2127,9 +2126,16 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit, } vadj_primary = listnode_head(vertex->Adj_N); + if (!vadj_primary) { + if (IS_DEBUG_LFA) + zlog_debug( + "ISIS-LFA: skipping computing LFAs due to no adjacencies"); + continue; + } sadj_primary = vadj_primary->sadj; parent_vertex = listnode_head(vertex->parents); + assert(parent_vertex); prefix_metric = vertex->d_N - parent_vertex->d_N; /* diff --git a/isisd/isis_lfa.h b/isisd/isis_lfa.h index 0ba1c1cef5d5..58ff115b021d 100644 --- a/isisd/isis_lfa.h +++ b/isisd/isis_lfa.h @@ -133,7 +133,7 @@ struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area, void isis_lfa_tiebreaker_delete(struct isis_area *area, int level, struct lfa_tiebreaker *tie_b); void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level); -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level); +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level); void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level, const char *ifname); void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 1b3491f5d38e..391d42fba156 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -442,47 +442,6 @@ void set_overload_on_start_timer(struct event *thread) isis_area_overload_bit_set(area, false); } -static void isis_reset_attach_bit(struct isis_adjacency *adj) -{ - struct isis_area *area = adj->circuit->area; - struct lspdb_head *head; - struct isis_lsp *lsp; - uint8_t lspid[ISIS_SYS_ID_LEN + 2]; - - /* - * If an L2 adjacency changed its state in L-1-2 area, we have to: - * - set the attached bit in L1 LSPs if it's the first L2 adjacency - * - remove the attached bit in L1 LSPs if it's the last L2 adjacency - */ - - if (area->is_type != IS_LEVEL_1_AND_2 || adj->level == ISIS_ADJ_LEVEL1) - return; - - if (!area->attached_bit_send) - return; - - head = &area->lspdb[IS_LEVEL_1 - 1]; - memset(lspid, 0, ISIS_SYS_ID_LEN + 2); - memcpy(lspid, area->isis->sysid, ISIS_SYS_ID_LEN); - - lsp = lsp_search(head, lspid); - if (!lsp) - return; - - if (adj->adj_state == ISIS_ADJ_UP - && !(lsp->hdr.lsp_bits & LSPBIT_ATT)) { - sched_debug("ISIS (%s): adj going up regenerate lsp-bits", - area->area_tag); - lsp_regenerate_schedule(area, IS_LEVEL_1, 0); - } else if (adj->adj_state == ISIS_ADJ_DOWN - && (lsp->hdr.lsp_bits & LSPBIT_ATT) - && !isis_level2_adj_up(area)) { - sched_debug("ISIS (%s): adj going down regenerate lsp-bits", - area->area_tag); - lsp_regenerate_schedule(area, IS_LEVEL_1, 0); - } -} - static uint8_t lsp_bits_generate(int level, int overload_bit, int attached_bit, struct isis_area *area) { @@ -523,13 +482,19 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, lsp->tlvs = tlvs; - if (area->dynhostname && lsp->tlvs->hostname - && lsp->hdr.rem_lifetime) { - isis_dynhn_insert( - area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname, - (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 - ? IS_LEVEL_2 - : IS_LEVEL_1); + if (area->dynhostname && lsp->hdr.rem_lifetime) { + if (lsp->tlvs->hostname) { + isis_dynhn_insert(area->isis, lsp->hdr.lsp_id, + lsp->tlvs->hostname, + (lsp->hdr.lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 + ? IS_LEVEL_2 + : IS_LEVEL_1); + } else { + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id) && + !LSP_FRAGMENT(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, lsp->hdr.lsp_id); + } } return; @@ -703,7 +668,7 @@ void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost, else if (!memcmp(isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost) snprintf(id, sizeof(id), "%.14s", cmd_hostname_get()); else - snprintf(id, sizeof(id), "%pSY", lsp_id); + snprintfrr(id, sizeof(id), "%pSY", lsp_id); if (frag) snprintf(dest, dest_len, "%s.%02x-%02x", id, @@ -746,6 +711,10 @@ void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object } } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove JSON in '-' format") +#endif + void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, char dynhost, struct isis *isis) { @@ -759,10 +728,20 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, own_json = json_object_new_object(); json_object_object_add(json, "lsp", own_json); json_object_string_add(own_json, "id", LSPid); +#if CONFDATE > 20240916 + CPP_NOTICE("remove own key") +#endif json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " "); + if (lsp->own_lsp) + json_object_boolean_add(own_json, "ownLSP", true); json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len); + json_object_int_add(json, "pduLen", lsp->hdr.pdu_len); snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno); +#if CONFDATE > 20240916 + CPP_NOTICE("remove seq-number key") +#endif json_object_string_add(json, "seq-number", buf); + json_object_string_add(json, "seqNumber", buf); snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum); json_object_string_add(json, "chksum", buf); if (lsp->hdr.rem_lifetime == 0) { @@ -772,8 +751,13 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, } else { json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime); } +#if CONFDATE > 20240916 + CPP_NOTICE("remove att-p-ol key") +#endif json_object_string_add( json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); + json_object_string_add(json, "attPOl", + lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); } void lsp_print_vty(struct isis_lsp *lsp, struct vty *vty, @@ -822,15 +806,24 @@ int lsp_print_all(struct vty *vty, struct json_object *json, { struct isis_lsp *lsp; int lsp_count = 0; + struct json_object *lsp_json = NULL; if (detail == ISIS_UI_LEVEL_BRIEF) { frr_each (lspdb, head, lsp) { - lsp_print_common(lsp, vty, json, dynhost, isis); + if (json) { + lsp_json = json_object_new_object(); + json_object_array_add(json, lsp_json); + } + lsp_print_common(lsp, vty, lsp_json, dynhost, isis); lsp_count++; } } else if (detail == ISIS_UI_LEVEL_DETAIL) { frr_each (lspdb, head, lsp) { - lsp_print_detail(lsp, vty, json, dynhost, isis); + if (json) { + lsp_json = json_object_new_object(); + json_object_array_add(json, lsp_json); + } + lsp_print_detail(lsp, vty, lsp_json, dynhost, isis); lsp_count++; } } @@ -1235,17 +1228,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } /* Add SRv6 Locator TLV. */ - if (area->srv6db.config.enabled && - !list_isempty(area->srv6db.srv6_locator_chunks)) { + if (area->srv6db.config.enabled && area->srv6db.srv6_locator) { struct isis_srv6_locator locator = {}; - struct srv6_locator_chunk *chunk; - - /* TODO: support more than one locator */ - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); locator.metric = 0; - locator.prefix = chunk->prefix; + locator.prefix = area->srv6db.srv6_locator->prefix; locator.flags = 0; locator.algorithm = 0; @@ -1265,7 +1252,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), - &chunk->prefix, 0, false, NULL); + &area->srv6db.srv6_locator->prefix, 0, + false, NULL); } /* IPv4 address and TE router ID TLVs. @@ -2238,6 +2226,10 @@ void lsp_tick(struct event *thread) &area->lspdb[level], next); + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, + lsp->hdr.lsp_id); + lspdb_del(&area->lspdb[level], lsp); lsp_destroy(lsp); lsp = NULL; @@ -2345,14 +2337,59 @@ static int lsp_handle_adj_state_change(struct isis_adjacency *adj) { lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); - /* when an adjacency state changes determine if we need to - * change attach_bits in other area's LSPs - */ - isis_reset_attach_bit(adj); - return 0; } +/* + * Iterate over all SRv6 locator TLVs + */ +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return LSP_ITER_CONTINUE; + + /* Parse LSP */ + if (lsp->tlvs) { + if (!pseudo_lsp) { + struct isis_item_list *srv6_locator_reachs; + struct isis_srv6_locator_tlv *r; + + srv6_locator_reachs = + isis_lookup_mt_items(&lsp->tlvs->srv6_locator, + mtid); + + for (r = srv6_locator_reachs + ? (struct isis_srv6_locator_tlv *) + srv6_locator_reachs->head + : NULL; + r; r = r->next) { + if ((*cb)((struct prefix *)&r->prefix, + r->metric, false /* ignore */, + r->subtlvs, arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + /* Parse LSP fragments if it is not a fragment itself */ + if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + if (isis_lsp_iterate_srv6_locator(frag, mtid, cb, + arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + + return LSP_ITER_CONTINUE; +} + /* * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given * address-family and MT-ID. diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 3839a9504c05..15db88b02f36 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -143,6 +143,8 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid, lsp_ip_reach_iter_cb cb, void *arg); int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid, lsp_is_reach_iter_cb cb, void *arg); +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg); #define lsp_flood(lsp, circuit) \ _lsp_flood((lsp), (circuit), __func__, __FILE__, __LINE__) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index da4c7bc00a42..b7ed8f760586 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -28,6 +28,7 @@ #include "libfrr.h" #include "routemap.h" #include "affinitymap.h" +#include "libagentx.h" #include "isisd/isis_affinitymap.h" #include "isisd/isis_constants.h" @@ -51,9 +52,16 @@ /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" -/* Default vty port */ -#define ISISD_VTY_PORT 2608 -#define FABRICD_VTY_PORT 2618 + +#define FABRICD_STATE_NAME "%s/fabricd.json", frr_libstatedir +#define ISISD_STATE_NAME "%s/isisd.json", frr_libstatedir + +/* The typo was there before. Do not fix it! The point is to load mis-saved + * state files from older versions. + * + * Also fabricd was using the same file. Sigh. + */ +#define ISISD_COMPAT_STATE_NAME "%s/isid-restart.json", frr_runstatedir /* isisd privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_SYS_ADMIN}; @@ -95,6 +103,12 @@ static __attribute__((__noreturn__)) void terminate(int i) isis_sr_term(); isis_srv6_term(); isis_zebra_stop(); + + isis_master_terminate(); + route_map_finish(); + vrf_terminate(); + + frr_fini(); exit(i); } @@ -212,24 +226,41 @@ static void isis_config_end(void) isis_config_finish(t_isis_cfg); } +/* actual paths filled in main() */ +static char state_path[512]; +static char state_compat_path[512]; +static char *state_paths[] = { + state_path, + state_compat_path, + NULL, +}; + +/* clang-format off */ +FRR_DAEMON_INFO( #ifdef FABRICD -FRR_DAEMON_INFO(fabricd, OPEN_FABRIC, .vty_port = FABRICD_VTY_PORT, + fabricd, OPEN_FABRIC, - .proghelp = "Implementation of the OpenFabric routing protocol.", + .vty_port = FABRICD_VTY_PORT, + .proghelp = "Implementation of the OpenFabric routing protocol.", #else -FRR_DAEMON_INFO(isisd, ISIS, .vty_port = ISISD_VTY_PORT, + isisd, ISIS, - .proghelp = "Implementation of the IS-IS routing protocol.", + .vty_port = ISISD_VTY_PORT, + .proghelp = "Implementation of the IS-IS routing protocol.", #endif - .copyright = - "Copyright (c) 2001-2002 Sampo Saaristo, Ofer Wald and Hannes Gredler", + .copyright = "Copyright (c) 2001-2002 Sampo Saaristo, Ofer Wald and Hannes Gredler", + + .signals = isisd_signals, + .n_signals = array_size(isisd_signals), - .signals = isisd_signals, - .n_signals = array_size(isisd_signals), + .privs = &isisd_privs, - .privs = &isisd_privs, .yang_modules = isisd_yang_modules, - .n_yang_modules = array_size(isisd_yang_modules), + .yang_modules = isisd_yang_modules, + .n_yang_modules = array_size(isisd_yang_modules), + + .state_paths = state_paths, ); +/* clang-format on */ /* * Main routine of isisd. Parse arguments and handle IS-IS state machine. @@ -269,12 +300,21 @@ int main(int argc, char **argv, char **envp) } } +#ifdef FABRICD + snprintf(state_path, sizeof(state_path), FABRICD_STATE_NAME); +#else + snprintf(state_path, sizeof(state_path), ISISD_STATE_NAME); +#endif + snprintf(state_compat_path, sizeof(state_compat_path), + ISISD_COMPAT_STATE_NAME); + /* thread master */ isis_master_init(frr_init()); master = im->master; /* * initializations */ + libagentx_init(); cmd_init_config_callbacks(isis_config_start, isis_config_end); isis_error_init(); access_list_init(); diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index e4ef6c8dfa3c..833d5143412e 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -370,18 +370,20 @@ const char *print_sys_hostname(const uint8_t *sysid) struct isis_dynhn *dyn; struct isis *isis = NULL; struct listnode *node; + struct isis_area *area = NULL; if (!sysid) return "nullsysid"; /* For our system ID return our host name */ - isis = isis_lookup_by_sysid(sysid); - if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + area = isis_area_lookup_by_sysid(sysid); + if (area && area->dynhostname && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) return cmd_hostname_get(); for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + area = isis_area_lookup_by_sysid(isis->sysid); dyn = dynhn_find_by_id(isis, sysid); - if (dyn) + if (area && area->dynhostname && dyn) return dyn->hostname; } diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 186ebfc729da..16cafa2ff034 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -879,28 +879,24 @@ const struct frr_yang_module_info frr_isisd_info = { .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-segs-left", .cbs = { .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify, - .destroy = isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_destroy, }, }, { .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-pop", .cbs = { .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify, - .destroy = isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_destroy, }, }, { .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-h-encaps", .cbs = { .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify, - .destroy = isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_destroy, }, }, { .xpath = "/frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-d", .cbs = { .modify = isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify, - .destroy = isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_destroy, }, }, { diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index be89fd2ac68a..c04a006a2e3c 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -334,20 +334,12 @@ void cli_show_isis_srv6_locator(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify( struct nb_cb_modify_args *args); -int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_destroy( - struct nb_cb_destroy_args *args); int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify( struct nb_cb_modify_args *args); -int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_destroy( - struct nb_cb_destroy_args *args); int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify( struct nb_cb_modify_args *args); -int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_destroy( - struct nb_cb_destroy_args *args); int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify( struct nb_cb_modify_args *args); -int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_destroy( - struct nb_cb_destroy_args *args); void cli_show_isis_srv6_node_msd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); int isis_instance_segment_routing_srv6_interface_modify( diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 5d0089d6fb37..2b47d5cbeb38 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -60,8 +60,8 @@ int isis_instance_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - vrf_name = yang_dnode_get_string(args->dnode, "./vrf"); - area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); + vrf_name = yang_dnode_get_string(args->dnode, "vrf"); + area_tag = yang_dnode_get_string(args->dnode, "area-tag"); area = isis_area_lookup_by_vrf(area_tag, vrf_name); if (area) @@ -252,11 +252,12 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) return NB_ERR_INCONSISTENCY; listnode_delete(area->area_addrs, addrp); - XFREE(MTYPE_ISIS_AREA_ADDR, addrp); /* * Last area address - reset the SystemID for this router */ - if (listcount(area->area_addrs) == 0) { + if (!memcmp(addrp->area_addr + addrp->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN) && + listcount(area->area_addrs) == 0) { for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (circuit->u.bc.is_dr[lvl - 1]) @@ -268,6 +269,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) zlog_debug("Router has no SystemID"); } + XFREE(MTYPE_ISIS_AREA_ADDR, addrp); + return NB_OK; } @@ -650,12 +653,12 @@ int isis_instance_lsp_generation_interval_level_2_modify( */ void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args) { - long init_delay = yang_dnode_get_uint16(args->dnode, "./init-delay"); - long short_delay = yang_dnode_get_uint16(args->dnode, "./short-delay"); - long long_delay = yang_dnode_get_uint16(args->dnode, "./long-delay"); - long holddown = yang_dnode_get_uint16(args->dnode, "./hold-down"); + long init_delay = yang_dnode_get_uint16(args->dnode, "init-delay"); + long short_delay = yang_dnode_get_uint16(args->dnode, "short-delay"); + long long_delay = yang_dnode_get_uint16(args->dnode, "long-delay"); + long holddown = yang_dnode_get_uint16(args->dnode, "hold-down"); long timetolearn = - yang_dnode_get_uint16(args->dnode, "./time-to-learn"); + yang_dnode_get_uint16(args->dnode, "time-to-learn"); struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true); size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx"); char *buf = XCALLOC(MTYPE_TMP, bufsiz); @@ -926,11 +929,11 @@ int isis_instance_spf_prefix_priorities_medium_access_list_name_destroy( */ void area_password_apply_finish(struct nb_cb_apply_finish_args *args) { - const char *password = yang_dnode_get_string(args->dnode, "./password"); + const char *password = yang_dnode_get_string(args->dnode, "password"); struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true); - int pass_type = yang_dnode_get_enum(args->dnode, "./password-type"); + int pass_type = yang_dnode_get_enum(args->dnode, "password-type"); uint8_t snp_auth = - yang_dnode_get_enum(args->dnode, "./authenticate-snp"); + yang_dnode_get_enum(args->dnode, "authenticate-snp"); switch (pass_type) { case ISIS_PASSWD_TYPE_CLEARTXT: @@ -997,11 +1000,11 @@ int isis_instance_area_password_authenticate_snp_modify( */ void domain_password_apply_finish(struct nb_cb_apply_finish_args *args) { - const char *password = yang_dnode_get_string(args->dnode, "./password"); + const char *password = yang_dnode_get_string(args->dnode, "password"); struct isis_area *area = nb_running_get_entry(args->dnode, NULL, true); - int pass_type = yang_dnode_get_enum(args->dnode, "./password-type"); + int pass_type = yang_dnode_get_enum(args->dnode, "password-type"); uint8_t snp_auth = - yang_dnode_get_enum(args->dnode, "./authenticate-snp"); + yang_dnode_get_enum(args->dnode, "authenticate-snp"); switch (pass_type) { case ISIS_PASSWD_TYPE_CLEARTXT: @@ -1073,9 +1076,9 @@ void default_info_origin_apply_finish(const struct lyd_node *dnode, int family) unsigned long metric = 0; const char *routemap = NULL; struct isis_area *area = nb_running_get_entry(dnode, NULL, true); - int level = yang_dnode_get_enum(dnode, "./level"); + int level = yang_dnode_get_enum(dnode, "level"); - if (yang_dnode_get_bool(dnode, "./always")) { + if (yang_dnode_get_bool(dnode, "always")) { originate_type = DEFAULT_ORIGINATE_ALWAYS; } else if (family == AF_INET6) { zlog_warn( @@ -1083,10 +1086,10 @@ void default_info_origin_apply_finish(const struct lyd_node *dnode, int family) __func__); } - if (yang_dnode_exists(dnode, "./metric")) - metric = yang_dnode_get_uint32(dnode, "./metric"); - if (yang_dnode_exists(dnode, "./route-map")) - routemap = yang_dnode_get_string(dnode, "./route-map"); + if (yang_dnode_exists(dnode, "metric")) + metric = yang_dnode_get_uint32(dnode, "metric"); + if (yang_dnode_exists(dnode, "route-map")) + routemap = yang_dnode_get_string(dnode, "route-map"); isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap, originate_type, 0); @@ -1119,7 +1122,7 @@ int isis_instance_default_information_originate_ipv4_destroy( return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - level = yang_dnode_get_enum(args->dnode, "./level"); + level = yang_dnode_get_enum(args->dnode, "level"); isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE, 0); return NB_OK; @@ -1182,7 +1185,7 @@ int isis_instance_default_information_originate_ipv6_destroy( return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - level = yang_dnode_get_enum(args->dnode, "./level"); + level = yang_dnode_get_enum(args->dnode, "level"); isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE, 0); return NB_OK; @@ -1236,14 +1239,14 @@ void redistribute_apply_finish(const struct lyd_node *dnode, int family) const char *routemap = NULL; struct isis_area *area; - type = yang_dnode_get_enum(dnode, "./protocol"); - level = yang_dnode_get_enum(dnode, "./level"); + type = yang_dnode_get_enum(dnode, "protocol"); + level = yang_dnode_get_enum(dnode, "level"); area = nb_running_get_entry(dnode, NULL, true); - if (yang_dnode_exists(dnode, "./metric")) - metric = yang_dnode_get_uint32(dnode, "./metric"); - if (yang_dnode_exists(dnode, "./route-map")) - routemap = yang_dnode_get_string(dnode, "./route-map"); + if (yang_dnode_exists(dnode, "metric")) + metric = yang_dnode_get_uint32(dnode, "metric"); + if (yang_dnode_exists(dnode, "route-map")) + routemap = yang_dnode_get_string(dnode, "route-map"); isis_redist_set(area, level, family, type, metric, routemap, 0, 0); } @@ -1273,8 +1276,8 @@ int isis_instance_redistribute_ipv4_destroy(struct nb_cb_destroy_args *args) return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - level = yang_dnode_get_enum(args->dnode, "./level"); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + level = yang_dnode_get_enum(args->dnode, "level"); + type = yang_dnode_get_enum(args->dnode, "protocol"); isis_redist_unset(area, level, AF_INET, type, 0); return NB_OK; @@ -1333,12 +1336,12 @@ int isis_instance_redistribute_ipv4_table_create(struct nb_cb_create_args *args) level = yang_dnode_get_enum(args->dnode, "../level"); area = nb_running_get_entry(args->dnode, "../.", true); - if (yang_dnode_exists(args->dnode, "./metric")) - metric = yang_dnode_get_uint32(args->dnode, "./metric"); - if (yang_dnode_exists(args->dnode, "./route-map")) - routemap = yang_dnode_get_string(args->dnode, "./route-map"); + if (yang_dnode_exists(args->dnode, "metric")) + metric = yang_dnode_get_uint32(args->dnode, "metric"); + if (yang_dnode_exists(args->dnode, "route-map")) + routemap = yang_dnode_get_string(args->dnode, "route-map"); - table = yang_dnode_get_uint16(args->dnode, "./table"); + table = yang_dnode_get_uint16(args->dnode, "table"); isis_redist_set(area, level, AF_INET, type, metric, routemap, 0, table); return NB_OK; @@ -1355,7 +1358,7 @@ int isis_instance_redistribute_ipv4_table_destroy(struct nb_cb_destroy_args *arg area = nb_running_get_entry(args->dnode, "../.", true); level = yang_dnode_get_enum(args->dnode, "../level"); type = yang_dnode_get_enum(args->dnode, "../protocol"); - table = yang_dnode_get_uint16(args->dnode, "./table"); + table = yang_dnode_get_uint16(args->dnode, "table"); isis_redist_unset(area, level, AF_INET, type, table); return NB_OK; @@ -1379,8 +1382,8 @@ int isis_instance_redistribute_ipv6_destroy(struct nb_cb_destroy_args *args) return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - level = yang_dnode_get_enum(args->dnode, "./level"); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + level = yang_dnode_get_enum(args->dnode, "level"); + type = yang_dnode_get_enum(args->dnode, "protocol"); isis_redist_unset(area, level, AF_INET6, type, 0); return NB_OK; @@ -1732,8 +1735,8 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_create( return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - index = yang_dnode_get_uint8(args->dnode, "./index"); - type = yang_dnode_get_enum(args->dnode, "./type"); + index = yang_dnode_get_uint8(args->dnode, "index"); + type = yang_dnode_get_enum(args->dnode, "type"); tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL1, index, type); nb_running_set_entry(args->dnode, tie_b); @@ -1881,8 +1884,8 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_create( return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - index = yang_dnode_get_uint8(args->dnode, "./index"); - type = yang_dnode_get_enum(args->dnode, "./type"); + index = yang_dnode_get_uint8(args->dnode, "index"); + type = yang_dnode_get_enum(args->dnode, "type"); tie_b = isis_lfa_tiebreaker_add(area, ISIS_LEVEL2, index, type); nb_running_set_entry(args->dnode, tie_b); @@ -2212,10 +2215,10 @@ int isis_instance_segment_routing_label_blocks_pre_validate( uint32_t srlb_lbound; uint32_t srlb_ubound; - srgb_lbound = yang_dnode_get_uint32(args->dnode, "./srgb/lower-bound"); - srgb_ubound = yang_dnode_get_uint32(args->dnode, "./srgb/upper-bound"); - srlb_lbound = yang_dnode_get_uint32(args->dnode, "./srlb/lower-bound"); - srlb_ubound = yang_dnode_get_uint32(args->dnode, "./srlb/upper-bound"); + srgb_lbound = yang_dnode_get_uint32(args->dnode, "srgb/lower-bound"); + srgb_ubound = yang_dnode_get_uint32(args->dnode, "srgb/upper-bound"); + srlb_lbound = yang_dnode_get_uint32(args->dnode, "srlb/lower-bound"); + srlb_ubound = yang_dnode_get_uint32(args->dnode, "srlb/upper-bound"); /* Check that the block size does not exceed 65535 */ if ((srgb_ubound - srgb_lbound + 1) > 65535) { @@ -2255,8 +2258,8 @@ void isis_instance_segment_routing_srgb_apply_finish( uint32_t lower_bound, upper_bound; area = nb_running_get_entry(args->dnode, NULL, true); - lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); - upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + lower_bound = yang_dnode_get_uint32(args->dnode, "lower-bound"); + upper_bound = yang_dnode_get_uint32(args->dnode, "upper-bound"); isis_sr_cfg_srgb_update(area, lower_bound, upper_bound); } @@ -2321,8 +2324,8 @@ void isis_instance_segment_routing_srlb_apply_finish( uint32_t lower_bound, upper_bound; area = nb_running_get_entry(args->dnode, NULL, true); - lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound"); - upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound"); + lower_bound = yang_dnode_get_uint32(args->dnode, "lower-bound"); + upper_bound = yang_dnode_get_uint32(args->dnode, "upper-bound"); isis_sr_cfg_srlb_update(area, lower_bound, upper_bound); } @@ -2428,7 +2431,7 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_create( return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); pcfg = isis_sr_cfg_prefix_add(area, &prefix, SR_ALGORITHM_SPF); nb_running_set_entry(args->dnode, pcfg); @@ -2466,13 +2469,13 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate( enum sr_sid_value_type sid_type; struct isis_prefix_sid psid = {}; - yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); srgb_lbound = yang_dnode_get_uint32( args->dnode, "../../label-blocks/srgb/lower-bound"); srgb_ubound = yang_dnode_get_uint32( args->dnode, "../../label-blocks/srgb/upper-bound"); - sid = yang_dnode_get_uint32(args->dnode, "./sid-value"); - sid_type = yang_dnode_get_enum(args->dnode, "./sid-value-type"); + sid = yang_dnode_get_uint32(args->dnode, "sid-value"); + sid_type = yang_dnode_get_enum(args->dnode, "sid-value-type"); /* Check for invalid indexes/labels. */ srgb_range = srgb_ubound - srgb_lbound + 1; @@ -2636,8 +2639,8 @@ int isis_instance_segment_routing_algorithm_prefix_sid_create( return NB_OK; area = nb_running_get_entry(args->dnode, NULL, true); - yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); - algorithm = yang_dnode_get_uint32(args->dnode, "./algo"); + yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); + algorithm = yang_dnode_get_uint32(args->dnode, "algo"); pcfg = isis_sr_cfg_prefix_add(area, &prefix, algorithm); pcfg->algorithm = algorithm; @@ -2676,13 +2679,13 @@ int isis_instance_segment_routing_algorithm_prefix_sid_pre_validate( enum sr_sid_value_type sid_type; struct isis_prefix_sid psid = {}; - yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); + yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); srgb_lbound = yang_dnode_get_uint32( args->dnode, "../../label-blocks/srgb/lower-bound"); srgb_ubound = yang_dnode_get_uint32( args->dnode, "../../label-blocks/srgb/upper-bound"); - sid = yang_dnode_get_uint32(args->dnode, "./sid-value"); - sid_type = yang_dnode_get_enum(args->dnode, "./sid-value-type"); + sid = yang_dnode_get_uint32(args->dnode, "sid-value"); + sid_type = yang_dnode_get_enum(args->dnode, "sid-value-type"); /* Check for invalid indexes/labels. */ srgb_range = srgb_ubound - srgb_lbound + 1; @@ -2835,19 +2838,22 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) { struct isis_area *area; struct flex_algo *fa; - bool advertise; + bool advertise, update_te; + struct isis_circuit *circuit; + struct listnode *node; uint32_t algorithm; uint32_t priority = FLEX_ALGO_PRIO_DEFAULT; struct isis_flex_algo_alloc_arg arg; - algorithm = yang_dnode_get_uint32(args->dnode, "./flex-algo"); - advertise = yang_dnode_exists(args->dnode, "./advertise-definition"); + algorithm = yang_dnode_get_uint32(args->dnode, "flex-algo"); + advertise = yang_dnode_exists(args->dnode, "advertise-definition"); switch (args->event) { case NB_EV_APPLY: area = nb_running_get_entry(args->dnode, NULL, true); arg.algorithm = algorithm; arg.area = area; + update_te = list_isempty(area->flex_algos->flex_algos); fa = flex_algo_alloc(area->flex_algos, algorithm, &arg); fa->priority = priority; fa->advertise_definition = advertise; @@ -2859,6 +2865,12 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) admin_group_allow_explicit_zero( &fa->admin_group_include_all); } + if (update_te) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, + circuit)) + isis_link_params_update_asla(circuit, + circuit->interface); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: @@ -2872,15 +2884,28 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) { + struct isis_circuit *circuit; + struct listnode *node, *nnode; + struct flex_algo *fa; struct isis_area *area; uint32_t algorithm; - algorithm = yang_dnode_get_uint32(args->dnode, "./flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "flex-algo"); area = nb_running_get_entry(args->dnode, NULL, true); switch (args->event) { case NB_EV_APPLY: - flex_algo_delete(area->flex_algos, algorithm); + for (ALL_LIST_ELEMENTS(area->flex_algos->flex_algos, node, + nnode, fa)) { + if (fa->algorithm == algorithm) + flex_algo_free(area->flex_algos, fa); + } + if (list_isempty(area->flex_algos->flex_algos)) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, + circuit)) + isis_link_params_update_asla(circuit, + circuit->interface); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: @@ -2904,8 +2929,8 @@ int isis_instance_flex_algo_advertise_definition_modify( uint32_t algorithm; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); - advertise = yang_dnode_exists(args->dnode, "./../advertise-definition"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); + advertise = yang_dnode_exists(args->dnode, "../advertise-definition"); switch (args->event) { case NB_EV_APPLY: @@ -2937,7 +2962,7 @@ int isis_instance_flex_algo_advertise_definition_destroy( area = nb_running_get_entry(args->dnode, NULL, true); - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); switch (args->event) { case NB_EV_APPLY: @@ -3153,7 +3178,7 @@ int isis_instance_flex_algo_prefix_metric_create(struct nb_cb_create_args *args) if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); switch (args->event) { case NB_EV_APPLY: @@ -3188,7 +3213,7 @@ int isis_instance_flex_algo_prefix_metric_destroy( if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); switch (args->event) { case NB_EV_APPLY: @@ -3223,7 +3248,7 @@ static int isis_instance_flex_algo_dplane_set(struct nb_cb_create_args *args, if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); switch (args->event) { case NB_EV_APPLY: @@ -3265,7 +3290,7 @@ static int isis_instance_flex_algo_dplane_unset(struct nb_cb_destroy_args *args, if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); switch (args->event) { case NB_EV_APPLY: @@ -3348,7 +3373,7 @@ int isis_instance_flex_algo_metric_type_modify(struct nb_cb_modify_args *args) if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); metric_type = yang_dnode_get_enum(args->dnode, NULL); switch (args->event) { @@ -3388,7 +3413,7 @@ int isis_instance_flex_algo_priority_modify(struct nb_cb_modify_args *args) if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); priority = yang_dnode_get_uint32(args->dnode, NULL); switch (args->event) { @@ -3424,7 +3449,7 @@ int isis_instance_flex_algo_priority_destroy(struct nb_cb_destroy_args *args) if (!area) return NB_ERR_RESOURCE; - algorithm = yang_dnode_get_uint32(args->dnode, "./../flex-algo"); + algorithm = yang_dnode_get_uint32(args->dnode, "../flex-algo"); priority = yang_dnode_get_uint32(args->dnode, NULL); switch (args->event) { @@ -3518,10 +3543,10 @@ int isis_instance_segment_routing_srv6_locator_modify( sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name, area->area_tag); - sr_debug("Trying to get a chunk from locator %s for IS-IS area %s", - loc_name, area->area_tag); + sr_debug("Trying to get locator %s for IS-IS area %s", loc_name, + area->area_tag); - if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + if (isis_zebra_srv6_manager_get_locator(loc_name) < 0) return NB_ERR; return NB_OK; @@ -3583,24 +3608,6 @@ int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_modify( return NB_OK; } -int isis_instance_segment_routing_srv6_msd_node_msd_max_segs_left_destroy( - struct nb_cb_destroy_args *args) -{ - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - area = nb_running_get_entry(args->dnode, NULL, true); - area->srv6db.config.max_seg_left_msd = - yang_get_default_uint8("./msd/node-msd/max-segs-left"); - - /* Update and regenerate LSP */ - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-pop */ @@ -3622,24 +3629,6 @@ int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_modify( return NB_OK; } -int isis_instance_segment_routing_srv6_msd_node_msd_max_end_pop_destroy( - struct nb_cb_destroy_args *args) -{ - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - area = nb_running_get_entry(args->dnode, NULL, true); - area->srv6db.config.max_end_pop_msd = - yang_get_default_uint8("./msd/node-msd/max-end-pop"); - - /* Update and regenerate LSP */ - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-h-encaps */ @@ -3661,24 +3650,6 @@ int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_modify( return NB_OK; } -int isis_instance_segment_routing_srv6_msd_node_msd_max_h_encaps_destroy( - struct nb_cb_destroy_args *args) -{ - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - area = nb_running_get_entry(args->dnode, NULL, true); - area->srv6db.config.max_h_encaps_msd = - yang_get_default_uint8("./msd/node-msd/max-h-encaps"); - - /* Update and regenerate LSP */ - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/msd/node-msd/max-end-d */ @@ -3700,24 +3671,6 @@ int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_modify( return NB_OK; } -int isis_instance_segment_routing_srv6_msd_node_msd_max_end_d_destroy( - struct nb_cb_destroy_args *args) -{ - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - area = nb_running_get_entry(args->dnode, NULL, true); - area->srv6db.config.max_end_d_msd = - yang_get_default_uint8("./msd/node-msd/max-end-d"); - - /* Update and regenerate LSP */ - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - /* * XPath: /frr-isisd:isis/instance/segment-routing-srv6/interface */ @@ -3826,7 +3779,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args) { struct interface *ifp; struct isis_circuit *circuit = NULL; - const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); + const char *area_tag = yang_dnode_get_string(args->dnode, "area-tag"); switch (args->event) { case NB_EV_PREPARE: @@ -3893,7 +3846,8 @@ int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args) case NB_EV_APPLY: circuit = nb_running_get_entry(args->dnode, NULL, true); circuit->is_type_config = circ_type; - isis_circuit_is_type_set(circuit, circ_type); + if (!circuit->area || circuit->area->is_type == IS_LEVEL_1_AND_2) + isis_circuit_is_type_set(circuit, circ_type); break; } diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c index 0cd43a7abc9e..23238d314a20 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -111,6 +111,7 @@ struct iih_info { bool v6_usable; struct isis_tlvs *tlvs; + int calculated_type; }; static int process_p2p_hello(struct iih_info *iih) @@ -151,6 +152,76 @@ static int process_p2p_hello(struct iih_info *iih) struct isis_adjacency *adj = iih->circuit->u.p2p.neighbor; /* If an adjacency exists, check it is with the source of the hello * packets */ + if (((iih->circuit->area->is_type == IS_LEVEL_1) && + ((iih->circuit->is_type_config == IS_LEVEL_1_AND_2) || + (iih->circuit->is_type_config == IS_LEVEL_1))) || + ((iih->circuit->area->is_type == IS_LEVEL_1_AND_2) && + (iih->circuit->is_type_config == IS_LEVEL_1) && + ((iih->circ_type == IS_LEVEL_1) || + (iih->circ_type == IS_LEVEL_1_AND_2))) || + ((iih->circuit->area->is_type == IS_LEVEL_1_AND_2) && + (iih->circuit->is_type_config == IS_LEVEL_1_AND_2) && + (iih->circ_type == IS_LEVEL_1))) { + if (!isis_tlvs_area_addresses_match(iih->tlvs, + iih->circuit->area + ->area_addrs)) { + if (IS_DEBUG_ADJ_PACKETS) { + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s, cir id %u, length %u", + iih->circuit->area->area_tag, + iih->circuit->interface->name, + circuit_t2string( + iih->circuit->is_type), + iih->circuit->circuit_id, + iih->pdu_len); + } + + return ISIS_WARNING; + } + + iih->calculated_type = IS_LEVEL_1; + + } + + else if (((iih->circuit->area->is_type == IS_LEVEL_2) && + ((iih->circuit->is_type_config == IS_LEVEL_1_AND_2) || + (iih->circuit->is_type_config == IS_LEVEL_2))) || + ((iih->circuit->area->is_type == IS_LEVEL_1_AND_2) && + (iih->circuit->is_type_config == IS_LEVEL_2) && + ((iih->circ_type == IS_LEVEL_2) || + (iih->circ_type == IS_LEVEL_1_AND_2))) || + ((iih->circuit->area->is_type == IS_LEVEL_1_AND_2) && + (iih->circuit->is_type_config == IS_LEVEL_1_AND_2) && + (iih->circ_type == IS_LEVEL_2))) { + iih->calculated_type = IS_LEVEL_2; + } + + else if ((iih->circuit->area->is_type == IS_LEVEL_1_AND_2) && + (iih->circuit->is_type_config == IS_LEVEL_1_AND_2) && + (iih->circ_type == IS_LEVEL_1_AND_2)) { + iih->calculated_type = IS_LEVEL_1_AND_2; + + if (!isis_tlvs_area_addresses_match(iih->tlvs, + iih->circuit->area + ->area_addrs)) { + iih->calculated_type = IS_LEVEL_2; + } + } + + else { + if (IS_DEBUG_ADJ_PACKETS) { + if (IS_DEBUG_ADJ_PACKETS) { + zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s, cir id %u, length %u", + iih->circuit->area->area_tag, + iih->circuit->interface->name, + circuit_t2string( + iih->circuit->is_type), + iih->circuit->circuit_id, + iih->pdu_len); + } + } + return ISIS_WARNING; + } + if (adj) { if (memcmp(iih->sys_id, adj->sysid, ISIS_SYS_ID_LEN)) { zlog_debug( @@ -160,12 +231,13 @@ static int process_p2p_hello(struct iih_info *iih) return ISIS_OK; } } - if (!adj || adj->level != iih->circ_type) { + if (!adj || adj->level != iih->calculated_type) { if (!adj) { - adj = isis_new_adj(iih->sys_id, NULL, iih->circ_type, - iih->circuit); + adj = isis_new_adj(iih->sys_id, NULL, + iih->calculated_type, iih->circuit); + } else { - adj->level = iih->circ_type; + adj->level = iih->calculated_type; } iih->circuit->u.p2p.neighbor = adj; /* Build lsp with the new neighbor entry when a new @@ -174,7 +246,7 @@ static int process_p2p_hello(struct iih_info *iih) * when an adjacency is up. This will result in the new * adjacency entry getting added to the lsp tlv neighbor list. */ - adj->circuit_t = iih->circ_type; + adj->circuit_t = iih->calculated_type; isis_adj_state_change(&adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } @@ -205,45 +277,35 @@ static int process_p2p_hello(struct iih_info *iih) /* 8.2.5.2 a) a match was detected */ if (isis_tlvs_area_addresses_match(iih->tlvs, iih->circuit->area->area_addrs)) { - /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ - if (iih->circuit->area->is_type == IS_LEVEL_1) { + /* 8.2.5.2 a) 2) If the calculated type is L1 - table 5 */ + if (iih->calculated_type == IS_LEVEL_1) { switch (iih->circ_type) { case IS_LEVEL_1: - case IS_LEVEL_1_AND_2: - if (adj->adj_state != ISIS_ADJ_UP - || adj->adj_usage == ISIS_ADJ_LEVEL1) { - isis_adj_process_threeway(adj, tw_adj, - ISIS_ADJ_LEVEL1); - } + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); break; - case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (7) reject - wrong system type event - */ - zlog_warn("wrongSystemType"); - return ISIS_WARNING; - } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { - /* (6) down - wrong system */ - isis_adj_state_change(&adj, - ISIS_ADJ_DOWN, - "Wrong System"); + case IS_LEVEL_1_AND_2: + if ((adj->adj_state != ISIS_ADJ_UP) || + (adj->adj_usage == ISIS_ADJ_LEVEL1) || + (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) { + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); } break; } } - /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ - if (iih->circuit->area->is_type == IS_LEVEL_1_AND_2) { + /* 8.2.5.2 a) 3) If the calculated type is L1L2 - table 6 */ + if (iih->calculated_type == IS_LEVEL_1_AND_2) { switch (iih->circ_type) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL1) { - isis_adj_process_threeway(adj, tw_adj, - ISIS_ADJ_LEVEL1); - } else if ((adj->adj_usage - == ISIS_ADJ_LEVEL1AND2) - || (adj->adj_usage - == ISIS_ADJ_LEVEL2)) { + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); + } else if ((adj->adj_usage == ISIS_ADJ_LEVEL2) || + (adj->adj_usage == + ISIS_ADJ_LEVEL1AND2)) { /* (8) down - wrong system */ isis_adj_state_change(&adj, ISIS_ADJ_DOWN, @@ -253,11 +315,11 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL2) { - isis_adj_process_threeway(adj, tw_adj, - ISIS_ADJ_LEVEL2); - } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) - || (adj->adj_usage - == ISIS_ADJ_LEVEL1AND2)) { + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); + } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || + (adj->adj_usage == + ISIS_ADJ_LEVEL1AND2)) { /* (8) down - wrong system */ isis_adj_state_change(&adj, ISIS_ADJ_DOWN, @@ -267,11 +329,10 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { - isis_adj_process_threeway(adj, tw_adj, - ISIS_ADJ_LEVEL1AND2); - } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) - || (adj->adj_usage - == ISIS_ADJ_LEVEL2)) { + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); + } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || + (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (8) down - wrong system */ isis_adj_state_change(&adj, ISIS_ADJ_DOWN, @@ -282,44 +343,26 @@ static int process_p2p_hello(struct iih_info *iih) } /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ - if (iih->circuit->area->is_type == IS_LEVEL_2) { + if (iih->calculated_type == IS_LEVEL_2) { switch (iih->circ_type) { - case IS_LEVEL_1: - if (adj->adj_state != ISIS_ADJ_UP) { - /* (5) reject - wrong system type event - */ - zlog_warn("wrongSystemType"); - return ISIS_WARNING; - } else if ((adj->adj_usage - == ISIS_ADJ_LEVEL1AND2) - || (adj->adj_usage - == ISIS_ADJ_LEVEL2)) { - /* (6) down - wrong system */ - isis_adj_state_change(&adj, - ISIS_ADJ_DOWN, - "Wrong System"); + case IS_LEVEL_1_AND_2: + if (adj->adj_state != ISIS_ADJ_UP || + adj->adj_usage == ISIS_ADJ_LEVEL2 || + adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); } break; - case IS_LEVEL_1_AND_2: case IS_LEVEL_2: - if (adj->adj_state != ISIS_ADJ_UP - || adj->adj_usage == ISIS_ADJ_LEVEL2) { - isis_adj_process_threeway(adj, tw_adj, - ISIS_ADJ_LEVEL2); - } else if (adj->adj_usage - == ISIS_ADJ_LEVEL1AND2) { - /* (6) down - wrong system */ - isis_adj_state_change(&adj, - ISIS_ADJ_DOWN, - "Wrong System"); - } + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); break; } } } /* 8.2.5.2 b) if no match was detected */ else if (listcount(iih->circuit->area->area_addrs) > 0) { - if (iih->circuit->area->is_type == IS_LEVEL_1) { + if (iih->calculated_type == IS_LEVEL_1) { /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ if (adj->adj_state != ISIS_ADJ_UP) { isis_adj_state_change(&adj, ISIS_ADJ_DOWN, @@ -358,8 +401,8 @@ static int process_p2p_hello(struct iih_info *iih) case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP || adj->adj_usage == ISIS_ADJ_LEVEL2) { - isis_adj_process_threeway(adj, tw_adj, - ISIS_ADJ_LEVEL2); + isis_adj_process_threeway(&adj, tw_adj, + iih->calculated_type); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - wrong system */ isis_adj_state_change(&adj, @@ -2039,7 +2082,7 @@ static void send_hello_cb(struct event *thread) circuit->u.p2p.t_send_p2p_hello = NULL; send_hello(circuit, 1); send_hello_sched(circuit, ISIS_LEVEL1, - 1000 * circuit->hello_interval[1]); + 1000 * circuit->hello_interval[0]); return; } diff --git a/isisd/isis_route.c b/isisd/isis_route.c index be92dcc22ef6..b907c962bee2 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -260,24 +260,6 @@ isis_route_info_new(struct prefix *prefix, struct prefix_ipv6 *src_p, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); - /* update neighbor router address */ - switch (prefix->family) { - case AF_INET: - if (depth == 2 && prefix->prefixlen == IPV4_MAX_BITLEN) - adj->router_address = prefix->u.prefix4; - break; - case AF_INET6: - if (depth == 2 && prefix->prefixlen == IPV6_MAX_BITLEN - && (!src_p || !src_p->prefixlen)) { - adj->router_address6 = prefix->u.prefix6; - } - break; - default: - flog_err(EC_LIB_DEVELOPMENT, - "%s: unknown address family [%d]", __func__, - prefix->family); - exit(1); - } adjinfo2nexthop(prefix->family, rinfo->nexthops, adj, sr, label_stack); if (!allow_ecmp) diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index f9e3780e29e3..83a06b69980b 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -2826,6 +2826,13 @@ static int isis_snmp_init(struct event_loop *tm) return 0; } +static int isis_snmp_terminate(void) +{ + smux_terminate(); + + return 0; +} + /* * ISIS notification functions: we have one function per notification */ @@ -3448,6 +3455,7 @@ static int isis_snmp_module_init(void) hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free); hook_register(frr_late_init, isis_snmp_init); + hook_register(frr_fini, isis_snmp_terminate); return 0; } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index a2230cd00995..86302076f82d 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -378,6 +378,8 @@ isis_spftree_new(struct isis_area *area, struct lspdb_head *lspdb, static void _isis_spftree_del(struct isis_spftree *spftree) { + void *info, *backup_info; + hash_clean_and_free(&spftree->prefix_sids, NULL); isis_zebra_rlfa_unregister_all(spftree); isis_rlfa_list_clear(spftree); @@ -391,10 +393,12 @@ static void _isis_spftree_del(struct isis_spftree *spftree) list_delete(&spftree->sadj_list); isis_vertex_queue_free(&spftree->tents); isis_vertex_queue_free(&spftree->paths); - isis_route_table_info_free(spftree->route_table->info); - isis_route_table_info_free(spftree->route_table_backup->info); + info = spftree->route_table->info; + backup_info = spftree->route_table_backup->info; route_table_finish(spftree->route_table); route_table_finish(spftree->route_table_backup); + isis_route_table_info_free(info); + isis_route_table_info_free(backup_info); } void isis_spftree_del(struct isis_spftree *spftree) @@ -699,6 +703,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree, } else { /* vertex->d_N > cost */ /* f) */ isis_vertex_queue_delete(&spftree->tents, vertex); + hash_release(spftree->prefix_sids, vertex); isis_vertex_del(vertex); } } @@ -804,6 +809,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype, /* 4) */ } else { isis_vertex_queue_delete(&spftree->tents, vertex); + hash_release(spftree->prefix_sids, vertex); isis_vertex_del(vertex); } } @@ -867,6 +873,9 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, || (mt_router_info && !mt_router_info->overload)); lspfragloop: + if (!lsp->tlvs) + return ISIS_OK; + if (lsp->hdr.seqno == 0) { zlog_warn("%s: lsp with 0 seq_num - ignore", __func__); return ISIS_WARNING; @@ -2221,21 +2230,35 @@ int _isis_spf_schedule(struct isis_area *area, int level, } static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, - uint8_t *root_sysid) + uint8_t *root_sysid, struct json_object **json) { struct listnode *node; struct isis_vertex *vertex; char buff[VID2STR_BUFFER]; + char vertex_name[VID2STR_BUFFER]; + char vertex_typestr[VID2STR_BUFFER]; + char vertex_interface[VID2STR_BUFFER]; + char vertex_parent[VID2STR_BUFFER + 11]; + char vertex_nexthop[VID2STR_BUFFER]; + char vertex_metricstr[20]; + struct ttable *tt; + char *table; - vty_out(vty, - "Vertex Type Metric Next-Hop Interface Parent\n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Vertex|Type|Metric|Next-Hop|Interface|Parent"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { if (VTYPE_IS(vertex->type) && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { - vty_out(vty, "%-20s %-12s %-6s", - print_sys_hostname(root_sysid), "", ""); - vty_out(vty, "%-30s\n", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + print_sys_hostname(root_sysid), "", "", + "", "", ""); continue; } @@ -2245,9 +2268,12 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, struct isis_vertex_adj *vadj; struct isis_vertex *pvertex; - vty_out(vty, "%-20s %-12s %-6u ", - vid2string(vertex, buff, sizeof(buff)), - vtype2string(vertex->type), vertex->d_N); + snprintf(vertex_name, sizeof(vertex_name), "%s", + vid2string(vertex, buff, sizeof(buff))); + snprintf(vertex_typestr, sizeof(vertex_typestr), "%s", + vtype2string(vertex->type)); + snprintf(vertex_metricstr, sizeof(vertex_metricstr), "%u", + vertex->d_N); for (unsigned int i = 0; i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0, vertex->parents ? listcount(vertex->parents) : 0); @@ -2267,36 +2293,60 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } if (rows) { - vty_out(vty, "\n"); - vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + vertex_name, vertex_typestr, + vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); + + /* store the first 3 elements */ + vertex_name[0] = '\0'; + vertex_typestr[0] = '\0'; + vertex_metricstr[0] = '\0'; } if (vadj) { struct isis_spf_adj *sadj = vadj->sadj; - vty_out(vty, "%-20s %-9s ", - print_sys_hostname(sadj->id), - sadj->adj ? sadj->adj->circuit - ->interface->name - : "-"); + snprintf(vertex_nexthop, sizeof(vertex_nexthop), + "%s", print_sys_hostname(sadj->id)); + snprintf(vertex_interface, + sizeof(vertex_interface), "%s", + sadj->adj ? sadj->adj->circuit + ->interface->name + : "-"); } if (pvertex) { - if (!vadj) - vty_out(vty, "%-20s %-9s ", "", ""); - - vty_out(vty, "%s(%d)", - vid2string(pvertex, buff, sizeof(buff)), - pvertex->type); + if (!vadj) { + vertex_nexthop[0] = '\0'; + vertex_interface[0] = '\0'; + } + snprintf(vertex_parent, sizeof(vertex_parent), + "%s(%d)", + vid2string(pvertex, buff, sizeof(buff)), + pvertex->type); } ++rows; } - vty_out(vty, "\n"); + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", vertex_name, + vertex_typestr, vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); } + if (json == NULL) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } else + *json = ttable_json_with_json_text( + tt, "ssdsss", + "vertex|type|metric|nextHop|interface|parent"); + ttable_del(tt); } -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json) { const char *tree_id_text = NULL; @@ -2318,14 +2368,18 @@ void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) return; } - vty_out(vty, "IS-IS paths to level-%d routers %s\n", spftree->level, - tree_id_text); - isis_print_paths(vty, &spftree->paths, spftree->sysid); - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "IS-IS paths to level-%d routers %s\n", + spftree->level, tree_id_text); + + isis_print_paths(vty, &spftree->paths, spftree->sysid, json); + if (!json) + vty_out(vty, "\n"); } static void show_isis_topology_common(struct vty *vty, int levels, - struct isis *isis, uint8_t algo) + struct isis *isis, uint8_t algo, + json_object **json) { #ifndef FABRICD struct isis_flex_algo_data *fa_data; @@ -2334,14 +2388,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, struct isis_spftree *spftree; struct listnode *node; struct isis_area *area; + json_object *json_level = NULL, *jstr = NULL, *json_val; + char key[18]; if (!isis->area_list || isis->area_list->count == 0) return; - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - vty_out(vty, - "Area %s:", area->area_tag ? area->area_tag : "null"); + if (json) + *json = json_object_new_object(); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { #ifndef FABRICD /* * The shapes of the flex algo spftree 2-dimensional array @@ -2356,18 +2412,39 @@ static void show_isis_topology_common(struct vty *vty, int levels, fa_data = (struct isis_flex_algo_data *)fa->data; } else fa_data = NULL; +#endif /* ifndef FABRICD */ - if (algo != SR_ALGORITHM_SPF) - vty_out(vty, " Algorithm %hhu\n", algo); - else + if (json) { + jstr = json_object_new_string( + area->area_tag ? area->area_tag : "null"); + json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); + } else { + vty_out(vty, "Area %s:", + area->area_tag ? area->area_tag : "null"); + +#ifndef FABRICD + if (algo != SR_ALGORITHM_SPF) + vty_out(vty, " Algorithm %hhu\n", algo); + else #endif /* ifndef FABRICD */ - vty_out(vty, "\n"); + vty_out(vty, "\n"); + } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((level & levels) == 0) continue; + if (json) { + json_level = json_object_new_object(); + jstr = json_object_new_string( + area->area_tag ? area->area_tag + : "null"); + json_object_object_add(json_level, "area", jstr); + } + if (area->ip_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV4] @@ -2377,9 +2454,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + } } if (area->ipv6_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV6] @@ -2388,9 +2472,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + } } if (isis_area_ipv6_dstsrc_enabled(area)) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = @@ -2400,18 +2491,36 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + } + } + if (json) { + snprintf(key, sizeof(key), "level-%d", level); + json_object_object_add(*json, key, json_level); } } if (fabricd_spftree(area)) { + json_val = NULL; + vty_out(vty, "IS-IS paths to level-2 routers with hop-by-hop metric\n"); - isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid); - vty_out(vty, "\n"); + isis_print_paths(vty, &fabricd_spftree(area)->paths, + isis->sysid, json ? &json_val : NULL); + if (json && json_val) + json_object_object_add(json_level, + "fabricd-paths", + json_val); + else + vty_out(vty, "\n"); } - - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "\n"); } } @@ -2420,8 +2529,9 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, " [vrf ] topology" #ifndef FABRICD " []" - " [algorithm (128-255)]" + " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ + " [json$uj]" , SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" @@ -2432,6 +2542,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, "Show Flex-algo routes\n" "Algorithm number\n" #endif /* ifndef FABRICD */ + JSON_STR ) { int levels = ISIS_LEVELS; @@ -2439,8 +2550,12 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, struct isis *isis = NULL; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; + bool all_algorithm = false; int idx_vrf = 0; - uint8_t algorithm = SR_ALGORITHM_SPF; + uint16_t algorithm = SR_ALGORITHM_SPF; + bool uj = use_json(argc, argv); + json_object *json = NULL, *json_vrf = NULL; + #ifndef FABRICD int idx = 0; @@ -2449,8 +2564,12 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, levels = ISIS_LEVEL1; if (argv_find(argv, argc, "level-2", &idx)) levels = ISIS_LEVEL2; - if (argv_find(argv, argc, "algorithm", &idx)) - algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "algorithm", &idx)) { + if (argv_find(argv, argc, "(128-255)", &idx)) + algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10); + else + all_algorithm = true; + } #endif /* ifndef FABRICD */ if (!im) { @@ -2459,16 +2578,58 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, } ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) + if (uj) + json = json_object_new_array(); + + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + if (all_algorithm) { + for (algorithm = SR_ALGORITHM_FLEX_MIN; + algorithm <= SR_ALGORITHM_FLEX_MAX; + algorithm++) + show_isis_topology_common(vty, levels, + isis, + (uint8_t)algorithm, + uj ? &json_vrf + : NULL); + } else { show_isis_topology_common(vty, levels, isis, - algorithm); - return CMD_SUCCESS; + (uint8_t)algorithm, + uj ? &json_vrf : NULL); + } + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int( + isis->vrf_id)); + json_object_array_add(json, json_vrf); + } } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) - show_isis_topology_common(vty, levels, isis, algorithm); + goto out; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis == NULL) + return CMD_SUCCESS; + if (all_algorithm) { + for (algorithm = SR_ALGORITHM_FLEX_MIN; + algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) { + show_isis_topology_common(vty, levels, isis, + (uint8_t)algorithm, + uj ? &json_vrf : NULL); + } + } else + show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm, + uj ? &json_vrf : NULL); + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int(isis->vrf_id)); + json_object_array_add(json, json_vrf); + } +out: + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); } return CMD_SUCCESS; @@ -2642,17 +2803,14 @@ DEFUN(show_isis_flex_algo, show_isis_flex_algo_cmd, ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - show_isis_flex_algo_common(vty, isis, - flex_algo); - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) show_isis_flex_algo_common(vty, isis, flex_algo); + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + show_isis_flex_algo_common(vty, isis, flex_algo); return CMD_SUCCESS; } @@ -2860,7 +3018,11 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, vty_out(vty, "%s\n", table); XFREE(MTYPE_TMP, table); } else if (json) { - *json = ttable_json(tt, prefix_sid ? "sdssdsdd" : "sdsss"); + *json = ttable_json_with_json_text( + tt, prefix_sid ? "sdssdsdd" : "sdsss", + prefix_sid + ? "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm" + : "prefix|metric|interface|nextHop|label(s)"); } ttable_del(tt); } @@ -2878,7 +3040,7 @@ static void show_isis_route_common(struct vty *vty, int levels, struct isis_spftree *spftree; struct listnode *node; struct isis_area *area; - char key[8]; + char key[18]; if (!isis->area_list || isis->area_list->count == 0) return; @@ -2908,6 +3070,7 @@ static void show_isis_route_common(struct vty *vty, int levels, jstr = json_object_new_string( area->area_tag ? area->area_tag : "null"); json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); } else { vty_out(vty, "Area %s:", area->area_tag ? area->area_tag : "null"); @@ -2943,8 +3106,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -2965,8 +3134,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -2988,8 +3163,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, prefix_sid, backup); @@ -3007,15 +3188,48 @@ static void show_isis_route_common(struct vty *vty, int levels, } } +static void show_isis_route_all_algos(struct vty *vty, int levels, + struct isis *isis, bool prefix_sid, + bool backup, json_object **json) +{ + uint16_t algo; + + json_object *json_algo = NULL, *json_algos = NULL; + + if (json) { + *json = json_object_new_object(); + json_algos = json_object_new_array(); + } + + for (algo = SR_ALGORITHM_FLEX_MIN; algo <= SR_ALGORITHM_FLEX_MAX; + algo++) { + show_isis_route_common(vty, levels, isis, prefix_sid, backup, + (uint8_t)algo, json ? &json_algo : NULL); + if (!json) + continue; + if (json_object_object_length(json_algo) == 0) { + json_object_free(json_algo); + continue; + } + json_object_object_add(json_algo, "algorithm", + json_object_new_int(algo)); + json_object_array_add(json_algos, json_algo); + } + + if (json) + json_object_object_add(*json, "algorithms", json_algos); +} + + DEFUN(show_isis_route, show_isis_route_cmd, "show " PROTO_NAME " [vrf ] route" #ifndef FABRICD " []" #endif /* ifndef FABRICD */ - " []" + " [prefix-sid] [backup]" #ifndef FABRICD - " [algorithm (128-255)]" + " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ " [json$uj]", SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR @@ -3037,6 +3251,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, struct listnode *node; const char *vrf_name = VRF_DEFAULT_NAME; bool all_vrf = false; + bool all_algorithm = false; bool prefix_sid = false; bool backup = false; bool uj = use_json(argc, argv); @@ -3063,40 +3278,50 @@ DEFUN(show_isis_route, show_isis_route_cmd, backup = true; #ifndef FABRICD - if (argv_find(argv, argc, "algorithm", &idx)) - algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "algorithm", &idx)) { + if (argv_find(argv, argc, "(128-255)", &idx)) + algorithm = (uint8_t)strtoul(argv[idx]->arg, NULL, 10); + else + all_algorithm = true; + } #endif /* ifndef FABRICD */ if (uj) json = json_object_new_array(); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { - show_isis_route_common( - vty, levels, isis, prefix_sid, backup, - algorithm, uj ? &json_vrf : NULL); - if (uj) { - json_object_object_add( - json_vrf, "vrf_id", - json_object_new_int( - isis->vrf_id)); - json_object_array_add(json, json_vrf); - } + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + if (all_algorithm) + show_isis_route_all_algos(vty, levels, isis, + prefix_sid, backup, + uj ? &json_vrf : NULL); + else + show_isis_route_common(vty, levels, isis, + prefix_sid, backup, + algorithm, + uj ? &json_vrf : NULL); + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int( + isis->vrf_id)); + json_object_array_add(json, json_vrf); } - goto out; } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) { + goto out; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + if (all_algorithm) + show_isis_route_all_algos(vty, levels, isis, prefix_sid, + backup, uj ? &json_vrf : NULL); + else show_isis_route_common(vty, levels, isis, prefix_sid, backup, algorithm, uj ? &json_vrf : NULL); - if (uj) { - json_object_object_add( - json_vrf, "vrf_id", - json_object_new_int(isis->vrf_id)); - json_object_array_add(json, json_vrf); - } + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int(isis->vrf_id)); + json_object_array_add(json, json_vrf); } } @@ -3309,16 +3534,14 @@ DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd, } ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - show_isis_frr_summary_common(vty, levels, isis); - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) show_isis_frr_summary_common(vty, levels, isis); + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + show_isis_frr_summary_common(vty, levels, isis); return CMD_SUCCESS; } diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 7e9754d9bfa5..ee2d29abe3ba 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -61,7 +61,8 @@ struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb, __FILE__, __LINE__) int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree); +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json); void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, json_object **json, bool prefix_sid, bool backup); void isis_spf_init(void); diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index 76cde6d28cd5..f7830380064e 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -462,8 +462,7 @@ void isis_area_delete_backup_adj_sids(struct isis_area *area, int level) struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra)) - if (sra->type == ISIS_SR_LAN_BACKUP - && (sra->adj->level & level)) + if (sra->type == ISIS_SR_ADJ_BACKUP && (sra->adj->level & level)) sr_adj_sid_del(sra); } @@ -689,7 +688,7 @@ void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup, circuit->ext = isis_alloc_ext_subtlvs(); sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra)); - sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL; + sra->type = backup ? ISIS_SR_ADJ_BACKUP : ISIS_SR_ADJ_NORMAL; sra->input_label = input_label; sra->nexthop.family = family; sra->nexthop.address = nexthop; @@ -819,7 +818,7 @@ static void sr_adj_sid_del(struct sr_adjacency *sra) exit(1); } - if (sra->type == ISIS_SR_LAN_BACKUP && sra->backup_nexthops) { + if (sra->type == ISIS_SR_ADJ_BACKUP && sra->backup_nexthops) { sra->backup_nexthops->del = (void (*)(void *))isis_nexthop_delete; list_delete(&sra->backup_nexthops); @@ -936,7 +935,6 @@ int sr_if_addr_update(struct interface *ifp) struct isis_circuit *circuit; struct isis_area *area; struct connected *connected; - struct listnode *node; bool need_lsp_regenerate = false; /* Get corresponding circuit */ @@ -948,7 +946,7 @@ int sr_if_addr_update(struct interface *ifp) if (!area) return 0; - FOR_ALL_INTERFACES_ADDRESSES (ifp, connected, node) { + frr_each (if_connected, ifp->connected, connected) { for (int i = 0; i < SR_ALGORITHM_COUNT; i++) { pcfgs[i] = isis_sr_cfg_prefix_find( area, connected->address, i); @@ -1022,8 +1020,6 @@ static void show_node(struct vty *vty, struct isis_area *area, int level, struct ttable *tt; char buf[128]; - vty_out(vty, " IS-IS %s SR-Nodes:\n\n", circuit_t2string(level)); - /* Prepare table. */ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); ttable_add_row(tt, "System ID|SRGB|SRLB|Algorithm|MSD"); @@ -1064,6 +1060,8 @@ static void show_node(struct vty *vty, struct isis_area *area, int level, if (tt->nrows > 1) { char *table; + vty_out(vty, " IS-IS %s SR-Nodes:\n\n", circuit_t2string(level)); + table = ttable_dump(tt, "\n"); vty_out(vty, "%s\n", table); XFREE(MTYPE_TMP, table); @@ -1075,7 +1073,7 @@ DEFUN(show_sr_node, show_sr_node_cmd, "show " PROTO_NAME " segment-routing node" #ifndef FABRICD - " [algorithm (128-255)]" + " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ , SHOW_STR PROTO_HELP @@ -1089,13 +1087,18 @@ DEFUN(show_sr_node, show_sr_node_cmd, { struct listnode *node, *inode; struct isis_area *area; - uint8_t algorithm = SR_ALGORITHM_SPF; + uint16_t algorithm = SR_ALGORITHM_SPF; + bool all_algorithm = false; struct isis *isis; #ifndef FABRICD int idx = 0; - if (argv_find(argv, argc, "algorithm", &idx)) - algorithm = (uint8_t)strtoul(argv[idx + 1]->arg, NULL, 10); + if (argv_find(argv, argc, "algorithm", &idx)) { + if (argv_find(argv, argc, "(128-255)", &idx)) + algorithm = (uint16_t)strtoul(argv[idx]->arg, NULL, 10); + else + all_algorithm = true; + } #endif /* ifndef FABRICD */ for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { @@ -1107,8 +1110,17 @@ DEFUN(show_sr_node, show_sr_node_cmd, continue; } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; - level++) - show_node(vty, area, level, algorithm); + level++) { + if (all_algorithm) { + for (algorithm = SR_ALGORITHM_FLEX_MIN; + algorithm <= SR_ALGORITHM_FLEX_MAX; + algorithm++) + show_node(vty, area, level, + (uint8_t)algorithm); + } else + show_node(vty, area, level, + (uint8_t)algorithm); + } } } diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h index 437876029997..76f776825da5 100644 --- a/isisd/isis_sr.h +++ b/isisd/isis_sr.h @@ -82,7 +82,7 @@ struct sr_local_block { /* Segment Routing Adjacency-SID type. */ enum sr_adj_type { ISIS_SR_ADJ_NORMAL = 0, - ISIS_SR_LAN_BACKUP, + ISIS_SR_ADJ_BACKUP, }; /* Segment Routing Adjacency. */ diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 0eb8ac3fb75f..b5974b1a6276 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area) struct srv6_locator_chunk *chunk; struct isis_srv6_sid *sid; struct srv6_adjacency *sra; + struct srv6_sid_ctx ctx = {}; if (strncmp(area->srv6db.config.srv6_locator_name, "", sizeof(area->srv6db.config.srv6_locator_name)) == 0) { @@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area) * Zebra */ isis_zebra_srv6_sid_uninstall(area, sid); + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + isis_zebra_release_srv6_sid(&ctx); + listnode_delete(area->srv6db.srv6_sids, sid); isis_srv6_sid_free(sid); } /* Uninstall all local Adjacency-SIDs. */ - for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) { + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = sra->nexthop; + isis_zebra_release_srv6_sid(&ctx); + srv6_endx_sid_del(sra); + } /* Inform Zebra that we are releasing the SRv6 locator */ ret = isis_zebra_srv6_manager_release_locator_chunk( @@ -146,6 +165,10 @@ bool isis_srv6_locator_unset(struct isis_area *area) srv6_locator_chunk_free(&chunk); } + /* Clear locator */ + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Clear locator name */ memset(area->srv6db.config.srv6_locator_name, 0, sizeof(area->srv6db.config.srv6_locator_name)); @@ -183,7 +206,7 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname) isis_zebra_srv6_sid_uninstall(area, sid); } - strncpy(area->srv6db.config.srv6_ifname, ifname, IF_NAMESIZE - 1); + strlcpy(area->srv6db.config.srv6_ifname, ifname, sizeof(area->srv6db.config.srv6_ifname)); if (!if_lookup_by_name(area->srv6db.config.srv6_ifname, VRF_DEFAULT)) { sr_debug("Interface %s not yet exist in data plane, deferring SIDs installation until it's created", area->srv6db.config.srv6_ifname); @@ -197,150 +220,36 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname) } } -/** - * Encode SID function in the SRv6 SID. - * - * @param sid - * @param func - * @param offset - * @param len - */ -static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset, - uint8_t len) -{ - for (uint8_t idx = 0; idx < len; idx++) { - uint8_t tidx = offset + idx; - sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); - if (func >> (len - 1 - idx) & 0x1) - sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); - } -} - -static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) -{ - struct listnode *node; - struct isis_srv6_sid *s; - struct srv6_adjacency *sra; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s)) - if (sid_same(&s->sid, sid)) - return true; - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra)) - if (sid_same(&sra->sid, sid)) - return true; - return false; -} - -/** - * Request a SID from the SRv6 locator. - * - * @param area IS-IS area - * @param chunk SRv6 locator chunk - * @param sid_func The FUNCTION part of the SID to be allocated (a negative - * number will allocate the first available SID) - * - * @return First available SID on success or in6addr_any if the SRv6 - * locator chunk is full - */ -static struct in6_addr -srv6_locator_request_sid(struct isis_area *area, - struct srv6_locator_chunk *chunk, int sid_func) -{ - struct in6_addr sid; - uint8_t offset = 0; - uint8_t func_len = 0; - uint32_t func_max; - bool allocated = false; - - if (!area || !chunk) - return in6addr_any; - - sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", - area->area_tag, chunk->locator_name); - - /* Let's build the SID, step by step. A SID has the following structure - (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ - - /* First, we encode the LOCATOR in the L most significant bits. */ - sid = chunk->prefix.prefix; - - /* The next part of the SID is the FUNCTION. Let's compute the length - * and the offset of the FUNCTION in the SID */ - func_len = chunk->function_bits_length; - offset = chunk->block_bits_length + chunk->node_bits_length; - - /* Then, encode the FUNCTION */ - if (sid_func >= 0) { - /* SID FUNCTION has been specified. We need to allocate a SID - * with the requested FUNCTION. */ - encode_sid_func(&sid, sid_func, offset, func_len); - if (sid_exist(area, &sid)) { - zlog_warn( - "ISIS-SRv6 (%s): the requested SID %pI6 is already used", - area->area_tag, &sid); - return sid; - } - allocated = true; - } else { - /* SID FUNCTION not specified. We need to choose a FUNCTION that - * is not already used. So let's iterate through all possible - * functions and get the first available one. */ - func_max = (1 << func_len) - 1; - for (uint32_t func = 1; func < func_max; func++) { - encode_sid_func(&sid, func, offset, func_len); - if (sid_exist(area, &sid)) - continue; - allocated = true; - break; - } - } - - if (!allocated) { - /* We ran out of available SIDs */ - zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", - area->area_tag, chunk->locator_name); - return in6addr_any; - } - - sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag, - &sid); - - return sid; -} - /** * Allocate an SRv6 SID from an SRv6 locator. * * @param area IS-IS area - * @param chunk SRv6 locator chunk + * @param locator SRv6 locator * @param behavior SRv6 Endpoint Behavior bound to the SID + * @param sid_value SRv6 SID value * * @result the allocated SID on success, NULL otherwise */ struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func) + struct in6_addr *sid_value) { struct isis_srv6_sid *sid = NULL; - if (!area || !chunk) + if (!area || !locator || !sid_value) return NULL; sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); - sid->sid = srv6_locator_request_sid(area, chunk, sid_func); - if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { - isis_srv6_sid_free(sid); - return NULL; - } + sid->sid = *sid_value; sid->behavior = behavior; - sid->structure.loc_block_len = chunk->block_bits_length; - sid->structure.loc_node_len = chunk->node_bits_length; - sid->structure.func_len = chunk->function_bits_length; - sid->structure.arg_len = chunk->argument_bits_length; - sid->locator = chunk; + sid->structure.loc_block_len = locator->block_bits_length; + sid->structure.loc_node_len = locator->node_bits_length; + sid->structure.func_len = locator->function_bits_length; + sid->structure.arg_len = locator->argument_bits_length; + sid->locator = locator; sid->area = area; return sid; @@ -363,7 +272,7 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) - if (sra->type == ISIS_SRV6_LAN_BACKUP && + if (sra->type == ISIS_SRV6_ADJ_BACKUP && (sra->adj->level & level)) srv6_endx_sid_del(sra); } @@ -376,9 +285,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) * @param adj IS-IS Adjacency * @param backup True to initialize backup Adjacency SID * @param nexthops List of backup nexthops (for backup End.X SIDs only) + * @param sid_value SID value associated to be associated with the adjacency */ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops) + struct list *nexthops, struct in6_addr *sid_value) { struct isis_circuit *circuit = adj->circuit; struct isis_area *area = circuit->area; @@ -387,11 +297,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, struct isis_srv6_lan_endx_sid_subtlv *ladj_sid; struct in6_addr nexthop; uint8_t flags = 0; - struct srv6_locator_chunk *chunk; + struct srv6_locator *locator; uint32_t behavior; - if (!area || !area->srv6db.srv6_locator_chunks || - list_isempty(area->srv6db.srv6_locator_chunks)) + if (!area || !area->srv6db.srv6_locator) return; sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, @@ -401,10 +310,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (!circuit->ipv6_router || !adj->ll_ipv6_count) return; - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); - if (!chunk) - return; + locator = area->srv6db.srv6_locator; nexthop = adj->ll_ipv6_addrs[0]; @@ -415,25 +321,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (circuit->ext == NULL) circuit->ext = isis_alloc_ext_subtlvs(); - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + behavior = (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) ? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID : SRV6_ENDPOINT_BEHAVIOR_END_X; sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra)); - sra->type = backup ? ISIS_SRV6_LAN_BACKUP : ISIS_SRV6_ADJ_NORMAL; + sra->type = backup ? ISIS_SRV6_ADJ_BACKUP : ISIS_SRV6_ADJ_NORMAL; sra->behavior = behavior; - sra->locator = chunk; - sra->structure.loc_block_len = chunk->block_bits_length; - sra->structure.loc_node_len = chunk->node_bits_length; - sra->structure.func_len = chunk->function_bits_length; - sra->structure.arg_len = chunk->argument_bits_length; + sra->locator = locator; + sra->structure.loc_block_len = locator->block_bits_length; + sra->structure.loc_node_len = locator->node_bits_length; + sra->structure.func_len = locator->function_bits_length; + sra->structure.arg_len = locator->argument_bits_length; sra->nexthop = nexthop; - sra->sid = srv6_locator_request_sid(area, chunk, -1); - if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { - XFREE(MTYPE_ISIS_SRV6_INFO, sra); - return; - } + sra->sid = *sid_value; switch (circuit->circ_type) { /* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ @@ -505,9 +407,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, * * @param adj IS-IS Adjacency */ -void srv6_endx_sid_add(struct isis_adjacency *adj) +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value) { - srv6_endx_sid_add_single(adj, false, NULL); + srv6_endx_sid_add_single(adj, false, NULL, sid_value); } /** @@ -538,7 +440,7 @@ void srv6_endx_sid_del(struct srv6_adjacency *sra) exit(1); } - if (sra->type == ISIS_SRV6_LAN_BACKUP && sra->backup_nexthops) { + if (sra->type == ISIS_SRV6_ADJ_BACKUP && sra->backup_nexthops) { sra->backup_nexthops->del = (void (*)(void *))isis_nexthop_delete; list_delete(&sra->backup_nexthops); @@ -610,7 +512,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family, family != AF_INET6) return 0; - srv6_endx_sid_add(adj); + isis_zebra_request_srv6_sid_endx(adj); return 0; } @@ -777,6 +679,7 @@ void isis_srv6_area_init(struct isis_area *area) srv6db->srv6_endx_sids = list_new(); /* Pull defaults from the YANG module */ +#ifndef FABRICD srv6db->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SRV6); srv6db->config.max_seg_left_msd = yang_get_default_uint8("%s/msd/node-msd/max-segs-left", @@ -788,7 +691,15 @@ void isis_srv6_area_init(struct isis_area *area) ISIS_SRV6); srv6db->config.max_end_d_msd = yang_get_default_uint8("%s/msd/node-msd/max-end-d", ISIS_SRV6); - strncpy(srv6db->config.srv6_ifname, yang_get_default_string("%s/interface", ISIS_SRV6), IF_NAMESIZE - 1); + strlcpy(srv6db->config.srv6_ifname, yang_get_default_string("%s/interface", ISIS_SRV6), sizeof(srv6db->config.srv6_ifname)); +#else + srv6db->config.enabled = false; + srv6db->config.max_seg_left_msd = ISIS_DEFAULT_SRV6_MAX_SEG_LEFT_MSD; + srv6db->config.max_end_pop_msd = ISIS_DEFAULT_SRV6_MAX_END_POP_MSD; + srv6db->config.max_h_encaps_msd = ISIS_DEFAULT_SRV6_MAX_H_ENCAPS_MSD; + srv6db->config.max_end_d_msd = ISIS_DEFAULT_SRV6_MAX_END_D_MSD; + strlcpy(srv6db->config.srv6_ifname, ISIS_DEFAULT_SRV6_IFNAME, sizeof(srv6db->config.srv6_ifname)); +#endif /* Initialize SRv6 Locator chunks list */ srv6db->srv6_locator_chunks = list_new(); @@ -823,6 +734,9 @@ void isis_srv6_area_term(struct isis_area *area) srv6_locator_chunk_free(&chunk); list_delete(&srv6db->srv6_locator_chunks); + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Free SRv6 SIDs list */ list_delete(&srv6db->srv6_sids); list_delete(&srv6db->srv6_endx_sids); diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 65c0978bc55a..bde14965f6aa 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -13,6 +13,12 @@ #include "lib/srv6.h" #include "isisd/isis_tlvs.h" +#define ISIS_DEFAULT_SRV6_MAX_SEG_LEFT_MSD 3 +#define ISIS_DEFAULT_SRV6_MAX_END_POP_MSD 3 +#define ISIS_DEFAULT_SRV6_MAX_H_ENCAPS_MSD 2 +#define ISIS_DEFAULT_SRV6_MAX_END_D_MSD 5 +#define ISIS_DEFAULT_SRV6_IFNAME "sr0" + /* SRv6 SID structure */ struct isis_srv6_sid_structure { uint8_t loc_block_len; @@ -38,7 +44,7 @@ struct isis_srv6_sid { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Backpointer to IS-IS area */ struct isis_area *area; @@ -62,7 +68,7 @@ struct isis_srv6_locator { /* SRv6 Adjacency-SID type */ enum srv6_adj_type { ISIS_SRV6_ADJ_NORMAL = 0, - ISIS_SRV6_LAN_BACKUP, + ISIS_SRV6_ADJ_BACKUP, }; /* SRv6 Adjacency. */ @@ -83,7 +89,7 @@ struct srv6_adjacency { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Adjacency-SID nexthop information */ struct in6_addr nexthop; @@ -103,6 +109,8 @@ struct srv6_adjacency { /* Per-area IS-IS SRv6 Data Base (SRv6 DB) */ struct isis_srv6_db { + /* List of SRv6 Locator */ + struct srv6_locator *srv6_locator; /* List of SRv6 Locator chunks */ struct list *srv6_locator_chunks; @@ -143,9 +151,9 @@ bool isis_srv6_locator_unset(struct isis_area *area); void isis_srv6_interface_set(struct isis_area *area, const char *ifname); struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func); + struct in6_addr *sid_value); extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); extern void isis_srv6_area_init(struct isis_area *area); @@ -163,8 +171,8 @@ void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc, struct isis_srv6_locator_tlv *loc_tlv); void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops); -void srv6_endx_sid_add(struct isis_adjacency *adj); + struct list *nexthops, struct in6_addr *sid_value); +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value); void srv6_endx_sid_del(struct srv6_adjacency *sra); struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj, enum srv6_adj_type type); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 90b53c540ef5..b6321dbac324 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -164,8 +164,8 @@ void isis_mpls_te_term(struct isis_area *area) XFREE(MTYPE_ISIS_MPLS_TE, area->mta); } -static void isis_link_params_update_asla(struct isis_circuit *circuit, - struct interface *ifp) +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp) { struct isis_asla_subtlvs *asla; struct listnode *node, *nnode; @@ -488,6 +488,10 @@ void isis_link_params_update(struct isis_circuit *circuit, ext->status = EXT_ADJ_SID; else if (IS_SUBTLV(ext, EXT_LAN_ADJ_SID)) ext->status = EXT_LAN_ADJ_SID; + else if (IS_SUBTLV(ext, EXT_SRV6_LAN_ENDX_SID)) + ext->status = EXT_SRV6_LAN_ENDX_SID; + else if (IS_SUBTLV(ext, EXT_SRV6_ENDX_SID)) + ext->status = EXT_SRV6_ENDX_SID; else ext->status = 0; } @@ -793,6 +797,12 @@ static struct ls_vertex *lsp_to_vertex(struct ls_ted *ted, struct isis_lsp *lsp) lnode.msd = cap->msd; SET_FLAG(lnode.flags, LS_NODE_MSD); } + if (cap->srv6_cap.is_srv6_capable) { + SET_FLAG(lnode.flags, LS_NODE_SRV6); + lnode.srv6_cap_flags = cap->srv6_cap.flags; + memcpy(&lnode.srv6_msd, &cap->srv6_msd, + sizeof(struct isis_srv6_msd)); + } } } @@ -1048,7 +1058,51 @@ static struct ls_attributes *get_attributes(struct ls_node_id adv, } } } + if (CHECK_FLAG(tlvs->status, EXT_SRV6_ENDX_SID)) { + struct isis_srv6_endx_sid_subtlv *endx = + (struct isis_srv6_endx_sid_subtlv *) + tlvs->srv6_endx_sid.head; + int i; + + for (; endx; endx = endx->next) { + if (endx->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG) { + i = 1; + SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SRV6SID); + } else { + i = 0; + SET_FLAG(attr->flags, LS_ATTR_ADJ_SRV6SID); + } + attr->adj_srv6_sid[i].flags = endx->flags; + attr->adj_srv6_sid[i].weight = endx->weight; + memcpy(&attr->adj_srv6_sid[i].sid, &endx->sid, + sizeof(struct in6_addr)); + attr->adj_srv6_sid[i].endpoint_behavior = endx->behavior; + } + } + if (CHECK_FLAG(tlvs->status, EXT_SRV6_LAN_ENDX_SID)) { + struct isis_srv6_lan_endx_sid_subtlv *lendx = + (struct isis_srv6_lan_endx_sid_subtlv *) + tlvs->srv6_lan_endx_sid.head; + int i; + for (; lendx; lendx = lendx->next) { + if (lendx->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG) { + i = 1; + SET_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SRV6SID); + } else { + i = 0; + SET_FLAG(attr->flags, LS_ATTR_ADJ_SRV6SID); + } + memcpy(&attr->adj_srv6_sid[i].neighbor.sysid, + &lendx->neighbor_id, ISIS_SYS_ID_LEN); + attr->adj_srv6_sid[i].flags = lendx->flags; + attr->adj_srv6_sid[i].weight = lendx->weight; + memcpy(&attr->adj_srv6_sid[i].sid, &lendx->sid, + sizeof(struct in6_addr)); + attr->adj_srv6_sid[i].endpoint_behavior = + lendx->behavior; + } + } return attr; } @@ -1204,8 +1258,11 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, if (!args || !prefix) return LSP_ITER_CONTINUE; - te_debug(" |- Process Extended %s Reachability %pFX", - prefix->family == AF_INET ? "IP" : "IPv6", prefix); + if (args->srv6_locator) + te_debug(" |- Process SRv6 Locator %pFX", prefix); + else + te_debug(" |- Process Extended %s Reachability %pFX", + prefix->family == AF_INET ? "IP" : "IPv6", prefix); vertex = args->vertex; @@ -1332,6 +1389,38 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, } } + /* Update SRv6 SID and locator if any */ + if (subtlvs && subtlvs->srv6_end_sids.count != 0) { + struct isis_srv6_end_sid_subtlv *psid; + struct ls_srv6_sid sr = {}; + + psid = (struct isis_srv6_end_sid_subtlv *) + subtlvs->srv6_end_sids.head; + sr.behavior = psid->behavior; + sr.flags = psid->flags; + memcpy(&sr.sid, &psid->sid, sizeof(struct in6_addr)); + + if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6) || + memcmp(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid))) { + memcpy(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid)); + SET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } else { + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + UNSET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } + /* Update status and Export Link State Edge if needed */ if (subnet->status != SYNC) { if (args->export) @@ -1400,12 +1489,18 @@ static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp) &args); /* Process all Extended IP (v4 & v6) in LSP (all fragments) */ + args.srv6_locator = false; isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); + args.srv6_locator = true; + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_STANDARD, lsp_to_subnet_cb, + &args); + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_IPV6_UNICAST, + lsp_to_subnet_cb, &args); /* Clean remaining Orphan Edges or Subnets */ if (IS_EXPORT_TE(mta)) @@ -1636,30 +1731,26 @@ DEFUN(show_isis_mpls_te_router, return CMD_SUCCESS; } ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { - for (ALL_LIST_ELEMENTS_RO(isis->area_list, - anode, area)) { - if (!IS_MPLS_TE(area->mta)) - continue; - - show_router_id(vty, area); - } - } - return 0; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) { - for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, - area)) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { if (!IS_MPLS_TE(area->mta)) continue; show_router_id(vty, area); } } + return 0; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { + if (!IS_MPLS_TE(area->mta)) + continue; + + show_router_id(vty, area); + } } return CMD_SUCCESS; @@ -2108,19 +2199,18 @@ DEFUN(show_isis_mpls_te_db, int rc = CMD_WARNING; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { - rc = show_isis_ted(vty, argv, argc, isis); - if (rc != CMD_SUCCESS) - return rc; - } - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis) + + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { rc = show_isis_ted(vty, argv, argc, isis); + if (rc != CMD_SUCCESS) + return rc; + } + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis) + rc = show_isis_ted(vty, argv, argc, isis); return rc; } diff --git a/isisd/isis_te.h b/isisd/isis_te.h index 5087cdac43cf..697f03b612dc 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -69,9 +69,10 @@ typedef enum _status_t { disable, enable, learn } status_t; /* Mode for Inter-AS LSP */ /* TODO: Check how if LSP is flooded in RFC5316 */ typedef enum _interas_mode_t { off, region, as, emulate } interas_mode_t; -#define IS_EXT_TE(e) (e && e->status != 0 \ - && e->status != EXT_ADJ_SID \ - && e->status != EXT_LAN_ADJ_SID) +#define IS_EXT_TE(e) \ + (e && e->status != 0 && e->status != EXT_ADJ_SID && \ + e->status != EXT_LAN_ADJ_SID && e->status != EXT_SRV6_ENDX_SID && \ + e->status != EXT_SRV6_LAN_ENDX_SID) #define IS_MPLS_TE(a) (a && a->status == enable) #define IS_EXPORT_TE(a) (a->export) @@ -102,6 +103,7 @@ struct isis_te_args { struct ls_ted *ted; struct ls_vertex *vertex; bool export; + bool srv6_locator; }; enum lsp_event { LSP_UNKNOWN, LSP_ADD, LSP_UPD, LSP_DEL, LSP_INC, LSP_TICK }; @@ -111,6 +113,8 @@ void isis_mpls_te_init(void); void isis_mpls_te_create(struct isis_area *area); void isis_mpls_te_disable(struct isis_area *area); void isis_mpls_te_term(struct isis_area *area); +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp); void isis_link_params_update(struct isis_circuit *, struct interface *); int isis_mpls_te_update(struct interface *); void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index ecf43faa7060..c7f45b246948 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -13,6 +13,11 @@ #include #include +#ifdef CRYPTO_OPENSSL +#include +#include +#endif + #ifdef CRYPTO_INTERNAL #include "md5.h" #endif @@ -343,9 +348,120 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid) } static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla, + struct json_object *ext_json, struct sbuf *buf, int indent) { char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE]; + struct json_object *json; + char cnt_buf[255]; + size_t i; + int j; + + if (ext_json) { + json = json_object_new_object(); + json_object_object_add(ext_json, "asla", json); + json_object_boolean_add(json, "legacyFlag", asla->legacy); + json_object_string_addf(json, "standardApp", "0x%02x", + asla->standard_apps); + if (IS_SUBTLV(asla, EXT_ADM_GRP)) + json_object_string_addf(json, "adminGroup", "0x%x", + asla->admin_group); + if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) && + admin_group_nb_words(&asla->ext_admin_group) != 0) { + struct json_object *ext_adm_grp_json; + + ext_adm_grp_json = json_object_new_object(); + json_object_object_add(json, "extendedAdminGroup", + ext_adm_grp_json); + for (i = 0; + i < admin_group_nb_words(&asla->ext_admin_group); + i++) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%lu", + (unsigned long)i); + json_object_string_addf(ext_adm_grp_json, + cnt_buf, "0x%x", + asla->ext_admin_group + .bitmap.data[i]); + } + } + if (IS_SUBTLV(asla, EXT_MAX_BW)) + json_object_string_addf(json, "maxBandwithBytesSec", + "%g", asla->max_bw); + if (IS_SUBTLV(asla, EXT_MAX_RSV_BW)) + json_object_string_addf(json, "maxResBandwithBytesSec", + "%g", asla->max_rsv_bw); + if (IS_SUBTLV(asla, EXT_UNRSV_BW)) { + struct json_object *unrsv_json = + json_object_new_object(); + + json_object_object_add(json, "unrsvBandwithBytesSec", + unrsv_json); + for (j = 0; j < MAX_CLASS_TYPE; j += 1) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); + json_object_string_addf(unrsv_json, cnt_buf, + "%g", asla->unrsv_bw[j]); + } + } + if (IS_SUBTLV(asla, EXT_TE_METRIC)) + json_object_int_add(json, "teMetric", asla->te_metric); + + /* Extended metrics */ + if (IS_SUBTLV(asla, EXT_DELAY)) { + struct json_object *avg_json; + + avg_json = json_object_new_object(); + json_object_object_add(json, "avgDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(asla->delay) + ? "Anomalous" + : "Normal"); + json_object_int_add(avg_json, "microSec", asla->delay); + } + if (IS_SUBTLV(asla, EXT_MM_DELAY)) { + struct json_object *avg_json; + + avg_json = json_object_new_object(); + json_object_object_add(json, "maxMinDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(asla->min_delay) + ? "Anomalous" + : "Normal"); + json_object_string_addf(avg_json, "microSec", "%u / %u", + asla->min_delay & TE_EXT_MASK, + asla->max_delay & TE_EXT_MASK); + } + if (IS_SUBTLV(asla, EXT_DELAY_VAR)) + json_object_int_add(json, "delayVariationMicroSec", + asla->delay_var & TE_EXT_MASK); + if (IS_SUBTLV(asla, EXT_PKT_LOSS)) { + struct json_object *link_json; + + link_json = json_object_new_object(); + json_object_object_add(json, "linkPacketLoss", + link_json); + json_object_string_add(link_json, "loss", + IS_ANORMAL(asla->pkt_loss) + ? "Anomalous" + : "Normal"); + json_object_string_addf(link_json, "percentage", "%g", + (float)((asla->pkt_loss & + TE_EXT_MASK) * + LOSS_PRECISION)); + } + if (IS_SUBTLV(asla, EXT_RES_BW)) + json_object_string_addf(json, + "unidirResidualBandBytesSec", + "%g", (asla->res_bw)); + if (IS_SUBTLV(asla, EXT_AVA_BW)) + json_object_string_addf(json, + "unidirAvailableBandBytesSec", + "%g", (asla->ava_bw)); + if (IS_SUBTLV(asla, EXT_USE_BW)) + json_object_string_addf(json, + "unidirUtilizedBandBytesSec", + "%g", (asla->use_bw)); + return; + } sbuf_push(buf, indent, "Application Specific Link Attributes:\n"); sbuf_push(buf, indent + 2, @@ -449,6 +565,10 @@ static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla, asla->use_bw); } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove JSON in '-' format") +#endif + /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct sbuf *buf, struct json_object *json, @@ -465,7 +585,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "0x%x", exts->adm_group); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "adm-group", aux_buf); + json_object_string_add(json, "admGroup", aux_buf); } else { sbuf_push(buf, indent, "Admin Group: 0x%08x\n", exts->adm_group); @@ -479,8 +603,23 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_EXTEND_ADM_GRP) && admin_group_nb_words(&exts->ext_admin_group) != 0) { - if (!json) { - /* TODO json after fix show database detail json */ + if (json) { + struct json_object *ext_adm_grp_json; + size_t i; + ext_adm_grp_json = json_object_new_object(); + json_object_object_add(json, "extendedAdminGroup", + ext_adm_grp_json); + for (i = 0; + i < admin_group_nb_words(&exts->ext_admin_group); + i++) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%lu", + (unsigned long)i); + json_object_string_addf(ext_adm_grp_json, + cnt_buf, "0x%x", + exts->ext_admin_group + .bitmap.data[i]); + } + } else { sbuf_push(buf, indent, "Ext Admin Group: %s\n", admin_group_string( admin_group_buf, @@ -500,10 +639,17 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_LLRI)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "link-local-id", exts->local_llri); json_object_int_add(json, "link-remote-id", exts->remote_llri); + json_object_int_add(json, "linkLocalId", + exts->local_llri); + json_object_int_add(json, "linkRemoteId", + exts->remote_llri); } else { sbuf_push(buf, indent, "Link Local ID: %u\n", exts->local_llri); @@ -515,7 +661,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET, &exts->local_addr, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "local-iface-ip", aux_buf); + json_object_string_add(json, "localIfaceIp", aux_buf); } else sbuf_push(buf, indent, "Local Interface IP Address(es): %pI4\n", @@ -525,8 +675,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET, &exts->neigh_addr, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "remote-iface-ip", aux_buf); + json_object_string_add(json, "remoteIfaceIp", aux_buf); } else sbuf_push(buf, indent, "Remote Interface IP Address(es): %pI4\n", @@ -536,8 +690,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->local_addr6, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "local-iface-ipv6", aux_buf); + json_object_string_add(json, "localIfaceIpv6", aux_buf); } else sbuf_push(buf, indent, "Local Interface IPv6 Address(es): %pI6\n", @@ -547,8 +705,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "remote-iface-ipv6", aux_buf); + json_object_string_add(json, "remoteIfaceIpv6", aux_buf); } else sbuf_push(buf, indent, "Remote Interface IPv6 Address(es): %pI6\n", @@ -558,8 +720,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", exts->max_bw); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "max-bandwith-bytes-sec", aux_buf); + json_object_string_add(json, "maxBandwithBytesSec", + aux_buf); } else sbuf_push(buf, indent, "Maximum Bandwidth: %g (Bytes/sec)\n", @@ -569,8 +736,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", exts->max_rsv_bw); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add( json, "max-res-bandwith-bytes-sec", aux_buf); + json_object_string_add(json, "maxResBandwithBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -580,6 +752,22 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_UNRSV_BW)) { if (json) { struct json_object *unrsv_json; + + unrsv_json = json_object_new_object(); + json_object_object_add(json, "unrsvBandwithBytesSec", + unrsv_json); + for (int j = 0; j < MAX_CLASS_TYPE; j += 1) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); + snprintfrr(aux_buf, sizeof(aux_buf), "%g", + exts->unrsv_bw[j]); + json_object_string_add(unrsv_json, cnt_buf, + aux_buf); + } + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ unrsv_json = json_object_new_object(); json_object_object_add(json, "unrsv-bandwith-bytes-sec", unrsv_json); @@ -590,6 +778,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_string_add(unrsv_json, cnt_buf, aux_buf); } + /* end old deprecated key format */ } else { sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { @@ -603,7 +792,11 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_TE_METRIC)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "te-metric", exts->te_metric); + json_object_int_add(json, "teMetric", exts->te_metric); } else sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", @@ -611,8 +804,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_RMT_AS)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "inter-as-te-remote-as", exts->remote_as); + json_object_int_add(json, "interAsTeRemoteAs", + exts->remote_as); } else sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %u\n", @@ -622,8 +820,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->remote_ip, aux_buf, sizeof(aux_buf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add( json, "inter-as-te-remote-asbr-ip", aux_buf); + json_object_string_add(json, "interAsTeRemoteAsbrIp", + aux_buf); } else sbuf_push(buf, indent, "Inter-AS TE Remote ASBR IP address: %pI4\n", @@ -634,12 +837,23 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *avg_json; avg_json = json_object_new_object(); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_object_add(json, "avg-delay", avg_json); json_object_string_add(avg_json, "delay", IS_ANORMAL(exts->delay) ? "Anomalous" : "Normal"); json_object_int_add(avg_json, "micro-sec", exts->delay); + + avg_json = json_object_new_object(); + json_object_object_add(json, "avgDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->delay) + ? "Anomalous" + : "Normal"); + json_object_int_add(avg_json, "microSec", exts->delay); } else sbuf_push(buf, indent, "%s Average Link Delay: %u (micro-sec)\n", @@ -651,6 +865,9 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *avg_json; avg_json = json_object_new_object(); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_object_add(json, "max-min-delay", avg_json); json_object_string_add(avg_json, "delay", IS_ANORMAL(exts->min_delay) @@ -661,6 +878,17 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, exts->max_delay & TE_EXT_MASK); json_object_string_add(avg_json, "micro-sec", aux_buf); + avg_json = json_object_new_object(); + json_object_object_add(json, "maxMinDelay", avg_json); + json_object_string_add(avg_json, "delay", + IS_ANORMAL(exts->min_delay) + ? "Anomalous" + : "Normal"); + snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u", + exts->min_delay & TE_EXT_MASK, + exts->max_delay & TE_EXT_MASK); + json_object_string_add(avg_json, "microSec", aux_buf); + } else sbuf_push( buf, indent, @@ -672,8 +900,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "delay-variation-micro-sec", exts->delay_var & TE_EXT_MASK); + json_object_int_add(json, "delayVariationMicroSec", + exts->delay_var & TE_EXT_MASK); } else sbuf_push(buf, indent, "Delay Variation: %u (micro-sec)\n", @@ -685,6 +918,10 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, (float)((exts->pkt_loss & TE_EXT_MASK) * LOSS_PRECISION)); struct json_object *link_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif link_json = json_object_new_object(); json_object_object_add(json, "link-packet-loss", link_json); @@ -692,8 +929,18 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, IS_ANORMAL(exts->pkt_loss) ? "Anomalous" : "Normal"); + /* typo */ json_object_string_add(link_json, "percentaje", aux_buf); + + link_json = json_object_new_object(); + json_object_object_add(json, "linkPacketLoss", + link_json); + json_object_string_add(link_json, "loss", + IS_ANORMAL(exts->pkt_loss) + ? "Anomalous" + : "Normal"); + json_object_string_add(link_json, "percentage", aux_buf); } else sbuf_push(buf, indent, "%s Link Packet Loss: %g (%%)\n", IS_ANORMAL(exts->pkt_loss) ? "Anomalous" @@ -705,9 +952,15 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->res_bw)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "unidir-residual-band-bytes-sec", aux_buf); + json_object_string_add(json, + "unidirResidualBandBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -718,9 +971,15 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->ava_bw)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add( json, "unidir-available-band-bytes-sec", aux_buf); + json_object_string_add(json, + "unidirAvailableBandBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -734,6 +993,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_string_add(json, "unidir-utilized-band-bytes-sec", aux_buf); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + json_object_string_add(json, + "unidirUtilizedBandBytesSec", + aux_buf); } else sbuf_push( buf, indent, @@ -745,49 +1010,89 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_adj_sid *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *adj_sid_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "adj-sid", arr_adj_json); for (adj = (struct isis_adj_sid *)exts->adj_sid.head; adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_string_add( - flags_json, "flag-f", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(adj_sid_json, "flag-f", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-v", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-l", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + adj_sid_json); + } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "adjSid", arr_adj_json); + for (adj = (struct isis_adj_sid *)exts->adj_sid.head; + adj; adj = adj->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + adj->sid); + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", + adj->sid); + json_object_int_add(adj_sid_json, "weight", + adj->weight); + json_object_boolean_add(adj_sid_json, "flagF", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? true + : false); + json_object_boolean_add(adj_sid_json, "flagB", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? true + : false); + json_object_boolean_add(adj_sid_json, "flagV", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? true + : false); + json_object_boolean_add(adj_sid_json, "flagL", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? true + : false); + json_object_boolean_add(adj_sid_json, "flagS", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? true + : false); + json_object_boolean_add(adj_sid_json, "flagP", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? true + : false); + json_object_array_add(arr_adj_json, + adj_sid_json); } } else for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -820,7 +1125,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { struct isis_lan_adj_sid *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *lan_adj_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "lan-adj-sid", arr_adj_json); @@ -834,42 +1144,82 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_string_add( - flags_json, "flag-f", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(lan_adj_json, "flag-f", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-v", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-l", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + lan_adj_json); + } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "lanAdjSid", arr_adj_json); + for (lan = (struct isis_lan_adj_sid *)exts->adj_sid.head; + lan; lan = lan->next) { + if (((mtid == ISIS_MT_IPV4_UNICAST) && + (lan->family != AF_INET)) || + ((mtid == ISIS_MT_IPV6_UNICAST) && + (lan->family != AF_INET6))) + continue; + snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", + lan->sid); + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", + lan->sid); + json_object_int_add(lan_adj_json, "weight", + lan->weight); + json_object_boolean_add(lan_adj_json, "flagF", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? true + : false); + json_object_boolean_add(lan_adj_json, "flagB", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? true + : false); + json_object_boolean_add(lan_adj_json, "flagV", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? true + : false); + json_object_boolean_add(lan_adj_json, "flagL", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? true + : false); + json_object_boolean_add(lan_adj_json, "flagS", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? true + : false); + json_object_boolean_add(lan_adj_json, "flagP", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? true + : false); + json_object_array_add(arr_adj_json, + lan_adj_json); } } else @@ -912,7 +1262,12 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_srv6_endx_sid_subtlv *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *srv6_endx_sid_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6-endx-sid", arr_adj_json); @@ -921,36 +1276,85 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &adj->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(adj->behavior)); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", + sr_algorithm_string( + adj->algorithm)); + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", + seg6local_action2str( + adj->behavior)); + json_object_string_add(srv6_endx_sid_json, + "flag-b", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-s", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-p", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); + if (adj->subsubtlvs) + isis_format_subsubtlvs(adj->subsubtlvs, + NULL, + srv6_endx_sid_json, + indent + 4); + } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "srv6EndXSID", + arr_adj_json); + for (adj = (struct isis_srv6_endx_sid_subtlv *) + exts->srv6_endx_sid.head; + adj; adj = adj->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", + &adj->sid); + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", + sr_algorithm_string( + adj->algorithm)); + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", + seg6local_action2str( + adj->behavior)); + json_object_boolean_add( + srv6_endx_sid_json, "flagB", + !!(adj->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); + json_object_boolean_add( + srv6_endx_sid_json, "flagS", + !!(adj->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); + json_object_boolean_add( + srv6_endx_sid_json, "flagP", + !!(adj->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, - NULL, json, + NULL, + srv6_endx_sid_json, indent + 4); } } else @@ -983,7 +1387,13 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) { struct isis_srv6_lan_endx_sid_subtlv *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, + *srv6_lan_endx_sid_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6-lan-endx-sid", arr_adj_json); @@ -992,41 +1402,97 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan; lan = lan->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &lan->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(lan->behavior)); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_string_addf(flags_json, + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", + sr_algorithm_string( + lan->algorithm)); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", + seg6local_action2str( + lan->behavior)); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-b", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-s", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-p", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_string_addf(srv6_lan_endx_sid_json, "neighbor-id", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); + if (lan->subsubtlvs) + isis_format_subsubtlvs(lan->subsubtlvs, + NULL, + srv6_lan_endx_sid_json, + indent + 4); + } + /* end old deprecated key format */ + + arr_adj_json = json_object_new_array(); + json_object_object_add(json, "srv6LanEndxSID", + arr_adj_json); + for (lan = (struct isis_srv6_lan_endx_sid_subtlv *) + exts->srv6_lan_endx_sid.head; + lan; lan = lan->next) { + snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", + &lan->sid); + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", + sr_algorithm_string( + lan->algorithm)); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", + seg6local_action2str( + lan->behavior)); + json_object_boolean_add( + srv6_lan_endx_sid_json, "flagB", + !!(lan->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); + json_object_boolean_add( + srv6_lan_endx_sid_json, "flagS", + !!(lan->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); + json_object_boolean_add( + srv6_lan_endx_sid_json, "flagP", + !!(lan->flags & + EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); + json_object_string_addf(srv6_lan_endx_sid_json, + "neighborID", "%pSY", + lan->neighbor_id); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, - NULL, json, + NULL, + srv6_lan_endx_sid_json, indent + 4); } } else @@ -1058,7 +1524,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } } for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla)) - format_item_asla_subtlvs(asla, buf, indent); + format_item_asla_subtlvs(asla, json, buf, indent); } static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts) @@ -2122,15 +2588,26 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; if (json) { - struct json_object *sr_json; + struct json_object *sr_json, *array_json; + sr_json = json_object_new_object(); - json_object_object_add(json, "sr", sr_json); + json_object_object_get_ex(json, "sr", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "sr", array_json); + } + json_object_array_add(array_json, sr_json); if (sid->flags & ISIS_PREFIX_SID_VALUE) { json_object_int_add(sr_json, "label", sid->value); } else { json_object_int_add(sr_json, "index", sid->value); } json_object_int_add(sr_json, "alg", sid->algorithm); + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated non boolean json") +#endif + /* old deprecated keys (no booleans) */ json_object_string_add( sr_json, "readvertised", ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes" @@ -2152,6 +2629,27 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, json_object_string_add( sr_json, "local", ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : "")); + /* end deprecated keys (no booleans) */ + + struct json_object *flags_json; + + flags_json = json_object_new_object(); + json_object_object_add(sr_json, "flags", flags_json); + + json_object_boolean_add(flags_json, "readvertised", + !!(sid->flags & + ISIS_PREFIX_SID_READVERTISED)); + json_object_boolean_add(flags_json, "node", + !!(sid->flags & ISIS_PREFIX_SID_NODE)); + json_object_boolean_add(flags_json, "noPHP", + !!(sid->flags & ISIS_PREFIX_SID_NO_PHP)); + json_object_boolean_add(flags_json, "explicitNull", + !!(sid->flags & + ISIS_PREFIX_SID_EXPLICIT_NULL)); + json_object_boolean_add(flags_json, "value", + !!(sid->flags & ISIS_PREFIX_SID_VALUE)); + json_object_boolean_add(flags_json, "local", + !!(sid->flags & ISIS_PREFIX_SID_LOCAL)); } else { sbuf_push(buf, indent, "SR Prefix-SID "); @@ -2281,7 +2779,11 @@ static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { prefix2str(p, prefixbuf, sizeof(prefixbuf)); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "ipv6-src-prefix", prefixbuf); + json_object_string_add(json, "ipv6SrcPrefix", prefixbuf); } else { sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", prefix2str(p, prefixbuf, sizeof(prefixbuf))); @@ -2383,6 +2885,11 @@ static void format_subsubtlv_srv6_sid_structure( if (json) { struct json_object *sid_struct_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ sid_struct_json = json_object_new_object(); json_object_object_add(json, "srv6-sid-structure", sid_struct_json); @@ -2394,6 +2901,19 @@ static void format_subsubtlv_srv6_sid_structure( sid_struct->func_len); json_object_int_add(sid_struct_json, "arg-len", sid_struct->arg_len); + /* end old deprecated key format */ + + sid_struct_json = json_object_new_object(); + json_object_object_add(json, "srv6SidStructure", + sid_struct_json); + json_object_int_add(sid_struct_json, "locBlockLen", + sid_struct->loc_block_len); + json_object_int_add(sid_struct_json, "locNodeLen", + sid_struct->loc_node_len); + json_object_int_add(sid_struct_json, "funcLen", + sid_struct->func_len); + json_object_int_add(sid_struct_json, "argLen", + sid_struct->arg_len); } else { sbuf_push(buf, indent, "SRv6 SID Structure "); sbuf_push(buf, 0, "Locator Block length: %hhu, ", @@ -2675,6 +3195,11 @@ static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *sid_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ sid_json = json_object_new_object(); json_object_object_add(json, "srv6-end-sid", sid_json); json_object_string_add(sid_json, "endpoint-behavior", @@ -2689,6 +3214,21 @@ static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i, isis_format_subsubtlvs(sid->subsubtlvs, NULL, subtlvs_json, 0); } + /* end old deprecated key format */ + + sid_json = json_object_new_object(); + json_object_object_add(json, "srv6EndSid", sid_json); + json_object_string_add(sid_json, "endpointBehavior", + seg6local_action2str(sid->behavior)); + json_object_string_addf(sid_json, "sidValue", "%pI6", &sid->sid); + if (sid->subsubtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(sid_json, "subsubtlvs", + subtlvs_json); + isis_format_subsubtlvs(sid->subsubtlvs, NULL, + subtlvs_json, 0); + } } else { sbuf_push(buf, indent, "SRv6 End SID "); sbuf_push(buf, 0, "Endpoint Behavior: %s, ", @@ -2836,9 +3376,13 @@ static void format_item_area_address(uint16_t mtid, struct isis_item *i, memcpy(iso_addr.area_addr, addr->addr, ISO_ADDR_SIZE); iso_addr.addr_len = addr->len; - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_addf(json, "area-addr", "%pIS", &iso_addr); - else + json_object_string_addf(json, "areaAddr", "%pIS", &iso_addr); + } else sbuf_push(buf, indent, "Area Address: %pIS\n", &iso_addr); } @@ -2924,11 +3468,34 @@ static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i, snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pPN", r->id); if (json) { - struct json_object *old_json; + struct json_object *old_json, *array_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ old_json = json_object_new_object(); - json_object_object_add(json, "old-reach-style", old_json); + json_object_object_get_ex(json, "old-reach-style", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "old-reach-style", + array_json); + } + json_object_array_add(array_json, old_json); json_object_string_add(old_json, "is-reach", sys_id); json_object_int_add(old_json, "metric", r->metric); + /* end old deprecated key format */ + + old_json = json_object_new_object(); + json_object_object_get_ex(json, "oldReachStyle", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "oldReachStyle", + array_json); + } + json_object_array_add(array_json, old_json); + json_object_string_add(old_json, "isReach", sys_id); + json_object_int_add(old_json, "metric", r->metric); } else sbuf_push(buf, indent, "IS Reachability: %s (Metric: %hhu)\n", sys_id, r->metric); @@ -3006,9 +3573,13 @@ static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i, char sys_id[ISO_SYSID_STRLEN]; snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", n->mac); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "lan-neighbor", sys_id); - else + json_object_string_add(json, "lanNeighbor", sys_id); + } else sbuf_push(buf, indent, "LAN Neighbor: %s\n", sys_id); } @@ -3081,6 +3652,9 @@ static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, char buf[255]; struct json_object *lsp_json; lsp_json = json_object_new_object(); +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_object_add(json, "lsp-entry", lsp_json); json_object_string_add(lsp_json, "id", sys_id); snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno); @@ -3088,6 +3662,15 @@ static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum); json_object_string_add(lsp_json, "chksum", buf); json_object_int_add(lsp_json, "lifetime", e->checksum); + + lsp_json = json_object_new_object(); + json_object_object_add(json, "lspEntry", lsp_json); + json_object_string_add(lsp_json, "id", sys_id); + snprintfrr(buf, sizeof(buf), "0x%08x", e->seqno); + json_object_string_add(lsp_json, "seq", buf); + snprintfrr(buf, sizeof(buf), "0x%04hx", e->checksum); + json_object_string_add(lsp_json, "chksum", buf); + json_object_int_add(lsp_json, "lifetime", e->checksum); } else sbuf_push( buf, indent, @@ -3168,9 +3751,19 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pPN", r->id); if (json) { - struct json_object *reach_json; + struct json_object *reach_json, *array_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ reach_json = json_object_new_object(); - json_object_object_add(json, "ext-reach", reach_json); + json_object_object_get_ex(json, "ext-reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ext-reach", array_json); + } + json_object_array_add(array_json, reach_json); json_object_string_add( reach_json, "mt-id", (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); @@ -3181,7 +3774,29 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, isis_mtid2str(mtid)); if (r->subtlvs) - format_item_ext_subtlvs(r->subtlvs, NULL, json, + format_item_ext_subtlvs(r->subtlvs, NULL, reach_json, + indent + 2, mtid); + /* end old deprecated key format */ + + reach_json = json_object_new_object(); + json_object_object_get_ex(json, "extReach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "extReach", array_json); + } + json_object_array_add(array_json, reach_json); + json_object_string_add(reach_json, "mtId", + (mtid == ISIS_MT_IPV4_UNICAST) + ? "Extended" + : "MT"); + json_object_string_add(reach_json, "id", sys_id); + json_object_int_add(reach_json, "metric", r->metric); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(reach_json, "mtName", + isis_mtid2str(mtid)); + + if (r->subtlvs) + format_item_ext_subtlvs(r->subtlvs, NULL, reach_json, indent + 2, mtid); } else { sbuf_push(buf, indent, "%s Reachability: %s (Metric: %u)", @@ -3309,13 +3924,40 @@ static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { - struct json_object *old_json; + struct json_object *old_json, *array_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ old_json = json_object_new_object(); - json_object_object_add(json, "old-ip-reach-style", old_json); + json_object_object_get_ex(json, "old-ip-reach-style", + &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "old-ip-reach-style", + old_json); + } + json_object_array_add(array_json, old_json); json_object_string_add(old_json, "prefix", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); json_object_int_add(old_json, "metric", r->metric); - } else + /* end old deprecated key format */ + + old_json = json_object_new_object(); + json_object_object_get_ex(json, "oldIpReachStyle", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "oldIpReachStyle", + old_json); + } + json_object_array_add(array_json, old_json); + json_object_string_add(old_json, "prefix", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(old_json, "metric", r->metric); + return; + } sbuf_push(buf, indent, "IP Reachability: %s (Metric: %hhu)\n", prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric); @@ -3407,6 +4049,10 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p, struct json_object *protocol_json; char buf[255]; +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ protocol_json = json_object_new_object(); json_object_object_add(json, "protocols-supported", protocol_json); @@ -3415,6 +4061,16 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p, json_object_string_add(protocol_json, buf, nlpid2str(p->protocols[i])); } + + protocol_json = json_object_new_object(); + json_object_object_add(json, "supportedProtocols", + protocol_json); + for (uint8_t i = 0; i < p->count; i++) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(protocol_json, buf, + nlpid2str(p->protocols[i])); + } + /* end old deprecated key format */ } else { sbuf_push(buf, indent, "Protocols Supported: "); for (uint8_t i = 0; i < p->count; i++) { @@ -3630,9 +4286,13 @@ static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i, char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "global-ipv6", addrbuf); - else + json_object_string_add(json, "globalIpv6", addrbuf); + } else sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf); } @@ -3700,12 +4360,30 @@ static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; if (json) { - struct json_object *mt_json; + struct json_object *mt_json, *array_json; mt_json = json_object_new_object(); - json_object_object_add(json, "mt", mt_json); + json_object_object_get_ex(json, "mt", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "mt", array_json); + } + json_object_array_add(array_json, mt_json); json_object_int_add(mt_json, "mtid", info->mtid); + json_object_string_add(mt_json, "mt-description", + isis_mtid2str_fake(info->mtid)); + json_object_string_add(mt_json, "mtDescription", + isis_mtid2str(mtid)); + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated non boolean format") +#endif json_object_string_add(mt_json, "overload", info->overload?"true":"false"); json_object_string_add(mt_json, "attached", info->attached?"true":"false"); + + json_object_boolean_add(mt_json, "overloadBit", + !!info->overload); + json_object_boolean_add(mt_json, "attachedbit", + !!info->attached); } else sbuf_push(buf, indent, "MT Router Info: %s%s%s\n", isis_mtid2str_fake(info->mtid), @@ -3788,9 +4466,13 @@ static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf, char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf)); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "te-router-id", addrbuf); - else + json_object_string_add(json, "teRouterId", addrbuf); + } else sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); } @@ -3861,27 +4543,64 @@ static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, struct json_object *json, int indent) { struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; + struct json_object *ext_json, *array_json; char prefixbuf[PREFIX2STR_BUFFER]; if (json) { - struct json_object *ext_json; +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ ext_json = json_object_new_object(); - json_object_object_add(json, "ext-ip-reach", ext_json); - json_object_string_add( - json, "mt-id", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); - json_object_string_add( - json, "ip-reach", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); - json_object_int_add(json, "ip-reach-metric", r->metric); - json_object_string_add(json, "down", r->down ? "yes" : ""); + json_object_object_get_ex(json, "ext-ip-reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ext-ip-reach", array_json); + } + json_object_array_add(array_json, ext_json); + json_object_string_add(ext_json, "mt-id", + (mtid == ISIS_MT_IPV4_UNICAST) + ? "Extended" + : "MT"); + json_object_string_add(ext_json, "ip-reach", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(ext_json, "ip-reach-metric", r->metric); + json_object_string_add(ext_json, "down", r->down ? "yes" : ""); + if (mtid != ISIS_MT_IPV4_UNICAST) + json_object_string_add(ext_json, "mt-name", + isis_mtid2str(mtid)); + if (r->subtlvs) { + struct json_object *subtlv_json; + subtlv_json = json_object_new_object(); + json_object_object_add(ext_json, "subtlvs", subtlv_json); + format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); + } + /* end old deprecated key format */ + + ext_json = json_object_new_object(); + json_object_object_get_ex(json, "extIpReach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "extIpReach", array_json); + } + json_object_array_add(array_json, ext_json); + json_object_string_add(ext_json, "mtId", + (mtid == ISIS_MT_IPV4_UNICAST) + ? "Extended" + : "MT"); + json_object_string_add(ext_json, "ipReach", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(ext_json, "ipReachMetric", r->metric); + json_object_boolean_add(ext_json, "down", !!r->down); if (mtid != ISIS_MT_IPV4_UNICAST) - json_object_string_add(json, "mt-name", + json_object_string_add(ext_json, "mtName", isis_mtid2str(mtid)); if (r->subtlvs) { struct json_object *subtlv_json; subtlv_json = json_object_new_object(); - json_object_object_add(json, "subtlvs", subtlv_json); + json_object_object_add(ext_json, "subtlvs", subtlv_json); format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); } } else { @@ -4141,9 +4860,13 @@ static void format_tlv_te_router_id_ipv6(const struct in6_addr *id, char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf)); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "ipv6-te-router-id", addrbuf); - else + json_object_string_add(json, "ipv6TeRouterId", addrbuf); + } else sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); } @@ -4220,6 +4943,11 @@ static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, if (json) { struct json_object *spine_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated format */ spine_json = json_object_new_object(); json_object_object_add(json, "spine-leaf-extension", spine_json); @@ -4238,6 +4966,25 @@ static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, spine_leaf->is_spine ? "yes" : ""); json_object_string_add(spine_json, "flag-backup", spine_leaf->is_backup ? "yes" : ""); + /* end old deprecated format */ + + spine_json = json_object_new_object(); + json_object_object_add(json, "spineLeafExtension", spine_json); + if (spine_leaf->has_tier) { + snprintfrr(aux_buf, sizeof(aux_buf), "%hhu", + spine_leaf->tier); + json_object_string_add(spine_json, "tier", + (spine_leaf->tier == + ISIS_TIER_UNDEFINED) + ? "undefined" + : aux_buf); + } + json_object_boolean_add(spine_json, "flagLeaf", + spine_leaf->is_leaf ? true : false); + json_object_boolean_add(spine_json, "flagSpine", + spine_leaf->is_spine ? true : false); + json_object_boolean_add(spine_json, "flagBackup", + spine_leaf->is_backup ? true : false); } else { sbuf_push(buf, indent, "Spine-Leaf-Extension:\n"); if (spine_leaf->has_tier) { @@ -4379,6 +5126,11 @@ format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", threeway_adj->neighbor_id); if (json) { struct json_object *three_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ three_json = json_object_new_object(); json_object_object_add(json, "p2p-three-way-adj", three_json); json_object_string_add( @@ -4387,11 +5139,28 @@ format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, json_object_int_add(three_json, "state", threeway_adj->state); json_object_int_add(three_json, "ext-local-circuit-id", threeway_adj->local_circuit_id); - if (!threeway_adj->neighbor_set) - return; - json_object_string_add(three_json, "neigh-system-id", sys_id); - json_object_int_add(three_json, "neigh-ext-circuit-id", - threeway_adj->neighbor_circuit_id); + if (threeway_adj->neighbor_set) { + json_object_string_add(three_json, "neigh-system-id", + sys_id); + json_object_int_add(three_json, "neigh-ext-circuit-id", + threeway_adj->neighbor_circuit_id); + } + /* end old deprecated key format */ + + three_json = json_object_new_object(); + json_object_object_add(json, "p2pThreeWayAdj", three_json); + json_object_string_add(three_json, "stateName", + isis_threeway_state_name( + threeway_adj->state)); + json_object_int_add(three_json, "state", threeway_adj->state); + json_object_int_add(three_json, "extLocalCircuitId", + threeway_adj->local_circuit_id); + if (threeway_adj->neighbor_set) { + json_object_string_add(three_json, "neighSystemId", + sys_id); + json_object_int_add(three_json, "neighExtCircuitId", + threeway_adj->neighbor_circuit_id); + } } else { sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n"); sbuf_push(buf, indent, " State: %s (%d)\n", @@ -4495,9 +5264,51 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { - struct json_object *reach_json; + struct json_object *reach_json, *array_json; + + reach_json = json_object_new_object(); + json_object_object_get_ex(json, "ipv6Reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ipv6Reach", array_json); + } + json_object_array_add(array_json, reach_json); + json_object_string_add(reach_json, "mtId", + (mtid == ISIS_MT_IPV4_UNICAST) ? "" + : "mt"); + json_object_string_add(reach_json, "prefix", + prefix2str(&r->prefix, prefixbuf, + sizeof(prefixbuf))); + json_object_int_add(reach_json, "metric", r->metric); + json_object_boolean_add(reach_json, "down", + r->down ? true : false); + json_object_boolean_add(reach_json, "external", + r->external ? true : false); + if (mtid != ISIS_MT_IPV4_UNICAST) { + json_object_string_add(reach_json, "mt-name", + isis_mtid2str(mtid)); + json_object_string_add(reach_json, "mtName", + isis_mtid2str(mtid)); + } + if (r->subtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(reach_json, "subtlvs", + subtlvs_json); + format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); + } + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated JSON key format */ reach_json = json_object_new_object(); - json_object_object_add(json, "ipv6-reach", reach_json); + json_object_object_get_ex(json, "ipv6-reach", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "ipv6-reach", array_json); + } + json_object_array_add(array_json, reach_json); json_object_string_add(reach_json, "mt-id", (mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt"); @@ -4515,9 +5326,11 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, if (r->subtlvs) { struct json_object *subtlvs_json; subtlvs_json = json_object_new_object(); - json_object_object_add(json, "subtlvs", subtlvs_json); + json_object_object_add(reach_json, "subtlvs", + subtlvs_json); format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); } + /* end deprecated key format */ } else { sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", @@ -4729,6 +5542,11 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, /* Router ID and Flags */ struct json_object *cap_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* deprecated JSON key format */ cap_json = json_object_new_object(); json_object_object_add(json, "router-capability", cap_json); inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); @@ -4739,10 +5557,26 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, json_object_string_add( cap_json, "flag-s", router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0"); + /* end deprecated JSON key format */ + + cap_json = json_object_new_object(); + json_object_object_add(json, "routerCapability", cap_json); + inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); + json_object_string_add(cap_json, "id", addrbuf); + json_object_boolean_add(cap_json, "flagD", + !!(router_cap->flags & ISIS_ROUTER_CAP_FLAG_D)); + json_object_boolean_add(cap_json, "flagS", + !!(router_cap->flags & ISIS_ROUTER_CAP_FLAG_S)); + /* Segment Routing Global Block as per RFC8667 section #3.1 */ if (router_cap->srgb.range_size != 0) { struct json_object *gb_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* deprecated old key format */ gb_json = json_object_new_object(); json_object_object_add(json, "segment-routing-gb", gb_json); json_object_string_add(gb_json, "ipv4", @@ -4755,23 +5589,52 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, router_cap->srgb.lower_bound); json_object_int_add(gb_json, "global-block-range", router_cap->srgb.range_size); + + gb_json = json_object_new_object(); + json_object_object_add(json, "segmentRoutingGb", gb_json); + json_object_boolean_add(gb_json, "ipv4", + !!IS_SR_IPV4(&router_cap->srgb)); + json_object_boolean_add(gb_json, "ipv6", + !!IS_SR_IPV6(&router_cap->srgb)); + json_object_int_add(gb_json, "globalBlockBase", + router_cap->srgb.lower_bound); + json_object_int_add(gb_json, "globalBlockRange", + router_cap->srgb.range_size); } /* Segment Routing Local Block as per RFC8667 section #3.3 */ if (router_cap->srlb.range_size != 0) { struct json_object *lb_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ lb_json = json_object_new_object(); json_object_object_add(json, "segment-routing-lb", lb_json); json_object_int_add(lb_json, "global-block-base", router_cap->srlb.lower_bound); json_object_int_add(lb_json, "global-block-range", router_cap->srlb.range_size); + /* end old deprecated key format */ + + lb_json = json_object_new_object(); + json_object_object_add(json, "segmentRoutingLb", lb_json); + json_object_int_add(lb_json, "globalBlockBase", + router_cap->srlb.lower_bound); + json_object_int_add(lb_json, "globalBlockRange", + router_cap->srlb.range_size); } /* Segment Routing Algorithms as per RFC8667 section #3.2 */ if (router_cap->algo[0] != SR_ALGORITHM_UNSET) { char buf[255]; struct json_object *alg_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ alg_json = json_object_new_object(); json_object_object_add(json, "segment-routing-algorithm", alg_json); @@ -4783,6 +5646,20 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, ? "SPF" : "Strict SPF"); } + /* end old deprecated key format */ + + alg_json = json_object_new_object(); + json_object_object_add(json, "segmentRoutingAlgorithm", + alg_json); + for (int i = 0; i < SR_ALGORITHM_COUNT; i++) { + if (router_cap->algo[i] != SR_ALGORITHM_UNSET) { + snprintfrr(buf, sizeof(buf), "%d", i); + json_object_string_add(alg_json, buf, + router_cap->algo[i] == 0 + ? "SPF" + : "Strict SPF"); + } + } } /* Segment Routing Node MSD as per RFC8491 section #2 */ @@ -5626,16 +6503,24 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, struct isis_auth *auth = (struct isis_auth *)i; char obuf[768]; - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "test-auth", "ok"); - else + json_object_string_add(json, "testAuth", "ok"); + } else sbuf_push(buf, indent, "Authentication:\n"); switch (auth->type) { case ISIS_PASSWD_TYPE_CLEARTXT: zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length); - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "auth-pass", obuf); - else + json_object_string_add(json, "authPass", obuf); + } else sbuf_push(buf, indent, " Password: %s\n", obuf); break; case ISIS_PASSWD_TYPE_HMAC_MD5: @@ -5643,15 +6528,23 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx", auth->value[j]); } - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "auth-hmac-md5", obuf); - else + json_object_string_add(json, "authHmacMd5", obuf); + } else sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); break; default: - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_int_add(json, "auth-unknown", auth->type); - else + json_object_int_add(json, "authUnknown", auth->type); + } else sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type); break; @@ -5766,12 +6659,25 @@ static void format_tlv_purge_originator(struct isis_purge_originator *poi, if (json) { struct json_object *purge_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old deprecated key format */ purge_json = json_object_new_object(); json_object_object_add(json, "purge_originator", purge_json); json_object_string_add(purge_json, "id", gen_id); if (poi->sender_set) json_object_string_add(purge_json, "rec-from", sen_id); + /* end old deprecated key format */ + + purge_json = json_object_new_object(); + json_object_object_add(json, "purgeOriginator", purge_json); + + json_object_string_add(purge_json, "id", gen_id); + if (poi->sender_set) + json_object_string_add(purge_json, "recFrom", sen_id); } else { sbuf_push(buf, indent, "Purge Originator Identification:\n"); sbuf_push(buf, indent, " Generator: %s\n", gen_id); @@ -6314,6 +7220,11 @@ static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *loc_json; + +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif + /* old json key format */ loc_json = json_object_new_object(); json_object_object_add(json, "srv6-locator", loc_json); json_object_int_add(loc_json, "mt-id", mtid); @@ -6335,6 +7246,26 @@ static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i, subtlvs_json); format_subtlvs(loc->subtlvs, NULL, subtlvs_json, 0); } + /* old deprecated key format */ + + loc_json = json_object_new_object(); + json_object_object_add(json, "srv6Locator", loc_json); + json_object_int_add(loc_json, "mtId", mtid); + json_object_string_addf(loc_json, "prefix", "%pFX", + &loc->prefix); + json_object_int_add(loc_json, "metric", loc->metric); + json_object_boolean_add(loc_json, "flagD", + !!CHECK_FLAG(loc->flags, + ISIS_TLV_SRV6_LOCATOR_FLAG_D)); + json_object_int_add(loc_json, "algorithm", loc->algorithm); + json_object_string_add(loc_json, "MTName", isis_mtid2str(mtid)); + if (loc->subtlvs) { + struct json_object *subtlvs_json; + subtlvs_json = json_object_new_object(); + json_object_object_add(loc_json, "subtlvs", + subtlvs_json); + format_subtlvs(loc->subtlvs, NULL, subtlvs_json, 0); + } } else { sbuf_push(buf, indent, "SRv6 Locator: %pFX (Metric: %u)%s", &loc->prefix, loc->metric, @@ -6618,9 +7549,13 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_ob &tlvs->area_addresses, buf, json, indent); if (tlvs->mt_router_info_empty) { - if (json) + if (json) { +#if CONFDATE > 20240916 + CPP_NOTICE("remove deprecated key format with -") +#endif json_object_string_add(json, "mt-router-info", "none"); - else + json_object_object_add(json, "mtRouterInfo", NULL); + } else sbuf_push(buf, indent, "MT Router Info: None\n"); } else { format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, @@ -8011,7 +8946,6 @@ void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, apply_mask_ipv4(&r->prefix); if (pcfgs) { - r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH); for (int i = 0; i < SR_ALGORITHM_COUNT; i++) { struct isis_prefix_sid *psid; struct sr_prefix_cfg *pcfg = pcfgs[i]; @@ -8021,6 +8955,10 @@ void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs, psid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid)); isis_sr_prefix_cfg2subtlv(pcfg, external, psid); + + if (!r->subtlvs) + r->subtlvs = isis_alloc_subtlvs( + ISIS_CONTEXT_SUBTLV_IP_REACH); append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid); } @@ -8039,7 +8977,6 @@ void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid, memcpy(&r->prefix, dest, sizeof(*dest)); apply_mask_ipv6(&r->prefix); if (pcfgs) { - r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH); for (int i = 0; i < SR_ALGORITHM_COUNT; i++) { struct isis_prefix_sid *psid; struct sr_prefix_cfg *pcfg = pcfgs[i]; @@ -8049,6 +8986,10 @@ void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid, psid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid)); isis_sr_prefix_cfg2subtlv(pcfg, external, psid); + + if (!r->subtlvs) + r->subtlvs = isis_alloc_subtlvs( + ISIS_CONTEXT_SUBTLV_IPV6_REACH); append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid); } diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 8252c1ac25a6..caf7d3ddfbfc 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -454,7 +454,7 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra) znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL; /* Set backup nexthops. */ - if (sra->type == ISIS_SR_LAN_BACKUP) { + if (sra->type == ISIS_SR_ADJ_BACKUP) { int count; count = isis_zebra_add_nexthops(isis, sra->backup_nexthops, @@ -644,6 +644,70 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size) return 0; } +/** + * Request an End.X SID for an IS-IS adjacency. + * + * @param adj IS-IS Adjacency + */ +void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) +{ + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct in6_addr nexthop; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + bool ret; + + if (!area || !area->srv6db.srv6_locator) + return; + + /* Determine nexthop IP address */ + if (!circuit->ipv6_router || !adj->ll_ipv6_count) + return; + + nexthop = adj->ll_ipv6_addrs[0]; + + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = nexthop; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End.X SID for IS-IS area %s", + __func__, area->area_tag); + return; + } +} + +static void request_srv6_sids(struct isis_area *area) +{ + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct listnode *node; + struct isis_adjacency *adj; + bool ret; + + if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator) + return; + + sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag); + + /* Request new SRv6 End SID */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End SID for IS-IS area %s", + __func__, area->area_tag); + return; + } + + /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { + if (adj->ll_ipv6_count > 0) + isis_zebra_request_srv6_sid_endx(adj); + } +} + /** * Release Label Range to the Label Manager. * @@ -1119,99 +1183,47 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra) } /** - * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). + * Internal function to process an SRv6 locator * - * @result 0 on success, -1 otherwise + * @param locator The locator to be processed */ -static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); - struct stream *s = NULL; - struct listnode *node; struct isis_area *area; - struct srv6_locator_chunk *c; - struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc(); - struct isis_srv6_sid *sid; - struct isis_adjacency *adj; - enum srv6_endpoint_behavior_codepoint behavior; - bool allocated = false; - - if (!isis) { - srv6_locator_chunk_free(&chunk); - return -1; - } + struct listnode *node; - /* Decode the received zebra message */ - s = zclient->ibuf; - if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { - srv6_locator_chunk_free(&chunk); + if (!isis || !locator) return -1; - } - sr_debug( - "Received SRv6 locator chunk from zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - chunk->locator_name, &chunk->prefix, chunk->block_bits_length, - chunk->node_bits_length, chunk->function_bits_length, - chunk->argument_bits_length); + zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u", + __func__, locator->name, &locator->prefix, + locator->block_bits_length, locator->node_bits_length, + locator->function_bits_length, locator->argument_bits_length); /* Walk through all areas of the ISIS instance */ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - if (strncmp(area->srv6db.config.srv6_locator_name, - chunk->locator_name, - sizeof(area->srv6db.config.srv6_locator_name)) != 0) + /* + * Check if the IS-IS area is configured to use the received + * locator + */ + if (strncmp(area->srv6db.config.srv6_locator_name, locator->name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + zlog_err("%s: SRv6 Locator name unmatch %s:%s", + __func__, area->srv6db.config.srv6_locator_name, + locator->name); continue; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks, - node, c)) { - if (!prefix_cmp(&c->prefix, &chunk->prefix)) { - srv6_locator_chunk_free(&chunk); - return 0; - } - } - - sr_debug( - "SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s", - chunk->locator_name, &chunk->prefix, area->area_tag); - - /* Add the SRv6 Locator chunk to the per-area chunks list */ - listnode_add(area->srv6db.srv6_locator_chunks, chunk); - - /* Decide which behavior to use,depending on the locator type - * (i.e. uSID vs classic locator) */ - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) - ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID - : SRV6_ENDPOINT_BEHAVIOR_END; - - /* Allocate new SRv6 End SID */ - sid = isis_srv6_sid_alloc(area, chunk, behavior, 0); - if (!sid) - return -1; - - /* Install the new SRv6 End SID in the forwarding plane through - * Zebra */ - isis_zebra_srv6_sid_install(area, sid); - - /* Store the SID */ - listnode_add(area->srv6db.srv6_sids, sid); - - /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ - for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { - if (adj->ll_ipv6_count > 0) - srv6_endx_sid_add(adj); } - /* Regenerate LSPs to advertise the new locator and the SID */ - lsp_regenerate_schedule(area, area->is_type, 0); + sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s", + locator->name, &locator->prefix, area->area_tag); - allocated = true; - break; - } + /* Store the locator in the IS-IS area */ + area->srv6db.srv6_locator = srv6_locator_alloc(locator->name); + srv6_locator_copy(area->srv6db.srv6_locator, locator); - if (!allocated) { - sr_debug("No IS-IS area configured for the locator %s", - chunk->locator_name); - srv6_locator_chunk_free(&chunk); + /* Request SIDs from the locator */ + request_srv6_sids(area); } return 0; @@ -1226,8 +1238,6 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); struct srv6_locator loc = {}; - struct listnode *node; - struct isis_area *area; if (!isis) return -1; @@ -1236,33 +1246,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) return -1; - sr_debug( - "New SRv6 locator allocated in zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - loc.name, &loc.prefix, loc.block_bits_length, - loc.node_bits_length, loc.function_bits_length, - loc.argument_bits_length); - - /* Lookup on the IS-IS areas */ - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - /* If SRv6 is enabled on this area and the configured locator - * corresponds to the new locator, then request a chunk from the - * locator */ - if (area->srv6db.config.enabled && - strncmp(area->srv6db.config.srv6_locator_name, loc.name, - sizeof(area->srv6db.config.srv6_locator_name)) == 0) { - sr_debug( - "Sending a request to get a chunk from the SRv6 locator %s (%pFX) " - "for IS-IS area %s", - loc.name, &loc.prefix, area->area_tag); - - if (isis_zebra_srv6_manager_get_locator_chunk( - loc.name) < 0) - return -1; - } - } - - return 0; + return isis_zebra_process_srv6_locator_internal(&loc); } /** @@ -1335,6 +1319,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) } } + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Regenerate LSPs to advertise that the locator no longer * exists */ lsp_regenerate_schedule(area, area->is_type, 0); @@ -1368,6 +1355,232 @@ int isis_zebra_srv6_manager_release_locator_chunk(const char *name) return srv6_manager_release_locator_chunk(zclient, name); } +/** + * Ask the SRv6 Manager (zebra) about a specific locator + * + * @param name Locator name + * @return 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_get_locator(const char *name) +{ + if (!name) + return -1; + + /* + * Send the Get Locator request to the SRv6 Manager and return the + * result + */ + return srv6_manager_get_locator(zclient, name); +} + +/** + * Ask the SRv6 Manager (zebra) to allocate a SID. + * + * Optionally, it is possible to provide an IPv6 address (sid_value parameter). + * + * When sid_value is provided, the SRv6 Manager allocates the requested SID + * address, if the request can be satisfied (explicit allocation). + * + * When sid_value is not provided, the SRv6 Manager allocates any available SID + * from the provided locator (dynamic allocation). + * + * @param ctx Context to be associated with the request SID + * @param sid_value IPv6 address to be associated with the requested SID (optional) + * @param locator_name Name of the locator from which the SID must be allocated + */ +bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret; + + if (!ctx || !locator_name) + return false; + + /* + * Send the Get SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name, NULL); + if (ret < 0) { + zlog_warn("%s: error getting SRv6 SID!", __func__); + return false; + } + + return true; +} + +/** + * Ask the SRv6 Manager (zebra) to release a previously allocated SID. + * + * This function is used to tell the SRv6 Manager that IS-IS no longer intends + * to use the SID. + * + * @param ctx Context to be associated with the SID to be released + */ +void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx) +{ + int ret; + + if (!ctx) + return; + + /* + * Send the Release SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_release_sid(zclient, ctx); + if (ret < 0) { + zlog_warn("%s: error releasing SRv6 SID!", __func__); + return; + } +} + +static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_sid_ctx ctx; + struct in6_addr sid_addr; + enum zapi_srv6_sid_notify note; + uint32_t sid_func; + struct isis_area *area; + struct listnode *node, *nnode, *n; + char buf[256]; + struct srv6_locator *locator; + struct prefix_ipv6 tmp_prefix; + struct srv6_adjacency *sra; + enum srv6_endpoint_behavior_codepoint behavior; + struct isis_srv6_sid *sid; + struct isis_adjacency *adj; + + if (!isis) + return -1; + + /* Decode the received notification message */ + if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, + &sid_func, NULL, ¬e, NULL)) { + zlog_err("%s : error in msg decode", __func__); + return -1; + } + + sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, + sid_func, zapi_srv6_sid_notify2str(note)); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator) + continue; + + locator = area->srv6db.srv6_locator; + + /* Verify that the received SID belongs to the configured locator */ + if (note == ZAPI_SRV6_SID_ALLOCATED) { + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = sid_addr; + + if (!prefix_match((struct prefix *)&locator->prefix, + (struct prefix *)&tmp_prefix)) { + sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match", + __func__, area->area_tag); + continue; + } + } + + /* Handle notification */ + switch (note) { + case ZAPI_SRV6_SID_ALLOCATED: + sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* Remove old End SIDs, if any */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, + node, nnode, sid)) { + isis_zebra_srv6_sid_uninstall(area, sid); + listnode_delete(area->srv6db.srv6_sids, + sid); + } + + /* Allocate new SRv6 End SID */ + behavior = + (CHECK_FLAG(locator->flags, + SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END; + sid = isis_srv6_sid_alloc(area, + area->srv6db + .srv6_locator, + behavior, &sid_addr); + if (!sid) { + zlog_warn("%s: isis_srv6_sid_alloc failed", + __func__); + return -1; + } + + /* + * Install the new SRv6 End SID in the forwarding plane through + * Zebra + */ + isis_zebra_srv6_sid_install(area, sid); + + /* Store the SID */ + listnode_add(area->srv6db.srv6_sids, sid); + + } else if (ctx.behavior == + ZEBRA_SEG6_LOCAL_ACTION_END_X) { + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, + n, adj)) { + /* Check if the End.X SID is for this adjacecny */ + if (adj->ll_ipv6_count == 0 || + memcmp(&adj->ll_ipv6_addrs[0], + &ctx.nh6, + sizeof(struct in6_addr)) != 0) + continue; + + /* Remove old End.X SIDs, if any */ + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, + node, nnode, sra)) + srv6_endx_sid_del(sra); + + /* Allocate new End.X SID for the adjacency */ + srv6_endx_sid_add_single(adj, false, + NULL, + &sid_addr); + } + } else { + zlog_warn("%s: unsupported behavior %u", + __func__, ctx.behavior); + return -1; + } + break; + case ZAPI_SRV6_SID_RELEASED: + sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + break; + case ZAPI_SRV6_SID_FAIL_ALLOC: + sr_debug("SRv6 SID %pI6 %s: Failed to allocate", + &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + zlog_warn("%s: SRv6 SID %pI6 %s failure to release", + __func__, &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + } + + /* Regenerate LSPs to advertise the new locator and the SID */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return 0; +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -1380,10 +1593,9 @@ static zclient_handler *const isis_handlers[] = { [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, - [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = - isis_zebra_process_srv6_locator_chunk, [ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add, [ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, + [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify, }; void isis_zebra_init(struct event_loop *master, int instance) @@ -1395,9 +1607,7 @@ void isis_zebra_init(struct event_loop *master, int instance) zclient->zebra_connected = isis_zebra_connected; /* Initialize special zclient for synchronous message exchanges. */ - struct zclient_options options = zclient_options_default; - options.synchronous = true; - zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_ISIS; zclient_sync->instance = instance; @@ -1418,5 +1628,4 @@ void isis_zebra_stop(void) zclient_free(zclient_sync); zclient_stop(zclient); zclient_free(zclient); - frr_fini(); } diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index f1684b7c25d4..79da16efac49 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -68,4 +68,11 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra); extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name); extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); +extern int isis_zebra_srv6_manager_get_locator(const char *name); +extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj); +extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx); + #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index b1064d894199..2863fd913f8f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -176,6 +176,11 @@ void isis_master_init(struct event_loop *master) im->master = master; } +void isis_master_terminate(void) +{ + list_delete(&im->isis); +} + struct isis *isis_new(const char *vrf_name) { struct vrf *vrf; @@ -272,7 +277,7 @@ void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit) isis_csm_state_change(ISIS_DISABLE, circuit, area); } -static void delete_area_addr(void *arg) +void isis_area_address_delete(void *arg) { struct iso_address *addr = (struct iso_address *)arg; @@ -330,7 +335,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->circuit_list = list_new(); area->adjacency_list = list_new(); area->area_addrs = list_new(); - area->area_addrs->del = delete_area_addr; + area->area_addrs->del = isis_area_address_delete; if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) event_add_timer(master, lsp_tick, area, 1, &area->t_tick); @@ -471,6 +476,29 @@ struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id) return NULL; } +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid) +{ + struct isis_area *area; + struct listnode *node; + struct isis *isis; + struct iso_address *addr = NULL; + + isis = isis_lookup_by_sysid(sysid); + if (isis == NULL) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, sysid, + ISIS_SYS_ID_LEN)) + return area; + } + } + + return NULL; +} + int isis_area_get(struct vty *vty, const char *area_tag) { struct isis_area *area; @@ -496,6 +524,7 @@ void isis_area_destroy(struct isis_area *area) { struct listnode *node, *nnode; struct isis_circuit *circuit; + struct iso_address *addr; QOBJ_UNREG(area); @@ -545,6 +574,15 @@ void isis_area_destroy(struct isis_area *area) if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) isis_redist_area_finish(area); + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN)) { + memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN); + area->isis->sysid_set = 0; + } + } + list_delete(&area->area_addrs); for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM; @@ -988,63 +1026,17 @@ int show_isis_interface_common_json(struct json_object *json, "no"); return CMD_SUCCESS; } - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { - areas_json = json_object_new_array(); - json_object_object_add(json, "areas", - areas_json); - for (ALL_LIST_ELEMENTS_RO(isis->area_list, - anode, area)) { - area_json = json_object_new_object(); - json_object_string_add( - area_json, "area", - area->area_tag ? area->area_tag - : "null"); - circuits_json = json_object_new_array(); - json_object_object_add(area_json, - "circuits", - circuits_json); - for (ALL_LIST_ELEMENTS_RO( - area->circuit_list, cnode, - circuit)) { - circuit_json = - json_object_new_object(); - json_object_int_add( - circuit_json, "circuit", - circuit->circuit_id); - if (!ifname) - isis_circuit_print_json( - circuit, - circuit_json, - detail); - else if (strcmp(circuit->interface->name, ifname) == 0) - isis_circuit_print_json( - circuit, - circuit_json, - detail); - json_object_array_add( - circuits_json, - circuit_json); - } - json_object_array_add(areas_json, - area_json); - } - } - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) { + + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { areas_json = json_object_new_array(); json_object_object_add(json, "areas", areas_json); - for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, - area)) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { area_json = json_object_new_object(); json_object_string_add(area_json, "area", area->area_tag ? area->area_tag : "null"); - circuits_json = json_object_new_array(); json_object_object_add(area_json, "circuits", circuits_json); @@ -1055,22 +1047,56 @@ int show_isis_interface_common_json(struct json_object *json, circuit_json, "circuit", circuit->circuit_id); if (!ifname) - isis_circuit_print_json( - circuit, circuit_json, - detail); - else if ( - strcmp(circuit->interface->name, - ifname) == 0) - isis_circuit_print_json( - circuit, circuit_json, - detail); + isis_circuit_print_json(circuit, + circuit_json, + detail); + else if (strcmp(circuit->interface->name, + ifname) == 0) + isis_circuit_print_json(circuit, + circuit_json, + detail); json_object_array_add(circuits_json, circuit_json); } json_object_array_add(areas_json, area_json); } } + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + areas_json = json_object_new_array(); + json_object_object_add(json, "areas", areas_json); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { + area_json = json_object_new_object(); + json_object_string_add(area_json, "area", + area->area_tag ? area->area_tag + : "null"); + + circuits_json = json_object_new_array(); + json_object_object_add(area_json, "circuits", + circuits_json); + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, + circuit)) { + circuit_json = json_object_new_object(); + json_object_int_add(circuit_json, "circuit", + circuit->circuit_id); + if (!ifname) + isis_circuit_print_json(circuit, + circuit_json, + detail); + else if (strcmp(circuit->interface->name, + ifname) == 0) + isis_circuit_print_json(circuit, + circuit_json, + detail); + json_object_array_add(circuits_json, + circuit_json); + } + json_object_array_add(areas_json, area_json); + } } + return CMD_SUCCESS; } @@ -1087,37 +1113,10 @@ int show_isis_interface_common_vty(struct vty *vty, const char *ifname, vty_out(vty, "IS-IS Routing Process not enabled\n"); return CMD_SUCCESS; } - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { - for (ALL_LIST_ELEMENTS_RO(isis->area_list, - anode, area)) { - vty_out(vty, "Area %s:\n", - area->area_tag); - if (detail == ISIS_UI_LEVEL_BRIEF) - vty_out(vty, - " Interface CircId State Type Level\n"); - - for (ALL_LIST_ELEMENTS_RO( - area->circuit_list, cnode, - circuit)) - if (!ifname) - isis_circuit_print_vty( - circuit, vty, - detail); - else if (strcmp(circuit->interface->name, ifname) == 0) - isis_circuit_print_vty( - circuit, vty, - detail); - } - } - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) { - for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, - area)) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { vty_out(vty, "Area %s:\n", area->area_tag); if (detail == ISIS_UI_LEVEL_BRIEF) @@ -1127,15 +1126,37 @@ int show_isis_interface_common_vty(struct vty *vty, const char *ifname, for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) if (!ifname) - isis_circuit_print_vty( - circuit, vty, detail); - else if ( - strcmp(circuit->interface->name, - ifname) == 0) - isis_circuit_print_vty( - circuit, vty, detail); + isis_circuit_print_vty(circuit, + vty, + detail); + else if (strcmp(circuit->interface->name, + ifname) == 0) + isis_circuit_print_vty(circuit, + vty, + detail); } } + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) { + vty_out(vty, "Area %s:\n", area->area_tag); + + if (detail == ISIS_UI_LEVEL_BRIEF) + vty_out(vty, + " Interface CircId State Type Level\n"); + + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, + circuit)) + if (!ifname) + isis_circuit_print_vty(circuit, vty, + detail); + else if (strcmp(circuit->interface->name, + ifname) == 0) + isis_circuit_print_vty(circuit, vty, + detail); + } } return CMD_SUCCESS; @@ -1318,7 +1339,7 @@ static void isis_neighbor_common_vty(struct vty *vty, const char *id, if (detail == ISIS_UI_LEVEL_BRIEF) vty_out(vty, - " System Id Interface L State Holdtime SNPA\n"); + " System Id Interface L State Holdtime SNPA\n"); for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { @@ -1376,28 +1397,23 @@ int show_isis_neighbor_common(struct vty *vty, struct json_object *json, return CMD_SUCCESS; } - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { - if (id_to_sysid(isis, id, sysid)) { - vty_out(vty, "Invalid system id %s\n", - id); - return CMD_SUCCESS; - } - isis_neighbor_common(vty, json, id, detail, - isis, sysid); - } - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { if (id_to_sysid(isis, id, sysid)) { vty_out(vty, "Invalid system id %s\n", id); return CMD_SUCCESS; } - isis_neighbor_common(vty, json, id, detail, isis, - sysid); + isis_neighbor_common(vty, json, id, detail, isis, sysid); } + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + if (id_to_sysid(isis, id, sysid)) { + vty_out(vty, "Invalid system id %s\n", id); + return CMD_SUCCESS; + } + isis_neighbor_common(vty, json, id, detail, isis, sysid); } return CMD_SUCCESS; @@ -1461,27 +1477,23 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_ return CMD_SUCCESS; } - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { - if (id_to_sysid(isis, id, sysid)) { - vty_out(vty, "Invalid system id %s\n", - id); - return CMD_SUCCESS; - } - isis_neighbor_common_clear(vty, id, sysid, - isis); - } - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) { + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { if (id_to_sysid(isis, id, sysid)) { vty_out(vty, "Invalid system id %s\n", id); return CMD_SUCCESS; } isis_neighbor_common_clear(vty, id, sysid, isis); } + return CMD_SUCCESS; + } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) { + if (id_to_sysid(isis, id, sysid)) { + vty_out(vty, "Invalid system id %s\n", id); + return CMD_SUCCESS; + } + isis_neighbor_common_clear(vty, id, sysid, isis); } return CMD_SUCCESS; @@ -2234,17 +2246,16 @@ DEFUN (show_hostname, struct isis *isis; ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - dynhn_print_all(vty, isis); - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) dynhn_print_all(vty, isis); + + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + dynhn_print_all(vty, isis); return CMD_SUCCESS; } @@ -2307,17 +2318,15 @@ DEFUN(show_isis_spf_ietf, show_isis_spf_ietf_cmd, return CMD_SUCCESS; } - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - isis_spf_ietf_common(vty, isis); - - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) isis_spf_ietf_common(vty, isis); + + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + isis_spf_ietf_common(vty, isis); return CMD_SUCCESS; } @@ -2596,17 +2605,16 @@ DEFUN(show_isis_summary, show_isis_summary_cmd, } if (uj) json = json_object_new_object(); - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - common_isis_summary(vty, json, isis); - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis != NULL) + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) common_isis_summary(vty, json, isis); + + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis != NULL) + common_isis_summary(vty, json, isis); if (uj) vty_json(vty, json); @@ -2679,8 +2687,10 @@ void show_isis_database_lspdb_json(struct json_object *json, struct lspdb_head *lspdb, const char *sysid_str, int ui_level) { + struct json_object *array_json, *lsp_json; struct isis_lsp *lsp; int lsp_count; + struct json_object *lsp_arr_json; if (lspdb_count(lspdb) > 0) { lsp = lsp_for_sysid(lspdb, sysid_str, area->isis); @@ -2690,16 +2700,27 @@ void show_isis_database_lspdb_json(struct json_object *json, } if (lsp) { + json_object_object_get_ex(json, "lsps", &array_json); + if (!array_json) { + array_json = json_object_new_array(); + json_object_object_add(json, "lsps", array_json); + } + lsp_json = json_object_new_object(); + json_object_array_add(array_json, lsp_json); + if (ui_level == ISIS_UI_LEVEL_DETAIL) - lsp_print_detail(lsp, NULL, json, + lsp_print_detail(lsp, NULL, lsp_json, area->dynhostname, area->isis); else - lsp_print_json(lsp, json, area->dynhostname, + lsp_print_json(lsp, lsp_json, area->dynhostname, area->isis); } else if (sysid_str == NULL) { - lsp_count = - lsp_print_all(NULL, json, lspdb, ui_level, - area->dynhostname, area->isis); + lsp_arr_json = json_object_new_array(); + json_object_object_add(json, "lsps", lsp_arr_json); + + lsp_count = lsp_print_all(NULL, lsp_arr_json, lspdb, + ui_level, area->dynhostname, + area->isis); json_object_int_add(json, "count", lsp_count); } @@ -2765,6 +2786,8 @@ static void show_isis_database_json(struct json_object *json, const char *sysid_ json_object_object_add(area_json,"area",tag_area_json); json_object_object_add(area_json,"levels",arr_json); for (level = 0; level < ISIS_LEVELS; level++) { + if (lspdb_count(&area->lspdb[level]) == 0) + continue; lsp_json = json_object_new_object(); show_isis_database_lspdb_json(lsp_json, area, level, &area->lspdb[level], @@ -2828,19 +2851,16 @@ static int show_isis_database(struct vty *vty, struct json_object *json, const c struct listnode *node; struct isis *isis; - if (vrf_name) { - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) - show_isis_database_common(vty, json, sysid_str, - ui_level, isis); - - return CMD_SUCCESS; - } - isis = isis_lookup_by_vrfname(vrf_name); - if (isis) + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) show_isis_database_common(vty, json, sysid_str, ui_level, isis); + + return CMD_SUCCESS; } + isis = isis_lookup_by_vrfname(vrf_name); + if (isis) + show_isis_database_common(vty, json, sysid_str, ui_level, isis); return CMD_SUCCESS; } @@ -3345,36 +3365,20 @@ void isis_area_advertise_high_metrics_set(struct isis_area *area, } } -/* - * Returns the path of the file (non-volatile memory) that contains restart - * information. - */ -char *isis_restart_filepath(void) -{ - static char filepath[MAXPATHLEN]; - snprintf(filepath, sizeof(filepath), ISISD_RESTART, ""); - return filepath; -} - /* * Record in non-volatile memory the overload on startup time. */ void isis_restart_write_overload_time(struct isis_area *isis_area, uint32_t overload_time) { - char *filepath; const char *area_name; json_object *json; json_object *json_areas; json_object *json_area; - filepath = isis_restart_filepath(); + json = frr_daemon_state_load(); area_name = isis_area->area_tag; - json = json_object_from_file(filepath); - if (json == NULL) - json = json_object_new_object(); - json_object_object_get_ex(json, "areas", &json_areas); if (!json_areas) { json_areas = json_object_new_object(); @@ -3389,8 +3393,8 @@ void isis_restart_write_overload_time(struct isis_area *isis_area, json_object_int_add(json_area, "overload_time", isis_area->overload_on_startup_time); - json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY); - json_object_free(json); + + frr_daemon_state_save(&json); } /* @@ -3398,7 +3402,6 @@ void isis_restart_write_overload_time(struct isis_area *isis_area, */ uint32_t isis_restart_read_overload_time(struct isis_area *isis_area) { - char *filepath; const char *area_name; json_object *json; json_object *json_areas; @@ -3406,12 +3409,9 @@ uint32_t isis_restart_read_overload_time(struct isis_area *isis_area) json_object *json_overload_time; uint32_t overload_time = 0; - filepath = isis_restart_filepath(); area_name = isis_area->area_tag; - json = json_object_from_file(filepath); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "areas", &json_areas); if (!json_areas) { @@ -3433,8 +3433,7 @@ uint32_t isis_restart_read_overload_time(struct isis_area *isis_area) json_object_object_del(json_areas, area_name); - json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); return overload_time; } diff --git a/isisd/isisd.h b/isisd/isisd.h index f5042e4ad5c2..1ae39f0ae95a 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -268,6 +268,7 @@ DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area)); void isis_terminate(void); void isis_master_init(struct event_loop *master); +void isis_master_terminate(void); void isis_vrf_link(struct isis *isis, struct vrf *vrf); void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id); @@ -285,10 +286,12 @@ void isis_area_add_circuit(struct isis_area *area, void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit); +void isis_area_address_delete(void *arg); struct isis_area *isis_area_create(const char *, const char *); struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id); struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, const char *vrf_name); +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid); int isis_area_get(struct vty *vty, const char *area_tag); void isis_area_destroy(struct isis_area *area); void isis_filter_update(struct access_list *access); diff --git a/isisd/subdir.am b/isisd/subdir.am index 3e7d9a90ecec..e33cb7655065 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -98,7 +98,7 @@ ISIS_SOURCES = \ isisd/isis_pfpacket.c \ # end -ISIS_LDADD_COMMON = lib/libfrr.la $(LIBCAP) +ISIS_LDADD_COMMON = lib/libfrr.la $(LIBCAP) $(LIBYANG_LIBS) # Building isisd diff --git a/ldpd/control.c b/ldpd/control.c index db52d4632539..a08ce4cc1a61 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -6,6 +6,7 @@ */ #include +#include #include #include "ldpd.h" diff --git a/ldpd/init.c b/ldpd/init.c index f0cb98e5c03e..ef782471b8db 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -229,9 +229,11 @@ send_capability(struct nbr *nbr, uint16_t capability, int enable) * Announcement Parameter in Capability messages sent to * its peers". */ - /* FALLTHROUGH */ + fatalx("send_capability: An LDP speaker MUST NOT include the Dynamic Capability Announcement Parameter"); + break; default: fatalx("send_capability: unsupported capability"); + break; } if (err) { @@ -333,7 +335,7 @@ recv_capability(struct nbr *nbr, char *buf, uint16_t len) * parameter and process any other Capability Parameters * in the message". */ - /* FALLTHROUGH */ + fallthrough; default: if (!CHECK_FLAG(ntohs(tlv.type), UNKNOWN_FLAG)) send_notification_rtlvs(nbr, S_UNSSUPORTDCAP, diff --git a/ldpd/lde.c b/ldpd/lde.c index c7e915deb332..876dd4163099 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -28,6 +28,7 @@ #include "stream.h" #include "network.h" #include "libfrr.h" +#include "zlog_live.h" static void lde_shutdown(void); static void lde_dispatch_imsg(struct event *thread); @@ -116,6 +117,8 @@ static struct frr_signal_t lde_signals[] = void lde(void) { + static struct zlog_live_cfg child_log; + #ifdef HAVE_SETPROCTITLE setproctitle("label decision engine"); #endif @@ -123,6 +126,8 @@ lde(void) log_procname = log_procnames[PROC_LDE_ENGINE]; master = frr_init(); + zlog_live_open_fd(&child_log, LOG_DEBUG, LDPD_FD_LOG); + /* no frr_config_fork() here, allow frr_pthread to create threads */ frr_is_after_fork = true; @@ -2135,12 +2140,8 @@ static void zclient_sync_retry(struct event *thread) */ static void zclient_sync_init(void) { - struct zclient_options options = zclient_options_default; - - options.synchronous = true; - /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_LDP; zclient_sync->session_id = 1; /* Distinguish from main session */ diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 33cf93cb266f..1f0fdb560fca 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -12,6 +12,12 @@ #ifndef _LDP_H_ #define _LDP_H_ +/* this does not include "%s/", frr_runstatedir because the command-line + * override option specifies a *directory* rather than a full file name. + * Therefore the final part is needed on its own. + */ +#define LDPD_SOCK_NAME "ldpd.sock" + /* misc */ #define LDP_VERSION 1 #define LDP_PORT 646 diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index 906b5c1bf29c..f3bcd1b254c8 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -1106,7 +1106,7 @@ show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_params *params) if (params->lib.remote_label != NO_LABEL && params->lib.remote_label != rt->remote_label) return (0); - /* FALLTHROUGH */ + fallthrough; case IMSG_CTL_SHOW_LIB_RCVD: rt = imsg->data; diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 0fd5d4613c08..df682a1347be 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -330,7 +330,6 @@ void kif_redistribute(const char *ifname) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - struct listnode *cnode; struct interface *ifp; struct connected *ifc; struct kif kif; @@ -343,7 +342,7 @@ kif_redistribute(const char *ifname) ifp2kif(ifp, &kif); main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { ifc2kaddr(ifp, ifc, &ka); main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka)); } @@ -400,7 +399,6 @@ ldp_ifp_destroy(struct interface *ifp) static int ldp_interface_status_change(struct interface *ifp) { - struct listnode *node; struct connected *ifc; struct kif kif; struct kaddr ka; @@ -411,12 +409,12 @@ ldp_interface_status_change(struct interface *ifp) main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif)); if (if_is_operative(ifp)) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { ifc2kaddr(ifp, ifc, &ka); main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka)); } } else { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { ifc2kaddr(ifp, ifc, &ka); main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka)); } @@ -682,7 +680,10 @@ static zclient_handler *const ldp_handlers[] = { void ldp_zebra_init(struct event_loop *master) { - if_zapi_callbacks(ldp_ifp_create, ldp_ifp_up, ldp_ifp_down, ldp_ifp_destroy); + hook_register_prio(if_real, 0, ldp_ifp_create); + hook_register_prio(if_up, 0, ldp_ifp_up); + hook_register_prio(if_down, 0, ldp_ifp_down); + hook_register_prio(if_unreal, 0, ldp_ifp_destroy); /* Set default values. */ zclient = zclient_new(master, &zclient_options_default, ldp_handlers, diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 3c616d4a8c8b..4d38fdcd02c9 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -9,6 +9,9 @@ */ #include + +#include +#include #include #include "ldpd.h" @@ -32,9 +35,11 @@ #include "qobj.h" #include "libfrr.h" #include "lib_errors.h" +#include "zlog_recirculate.h" +#include "libagentx.h" static void ldpd_shutdown(void); -static pid_t start_child(enum ldpd_process, char *, int, int); +static pid_t start_child(enum ldpd_process, char *, int, int, int); static void main_dispatch_ldpe(struct event *thread); static void main_dispatch_lde(struct event *thread); static int main_imsg_send_ipc_sockets(struct imsgbuf *, @@ -66,6 +71,8 @@ DEFINE_QOBJ_TYPE(l2vpn_pw); DEFINE_QOBJ_TYPE(l2vpn); DEFINE_QOBJ_TYPE(ldpd_conf); +const char *log_procname; + struct ldpd_global global; struct ldpd_init init; struct ldpd_conf *ldpd_conf, *vty_conf; @@ -101,7 +108,6 @@ void ldp_agentx_enabled(void) enum ldpd_process ldpd_process; #define LDP_DEFAULT_CONFIG "ldpd.conf" -#define LDP_VTY_PORT 2612 /* Master of threads. */ struct event_loop *master; @@ -194,6 +200,7 @@ static const struct frr_yang_module_info *const ldpd_yang_modules[] = { &frr_vrf_info, }; +/* clang-format off */ FRR_DAEMON_INFO(ldpd, LDP, .vty_port = LDP_VTY_PORT, @@ -207,6 +214,7 @@ FRR_DAEMON_INFO(ldpd, LDP, .yang_modules = ldpd_yang_modules, .n_yang_modules = array_size(ldpd_yang_modules), ); +/* clang-format on */ static void ldp_config_fork_apply(struct event *t) { @@ -227,14 +235,14 @@ main(int argc, char *argv[]) { char *saved_argv0; int lflag = 0, eflag = 0; - int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2]; - int pipe_parent2lde[2], pipe_parent2lde_sync[2]; - char *ctl_sock_name; + int pipe_parent2ldpe[2]; + int pipe_parent2ldpe_sync[2]; + int pipe_ldpe_log[2]; + int pipe_parent2lde[2]; + int pipe_parent2lde_sync[2]; + int pipe_lde_log[2]; bool ctl_sock_used = false; - snprintf(ctl_sock_path, sizeof(ctl_sock_path), LDPD_SOCKET, - "", ""); - ldpd_process = PROC_MAIN; log_procname = log_procnames[ldpd_process]; @@ -260,21 +268,8 @@ main(int argc, char *argv[]) break; case OPTION_CTLSOCK: ctl_sock_used = true; - ctl_sock_name = strrchr(LDPD_SOCKET, '/'); - if (ctl_sock_name) - /* skip '/' */ - ctl_sock_name++; - else - /* - * LDPD_SOCKET configured as relative path - * during config? Should really never happen for - * sensible config - */ - ctl_sock_name = (char *)LDPD_SOCKET; - strlcpy(ctl_sock_path, optarg, sizeof(ctl_sock_path)); - strlcat(ctl_sock_path, "/", sizeof(ctl_sock_path)); - strlcat(ctl_sock_path, ctl_sock_name, - sizeof(ctl_sock_path)); + snprintf(ctl_sock_path, sizeof(ctl_sock_path), + "%s/" LDPD_SOCK_NAME, optarg); break; case 'n': init.instance = atoi(optarg); @@ -292,9 +287,9 @@ main(int argc, char *argv[]) } } - if (ldpd_di.pathspace && !ctl_sock_used) - snprintf(ctl_sock_path, sizeof(ctl_sock_path), LDPD_SOCKET, - "/", ldpd_di.pathspace); + if (!ctl_sock_used) + snprintf(ctl_sock_path, sizeof(ctl_sock_path), + "%s/" LDPD_SOCK_NAME, frr_runstatedir); strlcpy(init.user, ldpd_privs.user, sizeof(init.user)); strlcpy(init.group, ldpd_privs.group, sizeof(init.group)); @@ -313,15 +308,6 @@ main(int argc, char *argv[]) exit(1); } - if (lflag || eflag) { - struct zprivs_ids_t ids; - - zprivs_preinit(&ldpd_privs); - zprivs_get_ids(&ids); - - zlog_init(ldpd_di.progname, "LDP", 0, - ids.uid_normal, ids.gid_normal); - } if (lflag) lde(); else if (eflag) @@ -334,6 +320,9 @@ main(int argc, char *argv[]) pipe_parent2ldpe_sync) == -1) fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pipe_ldpe_log) == -1) + fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1) fatal("socketpair"); @@ -341,6 +330,9 @@ main(int argc, char *argv[]) pipe_parent2lde_sync) == -1) fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, pipe_lde_log) == -1) + fatal("socketpair"); + sock_set_nonblock(pipe_parent2ldpe[0]); sock_set_cloexec(pipe_parent2ldpe[0]); sock_set_nonblock(pipe_parent2ldpe[1]); @@ -348,6 +340,11 @@ main(int argc, char *argv[]) sock_set_nonblock(pipe_parent2ldpe_sync[0]); sock_set_cloexec(pipe_parent2ldpe_sync[0]); sock_set_cloexec(pipe_parent2ldpe_sync[1]); + sock_set_nonblock(pipe_ldpe_log[0]); + sock_set_cloexec(pipe_ldpe_log[0]); + sock_set_nonblock(pipe_ldpe_log[1]); + sock_set_cloexec(pipe_ldpe_log[1]); + sock_set_nonblock(pipe_parent2lde[0]); sock_set_cloexec(pipe_parent2lde[0]); sock_set_nonblock(pipe_parent2lde[1]); @@ -355,15 +352,26 @@ main(int argc, char *argv[]) sock_set_nonblock(pipe_parent2lde_sync[0]); sock_set_cloexec(pipe_parent2lde_sync[0]); sock_set_cloexec(pipe_parent2lde_sync[1]); + sock_set_nonblock(pipe_lde_log[0]); + sock_set_cloexec(pipe_lde_log[0]); + sock_set_nonblock(pipe_lde_log[1]); + sock_set_cloexec(pipe_lde_log[1]); /* start children */ lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0, - pipe_parent2lde[1], pipe_parent2lde_sync[1]); + pipe_parent2lde[1], pipe_parent2lde_sync[1], pipe_lde_log[1]); ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0, - pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1]); + pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1], pipe_ldpe_log[1]); master = frr_init(); + /* The two child processes use the zlog_live backend to send their + * messages here, where the actual logging config is then applied. + * Look for zlog_live_open_fd() to find the other end of this. + */ + zlog_recirculate_subscribe(master, pipe_lde_log[0]); + zlog_recirculate_subscribe(master, pipe_ldpe_log[0]); + libagentx_init(); vrf_init(NULL, NULL, NULL, NULL); access_list_init(); ldp_vty_init(); @@ -497,7 +505,8 @@ ldpd_shutdown(void) } static pid_t -start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync) +start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync, + int fd_log) { char *argv[7]; int argc = 0, nullfd; @@ -512,6 +521,7 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync) default: close(fd_async); close(fd_sync); + close(fd_log); return (pid); } @@ -533,6 +543,9 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync) if (dup2(fd_sync, LDPD_FD_SYNC) == -1) fatal("cannot setup imsg sync fd"); + if (dup2(fd_log, LDPD_FD_LOG) == -1) + fatal("cannot setup zlog fd"); + argv[argc++] = argv0; switch (p) { case PROC_MAIN: @@ -582,9 +595,6 @@ static void main_dispatch_ldpe(struct event *thread) break; switch (imsg.hdr.type) { - case IMSG_LOG: - logit(imsg.hdr.pid, "%s", (const char *)imsg.data); - break; case IMSG_REQUEST_SOCKETS: af = imsg.hdr.pid; main_imsg_send_net_sockets(af); @@ -650,9 +660,6 @@ static void main_dispatch_lde(struct event *thread) break; switch (imsg.hdr.type) { - case IMSG_LOG: - logit(imsg.hdr.pid, "%s", (const char *)imsg.data); - break; case IMSG_KLABEL_CHANGE: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct kroute)) diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 1fec5beafc7a..ad831a6ea358 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -30,6 +30,7 @@ #define LDPD_FD_ASYNC 3 #define LDPD_FD_SYNC 4 +#define LDPD_FD_LOG 5 #define LDPD_OPT_VERBOSE 0x00000001 #define LDPD_OPT_VERBOSE2 0x00000002 @@ -139,7 +140,6 @@ enum imsg_type { IMSG_RECONF_L2VPN_IPW, IMSG_RECONF_END, IMSG_DEBUG_UPDATE, - IMSG_LOG, IMSG_ACL_CHECK, IMSG_INIT, IMSG_PW_UPDATE, @@ -341,7 +341,7 @@ struct iface_ldp_sync { struct iface { RB_ENTRY(iface) entry; - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; ifindex_t ifindex; struct if_addr_head addr_list; struct in6_addr linklocal; @@ -447,7 +447,7 @@ struct ldp_entity_stats { struct l2vpn_if { RB_ENTRY(l2vpn_if) entry; struct l2vpn *l2vpn; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int operative; uint8_t mac[ETH_ALEN]; @@ -464,7 +464,7 @@ struct l2vpn_pw { int af; union ldpd_addr addr; uint32_t pwid; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; bool enabled; uint32_t remote_group; @@ -496,7 +496,7 @@ struct l2vpn { int type; int pw_type; int mtu; - char br_ifname[INTERFACE_NAMSIZ]; + char br_ifname[IFNAMSIZ]; ifindex_t br_ifindex; struct l2vpn_if_head if_tree; struct l2vpn_pw_head pw_tree; @@ -618,7 +618,7 @@ struct kroute { }; struct kaddr { - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int af; union ldpd_addr addr; @@ -627,7 +627,7 @@ struct kaddr { }; struct kif { - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int flags; int operative; @@ -645,7 +645,7 @@ struct acl_check { /* control data structures */ struct ctl_iface { int af; - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; ifindex_t ifindex; int state; enum iface_type type; @@ -656,7 +656,7 @@ struct ctl_iface { }; struct ctl_disc_if { - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; int active_v4; int active_v6; int no_adj; @@ -672,7 +672,7 @@ struct ctl_adj { int af; struct in_addr id; enum hello_type type; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; union ldpd_addr src_addr; uint16_t holdtime; uint16_t holdtime_remaining; @@ -712,7 +712,7 @@ struct ctl_rt { struct ctl_pw { uint16_t type; char l2vpn_name[L2VPN_NAME_LEN]; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; uint32_t pwid; struct in_addr lsr_id; uint32_t local_label; @@ -728,7 +728,7 @@ struct ctl_pw { }; struct ctl_ldp_sync { - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; ifindex_t ifindex; bool in_sync; bool timer_running; diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index e66b9e92dd43..6e844c0aa18d 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -23,6 +23,7 @@ #include "privs.h" #include "sigevent.h" #include "libfrr.h" +#include "zlog_live.h" static void ldpe_shutdown(void); static void ldpe_dispatch_main(struct event *thread); @@ -93,6 +94,8 @@ char *pkt_ptr; /* packet buffer */ void ldpe(void) { + static struct zlog_live_cfg child_log; + #ifdef HAVE_SETPROCTITLE setproctitle("ldp engine"); #endif @@ -100,6 +103,8 @@ ldpe(void) log_procname = log_procnames[ldpd_process]; master = frr_init(); + zlog_live_open_fd(&child_log, LOG_DEBUG, LDPD_FD_LOG); + /* no frr_config_fork() here, allow frr_pthread to create threads */ frr_is_after_fork = true; diff --git a/ldpd/log.c b/ldpd/log.c deleted file mode 100644 index 7c4d782dcfaa..000000000000 --- a/ldpd/log.c +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: ISC -/* $OpenBSD$ */ - -/* - * Copyright (c) 2003, 2004 Henning Brauer - */ - -#include - -#include "ldpd.h" -#include "ldpe.h" -#include "lde.h" -#include "log.h" -#include "printfrr.h" - -#include - -const char *log_procname; - -void -logit(int pri, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vlog(pri, fmt, ap); - va_end(ap); -} - -void -vlog(int pri, const char *fmt, va_list ap) -{ - char buf[1024]; - - switch (ldpd_process) { - case PROC_LDE_ENGINE: - vsnprintfrr(buf, sizeof(buf), fmt, ap); - lde_imsg_compose_parent_sync(IMSG_LOG, pri, buf, strlen(buf) + 1); - break; - case PROC_LDP_ENGINE: - vsnprintfrr(buf, sizeof(buf), fmt, ap); - ldpe_imsg_compose_parent_sync(IMSG_LOG, pri, buf, strlen(buf) + 1); - break; - case PROC_MAIN: - vzlog(pri, fmt, ap); - break; - } -} - -void -log_warn(const char *emsg, ...) -{ - char *nfmt; - va_list ap; - - /* best effort to even work in out of memory situations */ - if (emsg == NULL) - logit(LOG_ERR, "%s", strerror(errno)); - else { - va_start(ap, emsg); - - if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { - /* we tried it... */ - vlog(LOG_ERR, emsg, ap); - logit(LOG_ERR, "%s", strerror(errno)); - } else { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat-nonliteral" - /* format extended above */ - vlog(LOG_ERR, nfmt, ap); -#pragma GCC diagnostic pop - free(nfmt); - } - va_end(ap); - } -} - -void -log_warnx(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vlog(LOG_ERR, emsg, ap); - va_end(ap); -} - -void -log_info(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vlog(LOG_INFO, emsg, ap); - va_end(ap); -} - -void -log_notice(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vlog(LOG_NOTICE, emsg, ap); - va_end(ap); -} - -void -log_debug(const char *emsg, ...) -{ - va_list ap; - - va_start(ap, emsg); - vlog(LOG_DEBUG, emsg, ap); - va_end(ap); -} - -void -fatal(const char *emsg) -{ - if (emsg == NULL) - logit(LOG_CRIT, "fatal in %s: %s", log_procname, strerror(errno)); - else - if (errno) - logit(LOG_CRIT, "fatal in %s: %s: %s", - log_procname, emsg, strerror(errno)); - else - logit(LOG_CRIT, "fatal in %s: %s", log_procname, emsg); - - exit(1); -} - -void -fatalx(const char *emsg) -{ - errno = 0; - fatal(emsg); -} diff --git a/ldpd/log.h b/ldpd/log.h index 641ad8ac5edb..aa6f700608a7 100644 --- a/ldpd/log.h +++ b/ldpd/log.h @@ -8,29 +8,30 @@ #ifndef LOG_H #define LOG_H -#include +#include "log.h" +#include "assert.h" extern const char *log_procname; -void logit(int, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void vlog(int, const char *, va_list) - __attribute__((__format__ (printf, 2, 0))); -void log_warn(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_warnx(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_info(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_notice(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_debug(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void fatal(const char *) - __attribute__ ((noreturn)) - __attribute__((__format__ (printf, 1, 0))); -void fatalx(const char *) - __attribute__ ((noreturn)) - __attribute__((__format__ (printf, 1, 0))); +#define log_warnx zlog_err /* yes this is poorly named */ +#define log_warn zlog_warn +#define log_info zlog_info +#define log_notice zlog_notice /* not used anywhere */ +#define log_debug zlog_debug + +#define fatal(msg) \ + do { \ + assertf(0, "fatal in %s: %pSQq (%m)", log_procname, \ + (const char *)msg); \ + __builtin_unreachable(); \ + } while (0) \ + /* end */ +#define fatalx(msg) \ + do { \ + assertf(0, "fatal in %s: %pSQq", log_procname, \ + (const char *)msg); \ + __builtin_unreachable(); \ + } while (0) \ + /* end */ #endif /* LOG_H */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index 5209c55bb854..2596c7948116 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -505,21 +505,12 @@ nbr_start_idtimer(struct nbr *nbr) { int secs; - secs = INIT_DELAY_TMR; - switch(nbr->idtimer_cnt) { - default: + if (nbr->idtimer_cnt > 2) { /* do not further increase the counter */ secs = MAX_DELAY_TMR; - break; - case 2: - secs *= 2; - /* FALLTHROUGH */ - case 1: - secs *= 2; - /* FALLTHROUGH */ - case 0: + } else { + secs = INIT_DELAY_TMR * (1 << nbr->idtimer_cnt); nbr->idtimer_cnt++; - break; } EVENT_OFF(nbr->initdelay_timer); @@ -690,6 +681,18 @@ nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp) if (nbrp && CHECK_FLAG(nbrp->flags, F_NBRP_GTSM_HOPS)) ttl = 256 - nbrp->gtsm_hops; + /* + * In linux networking stack, the received mpls packets + * will be processed by the host twice, one as mpls packet, + * the other as ip packet, so its ttl will be decreased 1. + * This behavior is based on the new kernel (5.10 and 6.1), + * and older versions may behave differently. + * + * Here, decrease 1 for IP_MINTTL if GTSM is enabled. + * And this workaround makes the GTSM mechanism a bit deviation. + */ + ttl -= 1; + switch (af) { case AF_INET: if (sock_set_ipv4_minttl(fd, ttl) == -1) diff --git a/ldpd/socket.c b/ldpd/socket.c index 6b7e475d7f62..71d5c21753f3 100644 --- a/ldpd/socket.c +++ b/ldpd/socket.c @@ -9,6 +9,7 @@ */ #include +#include #include "ldpd.h" #include "ldpe.h" diff --git a/ldpd/subdir.am b/ldpd/subdir.am index 0b948adb6fc2..ad5933fec363 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -28,7 +28,6 @@ ldpd_libldp_a_SOURCES = \ ldpd/ldp_vty_exec.c \ ldpd/ldp_zebra.c \ ldpd/ldpe.c \ - ldpd/log.c \ ldpd/logmsg.c \ ldpd/neighbor.c \ ldpd/notification.c \ diff --git a/lib/.gitignore b/lib/.gitignore index 6176b30f8d2f..1c9314bf0d65 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,3 +1,4 @@ +/config_paths.h /version.c /version.h /gitversion.h @@ -11,3 +12,4 @@ /grammar_sandbox /clippy /defun_lex.c +vtysh_daemons.h diff --git a/lib/affinitymap.c b/lib/affinitymap.c index 17e1b2cc0169..6ff8e83f91a0 100644 --- a/lib/affinitymap.c +++ b/lib/affinitymap.c @@ -41,13 +41,11 @@ #include "jhash.h" DEFINE_MTYPE_STATIC(LIB, AFFINITY_MAP, "Affinity map"); -DEFINE_MTYPE(LIB, AFFINITY_MAP_NAME, "Affinity map name"); -DEFINE_MTYPE_STATIC(LIB, AFFINITY_MAP_INDEX, "Affinity map index"); DEFINE_QOBJ_TYPE(affinity_maps); DEFINE_QOBJ_TYPE(affinity_map); -struct affinity_maps affinity_map_master = {NULL, NULL, NULL, NULL}; +struct affinity_maps affinity_map_master = {NULL, NULL}; static void affinity_map_free(struct affinity_map *map) { @@ -106,36 +104,6 @@ struct affinity_map *affinity_map_get(const char *name) return NULL; } - -char *affinity_map_name_get(int pos) -{ - struct listnode *node; - struct affinity_map *map; - - if (!affinity_map_master.maps) - return NULL; - - for (ALL_LIST_ELEMENTS_RO(affinity_map_master.maps, node, map)) - if (map->bit_position == pos) - return map->name; - return NULL; -} - -bool affinity_map_check_use_hook(const char *affmap_name) -{ - if (affinity_map_master.check_use_hook) - return (*affinity_map_master.check_use_hook)(affmap_name); - return false; -} - -bool affinity_map_check_update_hook(const char *affmap_name, uint16_t new_pos) -{ - if (affinity_map_master.check_update_hook) - return (*affinity_map_master.check_update_hook)(affmap_name, - new_pos); - return true; -} - void affinity_map_update_hook(const char *affmap_name, uint16_t new_pos) { struct affinity_map *map; @@ -153,18 +121,6 @@ void affinity_map_update_hook(const char *affmap_name, uint16_t new_pos) new_pos); } - -void affinity_map_set_check_use_hook(bool (*func)(const char *affmap_name)) -{ - affinity_map_master.check_use_hook = func; -} - -void affinity_map_set_check_update_hook(bool (*func)(const char *affmap_name, - uint16_t new_pos)) -{ - affinity_map_master.check_update_hook = func; -} - void affinity_map_set_update_hook(void (*func)(const char *affmap_name, uint16_t old_pos, uint16_t new_pos)) diff --git a/lib/affinitymap.h b/lib/affinitymap.h index 19edf5a269ea..ebe2659bf7fc 100644 --- a/lib/affinitymap.h +++ b/lib/affinitymap.h @@ -50,8 +50,6 @@ DECLARE_QOBJ_TYPE(affinity_map); struct affinity_maps { struct list *maps; - bool (*check_use_hook)(const char *affmap_name); - bool (*check_update_hook)(const char *affmap_name, uint16_t new_pos); void (*update_hook)(const char *affmap_name, uint16_t old_pos, uint16_t new_pos); @@ -60,26 +58,18 @@ struct affinity_maps { DECLARE_QOBJ_TYPE(affinity_maps); extern const struct frr_yang_module_info frr_affinity_map_info; +extern const struct frr_yang_module_info frr_affinity_map_cli_info; void affinity_map_set(const char *name, int pos); void affinity_map_unset(const char *name); struct affinity_map *affinity_map_get(const char *name); -char *affinity_map_name_get(const int pos); -bool affinity_map_check_use_hook(const char *affmap_name); -bool affinity_map_check_update_hook(const char *affmap_name, uint16_t new_pos); void affinity_map_update_hook(const char *affmap_name, uint16_t new_pos); -void affinity_map_set_check_use_hook(bool (*func)(const char *affmap_name)); -void affinity_map_set_check_update_hook(bool (*func)(const char *affmap_name, - uint16_t new_pos)); void affinity_map_set_update_hook(void (*func)(const char *affmap_name, uint16_t old_pos, uint16_t new_pos)); -void cli_show_affinity_map(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults); - void affinity_map_init(void); diff --git a/lib/affinitymap_cli.c b/lib/affinitymap_cli.c index a2d5e8eccf4e..73b91e775b7f 100644 --- a/lib/affinitymap_cli.c +++ b/lib/affinitymap_cli.c @@ -30,15 +30,6 @@ #include "lib/affinitymap.h" #include "lib/affinitymap_cli_clippy.c" -/* Route map node structure. */ -static int affinity_map_config_write(struct vty *vty); -static struct cmd_node affinitymap_node = { - .name = "affinity-map", - .node = AFFMAP_NODE, - .prompt = "", - .config_write = affinity_map_config_write, -}; - /* max value is EXT_ADMIN_GROUP_MAX_POSITIONS - 1 */ DEFPY_YANG_NOSH(affinity_map, affinity_map_cmd, "affinity-map NAME$name bit-position (0-1023)$position", @@ -75,33 +66,32 @@ DEFPY_YANG_NOSH(no_affinity_map, no_affinity_map_cmd, return nb_cli_apply_changes(vty, NULL); } -static int affinity_map_config_write(struct vty *vty) -{ - const struct lyd_node *dnode; - int written = 0; - - dnode = yang_dnode_get(running_config->dnode, "/frr-affinity-map:lib"); - if (dnode) { - nb_cli_show_dnode_cmds(vty, dnode, false); - written = 1; - } - - return written; -} - -void cli_show_affinity_map(struct vty *vty, const struct lyd_node *dnode, +static void cli_show_affinity_map(struct vty *vty, const struct lyd_node *dnode, bool show_defaults __attribute__((__unused__))) { vty_out(vty, "affinity-map %s bit-position %u\n", - yang_dnode_get_string(dnode, "./name"), - yang_dnode_get_uint16(dnode, "./value")); + yang_dnode_get_string(dnode, "name"), + yang_dnode_get_uint16(dnode, "value")); } +const struct frr_yang_module_info frr_affinity_map_cli_info = { + .name = "frr-affinity-map", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-affinity-map:lib/affinity-maps/affinity-map", + .cbs.cli_show = cli_show_affinity_map, + }, + { + .xpath = NULL, + }, + } +}; + /* Initialization of affinity map vector. */ void affinity_map_init(void) { /* CLI commands. */ - install_node(&affinitymap_node); install_element(CONFIG_NODE, &affinity_map_cmd); install_element(CONFIG_NODE, &no_affinity_map_cmd); } diff --git a/lib/affinitymap_northbound.c b/lib/affinitymap_northbound.c index 331075f5c111..003e0c11b939 100644 --- a/lib/affinitymap_northbound.c +++ b/lib/affinitymap_northbound.c @@ -47,11 +47,6 @@ static int lib_affinity_map_destroy(struct nb_cb_destroy_args *args) switch (args->event) { case NB_EV_VALIDATE: - if (!affinity_map_check_use_hook(name)) - break; - snprintf(args->errmsg, args->errmsg_len, - "affinity-map %s is used", name); - return NB_ERR_VALIDATION; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -68,7 +63,6 @@ static int lib_affinity_map_destroy(struct nb_cb_destroy_args *args) static int lib_affinity_map_value_modify(struct nb_cb_modify_args *args) { const char *name; - char *map_name; uint16_t pos; name = yang_dnode_get_string( @@ -79,20 +73,6 @@ static int lib_affinity_map_value_modify(struct nb_cb_modify_args *args) switch (args->event) { case NB_EV_VALIDATE: - map_name = affinity_map_name_get(pos); - if (map_name && - strncmp(map_name, name, AFFINITY_NAME_SIZE) != 0) { - snprintf(args->errmsg, args->errmsg_len, - "bit-position is used by %s.", map_name); - return NB_ERR_VALIDATION; - } - if (!affinity_map_check_update_hook(name, pos)) { - snprintf( - args->errmsg, args->errmsg_len, - "affinity-map new bit-position > 31 but is used with standard admin-groups"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -105,11 +85,6 @@ static int lib_affinity_map_value_modify(struct nb_cb_modify_args *args) return NB_OK; } -static int lib_affinity_map_value_destroy(struct nb_cb_destroy_args *args) -{ - return NB_OK; -} - /* clang-format off */ const struct frr_yang_module_info frr_affinity_map_info = { .name = "frr-affinity-map", @@ -119,14 +94,13 @@ const struct frr_yang_module_info frr_affinity_map_info = { .cbs = { .create = lib_affinity_map_create, .destroy = lib_affinity_map_destroy, - .cli_show = cli_show_affinity_map, - } + }, + .priority = NB_DFLT_PRIORITY - 1, }, { .xpath = "/frr-affinity-map:lib/affinity-maps/affinity-map/value", .cbs = { .modify = lib_affinity_map_value_modify, - .destroy = lib_affinity_map_value_destroy, } }, { diff --git a/lib/agentx.c b/lib/agentx.c index 45f14c270393..2a3ff2355efb 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -4,12 +4,14 @@ */ #include +#include #ifdef SNMP_AGENTX #include #include #include #include +#include #include "command.h" #include "smux.h" @@ -20,12 +22,13 @@ #include "hook.h" #include "libfrr.h" #include "xref.h" +#include "lib/libagentx.h" XREF_SETUP(); DEFINE_HOOK(agentx_enabled, (), ()); -static bool agentx_enabled = false; +//bool agentx_enabled = false; static struct event_loop *agentx_tm; static struct event *timeout_thr = NULL; @@ -43,7 +46,7 @@ static void agentx_timeout(struct event *t) static void agentx_read(struct event *t) { - fd_set fds; + netsnmp_large_fd_set lfds; int flags, new_flags = 0; int nonblock = false; struct listnode *ln = EVENT_ARG(t); @@ -68,9 +71,9 @@ static void agentx_read(struct event *t) flog_err(EC_LIB_SYSTEM_CALL, "Failed to set snmp fd non blocking: %s(%d)", strerror(errno), errno); - FD_ZERO(&fds); - FD_SET(EVENT_FD(t), &fds); - snmp_read(&fds); + netsnmp_large_fd_set_init(&lfds, FD_SETSIZE); + netsnmp_large_fd_setfd(t->u.fd, &lfds); + snmp_read2(&lfds); /* Reset the flag */ if (!nonblock) { @@ -85,6 +88,7 @@ static void agentx_read(struct event *t) netsnmp_check_outstanding_agent_requests(); agentx_events_update(); + netsnmp_large_fd_set_cleanup(&lfds); } static void agentx_events_update(void) @@ -92,15 +96,15 @@ static void agentx_events_update(void) int maxfd = 0; int block = 1; struct timeval timeout = {.tv_sec = 0, .tv_usec = 0}; - fd_set fds; + netsnmp_large_fd_set lfds; struct listnode *ln; struct event **thr; int fd, thr_fd; event_cancel(&timeout_thr); - FD_ZERO(&fds); - snmp_select_info(&maxfd, &fds, &timeout, &block); + netsnmp_large_fd_set_init(&lfds, FD_SETSIZE); + snmp_select_info2(&maxfd, &lfds, &timeout, &block); if (!block) { event_add_timer_tv(agentx_tm, agentx_timeout, NULL, &timeout, @@ -118,7 +122,7 @@ static void agentx_events_update(void) /* caught up */ if (thr_fd == fd) { struct listnode *nextln = listnextnode(ln); - if (!FD_ISSET(fd, &fds)) { + if (!netsnmp_large_fd_is_set(fd, &lfds)) { event_cancel(thr); XFREE(MTYPE_TMP, thr); list_delete_node(events, ln); @@ -128,7 +132,7 @@ static void agentx_events_update(void) thr_fd = thr ? EVENT_FD(*thr) : -1; } /* need listener, but haven't hit one where it would be */ - else if (FD_ISSET(fd, &fds)) { + else if (netsnmp_large_fd_is_set(fd, &lfds)) { struct listnode *newln; thr = XCALLOC(MTYPE_TMP, sizeof(struct event *)); @@ -147,17 +151,9 @@ static void agentx_events_update(void) list_delete_node(events, ln); ln = nextln; } + netsnmp_large_fd_set_cleanup(&lfds); } -/* AgentX node. */ -static int config_write_agentx(struct vty *vty); -static struct cmd_node agentx_node = { - .name = "smux", - .node = SMUX_NODE, - .prompt = "", - .config_write = config_write_agentx, -}; - /* Logging NetSNMP messages */ static int agentx_log_callback(int major, int minor, void *serverarg, void *clientarg) @@ -197,17 +193,7 @@ static int agentx_log_callback(int major, int minor, void *serverarg, return SNMP_ERR_NOERROR; } -static int config_write_agentx(struct vty *vty) -{ - if (agentx_enabled) - vty_out(vty, "agentx\n"); - return 1; -} - -DEFUN (agentx_enable, - agentx_enable_cmd, - "agentx", - "SNMP AgentX protocol settings\n") +static int agentx_cli_on(void) { if (!agentx_enabled) { init_snmp(FRR_SMUX_NAME); @@ -217,19 +203,14 @@ DEFUN (agentx_enable, hook_call(agentx_enabled); } - return CMD_SUCCESS; + return 1; } -DEFUN (no_agentx, - no_agentx_cmd, - "no agentx", - NO_STR - "SNMP AgentX protocol settings\n") +static int agentx_cli_off(void) { if (!agentx_enabled) - return CMD_SUCCESS; - vty_out(vty, "SNMP AgentX support cannot be disabled once enabled\n"); - return CMD_WARNING_CONFIG_FAILED; + return 1; + return 0; } static int smux_disable(void) @@ -248,6 +229,9 @@ void smux_init(struct event_loop *tm) { agentx_tm = tm; + hook_register(agentx_cli_enabled, agentx_cli_on); + hook_register(agentx_cli_disabled, agentx_cli_off); + netsnmp_enable_subagent(); snmp_disable_log(); snmp_enable_calllog(); @@ -255,10 +239,6 @@ void smux_init(struct event_loop *tm) agentx_log_callback, NULL); init_agent(FRR_SMUX_NAME); - install_node(&agentx_node); - install_element(CONFIG_NODE, &agentx_enable_cmd); - install_element(CONFIG_NODE, &no_agentx_cmd); - hook_register(frr_early_fini, smux_disable); } @@ -397,4 +377,16 @@ void smux_events_update(void) agentx_events_update(); } +static void smux_events_delete_thread(void *arg) +{ + XFREE(MTYPE_TMP, arg); +} + +void smux_terminate(void) +{ + if (events) { + events->del = smux_events_delete_thread; + list_delete(&events); + } +} #endif /* SNMP_AGENTX */ diff --git a/lib/atomlist.h b/lib/atomlist.h index 2b6a3a176f94..3eb498a23a17 100644 --- a/lib/atomlist.h +++ b/lib/atomlist.h @@ -7,7 +7,9 @@ #define _FRR_ATOMLIST_H #include "typesafe.h" +#ifndef _TYPESAFE_EXPAND_MACROS #include "frratomic.h" +#endif /* _TYPESAFE_EXPAND_MACROS */ #ifdef __cplusplus extern "C" { diff --git a/lib/base64.c b/lib/base64.c index 1507b0252b4e..00dd35ffb5ae 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -9,8 +9,8 @@ #endif #include "base64.h" +#include "compiler.h" -static const int CHARS_PER_LINE = 72; static const char *ENCODING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -18,7 +18,6 @@ void base64_init_encodestate(struct base64_encodestate *state_in) { state_in->step = step_A; state_in->result = 0; - state_in->stepcount = 0; } char base64_encode_value(char value_in) @@ -41,6 +40,7 @@ int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, switch (state_in->step) { while (1) { + fallthrough; case step_A: if (plainchar == plaintextend) { state_in->result = result; @@ -51,7 +51,7 @@ int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, result = (fragment & 0x0fc) >> 2; *codechar++ = base64_encode_value(result); result = (fragment & 0x003) << 4; - /* fall through */ + fallthrough; case step_B: if (plainchar == plaintextend) { state_in->result = result; @@ -62,7 +62,7 @@ int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, result |= (fragment & 0x0f0) >> 4; *codechar++ = base64_encode_value(result); result = (fragment & 0x00f) << 2; - /* fall through */ + fallthrough; case step_C: if (plainchar == plaintextend) { state_in->result = result; @@ -74,12 +74,6 @@ int base64_encode_block(const char *plaintext_in, int length_in, char *code_out, *codechar++ = base64_encode_value(result); result = (fragment & 0x03f) >> 0; *codechar++ = base64_encode_value(result); - - ++(state_in->stepcount); - if (state_in->stepcount == CHARS_PER_LINE/4) { - *codechar++ = '\n'; - state_in->stepcount = 0; - } } } /* control should not reach here */ @@ -103,7 +97,6 @@ int base64_encode_blockend(char *code_out, struct base64_encodestate *state_in) case step_A: break; } - *codechar++ = '\n'; return codechar - code_out; } @@ -146,6 +139,7 @@ int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, switch (state_in->step) { while (1) { + fallthrough; case step_a: do { if (codec == code_in+length_in) { @@ -156,7 +150,7 @@ int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, fragmt = base64_decode_value(*codec++); } while (fragmt < 0); *plainc = (fragmt & 0x03f) << 2; - /* fall through */ + fallthrough; case step_b: do { if (codec == code_in+length_in) { @@ -168,7 +162,7 @@ int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, } while (fragmt < 0); *plainc++ |= (fragmt & 0x030) >> 4; *plainc = (fragmt & 0x00f) << 4; - /* fall through */ + fallthrough; case step_c: do { if (codec == code_in+length_in) { @@ -180,7 +174,7 @@ int base64_decode_block(const char *code_in, int length_in, char *plaintext_out, } while (fragmt < 0); *plainc++ |= (fragmt & 0x03c) >> 2; *plainc = (fragmt & 0x003) << 6; - /* fall through */ + fallthrough; case step_d: do { if (codec == code_in+length_in) { diff --git a/lib/base64.h b/lib/base64.h index 839f92aa7cf8..9bf4ace82f83 100644 --- a/lib/base64.h +++ b/lib/base64.h @@ -14,7 +14,6 @@ enum base64_encodestep { struct base64_encodestate { enum base64_encodestep step; char result; - int stepcount; }; void base64_init_encodestate(struct base64_encodestate *state_in); diff --git a/lib/bfd.c b/lib/bfd.c index 8c3246ff9a07..4535fc123378 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -1282,7 +1282,6 @@ static bool bfd_source_cache_update(struct bfd_source_cache *source, const struct zapi_nexthop *nh = &route->nexthops[nh_index]; const struct interface *interface; const struct connected *connected; - const struct listnode *node; interface = if_lookup_by_index(nh->ifindex, nh->vrf_id); if (interface == NULL) { @@ -1291,8 +1290,7 @@ static bool bfd_source_cache_update(struct bfd_source_cache *source, continue; } - for (ALL_LIST_ELEMENTS_RO(interface->connected, node, - connected)) { + frr_each (if_connected_const, interface->connected, connected) { if (source->address.family != connected->address->family) continue; @@ -1336,3 +1334,9 @@ int bfd_nht_update(const struct prefix *match, const struct zapi_route *route) return 0; } + +bool bfd_session_is_down(const struct bfd_session_params *session) +{ + return session->bss.state == BSS_DOWN || + session->bss.state == BSS_ADMIN_DOWN; +} diff --git a/lib/bfd.h b/lib/bfd.h index bfa5287340f2..48929a95642c 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -464,6 +464,8 @@ extern bool bfd_protocol_integration_shutting_down(void); extern int bfd_nht_update(const struct prefix *match, const struct zapi_route *route); +extern bool bfd_session_is_down(const struct bfd_session_params *session); + #ifdef __cplusplus } #endif diff --git a/lib/bitfield.h b/lib/bitfield.h index cc8c31141610..3fda627b7440 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -116,6 +116,7 @@ DECLARE_MTYPE(BITFIELD); (v).m = (v).m + 1; \ (v).data = XREALLOC(MTYPE_BITFIELD, (v).data, \ (v).m * sizeof(word_t)); \ + (v).data[(v).m - 1] = 0; \ } \ } while (0) diff --git a/lib/buffer.h b/lib/buffer.h index 5d98c31dbc4c..a0b82d2121c3 100644 --- a/lib/buffer.h +++ b/lib/buffer.h @@ -14,21 +14,21 @@ extern "C" { /* Create a new buffer. Memory will be allocated in chunks of the given size. If the argument is 0, the library will supply a reasonable default size suitable for buffering socket I/O. */ -extern struct buffer *buffer_new(size_t); +extern struct buffer *buffer_new(size_t size); /* Free all data in the buffer. */ -extern void buffer_reset(struct buffer *); +extern void buffer_reset(struct buffer *b); /* This function first calls buffer_reset to release all buffered data. Then it frees the struct buffer itself. */ -extern void buffer_free(struct buffer *); +extern void buffer_free(struct buffer *b); /* Add the given data to the end of the buffer. */ -extern void buffer_put(struct buffer *, const void *, size_t); +extern void buffer_put(struct buffer *b, const void *p, size_t size); /* Add a single character to the end of the buffer. */ -extern void buffer_putc(struct buffer *, uint8_t); +extern void buffer_putc(struct buffer *b, uint8_t c); /* Add a NUL-terminated string to the end of the buffer. */ -extern void buffer_putstr(struct buffer *, const char *); +extern void buffer_putstr(struct buffer *b, const char *str); /* Add given data, inline-expanding \n to \r\n */ extern void buffer_put_crlf(struct buffer *b, const void *p, size_t size); @@ -36,10 +36,10 @@ extern void buffer_put_crlf(struct buffer *b, const void *p, size_t size); single NUL-terminated string allocated using XMALLOC(MTYPE_TMP). Note that this function does not alter the state of the buffer, so the data is still inside waiting to be flushed. */ -char *buffer_getstr(struct buffer *); +char *buffer_getstr(struct buffer *b); /* Returns 1 if there is no pending data in the buffer. Otherwise returns 0. */ -int buffer_empty(struct buffer *); +int buffer_empty(struct buffer *b); typedef enum { /* An I/O error occurred. The buffer should be destroyed and the @@ -59,12 +59,12 @@ typedef enum { /* Try to write this data to the file descriptor. Any data that cannot be written immediately is added to the buffer queue. */ -extern buffer_status_t buffer_write(struct buffer *, int fd, const void *, - size_t); +extern buffer_status_t buffer_write(struct buffer *b, int fd, const void *p, + size_t size); /* This function attempts to flush some (but perhaps not all) of the queued data to the given file descriptor. */ -extern buffer_status_t buffer_flush_available(struct buffer *, int fd); +extern buffer_status_t buffer_flush_available(struct buffer *b, int fd); /* The following 2 functions (buffer_flush_all and buffer_flush_window) are for use in lib/vty.c only. They should not be used elsewhere. */ @@ -72,7 +72,7 @@ extern buffer_status_t buffer_flush_available(struct buffer *, int fd); /* Call buffer_flush_available repeatedly until either all data has been flushed, or an I/O error has been encountered, or the operation would block. */ -extern buffer_status_t buffer_flush_all(struct buffer *, int fd); +extern buffer_status_t buffer_flush_all(struct buffer *b, int fd); /* Attempt to write enough data to the given fd to fill a window of the given width and height (and remove the data written from the buffer). @@ -85,7 +85,7 @@ extern buffer_status_t buffer_flush_all(struct buffer *, int fd); to return -1 (because the logic for handling the erase and more features is too complicated to retry the write later). */ -extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width, +extern buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, int height, int erase, int no_more); #ifdef __cplusplus diff --git a/lib/checksum.c b/lib/checksum.c index 6c5f06de458a..b1ad813fd90b 100644 --- a/lib/checksum.c +++ b/lib/checksum.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Checksum routine for Internet Protocol family headers (C Version). * diff --git a/lib/checksum.h b/lib/checksum.h index 508c3f38a60f..2856a0d8095f 100644 --- a/lib/checksum.h +++ b/lib/checksum.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #ifndef _FRR_CHECKSUM_H #define _FRR_CHECKSUM_H diff --git a/lib/command.c b/lib/command.c index affb551b4598..51f2529e3ead 100644 --- a/lib/command.c +++ b/lib/command.c @@ -10,6 +10,10 @@ */ #include +#include +#include +#include + #include #include "command.h" @@ -39,6 +43,8 @@ #include "frrscript.h" +#include "lib/config_paths.h" + DEFINE_MTYPE_STATIC(LIB, HOST, "Host config"); DEFINE_MTYPE(LIB, COMPLETION, "Completion item"); @@ -477,33 +483,18 @@ static int config_write_host(struct vty *vty) } log_config_write(vty); - /* print disable always, but enable only if default is flipped - * => prep for future removal of compile-time knob - */ if (!cputime_enabled) vty_out(vty, "no service cputime-stats\n"); -#ifdef EXCLUDE_CPU_TIME - else - vty_out(vty, "service cputime-stats\n"); -#endif if (!cputime_threshold) vty_out(vty, "no service cputime-warning\n"); -#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000 - else /* again, always print non-default */ -#else - else if (cputime_threshold != 5000000) -#endif + else if (cputime_threshold != CONSUMED_TIME_CHECK) vty_out(vty, "service cputime-warning %lu\n", cputime_threshold / 1000); if (!walltime_threshold) vty_out(vty, "no service walltime-warning\n"); -#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000 - else /* again, always print non-default */ -#else - else if (walltime_threshold != 5000000) -#endif + else if (walltime_threshold != CONSUMED_TIME_CHECK) vty_out(vty, "service walltime-warning %lu\n", walltime_threshold / 1000); @@ -687,6 +678,21 @@ vector cmd_describe_command(vector vline, struct vty *vty, int *status) static struct list *varhandlers = NULL; +static int __add_key_comp(const struct lyd_node *dnode, void *arg) +{ + const char *key_value = yang_dnode_get_string(dnode, NULL); + + vector_set((vector)arg, XSTRDUP(MTYPE_COMPLETION, key_value)); + + return YANG_ITER_CONTINUE; +} + +static void __get_list_keys(vector comps, const char *xpath) +{ + yang_dnode_iterate(__add_key_comp, comps, + vty_shared_candidate_config->dnode, "%s", xpath); +} + void cmd_variable_complete(struct cmd_token *token, const char *arg, vector comps) { @@ -703,7 +709,10 @@ void cmd_variable_complete(struct cmd_token *token, const char *arg, if (cvh->varname && (!token->varname || strcmp(cvh->varname, token->varname))) continue; - cvh->completions(tmpcomps, token); + if (cvh->xpath) + __get_list_keys(tmpcomps, cvh->xpath); + if (cvh->completions) + cvh->completions(tmpcomps, token); break; } @@ -762,7 +771,7 @@ void cmd_variable_handler_register(const struct cmd_variable_handler *cvh) if (!varhandlers) return; - for (; cvh->completions; cvh++) + for (; cvh->completions || cvh->xpath; cvh++) listnode_add(varhandlers, (void *)cvh); } @@ -1331,8 +1340,8 @@ DEFUN (config_terminal, config_terminal_cmd, "configure [terminal [file-lock]]", "Configuration from vty interface\n" - "Configuration with locked datastores\n" - "Configuration terminal\n") + "Configuration terminal\n" + "Configuration with locked datastores\n") { return vty_config_enter(vty, false, false, argc == 3); } @@ -1365,7 +1374,7 @@ DEFUN (disable, } /* Down vty node level. */ -DEFUN (config_exit, +DEFUN_YANG (config_exit, config_exit_cmd, "exit", "Exit current mode and down to previous mode\n") @@ -1644,6 +1653,10 @@ static int vty_write_config(struct vty *vty) return CMD_SUCCESS; } +/* cross-reference frr_daemon_state_save in libfrr.c + * the code there is similar but not identical (state files always use the same + * name for the new write, and don't keep a backup of previous state.) + */ static int file_write_config(struct vty *vty) { int fd, dirfd; diff --git a/lib/command.h b/lib/command.h index 718d34b007cd..397aa7de9ab7 100644 --- a/lib/command.h +++ b/lib/command.h @@ -82,12 +82,16 @@ enum node_type { AUTH_ENABLE_NODE, /* Authentication mode for change enable. */ ENABLE_NODE, /* Enable node. */ CONFIG_NODE, /* Config node. Default mode of config file. */ + PREFIX_NODE, /* ip prefix-list node. */ + PREFIX_IPV6_NODE, /* ipv6 prefix-list node. */ DEBUG_NODE, /* Debug node. */ VRF_DEBUG_NODE, /* Vrf Debug node. */ NORTHBOUND_DEBUG_NODE, /* Northbound Debug node. */ DEBUG_VNC_NODE, /* Debug VNC node. */ RMAP_DEBUG_NODE, /* Route-map debug node */ RESOLVER_DEBUG_NODE, /* Resolver debug node */ + MGMT_BE_DEBUG_NODE, /* mgmtd backend-client debug node */ + MGMT_FE_DEBUG_NODE, /* mgmtd frontend-client debug node */ AAA_NODE, /* AAA node. */ EXTLOG_NODE, /* RFC5424 & co. extended syslog */ KEYCHAIN_NODE, /* Key-chain node. */ @@ -131,10 +135,8 @@ enum node_type { ISIS_NODE, /* ISIS protocol mode */ ISIS_FLEX_ALGO_NODE, /* ISIS Flex Algo mode */ ACCESS_NODE, /* Access list node. */ - PREFIX_NODE, /* Prefix list node. */ ACCESS_IPV6_NODE, /* Access list node. */ ACCESS_MAC_NODE, /* MAC access list node*/ - PREFIX_IPV6_NODE, /* Prefix list node. */ AS_LIST_NODE, /* AS list node. */ COMMUNITY_LIST_NODE, /* Community list node. */ COMMUNITY_ALIAS_NODE, /* Community alias node. */ @@ -158,6 +160,10 @@ enum node_type { SRV6_NODE, /* SRv6 node */ SRV6_LOCS_NODE, /* SRv6 locators node */ SRV6_LOC_NODE, /* SRv6 locator node */ + SRV6_ENCAP_NODE, /* SRv6 encapsulation node */ + SRV6_SID_FORMATS_NODE, /* SRv6 SID formats config node */ + SRV6_SID_FORMAT_USID_F3216_NODE, /* SRv6 uSID f3216 format config node */ + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, /* SRv6 uncompressed f4024 format config node */ VTY_NODE, /* Vty node. */ FPM_NODE, /* Dataplane FPM node. */ LINK_PARAMS_NODE, /* Link-parameters node */ @@ -174,6 +180,11 @@ enum node_type { BMP_NODE, /* BMP config under router bgp */ ISIS_SRV6_NODE, /* ISIS SRv6 node */ ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ + MGMTD_NODE, /* MGMTD node. */ + RPKI_VRF_NODE, /* RPKI node for VRF */ + PIM_NODE, /* PIM protocol mode */ + PIM6_NODE, /* PIM protocol for IPv6 mode */ + BGP_RTC_NODE, /* BGP-RTC configuration node */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ @@ -242,9 +253,11 @@ struct cmd_node { /* Argc max counts. */ #define CMD_ARGC_MAX 256 +/* clang-format off */ + /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - static const struct cmd_element cmdname = { \ + const struct cmd_element cmdname = { \ .string = cmdstr, \ .func = funcname, \ .doc = helpstr, \ @@ -271,7 +284,7 @@ struct cmd_node { /* DEFPY variants */ #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ funcdecl_##funcname #define DEFPY(funcname, cmdname, cmdstr, helpstr) \ @@ -286,6 +299,10 @@ struct cmd_node { #define DEFPY_YANG(funcname, cmdname, cmdstr, helpstr) \ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) +#define DEFPY_YANG_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, \ + CMD_ATTR_YANG | CMD_ATTR_HIDDEN) + #define DEFPY_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_YANG | CMD_ATTR_NOSH) @@ -294,7 +311,7 @@ struct cmd_node { #define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ @@ -310,6 +327,10 @@ struct cmd_node { #define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_NOSH) +#define DEFUN_YANG_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, \ + CMD_ATTR_YANG | CMD_ATTR_HIDDEN) + #define DEFUN_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_YANG | CMD_ATTR_NOSH) @@ -327,7 +348,8 @@ struct cmd_node { /* DEFUN + DEFSH */ #define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, \ + daemon) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ @@ -339,7 +361,7 @@ struct cmd_node { /* ALIAS macro which define existing command's alias. */ #define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, 0) @@ -358,6 +380,8 @@ struct cmd_node { #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) +/* clang-format on */ + /* Some macroes */ /* @@ -449,6 +473,8 @@ struct cmd_node { #define MPLS_LDP_SYNC_HOLDDOWN_STR \ "Time to wait for LDP-SYNC to occur before restoring if cost\n" #define NO_MPLS_LDP_SYNC_HOLDDOWN_STR "holddown timer disable\n" +#define BGP_AF_STR "Address Family\n" +#define BGP_AF_MODIFIER_STR "Address Family modifier\n" /* Command warnings. */ #define NO_PASSWD_CMD_WARNING \ @@ -623,6 +649,7 @@ extern void cmd_banner_motd_line(const char *line); struct cmd_variable_handler { const char *tokenname, *varname; + const char *xpath; /* fill comps from set of values at xpath */ void (*completions)(vector out, struct cmd_token *token); }; diff --git a/lib/command_graph.c b/lib/command_graph.c index ff3c11db69b5..20ab6b321b5c 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -267,6 +267,9 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb) case NEG_ONLY_TKN: case WORD_TKN: case ASNUM_TKN: +#ifdef BUILDING_CLIPPY + case CMD_ELEMENT_TKN: +#endif return true; } diff --git a/lib/command_graph.h b/lib/command_graph.h index 25aa47db7b65..313c97fe879e 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -54,6 +54,9 @@ enum cmd_token_type { END_TKN, // last token in line NEG_ONLY_TKN, // filter token, match if "no ..." command +#ifdef BUILDING_CLIPPY + CMD_ELEMENT_TKN, // python bindings only +#endif SPECIAL_TKN = FORK_TKN, }; /* clang-format on */ diff --git a/lib/command_match.c b/lib/command_match.c index f740b726008c..97e6aeb4698a 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -405,10 +405,10 @@ enum matcher_rv command_complete(struct graph *graph, vector vline, listnode_add(next, newstack); break; case partly_match: - trace_matcher("trivial_match\n"); + trace_matcher("partly_match\n"); if (exact_match_exists && !last_token) break; - /* fallthru */ + fallthrough; case exact_match: trace_matcher("exact_match\n"); if (last_token) { diff --git a/lib/command_py.c b/lib/command_py.c index f8abcf8ef401..a77adcd7dc68 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -29,6 +29,7 @@ struct wrap_graph; static PyObject *graph_to_pyobj(struct wrap_graph *graph, struct graph_node *gn); +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i); /* * nodes are wrapped as follows: @@ -44,13 +45,6 @@ struct wrap_graph_node { bool allowrepeat; const char *type; - bool deprecated; - bool hidden; - const char *text; - const char *desc; - const char *varname; - long long min, max; - struct graph_node *node; struct wrap_graph *wgraph; size_t idx; @@ -68,6 +62,7 @@ struct wrap_graph { char *definition; struct graph *graph; + size_t n_nodewrappers; struct wrap_graph_node **nodewrappers; }; @@ -84,11 +79,75 @@ static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) READONLY, (char *)#name " (" #type ")" \ } static PyMemberDef members_graph_node[] = { - member(allowrepeat, T_BOOL), member(type, T_STRING), - member(deprecated, T_BOOL), member(hidden, T_BOOL), - member(text, T_STRING), member(desc, T_STRING), - member(min, T_LONGLONG), member(max, T_LONGLONG), - member(varname, T_STRING), {}, + /* clang-format off */ + member(type, T_STRING), + member(idx, T_ULONG), + {}, + /* clang-format on */ +}; +#undef member + +static PyObject *graph_node_get_str(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + const char *val = *(const char **)offset; + + if (!val) + Py_RETURN_NONE; + return PyUnicode_FromString(val); +} + +static PyObject *graph_node_get_bool(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + bool val = *(bool *)offset; + + return PyBool_FromLong(val); +} + +static PyObject *graph_node_get_ll(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + long long val = *(long long *)offset; + + return PyLong_FromLongLong(val); +} + +static PyObject *graph_node_get_u8(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + uint8_t val = *(uint8_t *)offset; + + return PyLong_FromUnsignedLong(val); +} + +/* clang-format off */ +#define member(name, variant) \ + { \ + (char *)#name, \ + graph_node_get_##variant, \ + NULL, \ + (char *)#name " (" #variant ")", \ + (void *)offsetof(struct cmd_token, name), \ + } +/* clang-format on */ + +static PyGetSetDef getset_graph_node[] = { + /* clang-format off */ + member(attr, u8), + member(allowrepeat, bool), + member(varname_src, u8), + member(text, str), + member(desc, str), + member(min, ll), + member(max, ll), + member(varname, str), + {}, + /* clang-format on */ }; #undef member @@ -101,12 +160,30 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; PyObject *pylist; - if (wrap->node->data - && ((struct cmd_token *)wrap->node->data)->type == END_TKN) + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == CMD_ELEMENT_TKN) return PyList_New(0); pylist = PyList_New(vector_active(wrap->node->to)); for (size_t i = 0; i < vector_active(wrap->node->to); i++) { struct graph_node *gn = vector_slot(wrap->node->to, i); + + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); + } + return pylist; +}; + +static PyObject *graph_node_prev(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + PyObject *pylist; + + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == START_TKN) + return PyList_New(0); + pylist = PyList_New(vector_active(wrap->node->from)); + for (size_t i = 0; i < vector_active(wrap->node->from); i++) { + struct graph_node *gn = vector_slot(wrap->node->from, i); + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); } return pylist; @@ -118,30 +195,60 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) static PyObject *graph_node_join(PyObject *self, PyObject *args) { struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; if (!wrap->node->data || ((struct cmd_token *)wrap->node->data)->type == END_TKN) Py_RETURN_NONE; - struct cmd_token *tok = wrap->node->data; + tok = wrap->node->data; if (tok->type != FORK_TKN) Py_RETURN_NONE; return graph_to_pyobj(wrap->wgraph, tok->forkjoin); }; +static PyObject *graph_node_fork(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; + + if (!wrap->node->data || + ((struct cmd_token *)wrap->node->data)->type == END_TKN) + Py_RETURN_NONE; + + tok = wrap->node->data; + if (tok->type != JOIN_TKN) + Py_RETURN_NONE; + + return graph_to_pyobj(wrap->wgraph, tok->forkjoin); +}; + static PyMethodDef methods_graph_node[] = { - {"next", graph_node_next, METH_NOARGS, "outbound graph edge list"}, - {"join", graph_node_join, METH_NOARGS, "outbound join node"}, - {}}; + { "next", graph_node_next, METH_NOARGS, "outbound graph edge list" }, + { "prev", graph_node_prev, METH_NOARGS, "inbound graph edge list" }, + { "join", graph_node_join, METH_NOARGS, "outbound join node" }, + { "fork", graph_node_fork, METH_NOARGS, "inbound fork node" }, + {} +}; static void graph_node_wrap_free(void *arg) { struct wrap_graph_node *wrap = arg; + + assert(wrap->idx < wrap->wgraph->n_nodewrappers); wrap->wgraph->nodewrappers[wrap->idx] = NULL; Py_DECREF(wrap->wgraph); } +static PyObject *repr_graph_node(PyObject *arg) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)arg; + + return PyUnicode_FromFormat("<_clippy.GraphNode %p [%zu] %s>", + wrap->node, wrap->idx, wrap->type); +} + static PyTypeObject typeobj_graph_node = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.GraphNode", .tp_basicsize = sizeof(struct wrap_graph_node), @@ -150,13 +257,14 @@ static PyTypeObject typeobj_graph_node = { .tp_new = refuse_new, .tp_free = graph_node_wrap_free, .tp_members = members_graph_node, + .tp_getset = getset_graph_node, .tp_methods = methods_graph_node, + .tp_repr = repr_graph_node, }; static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, struct graph_node *gn) { - struct wrap_graph_node *wrap; size_t i; for (i = 0; i < vector_active(wgraph->graph->nodes); i++) @@ -166,6 +274,24 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, PyErr_SetString(PyExc_ValueError, "cannot find node in graph"); return NULL; } + + return graph_to_pyobj_idx(wgraph, i); +} + +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i) +{ + struct wrap_graph_node *wrap; + struct graph_node *gn = vector_slot(wgraph->graph->nodes, i); + + if (i >= wgraph->n_nodewrappers) { + wgraph->nodewrappers = + realloc(wgraph->nodewrappers, + (i + 1) * sizeof(wgraph->nodewrappers[0])); + memset(wgraph->nodewrappers + wgraph->n_nodewrappers, 0, + sizeof(wgraph->nodewrappers[0]) * + (i + 1 - wgraph->n_nodewrappers)); + wgraph->n_nodewrappers = i + 1; + } if (wgraph->nodewrappers[i]) { PyObject *obj = (PyObject *)wgraph->nodewrappers[i]; Py_INCREF(obj); @@ -209,19 +335,11 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, item(START_TKN); item(END_TKN); item(NEG_ONLY_TKN); + item(CMD_ELEMENT_TKN); #undef item default: wrap->type = "???"; } - - wrap->deprecated = !!(tok->attr & CMD_ATTR_DEPRECATED); - wrap->hidden = !!(tok->attr & CMD_ATTR_HIDDEN); - wrap->text = tok->text; - wrap->desc = tok->desc; - wrap->varname = tok->varname; - wrap->min = tok->min; - wrap->max = tok->max; - wrap->allowrepeat = tok->allowrepeat; } return (PyObject *)wrap; @@ -246,9 +364,13 @@ static PyObject *graph_first(PyObject *self, PyObject *args) return graph_to_pyobj(gwrap, gn); }; +static PyObject *graph_merge(PyObject *self, PyObject *args); + static PyMethodDef methods_graph[] = { - {"first", graph_first, METH_NOARGS, "first graph node"}, - {}}; + { "first", graph_first, METH_NOARGS, "first graph node" }, + { "merge", graph_merge, METH_VARARGS, "merge graphs" }, + {} +}; static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -262,6 +384,30 @@ static void graph_wrap_free(void *arg) free(wgraph->definition); } +static Py_ssize_t graph_length(PyObject *self) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + return vector_active(gwrap->graph->nodes); +} + +static PyObject *graph_item(PyObject *self, Py_ssize_t idx) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + if (idx >= vector_active(gwrap->graph->nodes)) + return PyErr_Format(PyExc_IndexError, + "index %zd past graph size %u", idx, + vector_active(gwrap->graph->nodes)); + + return graph_to_pyobj_idx(gwrap, idx); +} + +static PySequenceMethods seq_graph = { + .sq_length = graph_length, + .sq_item = graph_item, +}; + static PyTypeObject typeobj_graph = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.Graph", .tp_basicsize = sizeof(struct wrap_graph), @@ -271,35 +417,62 @@ static PyTypeObject typeobj_graph = { .tp_free = graph_wrap_free, .tp_members = members_graph, .tp_methods = methods_graph, + .tp_as_sequence = &seq_graph, }; +static PyObject *graph_merge(PyObject *self, PyObject *args) +{ + PyObject *py_other; + struct wrap_graph *gwrap = (struct wrap_graph *)self; + struct wrap_graph *gother; + + if (!PyArg_ParseTuple(args, "O!", &typeobj_graph, &py_other)) + return NULL; + + gother = (struct wrap_graph *)py_other; + cmd_graph_merge(gwrap->graph, gother->graph, +1); + Py_RETURN_NONE; +} + /* top call / entrypoint for python code */ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) { - const char *def, *doc = NULL; + const char *def, *doc = NULL, *name = NULL; struct wrap_graph *gwrap; - static const char *kwnames[] = {"cmddef", "doc", NULL}; + static const char *const kwnames[] = { "cmddef", "doc", "name", NULL }; gwrap = (struct wrap_graph *)typeobj_graph.tp_alloc(&typeobj_graph, 0); if (!gwrap) return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", (char **)kwnames, - &def, &doc)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "z|ss", (char **)kwnames, + &def, &doc, &name)) return NULL; struct graph *graph = graph_new(); struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL); graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del); - struct cmd_element cmd = {.string = def, .doc = doc}; - cmd_graph_parse(graph, &cmd); - cmd_graph_names(graph); + if (def) { + struct cmd_element cmd = { .string = def, .doc = doc }; + struct graph_node *last; + + cmd_graph_parse(graph, &cmd); + cmd_graph_names(graph); + + last = vector_slot(graph->nodes, + vector_active(graph->nodes) - 1); + assert(last->data == &cmd); + + last->data = cmd_token_new(CMD_ELEMENT_TKN, 0, name, def); + last->del = (void (*)(void *))cmd_token_del; + + gwrap->definition = strdup(def); + } else { + gwrap->definition = strdup("NULL"); + } gwrap->graph = graph; - gwrap->definition = strdup(def); - gwrap->nodewrappers = calloc(vector_active(graph->nodes), - sizeof(gwrap->nodewrappers[0])); return (PyObject *)gwrap; } diff --git a/lib/compiler.h b/lib/compiler.h index ce6727685f13..9d39026c6675 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -32,8 +32,8 @@ extern "C" { #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5) # define _RET_NONNULL , returns_nonnull #endif -#if __has_attribute(fallthrough) -# define _FALLTHROUGH __attribute__((fallthrough)); +#if __has_attribute(fallthrough) && !defined(__cplusplus) +# define fallthrough __attribute__((fallthrough)); #endif # define _CONSTRUCTOR(x) constructor(x) # define _DEPRECATED(x) deprecated(x) @@ -56,8 +56,8 @@ extern "C" { #if __GNUC__ < 5 # define __has_attribute(x) 0 #endif -#if __GNUC__ >= 7 -# define _FALLTHROUGH __attribute__((fallthrough)); +#if __GNUC__ >= 7 && !defined(__cplusplus) +# define fallthrough __attribute__((fallthrough)); #endif #endif @@ -112,8 +112,8 @@ extern "C" { #ifndef _ALLOC_SIZE # define _ALLOC_SIZE(x) #endif -#ifndef _FALLTHROUGH -#define _FALLTHROUGH +#if !defined(fallthrough) && !defined(__cplusplus) +#define fallthrough #endif #ifndef _DEPRECATED #define _DEPRECATED(x) deprecated @@ -424,10 +424,10 @@ _Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8, * type.) */ #ifndef __cplusplus -#define prefixtype(uname, typename, fieldname) typename *fieldname; +#define uniontype(uname, typename, fieldname) typename *fieldname; #define TRANSPARENT_UNION __attribute__((transparent_union)) #else -#define prefixtype(uname, typename, fieldname) \ +#define uniontype(uname, typename, fieldname) \ typename *fieldname; \ uname(typename *x) \ { \ @@ -455,6 +455,12 @@ _Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8, #define unlikely(_x) !!(_x) #endif +#ifdef __MACH__ +#define _DATA_SECTION(name) __attribute__((section("__DATA," name))) +#else +#define _DATA_SECTION(name) __attribute__((section(".data." name))) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/config_paths.h.in b/lib/config_paths.h.in new file mode 100644 index 000000000000..cc409056324c --- /dev/null +++ b/lib/config_paths.h.in @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* autogenerated by configure / config.status */ + +/* IF YOU ARE INCLUDING THIS FILE FROM A DAEMON OR ZEBRA, YOU ARE PROBABLY + * DOING SOMETHING WRONG. Check for / add a library function that retrieves + * the path you need. + * + * Only libfrr and watchfrr should be including this file. + */ + +/* the replacements for these are emitted by AX_SUBST_EXPANDED, which also + * adds the e_ prefix + */ +#define FRR_RUNSTATE_PATH "@e_frr_runstatedir@" +#define FRR_LIBSTATE_PATH "@e_frr_libstatedir@" +#define YANG_MODELS_PATH "@e_yangmodelsdir@" +#define MODULE_PATH "@e_moduledir@" +#define SCRIPT_PATH "@e_scriptdir@" + +/* for extra footgunning, this one has a trailing slash */ +#define SYSCONFDIR "@e_frr_sysconfdir@/" + +#define VTYSH_BIN_PATH "@e_vtysh_bin@" +#define WATCHFRR_SH_PATH "@e_watchfrr_sh@" diff --git a/lib/darr.c b/lib/darr.c index 2c8b7b8778a1..7a0127410493 100644 --- a/lib/darr.c +++ b/lib/darr.c @@ -7,8 +7,10 @@ */ #include #include "darr.h" +#include "memory.h" -void __dar_resize(void **a, uint count, size_t esize); +DEFINE_MTYPE(LIB, DARR, "Dynamic Array"); +DEFINE_MTYPE(LIB, DARR_STR, "Dynamic Array String"); static uint _msb(uint count) { @@ -51,32 +53,75 @@ static size_t darr_size(uint count, size_t esize) return count * esize + sizeof(struct darr_metadata); } -void *__darr_resize(void *a, uint count, size_t esize) +char *__darr_in_vsprintf(char **sp, bool concat, const char *fmt, va_list ap) +{ + size_t inlen = concat ? darr_strlen(*sp) : 0; + size_t capcount = strlen(fmt) + MIN(inlen + 64, 128); + ssize_t len; + va_list ap_copy; + + darr_ensure_cap(*sp, capcount); + + if (!concat) + darr_reset(*sp); + + /* code below counts on having a NUL terminated string */ + if (darr_len(*sp) == 0) + *darr_append(*sp) = 0; +again: + va_copy(ap_copy, ap); + len = vsnprintf(darr_last(*sp), darr_avail(*sp) + 1, fmt, ap_copy); + va_end(ap_copy); + if (len < 0) + darr_in_strcat(*sp, fmt); + else if ((size_t)len <= darr_avail(*sp)) + _darr_len(*sp) += len; + else { + darr_ensure_cap(*sp, darr_len(*sp) + (size_t)len); + goto again; + } + return *sp; +} + +char *__darr_in_sprintf(char **sp, bool concat, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)__darr_in_vsprintf(sp, concat, fmt, ap); + va_end(ap); + return *sp; +} + + +void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mtype) { uint ncount = darr_next_count(count, esize); size_t osz = (a == NULL) ? 0 : darr_size(darr_cap(a), esize); size_t sz = darr_size(ncount, esize); - struct darr_metadata *dm = realloc(a ? _darr_meta(a) : NULL, sz); - /* do *not* use a */ - - assert(dm); - if (sz > osz) - memset((char *)dm + osz, 0, sz - osz); + struct darr_metadata *dm; + if (a) { + dm = XREALLOC(_darr_meta(a)->mtype, _darr_meta(a), sz); + if (sz > osz) + memset((char *)dm + osz, 0, sz - osz); + } else { + dm = XCALLOC(mtype, sz); + dm->mtype = mtype; + } dm->cap = ncount; - return (void *)(dm + 1); } -void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero) +void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero, + struct memtype *mtype) { - struct darr_metadata *dm; uint olen, nlen; if (!a) - a = __darr_resize(NULL, at + count, esize); + a = __darr_resize(NULL, at + count, esize, mtype); dm = (struct darr_metadata *)a - 1; olen = dm->len; @@ -91,7 +136,7 @@ void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero) nlen = olen + count; if (nlen > dm->cap) { - a = __darr_resize(a, nlen, esize); + a = __darr_resize(a, nlen, esize, mtype); dm = (struct darr_metadata *)a - 1; } @@ -109,6 +154,6 @@ void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero) memset(_a_at(at), 0, esize * count); } - return (void *)a; + return a; #undef _a_at } diff --git a/lib/darr.h b/lib/darr.h index ca46fb30543f..2b9a0a0c025b 100644 --- a/lib/darr.h +++ b/lib/darr.h @@ -3,22 +3,39 @@ * June 23 2023, Christian Hopps * * Copyright (c) 2023, LabN Consulting, L.L.C. - * + */ +#ifndef _FRR_DARR_H_ +#define _FRR_DARR_H_ + +/* * API functions: * ============== * - darr_append + * - darr_append_mt * - darr_append_n + * - darr_append_n_mt * - darr_append_nz + * - darr_append_nz_mt * - darr_cap + * - darr_ensure_avail + * - darr_ensure_avail_mt * - darr_ensure_cap + * - darr_ensure_cap_mt * - darr_ensure_i - * - darr_foreach_i - * - darr_foreach_p + * - darr_ensure_i_mt * - darr_free + * - darr_free_free + * - darr_free_func * - darr_insert + * - darr_insert_mt * - darr_insertz + * - darr_insertz_mt * - darr_insert_n + * - darr_insert_n_mt * - darr_insert_nz + * - darr_insert_nz_mt + * - darr_last + * - darr_lasti * - darr_len * - darr_maxi * - darr_pop @@ -28,38 +45,81 @@ * - darr_remove_n * - darr_reset * - darr_setlen + * + * Iteration + * --------- + * - darr_foreach_i + * - darr_foreach_p + * + * String Utilities + * ---------------- + * - darr_in_strcat_tail + * - darr_in_strcatf, darr_in_vstrcatf + * - darr_in_strdup + * - darr_in_strdup_cap + * - darr_in_sprintf, darr_in_vsprintf + * - darr_set_strlen + * - darr_strdup + * - darr_strdup_cap + * - darr_strlen + * - darr_strnul + * - darr_sprintf, darr_vsprintf */ /* * A few assured items * * - DAs will never have capacity 0 unless they are NULL pointers. */ + +/* + * NOTE: valgrind by default enables a "length64" heuristic (among others) which + * identifies "interior-pointer" 8 bytes forward of a "start-pointer" as a + * "start-pointer". This should cause what normally would be "possibly-lost" + * errors to instead be definite for dynamic arrays. This is b/c the header is 8 bytes + */ + #include +#include +#include "memory.h" + +DECLARE_MTYPE(DARR); +DECLARE_MTYPE(DARR_STR); struct darr_metadata { - uint len; - uint cap; + uint32_t len; + uint32_t cap; + struct memtype *mtype; }; -void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero); -void *__darr_resize(void *a, uint count, size_t esize); -#define _darr_esize(A) sizeof((A)[0]) -#define darr_esize(A) sizeof((A)[0]) -#define _darr_len(A) _darr_meta(A)->len -#define _darr_meta(A) (((struct darr_metadata *)(A)) - 1) -#define _darr_resize(A, C) ({ (A) = __darr_resize((A), C, _darr_esize(A)); }) +void *__darr_insert_n(void *a, uint at, uint count, size_t esize, bool zero, + struct memtype *mt); +char *__darr_in_sprintf(char **sp, bool concat, const char *fmt, ...) + PRINTFRR(3, 4); +char *__darr_in_vsprintf(char **sp, bool concat, const char *fmt, va_list ap) + PRINTFRR(3, 0); +void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); + + +#define _darr_esize(A) sizeof((A)[0]) +#define darr_esize(A) sizeof((A)[0]) +#define _darr_len(A) _darr_meta(A)->len +#define _darr_meta(A) (((struct darr_metadata *)(A)) - 1) +#define _darr_resize_mt(A, C, MT) \ + ({ (A) = __darr_resize(A, C, _darr_esize(A), MT); }) +#define _darr_resize(A, C) _darr_resize_mt(A, C, MTYPE_DARR) /* Get the current capacity of the array */ #define darr_cap(A) (((A) == NULL) ? 0 : _darr_meta(A)->cap) +/* Get the current available expansion space */ +#define darr_avail(A) (((A) == NULL) ? 0 : (darr_cap(A) - darr_len(A))) + /* Get the largest possible index one can `darr_ensure_i` w/o resizing */ #define darr_maxi(A) ((int)darr_cap(A) - 1) /** - * Get the current length of the array. - * - * As long as `A` is non-NULL, this macro may be used as an L-value to modify - * the length of the array. + * darr_len() - Get the current length of the array as a unsigned int. + * darr_ilen() - Get the current length of the array as an int. * * Args: * A: The dynamic array, can be NULL. @@ -67,7 +127,19 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * The current length of the array. */ -#define darr_len(A) (((A) == NULL) ? 0 : _darr_meta(A)->len) +#define darr_len(A) (((A) == NULL) ? 0 : _darr_meta(A)->len) +#define darr_ilen(A) (((A) == NULL) ? 0 : (ssize_t)_darr_meta(A)->len) + +/** + * darr_lasti() - Get the last element's index. + * + * Args: + * A: The dynamic array, can be NULL. + * + * Return: + * The current last element index, or -1 for none. + */ +#define darr_lasti(A) (darr_ilen(A) - 1) /** * Set the current length of the array `A` to 0. @@ -96,11 +168,41 @@ void *__darr_resize(void *a, uint count, size_t esize); assert((A) || !(L)); \ if ((A)) { \ /* have to cast to avoid compiler warning for "0" */ \ - assert((long long)darr_cap(A) >= (L)); \ + assert((long long)darr_cap(A) >= (long long)(L)); \ _darr_len(A) = (L); \ } \ } while (0) +/** + * Set the string length of the array `S` to `L`, and NUL + * terminate the string at L. The dynamic array length will be `L` + 1. + * + * Thus after calling: + * + * darr_len(S) == L + 1 + * darr_strlen(S) == L + * S[L] == 0 + * + * This function does *not* guarantee the `L` + 1 memory is allocated to + * the array, use `darr_ensure` or `*_cap` functions for that. + * + * Args: + * S: The dynamic array, cannot be NULL. + * L: The new str length of the array, will set + * + * Return: + * A pointer to the end of S (i.e., pointing to the NUL byte). + */ +#define darr_set_strlen(S, L) \ + ({ \ + assert((S)); \ + /* have to cast to avoid compiler warning for "0" */ \ + assert((long long)darr_cap(S) >= (long long)(L)); \ + _darr_len(S) = (L) + 1; \ + *darr_last(S) = 0; \ + darr_last(S); \ + }) + /** * Free memory allocated for the dynamic array `A` * @@ -111,11 +213,73 @@ void *__darr_resize(void *a, uint count, size_t esize); #define darr_free(A) \ do { \ if ((A)) { \ - free(_darr_meta(A)); \ + struct darr_metadata *__meta = _darr_meta(A); \ + XFREE(__meta->mtype, __meta); \ (A) = NULL; \ } \ } while (0) +/** + * Free memory allocated for the dynamic array `A`, calling `darr_free` for + * each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + */ +#define darr_free_free(A) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) \ + if ((A)[__i]) { \ + struct darr_metadata *__meta = \ + _darr_meta((A)[__i]); \ + XFREE(__meta->mtype, __meta); \ + } \ + darr_free(A); \ + } while (0) + +/** + * Free memory allocated for the dynamic array `A`, calling `F` routine + * for each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + * F: The function to call for each element. + */ + +#define darr_free_func(A, F) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) { \ + F((A)[__i]); \ + } \ + darr_free(A); \ + } while (0) + +/** + * Make sure that there is room in the dynamic array `A` to add `C` elements. + * + * Available space is `darr_cap(a) - darr_len(a)`. + * + * The value `A` may be changed as a result of this call in which case any + * pointers into the previous memory block are no longer valid. The `A` value + * is guaranteed not to change if there is sufficient capacity in the array. + * + * Args: + * A: (IN/OUT) the dynamic array, can be NULL. + * S: Amount of free space to guarantee. + * + * Return: + * A pointer to the (possibly moved) array. + */ +#define darr_ensure_avail_mt(A, S, MT) \ + ({ \ + ssize_t need = (ssize_t)(S) - \ + (ssize_t)(darr_cap(A) - darr_len(A)); \ + if (need > 0) \ + _darr_resize_mt((A), darr_cap(A) + need, MT); \ + (A); \ + }) +#define darr_ensure_avail(A, S) darr_ensure_avail_mt(A, S, MTYPE_DARR) + /** * Make sure that there is room in the dynamic array `A` for `C` elements. * @@ -123,19 +287,26 @@ void *__darr_resize(void *a, uint count, size_t esize); * pointers into the previous memory block are no longer valid. The `A` value * is guaranteed not to change if there is sufficient capacity in the array. * + * The exception to the no-change rule is if @C is passed as 0, it will be + * considered 1 so that an array is always allocated if currently NULL, + * i.e., @A will never be NULL after a call to darr_ensure_cap_mt() + * * Args: * A: (IN/OUT) the dynamic array, can be NULL. - * I: the index to guarantee memory exists for + * C: Total capacity to guarantee. * * Return: * A pointer to the (possibly moved) array. */ -#define darr_ensure_cap(A, C) \ +#define darr_ensure_cap_mt(A, C, MT) \ ({ \ - if (darr_cap(A) < (C)) \ - _darr_resize((A), (C)); \ + /* Cast to avoid warning when C == 0 */ \ + uint _c = (C) > 0 ? (C) : 1; \ + if ((size_t)darr_cap(A) < _c) \ + _darr_resize_mt((A), _c, MT); \ (A); \ }) +#define darr_ensure_cap(A, C) darr_ensure_cap_mt(A, C, MTYPE_DARR) /** * Return a pointer to the (I)th element of array `A`, making sure there is @@ -155,18 +326,22 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * A pointer to the (I)th element in `A` */ -#define darr_ensure_i(A, I) \ +#define darr_ensure_i_mt(A, I, MT) \ ({ \ - if ((int)(I) > darr_maxi(A)) \ - _darr_resize((A), (I) + 1); \ - if ((I) + 1 > _darr_len(A)) \ - _darr_len(A) = (I) + 1; \ - &(A)[I]; \ + assert((int)(I) >= 0 && (uint)(I) <= INT_MAX); \ + int _i = (int)(I); \ + if (_i > darr_maxi(A)) \ + _darr_resize_mt((A), _i + 1, MT); \ + assert((A) != NULL); \ + if ((uint)_i + 1 > _darr_len(A)) \ + _darr_len(A) = _i + 1; \ + &(A)[_i]; \ }) +#define darr_ensure_i(A, I) darr_ensure_i_mt(A, I, MTYPE_DARR) -#define _darr_insert_n(A, I, N, Z) \ +#define _darr_insert_n(A, I, N, Z, MT) \ ({ \ - (A) = __darr_insert_n(A, I, N, _darr_esize(A), Z); \ + (A) = __darr_insert_n(A, I, N, _darr_esize(A), Z, MT); \ &(A)[I]; \ }) /** @@ -187,8 +362,10 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * A pointer to the first inserted element in the array. */ -#define darr_insert_n(A, I, N) _darr_insert_n(A, I, N, false) -#define darr_insert_nz(A, I, N) _darr_insert_n(A, I, N, true) +#define darr_insert_n(A, I, N) _darr_insert_n(A, I, N, false, MTYPE_DARR) +#define darr_insert_n_mt(A, I, N) _darr_insert_n(A, I, N, false, MT) +#define darr_insert_nz(A, I, N) _darr_insert_n(A, I, N, true, MTYPE_DARR) +#define darr_insert_nz_mt(A, I, N) _darr_insert_n(A, I, N, true, MT) /** * Insert an uninitialized element in the array at index `I`. @@ -208,8 +385,10 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * A pointer to the element in the array. */ -#define darr_insert(A, I) _darr_insert_n(A, I, 1, false) -#define darr_insertz(A, I) _darr_insert_n(A, I, 1, true) +#define darr_insert(A, I) _darr_insert_n(A, I, 1, false, MTYPE_DARR) +#define darr_insert_mt(A, I) _darr_insert_n(A, I, 1, false, MT) +#define darr_insertz(A, I) _darr_insert_n(A, I, 1, true, MTYPE_DARR) +#define darr_insertz_mt(A, I) _darr_insert_n(A, I, 1, true, MT) /** * Remove `N` elements from the array starting at index `I`. @@ -247,10 +426,10 @@ void *__darr_resize(void *a, uint count, size_t esize); #define darr_remove(A, I) darr_remove_n(A, I, 1) -#define _darr_append_n(A, N, Z) \ +#define _darr_append_n(A, N, Z, MT) \ ({ \ uint __len = darr_len(A); \ - darr_ensure_cap(A, __len + (N)); \ + darr_ensure_cap_mt(A, __len + (N), MT); \ _darr_len(A) = __len + (N); \ if (Z) \ memset(&(A)[__len], 0, (N)*_darr_esize(A)); \ @@ -267,8 +446,10 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * A pointer to the first of the added elements at the end of the array. */ -#define darr_append_n(A, N) _darr_append_n(A, N, false) -#define darr_append_nz(A, N) _darr_append_n(A, N, true) +#define darr_append_n(A, N) _darr_append_n(A, N, false, MTYPE_DARR) +#define darr_append_n_mt(A, N, MT) _darr_append_n(A, N, false, MT) +#define darr_append_nz(A, N) _darr_append_n(A, N, true, MTYPE_DARR) +#define darr_append_nz_mt(A, N, MT) _darr_append_n(A, N, true, MT) /** * Extending the array's length by 1. @@ -281,8 +462,10 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * A pointer to the new element at the end of the array. */ -#define darr_append(A) _darr_append_n(A, 1, false) -#define darr_appendz(A) _darr_append_n(A, 1, true) +#define darr_append(A) _darr_append_n(A, 1, false, MTYPE_DARR) +#define darr_append_mt(A, MT) _darr_append_n(A, 1, false, MT) +#define darr_appendz(A) _darr_append_n(A, 1, true, MTYPE_DARR) +#define darr_appendz_mt(A, MT) _darr_append_n(A, 1, true, MT) /** * Append an element `E` onto the array `A`, extending it's length by 1. @@ -295,8 +478,10 @@ void *__darr_resize(void *a, uint count, size_t esize); * Return: * A pointer to the element in the array. */ -#define darr_push(A, E) (*darr_append(A) = (E)) -#define darr_pushz(A) (darr_appendz(A)) +#define darr_push(A, E) (*darr_append(A) = (E)) +#define darr_push_mt(A, E, MT) (*darr_append_mt(A, MT) = (E)) +#define darr_pushz(A) (darr_appendz(A)) +#define darr_pushz_mt(A, MT) (darr_appendz_mt(A, MT)) /** @@ -344,6 +529,246 @@ void *__darr_resize(void *a, uint count, size_t esize); */ #define darr_end(A) ((A) + darr_len(A)) +/** + * darr_last() - Get a pointer to the last element of the array. + * darr_strnul() - Get a pointer to the NUL byte of the darr string or NULL. + * + * Args: + * A: The dynamic array, can be NULL. + * + * Return: + * A pointer to the last element of the array or NULL if the array is + * empty. + */ +#define darr_last(A) \ + ({ \ + uint __len = darr_len(A); \ + ((__len > 0) ? &(A)[__len - 1] : NULL); \ + }) +#define darr_strnul(S) darr_last(S) + +/** + * darr_in_sprintf() - sprintf into D. + * + * Args: + * D: The destination darr, D's value may be NULL. + * F: The format string + * ...: variable arguments for format string. + * + * Return: + * The dynamic_array D with the new string content. + */ +#define darr_in_sprintf(D, F, ...) __darr_in_sprintf(&(D), 0, F, __VA_ARGS__) + + +/** + * darr_in_strcat() - concat a string into a darr string. + * + * Args: + * D: The destination darr, D's value may be NULL. + * S: The string to concat onto D. + * + * Return: + * The dynamic_array D with the new string content. + */ +#define darr_in_strcat(D, S) \ + ({ \ + uint __dlen = darr_strlen(D); \ + uint __slen = strlen(S); \ + darr_ensure_cap_mt(D, __dlen + __slen + 1, MTYPE_DARR_STR); \ + if (darr_len(D) == 0) \ + *darr_append(D) = 0; \ + memcpy(darr_last(D), (S), __slen + 1); \ + _darr_len(D) += __slen; \ + D; \ + }) + +/** + * darr_in_strcatf() - concat a formatted string into a darr string. + * + * Args: + * D: The destination darr, D's value may be NULL. + * F: The format string to concat onto D after adding arguments. + * ...: The arguments for the format string. + * Return: + * The dynamic_array D with the new string content. + */ +#define darr_in_strcatf(D, F, ...) \ + __darr_in_sprintf(&(D), true, (F), __VA_ARGS__) + +/** + * darr_in_strcat_tail() - copies end of one darr str to another. + * + * This is a rather specialized function, it takes 2 darr's, a destination and a + * source. If the source is not longer than the destination nothing is done. + * Otherwise the characters in the source that lie beyond the length of the dest + * are added to the dest. No checking is done to make sure the common prefix + * matches. For example: + * + * D: "/foo" + * S: "/foo/bar" + * -> D: "/foo/bar" + * + * perhaps surprising results: + * D: "/foo" + * S: "/zoo/bar" + * -> D: "/foo/bar" + * + * Args: + * D: The destination darr, D's value may be NULL. + * S: The string to copy the tail from. + * + * Return: + * The dynamic_array D with the extended string content. + */ +#define darr_in_strcat_tail(D, S) \ + ({ \ + int __dsize, __ssize, __extra; \ + \ + if (darr_len(D) == 0) \ + *darr_append(D) = 0; \ + __dsize = darr_ilen(D); \ + __ssize = darr_ilen(S); \ + __extra = __ssize - __dsize; \ + if (__extra > 0) { \ + darr_ensure_cap_mt(D, (uint)__ssize, MTYPE_DARR_STR); \ + memcpy(darr_last(D), (S) + __dsize - 1, __extra + 1); \ + _darr_len(D) += __extra; \ + } \ + D; \ + }) + +/** + * darr_in_strdup_cap() - duplicate the string into a darr reserving capacity. + * darr_in_strdup() - duplicate the string into a darr. + * + * Args: + * D: The destination darr, D's value may be NULL. + * S: The string to duplicate. + * C: The capacity to reserve. + * + * Return: + * The dynamic_array D with the duplicated string. + */ +#define darr_in_strdup_cap(D, S, C) \ + ({ \ + size_t __size = strlen(S) + 1; \ + darr_reset(D); \ + darr_ensure_cap_mt(D, \ + ((size_t)(C) > __size) ? (size_t)(C) \ + : __size, \ + MTYPE_DARR_STR); \ + strlcpy(D, (S), darr_cap(D)); \ + darr_setlen((D), (size_t)__size); \ + D; \ + }) +#define darr_in_strdup(D, S) darr_in_strdup_cap(D, S, 1) + +/** + * darr_in_vsprintf() - vsprintf into D. + * + * Args: + * D: The destination darr, D's value may be NULL. + * F: The format string + * A: Varargs + * + * Return: + * The dynamic_array D with the new string content. + */ +#define darr_in_vsprintf(D, F, A) __darr_in_vsprintf(&(D), 0, F, A) + +/** + * darr_in_vstrcatf() - concat a formatted string into a darr string. + * + * Args: + * D: The destination darr, D's value may be NULL. + * F: The format string to concat onto D after adding arguments. + * A: Varargs + * + * Return: + * The dynamic_array D with the new string content. + */ +#define darr_in_vstrcatf(D, F, A) __darr_in_vsprintf(&(D), true, (F), (A)) + +/** + * darr_sprintf() - sprintf into a new dynamic array. + * + * Args: + * F: The format string + * ...: variable arguments for format string. + * + * Return: + * A char * dynamic_array with the new string content. + */ +#define darr_sprintf(F, ...) \ + ({ \ + char *d = NULL; \ + __darr_in_sprintf(&d, false, F, __VA_ARGS__); \ + d; \ + }) + +/** + * darr_strdup_cap() - duplicate the string reserving capacity. + * darr_strdup() - duplicate the string into a dynamic array. + * + * Args: + * S: The string to duplicate. + * C: The capacity to reserve. + * + * Return: + * The dynamic_array with the duplicated string. + */ +#define darr_strdup_cap(S, C) \ + ({ \ + size_t __size = strlen(S) + 1; \ + char *__s = NULL; \ + /* Cast to ssize_t to avoid warning when C == 0 */ \ + darr_ensure_cap_mt(__s, \ + ((ssize_t)(C) > (ssize_t)__size) \ + ? (size_t)(C) \ + : __size, \ + MTYPE_DARR_STR); \ + strlcpy(__s, (S), darr_cap(__s)); \ + darr_setlen(__s, (size_t)__size); \ + __s; \ + }) +#define darr_strdup(S) darr_strdup_cap(S, 0) + +/** + * darr_strlen() - get the length of the NUL terminated string in a darr. + * + * Args: + * S: The string to measure, value may be NULL. + * + * Return: + * The length of the NUL terminated string in @S + */ +#define darr_strlen(S) \ + ({ \ + uint __size = darr_len(S); \ + if (__size) \ + __size -= 1; \ + assert(!(S) || ((char *)(S))[__size] == 0); \ + __size; \ + }) + +/** + * darr_vsprintf() - vsprintf into a new dynamic array. + * + * Args: + * F: The format string + * A: Varargs + * + * Return: + * The dynamic_array D with the new string content. + */ +#define darr_vsprintf(F, A) \ + ({ \ + char *d = NULL; \ + darr_in_vsprintf(d, F, A); \ + d; \ + }) + /** * Iterate over array `A` using a pointer to each element in `P`. * @@ -361,3 +786,5 @@ void *__darr_resize(void *a, uint count, size_t esize); * I: A uint variable to store the current element index in. */ #define darr_foreach_i(A, I) for ((I) = 0; (I) < darr_len(A); (I)++) + +#endif /* _FRR_DARR_H_ */ diff --git a/lib/defun_lex.l b/lib/defun_lex.l index 124f864166f0..3104e48063b5 100644 --- a/lib/defun_lex.l +++ b/lib/defun_lex.l @@ -140,6 +140,7 @@ SPECIAL [(),] "DEFPY_ATTR" value = strdup(yytext); return DEFUNNY; "DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY; "DEFPY_YANG" value = strdup(yytext); return DEFUNNY; +"DEFPY_YANG_HIDDEN" value = strdup(yytext); return DEFUNNY; "DEFPY_YANG_NOSH" value = strdup(yytext); return DEFUNNY; "ALIAS" value = strdup(yytext); return DEFUNNY; "ALIAS_HIDDEN" value = strdup(yytext); return DEFUNNY; diff --git a/lib/distribute.c b/lib/distribute.c index 65487676d6c6..c0693b084908 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -17,8 +17,6 @@ DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list"); DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname"); DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name"); -static struct list *dist_ctx_list; - static struct distribute *distribute_new(void) { return XCALLOC(MTYPE_DISTRIBUTE, sizeof(struct distribute)); @@ -244,11 +242,10 @@ static enum distribute_type distribute_direction(const char *dir, bool v4) __builtin_unreachable(); } -int distribute_list_parser(bool prefix, bool v4, const char *dir, - const char *list, const char *ifname) +int distribute_list_parser(struct distribute_ctx *ctx, bool prefix, bool v4, + const char *dir, const char *list, const char *ifname) { enum distribute_type type = distribute_direction(dir, v4); - struct distribute_ctx *ctx = listnode_head(dist_ctx_list); void (*distfn)(struct distribute_ctx *, const char *, enum distribute_type, const char *) = @@ -259,12 +256,12 @@ int distribute_list_parser(bool prefix, bool v4, const char *dir, return CMD_SUCCESS; } -int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4, - const char *dir, const char *list, - const char *ifname) + +int distribute_list_no_parser(struct distribute_ctx *ctx, struct vty *vty, + bool prefix, bool v4, const char *dir, + const char *list, const char *ifname) { enum distribute_type type = distribute_direction(dir, v4); - struct distribute_ctx *ctx = listnode_head(dist_ctx_list); int ret; int (*distfn)(struct distribute_ctx *, const char *, @@ -274,7 +271,8 @@ int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4, ret = distfn(ctx, ifname, type, list); if (!ret) { - vty_out(vty, "distribute list doesn't exist\n"); + if (vty) + vty_out(vty, "distribute list doesn't exist\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -443,17 +441,165 @@ int config_write_distribute(struct vty *vty, return write; } +/* ---------- */ +/* Northbound */ +/* ---------- */ + +int group_distribute_list_create_helper( + struct nb_cb_create_args *args, struct distribute_ctx *ctx) +{ + nb_running_set_entry(args->dnode, ctx); + return NB_OK; +} + +/* + * XPath: /frr-ripd:ripd/instance/distribute-lists/distribute-list/{in,out}/{access,prefix}-list + */ + +static int distribute_list_leaf_update(const struct lyd_node *dnode, + int ip_version, bool no); + +int group_distribute_list_destroy(struct nb_cb_destroy_args *args) +{ + struct lyd_node *dnode; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* + * We don't keep the IP version of distribute-list anywhere, so we're + * trying to remove both. If one doesn't exist, it's simply skipped by + * the remove function. + */ + + dnode = yang_dnode_get(args->dnode, "in/access-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + dnode = yang_dnode_get(args->dnode, "in/prefix-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + dnode = yang_dnode_get(args->dnode, "out/access-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + dnode = yang_dnode_get(args->dnode, "out/prefix-list"); + if (dnode) { + distribute_list_leaf_update(dnode, 4, true); + distribute_list_leaf_update(dnode, 6, true); + } + + nb_running_unset_entry(args->dnode); + return NB_OK; +} + +static int distribute_list_leaf_update(const struct lyd_node *dnode, + int ip_version, bool no) +{ + struct distribute_ctx *ctx; + struct lyd_node *dir_node = lyd_parent(dnode); + struct lyd_node_inner *list_node = dir_node->parent; + struct lyd_node *intf_key = list_node->child; + bool ipv4 = ip_version == 4 ? true : false; + bool prefix; + + ctx = nb_running_get_entry_non_rec(&list_node->node, NULL, false); + + prefix = dnode->schema->name[0] == 'p' ? true : false; + if (no) + distribute_list_no_parser(ctx, NULL, prefix, ipv4, + dir_node->schema->name, + lyd_get_value(dnode), + lyd_get_value(intf_key)); + else + distribute_list_parser(ctx, prefix, ipv4, + dir_node->schema->name, + lyd_get_value(dnode), + lyd_get_value(intf_key)); + return NB_OK; +} + +static int distribute_list_leaf_modify(struct nb_cb_modify_args *args, + int ip_version) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + return distribute_list_leaf_update(args->dnode, ip_version, false); +} + +static int distribute_list_leaf_destroy(struct nb_cb_destroy_args *args, + int ip_version) +{ + if (args->event != NB_EV_APPLY) + return NB_OK; + return distribute_list_leaf_update(args->dnode, ip_version, true); +} + +int group_distribute_list_ipv4_modify(struct nb_cb_modify_args *args) +{ + return distribute_list_leaf_modify(args, 4); +} +int group_distribute_list_ipv4_destroy(struct nb_cb_destroy_args *args) +{ + return distribute_list_leaf_destroy(args, 4); +} +int group_distribute_list_ipv6_modify(struct nb_cb_modify_args *args) +{ + return distribute_list_leaf_modify(args, 6); +} +int group_distribute_list_ipv6_destroy(struct nb_cb_destroy_args *args) +{ + return distribute_list_leaf_destroy(args, 6); +} + +static int distribute_list_leaf_cli_show(struct vty *vty, + const struct lyd_node *dnode, + int ip_version) +{ + struct lyd_node *dir_node = lyd_parent(dnode); + struct lyd_node_inner *list_node = dir_node->parent; + struct lyd_node *intf_key = list_node->child; + bool ipv6 = ip_version == 6 ? true : false; + bool prefix; + + prefix = dnode->schema->name[0] == 'p' ? true : false; + vty_out(vty, + " %sdistribute-list %s%s %s %s\n", + ipv6 ? "ipv6 " : "", + prefix ? "prefix " : "", + lyd_get_value(dnode), + dir_node->schema->name, + lyd_get_value(intf_key)); + + return NB_OK; +} + +void group_distribute_list_ipv4_cli_show(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + distribute_list_leaf_cli_show(vty, dnode, 4); +} +void group_distribute_list_ipv6_cli_show(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + distribute_list_leaf_cli_show(vty, dnode, 6); +} + +/* ------------- */ +/* Setup/Cleanup */ +/* ------------- */ + void distribute_list_delete(struct distribute_ctx **ctx) { hash_clean_and_free(&(*ctx)->disthash, (void (*)(void *))distribute_free); - if (dist_ctx_list) { - listnode_delete(dist_ctx_list, *ctx); - if (list_isempty(dist_ctx_list)) - list_delete(&dist_ctx_list); - } - XFREE(MTYPE_DISTRIBUTE_CTX, (*ctx)); } @@ -464,11 +610,9 @@ struct distribute_ctx *distribute_list_ctx_create(struct vrf *vrf) ctx = XCALLOC(MTYPE_DISTRIBUTE_CTX, sizeof(struct distribute_ctx)); ctx->vrf = vrf; - ctx->disthash = hash_create( - distribute_hash_make, - (bool (*)(const void *, const void *))distribute_cmp, NULL); - if (!dist_ctx_list) - dist_ctx_list = list_new(); - listnode_add(dist_ctx_list, ctx); + ctx->disthash = + hash_create(distribute_hash_make, + (bool (*)(const void *, const void *))distribute_cmp, + NULL); return ctx; } diff --git a/lib/distribute.h b/lib/distribute.h index 75783712a199..a0bc34898252 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -9,6 +9,7 @@ #include #include "if.h" #include "filter.h" +#include "northbound.h" #ifdef __cplusplus extern "C" { @@ -69,11 +70,43 @@ extern enum filter_type distribute_apply_in(struct interface *, extern enum filter_type distribute_apply_out(struct interface *, struct prefix *); -extern int distribute_list_parser(bool prefix, bool v4, const char *dir, - const char *list, const char *ifname); -extern int distribute_list_no_parser(struct vty *vty, bool prefix, bool v4, +extern int distribute_list_parser(struct distribute_ctx *ctx, bool prefix, + bool v4, const char *dir, const char *list, + const char *ifname); +extern int distribute_list_no_parser(struct distribute_ctx *ctx, + struct vty *vty, bool prefix, bool v4, const char *dir, const char *list, const char *ifname); + +/* + * Northbound + */ + +/* + * Define your own create callback and then call thes helper with your + * distribute list context when a list entry is created. Additionally, plug the + * destroy callback into the frr_module_yang_info struct, or call it if you have + * your own callback destroy function. + */ +extern int group_distribute_list_create_helper(struct nb_cb_create_args *args, + struct distribute_ctx *ctx); +extern int group_distribute_list_destroy(struct nb_cb_destroy_args *args); + +/* + * Plug 3 of these handlers in for your distribute-list for all the northbound + * distribute_list leaf callbacks. If you need multi-protocol then use the + * grouping twice under 2 different containers. + */ +extern int group_distribute_list_ipv4_modify(struct nb_cb_modify_args *args); +extern int group_distribute_list_ipv4_destroy(struct nb_cb_destroy_args *args); +extern void group_distribute_list_ipv4_cli_show(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); +extern int group_distribute_list_ipv6_modify(struct nb_cb_modify_args *args); +extern int group_distribute_list_ipv6_destroy(struct nb_cb_destroy_args *args); +extern void group_distribute_list_ipv6_cli_show(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); #ifdef __cplusplus } #endif diff --git a/lib/elf_py.c b/lib/elf_py.c index 643495d8c76f..2b4fea373f03 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -1358,6 +1358,15 @@ bool elf_py_init(PyObject *pymod) (void)methods_elfpy; #endif +#if defined(HAVE_GELF_GETNOTE) && defined(HAVE_ELF_GETDATA_RAWCHUNK) + PyObject *elf_notes = Py_True; +#else + PyObject *elf_notes = Py_False; +#endif + Py_INCREF(elf_notes); + if (PyModule_AddObject(pymod, "elf_notes", elf_notes)) + Py_DECREF(elf_notes); + ELFFormatError = PyErr_NewException("_clippy.ELFFormatError", PyExc_ValueError, NULL); PyModule_AddObject(pymod, "ELFFormatError", ELFFormatError); diff --git a/lib/event.c b/lib/event.c index 458e29f2481b..d925d0d5f0fc 100644 --- a/lib/event.c +++ b/lib/event.c @@ -6,6 +6,8 @@ /* #define DEBUG */ #include + +#include #include #include "frrevent.h" @@ -55,11 +57,6 @@ static int event_timer_cmp(const struct event *a, const struct event *b) DECLARE_HEAP(event_timer_list, struct event, timeritem, event_timer_cmp); -#if defined(__APPLE__) -#include -#include -#endif - #define AWAKEN(m) \ do { \ const unsigned char wakebyte = 0x01; \ @@ -75,14 +72,7 @@ static struct list *masters; static void thread_free(struct event_loop *master, struct event *thread); -#ifndef EXCLUDE_CPU_TIME -#define EXCLUDE_CPU_TIME 0 -#endif -#ifndef CONSUMED_TIME_CHECK -#define CONSUMED_TIME_CHECK 0 -#endif - -bool cputime_enabled = !EXCLUDE_CPU_TIME; +bool cputime_enabled = true; unsigned long cputime_threshold = CONSUMED_TIME_CHECK; unsigned long walltime_threshold = CONSUMED_TIME_CHECK; @@ -223,7 +213,7 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) "Active Runtime(ms) Invoked Avg uSec Max uSecs"); vty_out(vty, " Avg uSec Max uSecs"); vty_out(vty, - " CPU_Warn Wall_Warn Starv_Warn Type Thread\n"); + " CPU_Warn Wall_Warn Starv_Warn Type Event\n"); if (cpu_records_count(m->cpu_records)) { struct cpu_event_history *rec; @@ -239,13 +229,13 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) } vty_out(vty, "\n"); - vty_out(vty, "Total thread statistics\n"); + vty_out(vty, "Total Event statistics\n"); vty_out(vty, "-------------------------\n"); vty_out(vty, "%30s %18s %18s\n", "", "CPU (user+system):", "Real (wall-clock):"); vty_out(vty, "Active Runtime(ms) Invoked Avg uSec Max uSecs"); - vty_out(vty, " Avg uSec Max uSecs CPU_Warn Wall_Warn"); - vty_out(vty, " Type Thread\n"); + vty_out(vty, " Avg uSec Max uSecs CPU_Warn Wall_Warn Starv_Warn"); + vty_out(vty, " Type Event\n"); if (tmp.total_calls > 0) vty_out_cpu_event_history(vty, &tmp); @@ -314,13 +304,13 @@ static uint8_t parse_filter(const char *filterstr) return filter; } -DEFUN_NOSH (show_thread_cpu, - show_thread_cpu_cmd, - "show thread cpu [FILTER]", - SHOW_STR - "Thread information\n" - "Thread CPU usage\n" - "Display filter (rwtex)\n") +DEFUN_NOSH (show_event_cpu, + show_event_cpu_cmd, + "show event cpu [FILTER]", + SHOW_STR + "Event information\n" + "Event CPU usage\n" + "Display filter (rwtexb)\n") { uint8_t filter = (uint8_t)-1U; int idx = 0; @@ -380,7 +370,7 @@ DEFPY (service_walltime_warning, return CMD_SUCCESS; } -static void show_thread_poll_helper(struct vty *vty, struct event_loop *m) +static void show_event_poll_helper(struct vty *vty, struct event_loop *m) { const char *name = m->name ? m->name : "main"; char underline[strlen(name) + 1]; @@ -421,31 +411,33 @@ static void show_thread_poll_helper(struct vty *vty, struct event_loop *m) } } -DEFUN_NOSH (show_thread_poll, - show_thread_poll_cmd, - "show thread poll", - SHOW_STR - "Thread information\n" - "Show poll FD's and information\n") +DEFUN_NOSH (show_event_poll, + show_event_poll_cmd, + "show event poll", + SHOW_STR + "Event information\n" + "Event Poll Information\n") { struct listnode *node; struct event_loop *m; frr_with_mutex (&masters_mtx) { for (ALL_LIST_ELEMENTS_RO(masters, node, m)) - show_thread_poll_helper(vty, m); + show_event_poll_helper(vty, m); } return CMD_SUCCESS; } - -DEFUN (clear_thread_cpu, - clear_thread_cpu_cmd, - "clear thread cpu [FILTER]", +#if CONFDATE > 20241231 +CPP_NOTICE("Remove `clear thread cpu` command") +#endif +DEFUN (clear_event_cpu, + clear_event_cpu_cmd, + "clear event cpu [FILTER]", "Clear stored data in all pthreads\n" - "Thread information\n" - "Thread CPU usage\n" + "Event information\n" + "Event CPU usage\n" "Display filter (rwtexb)\n") { uint8_t filter = (uint8_t)-1U; @@ -465,7 +457,15 @@ DEFUN (clear_thread_cpu, return CMD_SUCCESS; } -static void show_thread_timers_helper(struct vty *vty, struct event_loop *m) +ALIAS (clear_event_cpu, + clear_thread_cpu_cmd, + "clear thread cpu [FILTER]", + "Clear stored data in all pthreads\n" + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtexb)\n") + +static void show_event_timers_helper(struct vty *vty, struct event_loop *m) { const char *name = m->name ? m->name : "main"; char underline[strlen(name) + 1]; @@ -482,19 +482,19 @@ static void show_thread_timers_helper(struct vty *vty, struct event_loop *m) } } -DEFPY_NOSH (show_thread_timers, - show_thread_timers_cmd, - "show thread timers", - SHOW_STR - "Thread information\n" - "Show all timers and how long they have in the system\n") +DEFPY_NOSH (show_event_timers, + show_event_timers_cmd, + "show event timers", + SHOW_STR + "Event information\n" + "Show all timers and how long they have in the system\n") { struct listnode *node; struct event_loop *m; frr_with_mutex (&masters_mtx) { for (ALL_LIST_ELEMENTS_RO(masters, node, m)) - show_thread_timers_helper(vty, m); + show_event_timers_helper(vty, m); } return CMD_SUCCESS; @@ -502,15 +502,16 @@ DEFPY_NOSH (show_thread_timers, void event_cmd_init(void) { - install_element(VIEW_NODE, &show_thread_cpu_cmd); - install_element(VIEW_NODE, &show_thread_poll_cmd); + install_element(VIEW_NODE, &show_event_cpu_cmd); + install_element(VIEW_NODE, &show_event_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); + install_element(ENABLE_NODE, &clear_event_cpu_cmd); install_element(CONFIG_NODE, &service_cputime_stats_cmd); install_element(CONFIG_NODE, &service_cputime_warning_cmd); install_element(CONFIG_NODE, &service_walltime_warning_cmd); - install_element(VIEW_NODE, &show_thread_timers_cmd); + install_element(VIEW_NODE, &show_event_timers_cmd); } /* CLI end ------------------------------------------------------------------ */ @@ -526,6 +527,7 @@ static void initializer(void) pthread_key_create(&thread_current, NULL); } +#define STUPIDLY_LARGE_FD_SIZE 100000 struct event_loop *event_master_create(const char *name) { struct event_loop *rv; @@ -552,6 +554,14 @@ struct event_loop *event_master_create(const char *name) rv->fd_limit = (int)limit.rlim_cur; } + if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE) { + if (frr_is_daemon()) + zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", + rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); + + rv->fd_limit = STUPIDLY_LARGE_FD_SIZE; + } + rv->read = XCALLOC(MTYPE_EVENT_POLL, sizeof(struct event *) * rv->fd_limit); @@ -1601,12 +1611,70 @@ static int thread_process_io_helper(struct event_loop *m, struct event *thread, return 1; } +static inline void thread_process_io_inner_loop(struct event_loop *m, + unsigned int num, + struct pollfd *pfds, nfds_t *i, + uint32_t *ready) +{ + /* no event for current fd? immediately continue */ + if (pfds[*i].revents == 0) + return; + + *ready = *ready + 1; + + /* + * Unless someone has called event_cancel from another + * pthread, the only thing that could have changed in + * m->handler.pfds while we were asleep is the .events + * field in a given pollfd. Barring event_cancel() that + * value should be a superset of the values we have in our + * copy, so there's no need to update it. Similarily, + * barring deletion, the fd should still be a valid index + * into the master's pfds. + * + * We are including POLLERR here to do a READ event + * this is because the read should fail and the + * read function should handle it appropriately + */ + if (pfds[*i].revents & (POLLIN | POLLHUP | POLLERR)) { + thread_process_io_helper(m, m->read[pfds[*i].fd], POLLIN, + pfds[*i].revents, *i); + } + if (pfds[*i].revents & POLLOUT) + thread_process_io_helper(m, m->write[pfds[*i].fd], POLLOUT, + pfds[*i].revents, *i); + + /* + * if one of our file descriptors is garbage, remove the same + * from both pfds + update sizes and index + */ + if (pfds[*i].revents & POLLNVAL) { + memmove(m->handler.pfds + *i, m->handler.pfds + *i + 1, + (m->handler.pfdcount - *i - 1) * sizeof(struct pollfd)); + m->handler.pfdcount--; + m->handler.pfds[m->handler.pfdcount].fd = 0; + m->handler.pfds[m->handler.pfdcount].events = 0; + + memmove(pfds + *i, pfds + *i + 1, + (m->handler.copycount - *i - 1) * sizeof(struct pollfd)); + m->handler.copycount--; + m->handler.copy[m->handler.copycount].fd = 0; + m->handler.copy[m->handler.copycount].events = 0; + + *i = *i - 1; + } +} + /** * Process I/O events. * * Walks through file descriptor array looking for those pollfds whose .revents * field has something interesting. Deletes any invalid file descriptors. * + * Try to impart some impartiality to handling of io. The event + * system will cycle through the fd's available for io + * giving each one a chance to go first. + * * @param m the thread master * @param num the number of active file descriptors (return value of poll()) */ @@ -1614,58 +1682,15 @@ static void thread_process_io(struct event_loop *m, unsigned int num) { unsigned int ready = 0; struct pollfd *pfds = m->handler.copy; + nfds_t i, last_read = m->last_read % m->handler.copycount; - for (nfds_t i = 0; i < m->handler.copycount && ready < num; ++i) { - /* no event for current fd? immediately continue */ - if (pfds[i].revents == 0) - continue; - - ready++; + for (i = last_read; i < m->handler.copycount && ready < num; ++i) + thread_process_io_inner_loop(m, num, pfds, &i, &ready); - /* - * Unless someone has called event_cancel from another - * pthread, the only thing that could have changed in - * m->handler.pfds while we were asleep is the .events - * field in a given pollfd. Barring event_cancel() that - * value should be a superset of the values we have in our - * copy, so there's no need to update it. Similarily, - * barring deletion, the fd should still be a valid index - * into the master's pfds. - * - * We are including POLLERR here to do a READ event - * this is because the read should fail and the - * read function should handle it appropriately - */ - if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) { - thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN, - pfds[i].revents, i); - } - if (pfds[i].revents & POLLOUT) - thread_process_io_helper(m, m->write[pfds[i].fd], - POLLOUT, pfds[i].revents, i); + for (i = 0; i < last_read && ready < num; ++i) + thread_process_io_inner_loop(m, num, pfds, &i, &ready); - /* - * if one of our file descriptors is garbage, remove the same - * from both pfds + update sizes and index - */ - if (pfds[i].revents & POLLNVAL) { - memmove(m->handler.pfds + i, m->handler.pfds + i + 1, - (m->handler.pfdcount - i - 1) - * sizeof(struct pollfd)); - m->handler.pfdcount--; - m->handler.pfds[m->handler.pfdcount].fd = 0; - m->handler.pfds[m->handler.pfdcount].events = 0; - - memmove(pfds + i, pfds + i + 1, - (m->handler.copycount - i - 1) - * sizeof(struct pollfd)); - m->handler.copycount--; - m->handler.copy[m->handler.copycount].fd = 0; - m->handler.copy[m->handler.copycount].events = 0; - - i--; - } - } + m->last_read++; } /* Add all timers that have popped to the ready list. */ @@ -1845,12 +1870,6 @@ struct event *event_fetch(struct event_loop *m, struct event *fetch) return fetch; } -static unsigned long timeval_elapsed(struct timeval a, struct timeval b) -{ - return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) - + (a.tv_usec - b.tv_usec)); -} - unsigned long event_consumed_time(RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime) { @@ -1953,6 +1972,7 @@ void event_getrusage(RUSAGE_T *r) void event_call(struct event *thread) { RUSAGE_T before, after; + bool suppress_warnings = EVENT_ARG(thread); /* if the thread being called is the CLI, it may change cputime_enabled * ("service cputime-stats" command), which can result in nonsensical @@ -2013,6 +2033,9 @@ void event_call(struct event *thread) atomic_fetch_or_explicit(&thread->hist->types, 1 << thread->add_type, memory_order_seq_cst); + if (suppress_warnings) + return; + if (cputime_enabled_here && cputime_enabled && cputime_threshold && cputime > cputime_threshold) { /* diff --git a/lib/explicit_bzero.c b/lib/explicit_bzero.c index fa64ed85bffb..e838f95e657b 100644 --- a/lib/explicit_bzero.c +++ b/lib/explicit_bzero.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Public domain. * Written by Matthew Dempsky. diff --git a/lib/filter.c b/lib/filter.c index f86adab5d606..0722bed1cbf5 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -410,7 +410,10 @@ void access_list_filter_add(struct access_list *access, filter->prev = access->tail; access->tail = filter; } +} +void access_list_filter_update(struct access_list *access) +{ /* Run hook function. */ if (access->master->add_hook) (*access->master->add_hook)(access); @@ -455,7 +458,6 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi, struct filter_cisco *filter; bool first; json_object *json = NULL; - json_object *json_proto = NULL; master = access_master_get(afi); if (master == NULL) { @@ -466,12 +468,7 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi, if (use_json) json = json_object_new_object(); - - /* Print the name of the protocol */ - if (json) { - json_proto = json_object_new_object(); - json_object_object_add(json, frr_protoname, json_proto); - } else + else vty_out(vty, "%s:\n", frr_protoname); for (access = master->str.head; access; access = access->next) { @@ -493,7 +490,7 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi, if (json) { json_acl = json_object_new_object(); - json_object_object_add(json_proto, + json_object_object_add(json, access->name, json_acl); @@ -593,7 +590,7 @@ DEFUN (show_mac_access_list_name, return filter_show(vty, argv[3]->arg, AFI_L2VPN, false); } -DEFUN (show_ip_access_list, +DEFUN_NOSH (show_ip_access_list, show_ip_access_list_cmd, "show ip access-list [json]", SHOW_STR @@ -605,7 +602,7 @@ DEFUN (show_ip_access_list, return filter_show(vty, NULL, AFI_IP, uj); } -DEFUN (show_ip_access_list_name, +DEFUN_NOSH (show_ip_access_list_name, show_ip_access_list_name_cmd, "show ip access-list ACCESSLIST4_NAME [json]", SHOW_STR @@ -619,7 +616,7 @@ DEFUN (show_ip_access_list_name, return filter_show(vty, argv[idx_acl]->arg, AFI_IP, uj); } -DEFUN (show_ipv6_access_list, +DEFUN_NOSH (show_ipv6_access_list, show_ipv6_access_list_cmd, "show ipv6 access-list [json]", SHOW_STR @@ -631,7 +628,7 @@ DEFUN (show_ipv6_access_list, return filter_show(vty, NULL, AFI_IP6, uj); } -DEFUN (show_ipv6_access_list_name, +DEFUN_NOSH (show_ipv6_access_list_name, show_ipv6_access_list_name_cmd, "show ipv6 access-list ACCESSLIST6_NAME [json]", SHOW_STR @@ -885,7 +882,7 @@ static void access_list_init_ipv6(void) install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd); } -void access_list_init(void) +void access_list_init_new(bool in_backend) { cmd_variable_handler_register(access_list_handlers); @@ -893,7 +890,15 @@ void access_list_init(void) access_list_init_ipv6(); access_list_init_mac(); - filter_cli_init(); + if (!in_backend) { + /* we do not want to handle config commands in the backend */ + filter_cli_init(); + } +} + +void access_list_init(void) +{ + access_list_init_new(false); } void access_list_reset(void) diff --git a/lib/filter.h b/lib/filter.h index e092f0771acc..4fa482ba4ee7 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -114,6 +114,7 @@ struct access_master { /* Prototypes for access-list. */ extern void access_list_init(void); +extern void access_list_init_new(bool in_backend); extern void access_list_reset(void); extern void access_list_add_hook(void (*func)(struct access_list *)); extern void access_list_delete_hook(void (*func)(struct access_list *)); @@ -124,13 +125,14 @@ extern enum filter_type access_list_apply(struct access_list *access, struct access_list *access_list_get(afi_t afi, const char *name); void access_list_delete(struct access_list *access); struct filter *filter_new(void); -void access_list_filter_add(struct access_list *access, - struct filter *filter); +void access_list_filter_add(struct access_list *access, struct filter *filter); void access_list_filter_delete(struct access_list *access, struct filter *filter); +void access_list_filter_update(struct access_list *access); int64_t filter_new_seq_get(struct access_list *access); extern const struct frr_yang_module_info frr_filter_info; +extern const struct frr_yang_module_info frr_filter_cli_info; /* filter_nb.c */ diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 5c3dc5e49d55..c40c2a75fed5 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -69,59 +69,66 @@ static int64_t acl_get_seq(struct vty *vty, const char *xpath, bool is_remove) return seq; } -static int acl_remove_if_empty(struct vty *vty, const char *iptype, - const char *name) +/** + * Remove main data structure filter list if there are no more entries or + * remark. This fixes compatibility with old CLI and tests. + */ +static int filter_remove_check_empty(struct vty *vty, const char *ftype, + const char *iptype, const char *name, + uint32_t del_seq, bool del_remark) { + const struct lyd_node *remark_dnode = NULL; + const struct lyd_node *entry_dnode = NULL; char xpath[XPATH_MAXLEN]; + uint32_t count; + + /* Count existing entries */ + count = yang_dnode_count(vty->candidate_config->dnode, + "/frr-filter:lib/%s-list[type='%s'][name='%s']/entry", + ftype, iptype, name); + + /* Check entry-to-delete actually exists */ + if (del_seq) { + snprintf(xpath, sizeof(xpath), + "/frr-filter:lib/%s-list[type='%s'][name='%s']/entry[sequence='%u']", + ftype, iptype, name, del_seq); + entry_dnode = yang_dnode_get(vty->candidate_config->dnode, + xpath); + + /* If exists, delete and don't count it, we need only remaining entries */ + if (entry_dnode) { + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + count--; + } + } + /* Delete the remark, or check whether it exists if we're keeping it */ snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list[type='%s'][name='%s']/remark", + "/frr-filter:lib/%s-list[type='%s'][name='%s']/remark", ftype, iptype, name); - /* List is not empty if there is a remark, check that: */ - if (yang_dnode_exists(vty->candidate_config->dnode, xpath)) - return CMD_SUCCESS; - - /* Check if we have any entries: */ - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list[type='%s'][name='%s']", iptype, - name); - /* - * NOTE: if the list is empty it will return the first sequence - * number: 5. - */ - if (acl_get_seq(vty, xpath, true) != 5) - return CMD_SUCCESS; + if (del_remark) + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + else + remark_dnode = yang_dnode_get(vty->candidate_config->dnode, + xpath); + + /* If there are no entries left and no remark, delete the whole list */ + if (count == 0 && !remark_dnode) { + snprintf(xpath, sizeof(xpath), + "/frr-filter:lib/%s-list[type='%s'][name='%s']", ftype, + iptype, name); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } - /* Nobody is using this list, lets remove it. */ - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } -static int acl_remove(struct vty *vty, const char *iptype, const char *name, - int64_t sseq) -{ - char xpath[XPATH_MAXLEN]; - int rv; - - snprintfrr( - xpath, sizeof(xpath), - "/frr-filter:lib/access-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']", - iptype, name, sseq); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return acl_remove_if_empty(vty, iptype, name); - - return rv; -} - /* * Cisco (legacy) access lists. */ DEFPY_YANG( access_list_std, access_list_std_cmd, - "access-list WORD$name [seq (1-4294967295)$seq] $action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>", + "access-list ACCESSLIST4_NAME$name [seq (1-4294967295)$seq] $action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>", ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR @@ -197,7 +204,7 @@ DEFPY_YANG( DEFPY_YANG( no_access_list_std, no_access_list_std_cmd, - "no access-list WORD$name [seq (1-4294967295)$seq] $action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>", + "no access-list ACCESSLIST4_NAME$name [seq (1-4294967295)$seq] $action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>", NO_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -213,7 +220,8 @@ DEFPY_YANG( /* If the user provided sequence number, then just go for it. */ if (seq_str != NULL) - return acl_remove(vty, "ipv4", name, seq); + return filter_remove_check_empty(vty, "access", "ipv4", name, + seq, false); /* Otherwise, to keep compatibility, we need to figure it out. */ ada.ada_type = "ipv4"; @@ -237,12 +245,13 @@ DEFPY_YANG( else return CMD_WARNING_CONFIG_FAILED; - return acl_remove(vty, "ipv4", name, sseq); + return filter_remove_check_empty(vty, "access", "ipv4", name, sseq, + false); } DEFPY_YANG( access_list_ext, access_list_ext_cmd, - "access-list WORD$name [seq (1-4294967295)$seq] $action ip ", + "access-list ACCESSLIST4_NAME$name [seq (1-4294967295)$seq] $action ip ", ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR @@ -360,7 +369,7 @@ DEFPY_YANG( DEFPY_YANG( no_access_list_ext, no_access_list_ext_cmd, - "no access-list WORD$name [seq (1-4294967295)$seq] $action ip ", + "no access-list ACCESSLIST4_NAME$name [seq (1-4294967295)$seq] $action ip ", NO_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -384,7 +393,8 @@ DEFPY_YANG( /* If the user provided sequence number, then just go for it. */ if (seq_str != NULL) - return acl_remove(vty, "ipv4", name, seq); + return filter_remove_check_empty(vty, "access", "ipv4", name, + seq, false); /* Otherwise, to keep compatibility, we need to figure it out. */ ada.ada_type = "ipv4"; @@ -429,7 +439,8 @@ DEFPY_YANG( else return CMD_WARNING_CONFIG_FAILED; - return acl_remove(vty, "ipv4", name, sseq); + return filter_remove_check_empty(vty, "access", "ipv4", name, sseq, + false); } /* @@ -437,7 +448,7 @@ DEFPY_YANG( */ DEFPY_YANG( access_list, access_list_cmd, - "access-list WORD$name [seq (1-4294967295)$seq] $action ", + "access-list ACCESSLIST4_NAME$name [seq (1-4294967295)$seq] $action ", ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR @@ -510,7 +521,7 @@ DEFPY_YANG( DEFPY_YANG( no_access_list, no_access_list_cmd, - "no access-list WORD$name [seq (1-4294967295)$seq] $action ", + "no access-list ACCESSLIST4_NAME$name [seq (1-4294967295)$seq] $action ", NO_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -525,7 +536,8 @@ DEFPY_YANG( /* If the user provided sequence number, then just go for it. */ if (seq_str != NULL) - return acl_remove(vty, "ipv4", name, seq); + return filter_remove_check_empty(vty, "access", "ipv4", name, + seq, false); /* Otherwise, to keep compatibility, we need to figure it out. */ ada.ada_type = "ipv4"; @@ -549,12 +561,13 @@ DEFPY_YANG( else return CMD_WARNING_CONFIG_FAILED; - return acl_remove(vty, "ipv4", name, sseq); + return filter_remove_check_empty(vty, "access", "ipv4", name, sseq, + false); } DEFPY_YANG( no_access_list_all, no_access_list_all_cmd, - "no access-list WORD$name", + "no access-list ACCESSLIST4_NAME$name", NO_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR) @@ -570,7 +583,7 @@ DEFPY_YANG( DEFPY_YANG( access_list_remark, access_list_remark_cmd, - "access-list WORD$name remark LINE...", + "access-list ACCESSLIST4_NAME$name remark LINE...", ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR ACCESS_LIST_REMARK_STR @@ -594,30 +607,18 @@ DEFPY_YANG( DEFPY_YANG( no_access_list_remark, no_access_list_remark_cmd, - "no access-list WORD$name remark", + "no access-list ACCESSLIST4_NAME$name remark", NO_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR ACCESS_LIST_REMARK_STR) { - char xpath[XPATH_MAXLEN]; - int rv; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark", - name); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return acl_remove_if_empty(vty, "ipv4", name); - - return rv; + return filter_remove_check_empty(vty, "access", "ipv4", name, 0, true); } ALIAS( no_access_list_remark, no_access_list_remark_line_cmd, - "no access-list WORD$name remark LINE...", + "no access-list ACCESSLIST4_NAME$name remark LINE...", NO_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -626,7 +627,7 @@ ALIAS( DEFPY_YANG( ipv6_access_list, ipv6_access_list_cmd, - "ipv6 access-list WORD$name [seq (1-4294967295)$seq] $action ", + "ipv6 access-list ACCESSLIST6_NAME$name [seq (1-4294967295)$seq] $action ", IPV6_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -700,7 +701,7 @@ DEFPY_YANG( DEFPY_YANG( no_ipv6_access_list, no_ipv6_access_list_cmd, - "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] $action ", + "no ipv6 access-list ACCESSLIST6_NAME$name [seq (1-4294967295)$seq] $action ", NO_STR IPV6_STR ACCESS_LIST_STR @@ -716,7 +717,8 @@ DEFPY_YANG( /* If the user provided sequence number, then just go for it. */ if (seq_str != NULL) - return acl_remove(vty, "ipv6", name, seq); + return filter_remove_check_empty(vty, "access", "ipv6", name, + seq, false); /* Otherwise, to keep compatibility, we need to figure it out. */ ada.ada_type = "ipv6"; @@ -740,12 +742,13 @@ DEFPY_YANG( else return CMD_WARNING_CONFIG_FAILED; - return acl_remove(vty, "ipv6", name, sseq); + return filter_remove_check_empty(vty, "access", "ipv6", name, sseq, + false); } DEFPY_YANG( no_ipv6_access_list_all, no_ipv6_access_list_all_cmd, - "no ipv6 access-list WORD$name", + "no ipv6 access-list ACCESSLIST6_NAME$name", NO_STR IPV6_STR ACCESS_LIST_STR @@ -762,7 +765,7 @@ DEFPY_YANG( DEFPY_YANG( ipv6_access_list_remark, ipv6_access_list_remark_cmd, - "ipv6 access-list WORD$name remark LINE...", + "ipv6 access-list ACCESSLIST6_NAME$name remark LINE...", IPV6_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -787,26 +790,14 @@ DEFPY_YANG( DEFPY_YANG( no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd, - "no ipv6 access-list WORD$name remark", + "no ipv6 access-list ACCESSLIST6_NAME$name remark", NO_STR IPV6_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR ACCESS_LIST_REMARK_STR) { - char xpath[XPATH_MAXLEN]; - int rv; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark", - name); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return acl_remove_if_empty(vty, "ipv6", name); - - return rv; + return filter_remove_check_empty(vty, "access", "ipv6", name, 0, true); } ALIAS( @@ -902,7 +893,8 @@ DEFPY_YANG( /* If the user provided sequence number, then just go for it. */ if (seq_str != NULL) - return acl_remove(vty, "mac", name, seq); + return filter_remove_check_empty(vty, "access", "mac", name, + seq, false); /* Otherwise, to keep compatibility, we need to figure it out. */ ada.ada_type = "mac"; @@ -922,7 +914,8 @@ DEFPY_YANG( else return CMD_WARNING_CONFIG_FAILED; - return acl_remove(vty, "mac", name, sseq); + return filter_remove_check_empty(vty, "access", "mac", name, sseq, + false); } DEFPY_YANG( @@ -976,19 +969,7 @@ DEFPY_YANG( ACCESS_LIST_ZEBRA_STR ACCESS_LIST_REMARK_STR) { - char xpath[XPATH_MAXLEN]; - int rv; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list[type='mac'][name='%s']/remark", - name); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return acl_remove_if_empty(vty, "mac", name); - - return rv; + return filter_remove_check_empty(vty, "access", "mac", name, 0, true); } ALIAS( @@ -1004,8 +985,8 @@ ALIAS( int access_list_cmp(const struct lyd_node *dnode1, const struct lyd_node *dnode2) { - uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); - uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); + uint32_t seq1 = yang_dnode_get_uint32(dnode1, "sequence"); + uint32_t seq2 = yang_dnode_get_uint32(dnode2, "sequence"); return seq1 - seq2; } @@ -1022,23 +1003,23 @@ void access_list_show(struct vty *vty, const struct lyd_node *dnode, struct in_addr addr, mask; char macstr[PREFIX2STR_BUFFER]; - is_any = yang_dnode_exists(dnode, "./any"); + is_any = yang_dnode_exists(dnode, "any"); switch (type) { case YALT_IPV4: if (is_any) break; - if (yang_dnode_exists(dnode, "./host") - || yang_dnode_exists(dnode, "./network/address") - || yang_dnode_exists(dnode, "./source-any")) { + if (yang_dnode_exists(dnode, "host") + || yang_dnode_exists(dnode, "network/address") + || yang_dnode_exists(dnode, "source-any")) { cisco_style = true; - if (yang_dnode_exists(dnode, "./destination-host") + if (yang_dnode_exists(dnode, "destination-host") || yang_dnode_exists( dnode, "./destination-network/address") - || yang_dnode_exists(dnode, "./destination-any")) + || yang_dnode_exists(dnode, "destination-any")) cisco_extended = true; } else { - yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix"); + yang_dnode_get_prefix(&p, dnode, "ipv4-prefix"); is_exact = yang_dnode_get_bool(dnode, "./ipv4-exact-match"); } @@ -1048,39 +1029,39 @@ void access_list_show(struct vty *vty, const struct lyd_node *dnode, if (is_any) break; - yang_dnode_get_prefix(&p, dnode, "./ipv6-prefix"); - is_exact = yang_dnode_get_bool(dnode, "./ipv6-exact-match"); + yang_dnode_get_prefix(&p, dnode, "ipv6-prefix"); + is_exact = yang_dnode_get_bool(dnode, "ipv6-exact-match"); break; case YALT_MAC: /* mac */ vty_out(vty, "mac "); if (is_any) break; - yang_dnode_get_prefix(&p, dnode, "./mac"); + yang_dnode_get_prefix(&p, dnode, "mac"); break; } vty_out(vty, "access-list %s seq %s %s", yang_dnode_get_string(dnode, "../name"), - yang_dnode_get_string(dnode, "./sequence"), - yang_dnode_get_string(dnode, "./action")); + yang_dnode_get_string(dnode, "sequence"), + yang_dnode_get_string(dnode, "action")); /* Handle Cisco style access lists. */ if (cisco_style) { if (cisco_extended) vty_out(vty, " ip"); - if (yang_dnode_exists(dnode, "./network")) { - yang_dnode_get_ipv4(&addr, dnode, "./network/address"); - yang_dnode_get_ipv4(&mask, dnode, "./network/mask"); + if (yang_dnode_exists(dnode, "network")) { + yang_dnode_get_ipv4(&addr, dnode, "network/address"); + yang_dnode_get_ipv4(&mask, dnode, "network/mask"); vty_out(vty, " %pI4 %pI4", &addr, &mask); - } else if (yang_dnode_exists(dnode, "./host")) { + } else if (yang_dnode_exists(dnode, "host")) { if (cisco_extended) vty_out(vty, " host"); vty_out(vty, " %s", - yang_dnode_get_string(dnode, "./host")); - } else if (yang_dnode_exists(dnode, "./source-any")) + yang_dnode_get_string(dnode, "host")); + } else if (yang_dnode_exists(dnode, "source-any")) vty_out(vty, " any"); /* Not extended, exit earlier. */ @@ -1090,17 +1071,17 @@ void access_list_show(struct vty *vty, const struct lyd_node *dnode, } /* Handle destination address. */ - if (yang_dnode_exists(dnode, "./destination-network")) { + if (yang_dnode_exists(dnode, "destination-network")) { yang_dnode_get_ipv4(&addr, dnode, "./destination-network/address"); yang_dnode_get_ipv4(&mask, dnode, "./destination-network/mask"); vty_out(vty, " %pI4 %pI4", &addr, &mask); - } else if (yang_dnode_exists(dnode, "./destination-host")) + } else if (yang_dnode_exists(dnode, "destination-host")) vty_out(vty, " host %s", yang_dnode_get_string(dnode, "./destination-host")); - else if (yang_dnode_exists(dnode, "./destination-any")) + else if (yang_dnode_exists(dnode, "destination-any")) vty_out(vty, " any"); vty_out(vty, "\n"); @@ -1149,62 +1130,17 @@ void access_list_remark_show(struct vty *vty, const struct lyd_node *dnode, * Prefix lists. */ -/** - * Remove main data structure prefix list if there are no more entries or - * remark. This fixes compatibility with old CLI and tests. - */ -static int plist_remove_if_empty(struct vty *vty, const char *iptype, - const char *name) -{ - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark", - iptype, name); - /* List is not empty if there is a remark, check that: */ - if (yang_dnode_exists(vty->candidate_config->dnode, xpath)) - return CMD_SUCCESS; - - /* Check if we have any entries: */ - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype, - name); - /* - * NOTE: if the list is empty it will return the first sequence - * number: 5. - */ - if (acl_get_seq(vty, xpath, true) != 5) - return CMD_SUCCESS; - - /* Nobody is using this list, lets remove it. */ - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, NULL); -} - static int plist_remove(struct vty *vty, const char *iptype, const char *name, - const char *seq, const char *action, + uint32_t seq, const char *action, union prefixconstptr prefix, int ge, int le) { int64_t sseq; struct plist_dup_args pda = {}; - char xpath[XPATH_MAXLEN]; - char xpath_entry[XPATH_MAXLEN + 32]; - int rv; /* If the user provided sequence number, then just go for it. */ - if (seq != NULL) { - snprintf( - xpath, sizeof(xpath), - "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']", - iptype, name, seq); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return plist_remove_if_empty(vty, iptype, name); - - return rv; - } + if (seq != 0) + return filter_remove_check_empty(vty, "prefix", iptype, name, + seq, false); /* Otherwise, to keep compatibility, we need to figure it out. */ pda.pda_type = iptype; @@ -1224,22 +1160,13 @@ static int plist_remove(struct vty *vty, const char *iptype, const char *name, else return CMD_WARNING_CONFIG_FAILED; - snprintfrr( - xpath_entry, sizeof(xpath_entry), - "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']", - iptype, name, sseq); - nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return plist_remove_if_empty(vty, iptype, name); - - return rv; + return filter_remove_check_empty(vty, "prefix", iptype, name, sseq, + false); } DEFPY_YANG( ip_prefix_list, ip_prefix_list_cmd, - "ip prefix-list WORD$name [seq (1-4294967295)$seq] $action ", + "ip prefix-list PREFIXLIST4_NAME$name [seq (1-4294967295)$seq] $action ", IP_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR @@ -1333,7 +1260,7 @@ DEFPY_YANG( DEFPY_YANG( no_ip_prefix_list, no_ip_prefix_list_cmd, - "no ip prefix-list WORD$name [seq (1-4294967295)$seq] $action ", + "no ip prefix-list PREFIXLIST4_NAME$name [seq (1-4294967295)$seq] $action ", NO_STR IP_STR PREFIX_LIST_STR @@ -1347,25 +1274,25 @@ DEFPY_YANG( "Maximum prefix length to be matched\n" "Maximum prefix length\n") { - return plist_remove(vty, "ipv4", name, seq_str, action, + return plist_remove(vty, "ipv4", name, seq, action, prefix_str ? prefix : NULL, ge, le); } DEFPY_YANG( no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd, - "no ip prefix-list WORD$name seq (1-4294967295)$seq", + "no ip prefix-list PREFIXLIST4_NAME$name seq (1-4294967295)$seq", NO_STR IP_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR ACCESS_LIST_SEQ_STR) { - return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0); + return plist_remove(vty, "ipv4", name, seq, NULL, NULL, 0, 0); } DEFPY_YANG( no_ip_prefix_list_all, no_ip_prefix_list_all_cmd, - "no ip prefix-list WORD$name", + "no ip prefix-list PREFIXLIST4_NAME$name", NO_STR IP_STR PREFIX_LIST_STR @@ -1382,7 +1309,7 @@ DEFPY_YANG( DEFPY_YANG( ip_prefix_list_remark, ip_prefix_list_remark_cmd, - "ip prefix-list WORD$name description LINE...", + "ip prefix-list PREFIXLIST4_NAME$name description LINE...", IP_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR @@ -1407,31 +1334,19 @@ DEFPY_YANG( DEFPY_YANG( no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd, - "no ip prefix-list WORD$name description", + "no ip prefix-list PREFIXLIST4_NAME$name description", NO_STR IP_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR ACCESS_LIST_REMARK_STR) { - char xpath[XPATH_MAXLEN]; - int rv; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark", - name); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return plist_remove_if_empty(vty, "ipv4", name); - - return rv; + return filter_remove_check_empty(vty, "prefix", "ipv4", name, 0, true); } ALIAS( no_ip_prefix_list_remark, no_ip_prefix_list_remark_line_cmd, - "no ip prefix-list WORD$name description LINE...", + "no ip prefix-list PREFIXLIST4_NAME$name description LINE...", NO_STR IP_STR PREFIX_LIST_STR @@ -1441,7 +1356,7 @@ ALIAS( DEFPY_YANG( ipv6_prefix_list, ipv6_prefix_list_cmd, - "ipv6 prefix-list WORD$name [seq (1-4294967295)] $action ", + "ipv6 prefix-list PREFIXLIST6_NAME$name [seq (1-4294967295)] $action ", IPV6_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR @@ -1535,7 +1450,7 @@ DEFPY_YANG( DEFPY_YANG( no_ipv6_prefix_list, no_ipv6_prefix_list_cmd, - "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] $action ", + "no ipv6 prefix-list PREFIXLIST6_NAME$name [seq (1-4294967295)$seq] $action ", NO_STR IPV6_STR PREFIX_LIST_STR @@ -1549,25 +1464,25 @@ DEFPY_YANG( "Minimum prefix length to be matched\n" "Minimum prefix length\n") { - return plist_remove(vty, "ipv6", name, seq_str, action, + return plist_remove(vty, "ipv6", name, seq, action, prefix_str ? prefix : NULL, ge, le); } DEFPY_YANG( no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd, - "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq", + "no ipv6 prefix-list PREFIXLIST6_NAME$name seq (1-4294967295)$seq", NO_STR IPV6_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR ACCESS_LIST_SEQ_STR) { - return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0); + return plist_remove(vty, "ipv6", name, seq, NULL, NULL, 0, 0); } DEFPY_YANG( no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd, - "no ipv6 prefix-list WORD$name", + "no ipv6 prefix-list PREFIXLIST6_NAME$name", NO_STR IPV6_STR PREFIX_LIST_STR @@ -1584,7 +1499,7 @@ DEFPY_YANG( DEFPY_YANG( ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd, - "ipv6 prefix-list WORD$name description LINE...", + "ipv6 prefix-list PREFIXLIST6_NAME$name description LINE...", IPV6_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR @@ -1609,31 +1524,19 @@ DEFPY_YANG( DEFPY_YANG( no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd, - "no ipv6 prefix-list WORD$name description", + "no ipv6 prefix-list PREFIXLIST6_NAME$name description", NO_STR IPV6_STR PREFIX_LIST_STR PREFIX_LIST_NAME_STR ACCESS_LIST_REMARK_STR) { - char xpath[XPATH_MAXLEN]; - int rv; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark", - name); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) - return plist_remove_if_empty(vty, "ipv6", name); - - return rv; + return filter_remove_check_empty(vty, "prefix", "ipv6", name, 0, true); } ALIAS( no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_line_cmd, - "no ipv6 prefix-list WORD$name description LINE...", + "no ipv6 prefix-list PREFIXLIST6_NAME$name description LINE...", NO_STR IPV6_STR PREFIX_LIST_STR @@ -1644,8 +1547,8 @@ ALIAS( int prefix_list_cmp(const struct lyd_node *dnode1, const struct lyd_node *dnode2) { - uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); - uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); + uint32_t seq1 = yang_dnode_get_uint32(dnode1, "sequence"); + uint32_t seq2 = yang_dnode_get_uint32(dnode2, "sequence"); return seq1 - seq2; } @@ -1658,11 +1561,11 @@ void prefix_list_show(struct vty *vty, const struct lyd_node *dnode, bool is_any; struct prefix p; - is_any = yang_dnode_exists(dnode, "./any"); + is_any = yang_dnode_exists(dnode, "any"); switch (type) { case YPLT_IPV4: if (!is_any) - yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix"); + yang_dnode_get_prefix(&p, dnode, "ipv4-prefix"); if (yang_dnode_exists(dnode, "./ipv4-prefix-length-greater-or-equal")) ge_str = yang_dnode_get_string( @@ -1692,8 +1595,8 @@ void prefix_list_show(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, "prefix-list %s seq %s %s", yang_dnode_get_string(dnode, "../name"), - yang_dnode_get_string(dnode, "./sequence"), - yang_dnode_get_string(dnode, "./action")); + yang_dnode_get_string(dnode, "sequence"), + yang_dnode_get_string(dnode, "action")); if (is_any) { vty_out(vty, " any\n"); diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 9511b8f5b5cd..3db081b534c3 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -17,23 +17,6 @@ #include "lib/plist_int.h" #include "lib/routemap.h" -/* Helper function. */ -static void acl_notify_route_map(struct access_list *acl, int route_map_event) -{ - switch (route_map_event) { - case RMAP_EVENT_FILTER_ADDED: - if (acl->master->add_hook) - (*acl->master->add_hook)(acl); - break; - case RMAP_EVENT_FILTER_DELETED: - if (acl->master->delete_hook) - (*acl->master->delete_hook)(acl); - break; - } - - route_map_notify_dependencies(acl->name, route_map_event); -} - static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args) { int type = yang_dnode_get_enum(args->dnode, "../../type"); @@ -112,7 +95,7 @@ prefix_list_nb_validate_v4_af_type(const struct lyd_node *plist_dnode, { int af_type; - af_type = yang_dnode_get_enum(plist_dnode, "./type"); + af_type = yang_dnode_get_enum(plist_dnode, "type"); if (af_type != YPLT_IPV4) { snprintf(errmsg, errmsg_len, "prefix-list type %u is mismatched.", af_type); @@ -128,7 +111,7 @@ prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode, { int af_type; - af_type = yang_dnode_get_enum(plist_dnode, "./type"); + af_type = yang_dnode_get_enum(plist_dnode, "type"); if (af_type != YPLT_IPV6) { snprintf(errmsg, errmsg_len, "prefix-list type %u is mismatched.", af_type); @@ -153,9 +136,6 @@ static int lib_prefix_list_entry_prefix_length_greater_or_equal_modify( ple->ge = yang_dnode_get_uint8(args->dnode, NULL); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -174,9 +154,6 @@ static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify( ple->le = yang_dnode_get_uint8(args->dnode, NULL); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -195,9 +172,6 @@ static int lib_prefix_list_entry_prefix_length_greater_or_equal_destroy( ple->ge = 0; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -216,9 +190,6 @@ static int lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy( ple->le = 0; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -381,14 +352,14 @@ static void plist_dnode_to_prefix(const struct lyd_node *dnode, bool *any, *ge = 0; *le = 0; - if (yang_dnode_exists(dnode, "./any")) { + if (yang_dnode_exists(dnode, "any")) { *any = true; return; } switch (yang_dnode_get_enum(dnode, "../type")) { case YPLT_IPV4: - yang_dnode_get_prefix(p, dnode, "./ipv4-prefix"); + yang_dnode_get_prefix(p, dnode, "ipv4-prefix"); if (yang_dnode_exists(dnode, "./ipv4-prefix-length-greater-or-equal")) *ge = yang_dnode_get_uint8( @@ -399,7 +370,7 @@ static void plist_dnode_to_prefix(const struct lyd_node *dnode, bool *any, dnode, "./ipv4-prefix-length-lesser-or-equal"); break; case YPLT_IPV6: - yang_dnode_get_prefix(p, dnode, "./ipv6-prefix"); + yang_dnode_get_prefix(p, dnode, "ipv6-prefix"); if (yang_dnode_exists(dnode, "./ipv6-prefix-length-greater-or-equal")) *ge = yang_dnode_get_uint8( @@ -468,8 +439,8 @@ static int lib_access_list_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - type = yang_dnode_get_enum(args->dnode, "./type"); - acl_name = yang_dnode_get_string(args->dnode, "./name"); + type = yang_dnode_get_enum(args->dnode, "type"); + acl_name = yang_dnode_get_string(args->dnode, "name"); switch (type) { case YALT_IPV4: @@ -550,7 +521,7 @@ static int lib_access_list_entry_create(struct nb_cb_create_args *args) return NB_OK; f = filter_new(); - f->seq = yang_dnode_get_uint32(args->dnode, "./sequence"); + f->seq = yang_dnode_get_uint32(args->dnode, "sequence"); acl = nb_running_get_entry(args->dnode, NULL, true); f->acl = acl; @@ -575,6 +546,15 @@ static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +static void +lib_access_list_entry_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct filter *f; + + f = nb_running_get_entry(args->dnode, NULL, true); + access_list_filter_update(f->acl); +} + /* * XPath: /frr-filter:lib/access-list/entry/action */ @@ -594,8 +574,6 @@ lib_access_list_entry_action_modify(struct nb_cb_modify_args *args) else f->type = FILTER_DENY; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -629,8 +607,6 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) fz = &f->u.zfilter; yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -647,8 +623,6 @@ lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) fz = &f->u.zfilter; memset(&fz->prefix, 0, sizeof(fz->prefix)); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -681,8 +655,6 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args) fz = &f->u.zfilter; fz->exact = yang_dnode_get_bool(args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -699,8 +671,6 @@ lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args) fz = &f->u.zfilter; fz->exact = 0; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -733,8 +703,6 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args) yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -751,7 +719,29 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args) fc = &f->u.cfilter; cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); + return NB_OK; +} + +/* + * XPath: /frr-filter:lib/access-list/entry/network + */ +static int lib_access_list_entry_network_create(struct nb_cb_create_args *args) +{ + /* Nothing to do here, everything is done in children callbacks */ + return NB_OK; +} + +static int lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args) +{ + struct filter_cisco *fc; + struct filter *f; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + f = nb_running_get_entry(args->dnode, NULL, true); + fc = &f->u.cfilter; + cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); return NB_OK; } @@ -784,8 +774,6 @@ lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args) fc = &f->u.cfilter; yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -817,8 +805,6 @@ lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args) fc = &f->u.cfilter; yang_dnode_get_ipv4(&fc->addr_mask, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -851,8 +837,6 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args) fc->addr.s_addr = INADDR_ANY; fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -869,8 +853,6 @@ lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args) fc = &f->u.cfilter; cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -903,8 +885,6 @@ static int lib_access_list_entry_destination_host_modify( yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -922,7 +902,32 @@ static int lib_access_list_entry_destination_host_destroy( fc->extended = 0; cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); + return NB_OK; +} + +/* + * XPath: /frr-filter:lib/access-list/entry/destination-network + */ +static int +lib_access_list_entry_destination_network_create(struct nb_cb_create_args *args) +{ + /* Nothing to do here, everything is done in children callbacks */ + return NB_OK; +} + +static int lib_access_list_entry_destination_network_destroy( + struct nb_cb_destroy_args *args) +{ + struct filter_cisco *fc; + struct filter *f; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + f = nb_running_get_entry(args->dnode, NULL, true); + fc = &f->u.cfilter; + fc->extended = 0; + cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); return NB_OK; } @@ -955,8 +960,6 @@ static int lib_access_list_entry_destination_network_address_modify( fc->extended = 1; yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -988,8 +991,6 @@ static int lib_access_list_entry_destination_network_mask_modify( fc->extended = 1; yang_dnode_get_ipv4(&fc->mask_mask, args->dnode, NULL); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -1022,8 +1023,6 @@ static int lib_access_list_entry_destination_any_create( fc->mask.s_addr = INADDR_ANY; fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -1041,8 +1040,6 @@ static int lib_access_list_entry_destination_any_destroy( fc->extended = 0; cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -1089,8 +1086,6 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args) break; } - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); - return NB_OK; } @@ -1106,8 +1101,6 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args) fz = &f->u.zfilter; fz->prefix.family = AF_UNSPEC; - acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); - return NB_OK; } @@ -1123,14 +1116,14 @@ static int lib_prefix_list_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - type = yang_dnode_get_enum(args->dnode, "./type"); - name = yang_dnode_get_string(args->dnode, "./name"); + type = yang_dnode_get_enum(args->dnode, "type"); + name = yang_dnode_get_string(args->dnode, "name"); switch (type) { case 0: /* ipv4 */ - pl = prefix_list_get(AFI_IP, 0, name); + pl = prefix_list_get(AFI_IP, 0, 0, name); break; case 1: /* ipv6 */ - pl = prefix_list_get(AFI_IP6, 0, name); + pl = prefix_list_get(AFI_IP6, 0, 0, name); break; } @@ -1201,7 +1194,7 @@ static int lib_prefix_list_entry_create(struct nb_cb_create_args *args) pl = nb_running_get_entry(args->dnode, NULL, true); ple = prefix_list_entry_new(); ple->pl = pl; - ple->seq = yang_dnode_get_uint32(args->dnode, "./sequence"); + ple->seq = yang_dnode_get_uint32(args->dnode, "sequence"); prefix_list_entry_set_empty(ple); nb_running_set_entry(args->dnode, ple); @@ -1224,6 +1217,22 @@ static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +static void +lib_prefix_list_entry_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct prefix_list_entry *ple; + + ple = nb_running_get_entry(args->dnode, NULL, true); + + /* + * Finish prefix entry update procedure. The procedure is started in + * children callbacks. `prefix_list_entry_update_start` can be called + * multiple times if multiple children are modified, but it is actually + * executed only once because of the protection by `ple->installed`. + */ + prefix_list_entry_update_finish(ple); +} + /* * XPath: /frr-filter:lib/prefix-list/entry/action */ @@ -1246,9 +1255,6 @@ static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args) else ple->type = PREFIX_DENY; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1276,10 +1282,6 @@ static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args) prefix_copy(&ple->prefix, &p); } - - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1297,9 +1299,6 @@ static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args) memset(&ple->prefix, 0, sizeof(ple->prefix)); - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1547,9 +1546,6 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args) break; } - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1567,9 +1563,6 @@ static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args) ple->any = false; - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - return NB_OK; } @@ -1597,6 +1590,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_access_list_entry_create, .destroy = lib_access_list_entry_destroy, + .apply_finish = lib_access_list_entry_apply_finish, .cli_cmp = access_list_cmp, .cli_show = access_list_show, } @@ -1628,6 +1622,13 @@ const struct frr_yang_module_info frr_filter_info = { .destroy = lib_access_list_entry_host_destroy, } }, + { + .xpath = "/frr-filter:lib/access-list/entry/network", + .cbs = { + .create = lib_access_list_entry_network_create, + .destroy = lib_access_list_entry_network_destroy, + } + }, { .xpath = "/frr-filter:lib/access-list/entry/network/address", .cbs = { @@ -1654,6 +1655,13 @@ const struct frr_yang_module_info frr_filter_info = { .destroy = lib_access_list_entry_destination_host_destroy, } }, + { + .xpath = "/frr-filter:lib/access-list/entry/destination-network", + .cbs = { + .create = lib_access_list_entry_destination_network_create, + .destroy = lib_access_list_entry_destination_network_destroy, + } + }, { .xpath = "/frr-filter:lib/access-list/entry/destination-network/address", .cbs = { @@ -1721,6 +1729,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_prefix_list_entry_create, .destroy = lib_prefix_list_entry_destroy, + .apply_finish = lib_prefix_list_entry_apply_finish, .cli_cmp = prefix_list_cmp, .cli_show = prefix_list_show, } @@ -1785,3 +1794,35 @@ const struct frr_yang_module_info frr_filter_info = { }, } }; + +const struct frr_yang_module_info frr_filter_cli_info = { + .name = "frr-filter", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-filter:lib/access-list/remark", + .cbs.cli_show = access_list_remark_show, + }, + { + .xpath = "/frr-filter:lib/access-list/entry", + .cbs = { + .cli_cmp = access_list_cmp, + .cli_show = access_list_show, + } + }, + { + .xpath = "/frr-filter:lib/prefix-list/remark", + .cbs.cli_show = prefix_list_remark_show, + }, + { + .xpath = "/frr-filter:lib/prefix-list/entry", + .cbs = { + .cli_cmp = prefix_list_cmp, + .cli_show = prefix_list_show, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/flex_algo.c b/lib/flex_algo.c index f48117ff1b15..ab0eef67cb3b 100644 --- a/lib/flex_algo.c +++ b/lib/flex_algo.c @@ -20,9 +20,6 @@ DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO_DATABASE, "Flex-Algo database"); DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO, "Flex-Algo algorithm information"); -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa); - struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, flex_algo_releaser_t releaser) { @@ -42,7 +39,7 @@ void flex_algos_free(struct flex_algos *flex_algos) struct flex_algo *fa; for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) - _flex_algo_delete(flex_algos, fa); + flex_algo_free(flex_algos, fa); list_delete(&flex_algos->flex_algos); XFREE(MTYPE_FLEX_ALGO_DATABASE, flex_algos); } @@ -63,8 +60,7 @@ struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, return fa; } -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa) +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa) { if (flex_algos->releaser) flex_algos->releaser(fa->data); @@ -75,19 +71,6 @@ static void _flex_algo_delete(struct flex_algos *flex_algos, XFREE(MTYPE_FLEX_ALGO, fa); } - -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm) -{ - struct listnode *node, *nnode; - struct flex_algo *fa; - - for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) { - if (fa->algorithm != algorithm) - continue; - _flex_algo_delete(flex_algos, fa); - } -} - /** * @brief Look up the local flex-algo object by its algorithm number. * @param algorithm flex-algo algorithm number diff --git a/lib/flex_algo.h b/lib/flex_algo.h index e617e7cae849..54b37783e609 100644 --- a/lib/flex_algo.h +++ b/lib/flex_algo.h @@ -115,11 +115,10 @@ struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, void flex_algos_free(struct flex_algos *flex_algos); struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, uint8_t algorithm, void *arg); +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa); struct flex_algo *flex_algo_lookup(struct flex_algos *flex_algos, uint8_t algorithm); -void flex_algos_free(struct flex_algos *flex_algos); bool flex_algo_definition_cmp(struct flex_algo *fa1, struct flex_algo *fa2); -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm); bool flex_algo_id_valid(uint16_t algorithm); char *flex_algo_metric_type_print(char *type_str, size_t sz, enum flex_algo_metric_type metric_type); diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index c4ead01bf6ea..3a4bc712fc52 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -5,6 +5,9 @@ */ #include + +#include + #include #ifdef HAVE_PTHREAD_NP_H #include @@ -89,9 +92,14 @@ struct frr_pthread *frr_pthread_new(const struct frr_pthread_attr *attr, MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t)); fpt->running_cond = XCALLOC(MTYPE_PTHREAD_PRIM, sizeof(pthread_cond_t)); + pthread_mutex_init(fpt->running_cond_mtx, NULL); pthread_cond_init(fpt->running_cond, NULL); + pthread_mutex_init(&fpt->startup_cond_mtx, NULL); + pthread_cond_init(&fpt->startup_cond, NULL); + fpt->started = false; + frr_with_mutex (&frr_pthread_list_mtx) { listnode_add(frr_pthread_list, fpt); } @@ -105,6 +113,8 @@ static void frr_pthread_destroy_nolock(struct frr_pthread *fpt) pthread_mutex_destroy(&fpt->mtx); pthread_mutex_destroy(fpt->running_cond_mtx); pthread_cond_destroy(fpt->running_cond); + pthread_mutex_destroy(&fpt->startup_cond_mtx); + pthread_cond_destroy(&fpt->startup_cond); XFREE(MTYPE_FRR_PTHREAD, fpt->name); XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond_mtx); XFREE(MTYPE_PTHREAD_PRIM, fpt->running_cond); @@ -137,11 +147,34 @@ int frr_pthread_set_name(struct frr_pthread *fpt) return ret; } +/* New pthread waits before running */ +static void frr_pthread_wait_startup(struct frr_pthread *fpt) +{ + frr_with_mutex (&fpt->startup_cond_mtx) { + while (!fpt->started) + pthread_cond_wait(&fpt->startup_cond, + &fpt->startup_cond_mtx); + } +} + +/* Parent pthread allows new pthread to start running */ +static void frr_pthread_notify_startup(struct frr_pthread *fpt) +{ + frr_with_mutex (&fpt->startup_cond_mtx) { + fpt->started = true; + pthread_cond_signal(&fpt->startup_cond); + } +} + static void *frr_pthread_inner(void *arg) { struct frr_pthread *fpt = arg; + /* The new pthead waits until the parent allows it to continue. */ + frr_pthread_wait_startup(fpt); + rcu_thread_start(fpt->rcu_thread); + return fpt->attr.start(fpt); } @@ -166,6 +199,9 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr) /* Restore caller's signals */ pthread_sigmask(SIG_SETMASK, &oldsigs, NULL); + /* Allow new child pthread to start */ + frr_pthread_notify_startup(fpt); + /* * Per pthread_create(3), the contents of fpt->thread are undefined if * pthread_create() did not succeed. Reset this value to zero. @@ -217,6 +253,43 @@ void frr_pthread_stop_all(void) } } +static void *frr_pthread_attr_non_controlled_start(void *arg) +{ + struct frr_pthread *fpt = arg; + + fpt->running = true; + + return NULL; +} + +/* Create a FRR pthread context from a non FRR pthread initialized from an + * external library in order to allow logging */ +int frr_pthread_non_controlled_startup(pthread_t thread, const char *name, + const char *os_name) +{ + struct rcu_thread *rcu_thread = rcu_thread_new(NULL); + + rcu_thread_start(rcu_thread); + + struct frr_pthread_attr attr = { + .start = frr_pthread_attr_non_controlled_start, + .stop = frr_pthread_attr_default.stop, + }; + struct frr_pthread *fpt; + + fpt = frr_pthread_new(&attr, name, os_name); + if (!fpt) + return -1; + + fpt->thread = thread; + fpt->rcu_thread = rcu_thread; + fpt->started = true; + + frr_pthread_inner(fpt); + + return 0; +} + /* * ---------------------------------------------------------------------------- * Default Event Loop diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h index f91044dfaef2..bb751b707186 100644 --- a/lib/frr_pthread.h +++ b/lib/frr_pthread.h @@ -46,6 +46,17 @@ struct frr_pthread { /* caller-specified data; start & stop funcs, name, id */ struct frr_pthread_attr attr; + /* + * Startup serialization: newly-started pthreads wait at a point + * very early in life so that there isn't a race with the + * starting pthread. The OS 'start' apis don't make any guarantees + * about which pthread runs first - the existing pthread that has + * called the 'start' api, or the new pthread that is just starting. + */ + pthread_cond_t startup_cond; + pthread_mutex_t startup_cond_mtx; + atomic_bool started; + /* * Notification mechanism for allowing pthreads to notify their parents * when they are ready to do work. This mechanism has two associated @@ -202,6 +213,9 @@ void frr_pthread_stop_all(void); #define pthread_condattr_setclock(A, B) #endif +int frr_pthread_non_controlled_startup(pthread_t thread, const char *name, + const char *os_name); + /* mutex auto-lock/unlock */ /* variant 1: diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c index b28dd7f1bbc5..5273d3697443 100644 --- a/lib/frr_zmq.c +++ b/lib/frr_zmq.c @@ -21,6 +21,8 @@ #include "log.h" #include "lib_errors.h" +XREF_SETUP(); + DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback"); /* libzmq's context */ diff --git a/lib/frrcu.c b/lib/frrcu.c index c7cc655e09ce..b85c525c5879 100644 --- a/lib/frrcu.c +++ b/lib/frrcu.c @@ -149,20 +149,9 @@ static struct rcu_thread *rcu_self(void) return (struct rcu_thread *)pthread_getspecific(rcu_thread_key); } -/* - * thread management (for the non-main thread) - */ -struct rcu_thread *rcu_thread_prepare(void) +struct rcu_thread *rcu_thread_new(void *arg) { - struct rcu_thread *rt, *cur; - - rcu_assert_read_locked(); - - if (!rcu_active) - rcu_start(); - - cur = rcu_self(); - assert(cur->depth); + struct rcu_thread *rt, *cur = arg; /* new thread always starts with rcu_read_lock held at depth 1, and * holding the same epoch as the parent (this makes it possible to @@ -172,13 +161,32 @@ struct rcu_thread *rcu_thread_prepare(void) rt->depth = 1; seqlock_init(&rt->rcu); - seqlock_acquire(&rt->rcu, &cur->rcu); + if (cur) + seqlock_acquire(&rt->rcu, &cur->rcu); rcu_threads_add_tail(&rcu_threads, rt); return rt; } +/* + * thread management (for the non-main thread) + */ +struct rcu_thread *rcu_thread_prepare(void) +{ + struct rcu_thread *cur; + + rcu_assert_read_locked(); + + if (!rcu_active) + rcu_start(); + + cur = rcu_self(); + assert(cur->depth); + + return rcu_thread_new(cur); +} + void rcu_thread_start(struct rcu_thread *rt) { pthread_setspecific(rcu_thread_key, rt); diff --git a/lib/frrcu.h b/lib/frrcu.h index e7a54dcbe5d4..81ab5528a9dd 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -40,6 +40,12 @@ extern "C" { /* opaque */ struct rcu_thread; +/* sets up rcu thread info + * + * return value must be passed into the thread's call to rcu_thread_start() + */ +extern struct rcu_thread *rcu_thread_new(void *arg); + /* called before new thread creation, sets up rcu thread info for new thread * before it actually exits. This ensures possible RCU references are held * for thread startup. @@ -150,7 +156,7 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action); #define rcu_call(func, ptr, field) \ do { \ typeof(ptr) _ptr = (ptr); \ - void (*fptype)(typeof(ptr)); \ + void (*_fptype)(typeof(ptr)); \ struct rcu_head *_rcu_head = &_ptr->field; \ static const struct rcu_action _rcu_action = { \ .type = RCUA_CALL, \ diff --git a/lib/frrdistance.h b/lib/frrdistance.h new file mode 100644 index 000000000000..d2fa76e610a7 --- /dev/null +++ b/lib/frrdistance.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zebra distance header + * Copyright (C) 2023 NVIDIA Corporation + * Donald Sharp + * + * Distance related defines. FRR needs a common set + * of values for distance. + */ +#ifndef __FRRDISTANCE_H__ +#define __FRRDISTANCE_H__ + +/* Default Administrative Distance of each protocol. */ +#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 +#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 +#define ZEBRA_STATIC_DISTANCE_DEFAULT 1 +#define ZEBRA_RIP_DISTANCE_DEFAULT 120 +#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120 +#define ZEBRA_OSPF_DISTANCE_DEFAULT 110 +#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110 +#define ZEBRA_ISIS_DISTANCE_DEFAULT 115 +#define ZEBRA_IBGP_DISTANCE_DEFAULT 200 +#define ZEBRA_EBGP_DISTANCE_DEFAULT 20 +#define ZEBRA_TABLE_DISTANCE_DEFAULT 15 +#define ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT 14 +#define ZEBRA_EIGRP_DISTANCE_DEFAULT 90 +#define ZEBRA_NHRP_DISTANCE_DEFAULT 10 +#define ZEBRA_LDP_DISTANCE_DEFAULT 150 +#define ZEBRA_BABEL_DISTANCE_DEFAULT 100 +#define ZEBRA_SHARP_DISTANCE_DEFAULT 150 +#define ZEBRA_PBR_DISTANCE_DEFAULT 200 +#define ZEBRA_OPENFABRIC_DISTANCE_DEFAULT 115 +#define ZEBRA_MAX_DISTANCE_DEFAULT 255 + +#endif diff --git a/lib/frrevent.h b/lib/frrevent.h index ab779d90889d..94640a76b70f 100644 --- a/lib/frrevent.h +++ b/lib/frrevent.h @@ -6,6 +6,7 @@ #ifndef _ZEBRA_THREAD_H #define _ZEBRA_THREAD_H +#include #include #include #include @@ -18,6 +19,8 @@ extern "C" { #endif +#define CONSUMED_TIME_CHECK 5000000 + extern bool cputime_enabled; extern unsigned long cputime_threshold; /* capturing wallclock time is always enabled since it is fast (reading @@ -89,6 +92,8 @@ struct event_loop { pthread_mutex_t mtx; pthread_t owner; + nfds_t last_read; + bool ready_run_loop; RUSAGE_T last_getrusage; }; @@ -151,6 +156,12 @@ struct cpu_event_history { /* Struct timeval's tv_usec one second value. */ #define TIMER_SECOND_MICRO 1000000L +static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b) +{ + return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) + + (a.tv_usec - b.tv_usec)); +} + /* Event yield time. */ #define EVENT_YIELD_TIME_SLOT 10 * 1000L /* 10ms */ diff --git a/lib/frrlua.c b/lib/frrlua.c index e626efe20b65..2cab1a5460f2 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -259,12 +259,12 @@ void *lua_tosockunion(lua_State *L, int idx) return su; } -void lua_pushintegerp(lua_State *L, const long long *num) +void lua_pushintegerp(lua_State *L, const int *num) { lua_pushinteger(L, *num); } -void lua_decode_integerp(lua_State *L, int idx, long long *num) +void lua_decode_integerp(lua_State *L, int idx, int *num) { int isnum; *num = lua_tonumberx(L, idx, &isnum); @@ -274,7 +274,7 @@ void lua_decode_integerp(lua_State *L, int idx, long long *num) void *lua_tointegerp(lua_State *L, int idx) { - long long *num = XCALLOC(MTYPE_SCRIPT_RES, sizeof(long long)); + int *num = XCALLOC(MTYPE_SCRIPT_RES, sizeof(int)); lua_decode_integerp(L, idx, num); return num; @@ -332,32 +332,39 @@ void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng) } } -void lua_decode_stringp(lua_State *L, int idx, char *str) +void lua_pushlonglongp(lua_State *L, const long long *num) { - strlcpy(str, lua_tostring(L, idx), strlen(str) + 1); + /* lua library function; this can take a long long */ + lua_pushinteger(L, *num); +} + +void lua_decode_longlongp(lua_State *L, int idx, long long *num) +{ + int isnum; + *num = lua_tonumberx(L, idx, &isnum); lua_pop(L, 1); + assert(isnum); } -void *lua_tostringp(lua_State *L, int idx) +void *lua_tolonglongp(lua_State *L, int idx) { - char *string = XSTRDUP(MTYPE_SCRIPT_RES, lua_tostring(L, idx)); + long long *num = XCALLOC(MTYPE_SCRIPT_RES, sizeof(long long)); - return string; + lua_decode_longlongp(L, idx, num); + return num; } -/* - * Decoder for const values, since we cannot modify them. - */ -void lua_decode_noop(lua_State *L, int idx, const void *ptr) +void lua_decode_stringp(lua_State *L, int idx, char *str) { + strlcpy(str, lua_tostring(L, idx), strlen(str) + 1); + lua_pop(L, 1); } - -/* - * Noop decoder for int. - */ -void lua_decode_integer_noop(lua_State *L, int idx, int i) +void *lua_tostringp(lua_State *L, int idx) { + char *string = XSTRDUP(MTYPE_SCRIPT_RES, lua_tostring(L, idx)); + + return string; } /* diff --git a/lib/frrlua.h b/lib/frrlua.h index d248312d625f..dc0f4d9986be 100644 --- a/lib/frrlua.h +++ b/lib/frrlua.h @@ -121,9 +121,9 @@ void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop); /* * Converts an int to a Lua value and pushes it on the stack. */ -void lua_pushintegerp(lua_State *L, const long long *num); +void lua_pushintegerp(lua_State *L, const int *num); -void lua_decode_integerp(lua_State *L, int idx, long long *num); +void lua_decode_integerp(lua_State *L, int idx, int *num); /* * Converts the Lua value at idx to an int. @@ -133,6 +133,21 @@ void lua_decode_integerp(lua_State *L, int idx, long long *num); */ void *lua_tointegerp(lua_State *L, int idx); +/* + * Converts a long long to a Lua value and pushes it on the stack. + */ +void lua_pushlonglongp(lua_State *L, const long long *num); + +void lua_decode_longlongp(lua_State *L, int idx, long long *num); + +/* + * Converts the Lua value at idx to a long long. + * + * Returns: + * long long allocated with MTYPE_TMP. + */ +void *lua_tolonglongp(lua_State *L, int idx); + void lua_decode_stringp(lua_State *L, int idx, char *str); /* @@ -143,13 +158,6 @@ void lua_decode_stringp(lua_State *L, int idx, char *str); */ void *lua_tostringp(lua_State *L, int idx); -/* - * No-op decoders - */ -void lua_decode_noop(lua_State *L, int idx, const void *ptr); - -void lua_decode_integer_noop(lua_State *L, int idx, int i); - /* * Retrieve an integer from table on the top of the stack. * diff --git a/lib/frrscript.c b/lib/frrscript.c index 50410fb58bd6..acdd1df67b4d 100644 --- a/lib/frrscript.c +++ b/lib/frrscript.c @@ -25,6 +25,8 @@ DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting"); struct frrscript_names_head frrscript_names_hash; +void _lua_decode_noop(lua_State *L, ...) {} + /* * Wrapper for frrscript_names_add * Use this to register hook calls when a daemon starts up diff --git a/lib/frrscript.h b/lib/frrscript.h index df49b5718c1d..ce313a1b63a8 100644 --- a/lib/frrscript.h +++ b/lib/frrscript.h @@ -180,6 +180,11 @@ void frrscript_fini(void); assert(lua_gettop(lfs->L) == 1); \ } while (0) +/* + * Noop function. Used below where we need a noop decoder for any type. + */ +void _lua_decode_noop(lua_State *, ...); + /* * Maps the type of value to its encoder/decoder. * Add new mappings here. @@ -192,7 +197,9 @@ void frrscript_fini(void); #define ENCODE_ARGS_WITH_STATE(L, value) \ _Generic((value), \ int : lua_pushinteger, \ -long long * : lua_pushintegerp, \ +int * : lua_pushintegerp, \ +long long : lua_pushinteger, \ +long long * : lua_pushlonglongp, \ struct prefix * : lua_pushprefix, \ struct interface * : lua_pushinterface, \ struct in_addr * : lua_pushinaddr, \ @@ -211,8 +218,8 @@ struct zebra_dplane_ctx * : lua_pushzebra_dplane_ctx \ #define DECODE_ARGS_WITH_STATE(L, value) \ _Generic((value), \ -int : lua_decode_integer_noop, \ -long long * : lua_decode_integerp, \ +int * : lua_decode_integerp, \ +long long * : lua_decode_longlongp, \ struct prefix * : lua_decode_prefix, \ struct interface * : lua_decode_interface, \ struct in_addr * : lua_decode_inaddr, \ @@ -220,13 +227,7 @@ struct in6_addr * : lua_decode_in6addr, \ union sockunion * : lua_decode_sockunion, \ char * : lua_decode_stringp, \ struct attr * : lua_decode_attr, \ -struct peer * : lua_decode_noop, \ -const struct prefix * : lua_decode_noop, \ -const struct ipaddr * : lua_decode_noop, \ -const struct ethaddr * : lua_decode_noop, \ -const struct nexthop_group * : lua_decode_noop, \ -const struct nexthop * : lua_decode_noop, \ -struct zebra_dplane_ctx * : lua_decode_noop \ +default : _lua_decode_noop \ )((L), -1, (value)) /* diff --git a/lib/frrsendmmsg.h b/lib/frrsendmmsg.h new file mode 100644 index 000000000000..ea63d139aa3c --- /dev/null +++ b/lib/frrsendmmsg.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * FRR sendmmsg wrapper + * Copyright (C) 2024 by Nvidia, Inc. + * Donald Sharp + */ +#ifndef __FRRSENDMMSG_H__ +#define __FRRSENDMMSG_H__ + +#if !defined(HAVE_STRUCT_MMSGHDR_MSG_HDR) || !defined(HAVE_SENDMMSG) +/* avoid conflicts in case we have partial support */ +#define mmsghdr frr_mmsghdr +#define sendmmsg frr_sendmmsg + +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +/* just go 1 at a time here, the loop this is used in will handle the rest */ +static inline int sendmmsg(int fd, struct mmsghdr *mmh, unsigned int len, + int flags) +{ + int rv = sendmsg(fd, &mmh->msg_hdr, 0); + + return rv > 0 ? 1 : rv; +} +#endif + +#endif diff --git a/lib/frrstr.c b/lib/frrstr.c index e5440c509374..1e743d4b0c2c 100644 --- a/lib/frrstr.c +++ b/lib/frrstr.c @@ -3,6 +3,7 @@ * FRR string processing utilities. * Copyright (C) 2018 Cumulus Networks, Inc. * Quentin Young + * Copyright (c) 2023, LabN Consulting, L.L.C. */ #include "zebra.h" @@ -225,3 +226,47 @@ char *frrstr_hex(char *buff, size_t bufsiz, const uint8_t *str, size_t num) return buff; } + +const char *frrstr_skip_over_char(const char *s, int skipc) +{ + int c, quote = 0; + + while ((c = *s++)) { + if (c == '\\') { + if (!*s++) + return NULL; + continue; + } + if (quote) { + if (c == quote) + quote = 0; + continue; + } + if (c == skipc) + return s; + if (c == '"' || c == '\'') + quote = c; + } + return NULL; +} + +/* + * Advance backward in string until reaching the char `toc` + * if beginning of string is reached w/o finding char return NULL + * + * /foo/bar'baz/booz'/foo + */ +const char *frrstr_back_to_char(const char *s, int toc) +{ + const char *next = s; + const char *prev = NULL; + + if (s[0] == 0) + return NULL; + if (!strpbrk(s, "'\"\\")) + return strrchr(s, toc); + while ((next = frrstr_skip_over_char(next, toc))) + prev = next - 1; + return prev; +} + diff --git a/lib/frrstr.h b/lib/frrstr.h index 19ba09e21319..33a499200108 100644 --- a/lib/frrstr.h +++ b/lib/frrstr.h @@ -3,6 +3,7 @@ * FRR string processing utilities. * Copyright (C) 2018 Cumulus Networks, Inc. * Quentin Young + * Copyright (c) 2023, LabN Consulting, L.L.C. */ #ifndef _FRRSTR_H_ @@ -166,6 +167,19 @@ int all_digit(const char *str); */ char *frrstr_hex(char *buff, size_t bufsiz, const uint8_t *str, size_t num); +/* + * Advance past a given char `skipc` in a string, while honoring quoting and + * backslash escapes (i.e., ignore `skipc` which occur in quoted sections). + */ +const char *frrstr_skip_over_char(const char *s, int skipc); + +/* + * Advance back from end to a given char `toc` in a string, while honoring + * quoting and backslash escapes. `toc` chars inside quote or escaped are + * ignored. + */ +const char *frrstr_back_to_char(const char *s, int toc); + #ifdef __cplusplus } #endif diff --git a/lib/hash.h b/lib/hash.h index 810faf903070..efa7011bc205 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -13,6 +13,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new hash structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* Default hash table size. */ #define HASH_INITIAL_SIZE 256 /* Expansion threshold */ @@ -28,12 +40,12 @@ struct hash_bucket { */ int len; - /* Linked list. */ - struct hash_bucket *next; - /* Hash key. */ unsigned int key; + /* Linked list. */ + struct hash_bucket *next; + /* Data. */ void *data; }; diff --git a/lib/hook.h b/lib/hook.h index 19e0f1fbfce7..58aa2009b961 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -163,6 +163,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, _hook_unregister(&_hook_##hookname, \ _hook_typecheck_arg_##hookname(func), arg, true) +#define hook_have_hooks(hookname) (_hook_##hookname.entries != NULL) + /* invoke hooks * this is private (static) to the file that has the DEFINE_HOOK statement */ diff --git a/lib/iana_afi.h b/lib/iana_afi.h index b9c19cc3d549..5cec59928b10 100644 --- a/lib/iana_afi.h +++ b/lib/iana_afi.h @@ -36,6 +36,7 @@ typedef enum { IANA_SAFI_ENCAP = 7, IANA_SAFI_EVPN = 70, IANA_SAFI_MPLS_VPN = 128, + IANA_SAFI_RTC = 132, /* BGP-RTC RFC 4684 */ IANA_SAFI_FLOWSPEC = 133 } iana_safi_t; @@ -94,6 +95,8 @@ static inline safi_t safi_iana2int(iana_safi_t safi) return SAFI_LABELED_UNICAST; case IANA_SAFI_FLOWSPEC: return SAFI_FLOWSPEC; + case IANA_SAFI_RTC: + return SAFI_RTC; case IANA_SAFI_RESERVED: return SAFI_MAX; } @@ -118,6 +121,8 @@ static inline iana_safi_t safi_int2iana(safi_t safi) return IANA_SAFI_LABELED_UNICAST; case SAFI_FLOWSPEC: return IANA_SAFI_FLOWSPEC; + case SAFI_RTC: + return IANA_SAFI_RTC; case SAFI_UNSPEC: case SAFI_MAX: return IANA_SAFI_RESERVED; diff --git a/lib/if.c b/lib/if.c index 6f567861d19c..8f15230f2334 100644 --- a/lib/if.c +++ b/lib/if.c @@ -6,6 +6,12 @@ #include +#include + +#ifdef GNU_LINUX +#include +#endif /* GNU_LINUX */ + #include "linklist.h" #include "vector.h" #include "lib_errors.h" @@ -42,15 +48,14 @@ RB_GENERATE(if_index_head, interface, index_entry, if_cmp_index_func); DEFINE_QOBJ_TYPE(interface); -DEFINE_HOOK(if_add, (struct interface * ifp), (ifp)); -DEFINE_KOOH(if_del, (struct interface * ifp), (ifp)); +DEFINE_HOOK(if_add, (struct interface *ifp), (ifp)); +DEFINE_KOOH(if_del, (struct interface *ifp), (ifp)); + +DEFINE_HOOK(if_real, (struct interface *ifp), (ifp)); +DEFINE_KOOH(if_unreal, (struct interface *ifp), (ifp)); -static struct interface_master{ - int (*create_hook)(struct interface *ifp); - int (*up_hook)(struct interface *ifp); - int (*down_hook)(struct interface *ifp); - int (*destroy_hook)(struct interface *ifp); -} ifp_master = { 0, }; +DEFINE_HOOK(if_up, (struct interface *ifp), (ifp)); +DEFINE_KOOH(if_down, (struct interface *ifp), (ifp)); /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the @@ -98,8 +103,8 @@ int if_cmp_name_func(const char *p1, const char *p2) if (!*p2) return 1; - x1 = strtol(p1, (char **)&tmp1, 10); - x2 = strtol(p2, (char **)&tmp2, 10); + x1 = strtol(p1, &tmp1, 10); + x2 = strtol(p2, &tmp2, 10); /* let's compare numbers now */ if (x1 < x2) @@ -165,8 +170,7 @@ static struct interface *if_new(struct vrf *vrf) ifp->vrf = vrf; - ifp->connected = list_new(); - ifp->connected->del = ifp_connected_free; + if_connected_init(ifp->connected); ifp->nbr_connected = list_new(); ifp->nbr_connected->del = (void (*)(void *))nbr_connected_free; @@ -180,14 +184,12 @@ static struct interface *if_new(struct vrf *vrf) void if_new_via_zapi(struct interface *ifp) { - if (ifp_master.create_hook) - (*ifp_master.create_hook)(ifp); + hook_call(if_real, ifp); } void if_destroy_via_zapi(struct interface *ifp) { - if (ifp_master.destroy_hook) - (*ifp_master.destroy_hook)(ifp); + hook_call(if_unreal, ifp); ifp->oldifindex = ifp->ifindex; if_set_index(ifp, IFINDEX_INTERNAL); @@ -198,14 +200,12 @@ void if_destroy_via_zapi(struct interface *ifp) void if_up_via_zapi(struct interface *ifp) { - if (ifp_master.up_hook) - (*ifp_master.up_hook)(ifp); + hook_call(if_up, ifp); } void if_down_via_zapi(struct interface *ifp) { - if (ifp_master.down_hook) - (*ifp_master.down_hook)(ifp); + hook_call(if_down, ifp); } static struct interface *if_create_name(const char *name, struct vrf *vrf) @@ -248,11 +248,14 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) /* Delete interface structure. */ void if_delete_retain(struct interface *ifp) { + struct connected *ifc; + hook_call(if_del, ifp); QOBJ_UNREG(ifp); /* Free connected address list */ - list_delete_all_node(ifp->connected); + while ((ifc = if_connected_pop(ifp->connected))) + ifp_connected_free(ifc); /* Free connected nbr address list */ list_delete_all_node(ifp->nbr_connected); @@ -270,7 +273,7 @@ void if_delete(struct interface **ifp) if_delete_retain(ptr); - list_delete(&ptr->connected); + if_connected_fini(ptr->connected); list_delete(&ptr->nbr_connected); if_link_params_free(ptr); @@ -367,8 +370,7 @@ struct interface *if_lookup_by_name(const char *name, vrf_id_t vrf_id) struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct interface if_tmp; - if (!vrf || !name - || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ) + if (!vrf || !name || strnlen(name, IFNAMSIZ) == IFNAMSIZ) return NULL; strlcpy(if_tmp.name, name, sizeof(if_tmp.name)); @@ -379,7 +381,7 @@ struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf) { struct interface if_tmp; - if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ) + if (!name || strnlen(name, IFNAMSIZ) == IFNAMSIZ) return NULL; strlcpy(if_tmp.name, name, sizeof(if_tmp.name)); @@ -391,7 +393,7 @@ static struct interface *if_lookup_by_name_all_vrf(const char *name) struct vrf *vrf; struct interface *ifp; - if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ) + if (!name || strnlen(name, IFNAMSIZ) == IFNAMSIZ) return NULL; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { @@ -433,7 +435,6 @@ struct interface *if_lookup_address_local(const void *src, int family, vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); - struct listnode *cnode; struct interface *ifp, *best_down = NULL; struct prefix *p; struct connected *c; @@ -442,7 +443,7 @@ struct interface *if_lookup_address_local(const void *src, int family, return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { p = c->address; if (!p || p->family != family) @@ -474,7 +475,6 @@ struct connected *if_lookup_address(const void *matchaddr, int family, struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct prefix addr; int bestlen = 0; - struct listnode *cnode; struct interface *ifp; struct connected *c; struct connected *match; @@ -493,7 +493,7 @@ struct connected *if_lookup_address(const void *matchaddr, int family, match = NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (c->address && (c->address->family == AF_INET) && prefix_match(CONNECTED_PREFIX(c), &addr) && (c->address->prefixlen > bestlen)) { @@ -509,12 +509,11 @@ struct connected *if_lookup_address(const void *matchaddr, int family, struct interface *if_lookup_prefix(const struct prefix *prefix, vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); - struct listnode *cnode; struct interface *ifp; struct connected *c; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (prefix_cmp(c->address, prefix) == 0) { return ifp; } @@ -675,21 +674,26 @@ int if_is_running(const struct interface *ifp) if ptm checking is enabled, then ptm check has passed */ int if_is_operative(const struct interface *ifp) { - return ((ifp->flags & IFF_UP) - && (((ifp->flags & IFF_RUNNING) - && (ifp->ptm_status || !ifp->ptm_enable)) - || !CHECK_FLAG(ifp->status, - ZEBRA_INTERFACE_LINKDETECTION))); + return ((ifp->flags & IFF_UP) && + (((ifp->flags & IFF_RUNNING) +#ifdef IFF_LOWER_UP + && (ifp->flags & IFF_LOWER_UP) +#endif /* IFF_LOWER_UP */ + && (ifp->ptm_status || !ifp->ptm_enable)) || + !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))); } /* Is the interface operative, eg. either UP & RUNNING or UP & !ZEBRA_INTERFACE_LINK_DETECTION, without PTM check */ int if_is_no_ptm_operative(const struct interface *ifp) { - return ((ifp->flags & IFF_UP) - && ((ifp->flags & IFF_RUNNING) - || !CHECK_FLAG(ifp->status, - ZEBRA_INTERFACE_LINKDETECTION))); + return ((ifp->flags & IFF_UP) && + (((ifp->flags & IFF_RUNNING) +#ifdef IFF_LOWER_UP + && (ifp->flags & IFF_LOWER_UP) +#endif /* IFF_LOWER_UP */ + ) || + !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))); } /* Is this loopback interface ? */ @@ -751,6 +755,9 @@ const char *if_flag_dump(unsigned long flag) strlcpy(logbuf, "<", BUFSIZ); IFF_OUT_LOG(IFF_UP, "UP"); +#ifdef IFF_LOWER_UP + IFF_OUT_LOG(IFF_LOWER_UP, "LOWER_UP"); +#endif /* IFF_LOWER_UP */ IFF_OUT_LOG(IFF_BROADCAST, "BROADCAST"); IFF_OUT_LOG(IFF_DEBUG, "DEBUG"); IFF_OUT_LOG(IFF_LOOPBACK, "LOOPBACK"); @@ -781,10 +788,9 @@ const char *if_flag_dump(unsigned long flag) /* For debugging */ static void if_dump(const struct interface *ifp) { - struct listnode *node; - struct connected *c __attribute__((unused)); + const struct connected *c; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) + frr_each (if_connected_const, ifp->connected, c) zlog_info( "Interface %s vrf %s(%u) index %d metric %d mtu %d mtu6 %d %s", ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, @@ -893,29 +899,13 @@ nbr_connected_log(struct nbr_connected *connected, char *str) zlog_info("%s", logbuf); } -/* If two connected address has same prefix return 1. */ -static int connected_same_prefix(const struct prefix *p1, - const struct prefix *p2) -{ - if (p1->family == p2->family) { - if (p1->family == AF_INET - && IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4)) - return 1; - if (p1->family == AF_INET6 - && IPV6_ADDR_SAME(&p1->u.prefix6, &p2->u.prefix6)) - return 1; - } - return 0; -} - /* count the number of connected addresses that are in the given family */ unsigned int connected_count_by_family(struct interface *ifp, int family) { - struct listnode *cnode; struct connected *connected; unsigned int cnt = 0; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) + frr_each (if_connected, ifp->connected, connected) if (connected->address->family == family) cnt++; @@ -925,15 +915,10 @@ unsigned int connected_count_by_family(struct interface *ifp, int family) struct connected *connected_lookup_prefix_exact(struct interface *ifp, const struct prefix *p) { - struct listnode *node; - struct listnode *next; struct connected *ifc; - for (node = listhead(ifp->connected); node; node = next) { - ifc = listgetdata(node); - next = node->next; - - if (connected_same_prefix(ifc->address, p)) + frr_each (if_connected, ifp->connected, ifc) { + if (prefix_same(ifc->address, p)) return ifc; } return NULL; @@ -942,17 +927,12 @@ struct connected *connected_lookup_prefix_exact(struct interface *ifp, struct connected *connected_delete_by_prefix(struct interface *ifp, struct prefix *p) { - struct listnode *node; - struct listnode *next; struct connected *ifc; /* In case of same prefix come, replace it with new one. */ - for (node = listhead(ifp->connected); node; node = next) { - ifc = listgetdata(node); - next = node->next; - - if (connected_same_prefix(ifc->address, p)) { - listnode_delete(ifp->connected, ifc); + frr_each_safe (if_connected, ifp->connected, ifc) { + if (prefix_same(ifc->address, p)) { + if_connected_del(ifp->connected, ifc); return ifc; } } @@ -964,13 +944,12 @@ struct connected *connected_delete_by_prefix(struct interface *ifp, struct connected *connected_lookup_prefix(struct interface *ifp, const struct prefix *addr) { - struct listnode *cnode; struct connected *c; struct connected *match; match = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (c->address && (c->address->family == addr->family) && prefix_match(CONNECTED_PREFIX(c), addr) && (!match @@ -1001,16 +980,15 @@ struct connected *connected_add_by_prefix(struct interface *ifp, } /* Add connected address to the interface. */ - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); return ifc; } struct connected *connected_get_linklocal(struct interface *ifp) { - struct listnode *n; struct connected *c = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) { + frr_each (if_connected, ifp->connected, c) { if (c->address->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6)) break; @@ -1340,14 +1318,14 @@ static void cli_show_interface(struct vty *vty, const struct lyd_node *dnode, char ifname[XPATH_MAXLEN]; char vrfname[XPATH_MAXLEN]; - netns_ifname_split(yang_dnode_get_string(dnode, "./name"), + netns_ifname_split(yang_dnode_get_string(dnode, "name"), ifname, vrfname); vty_out(vty, "interface %s", ifname); if (!strmatch(vrfname, VRF_DEFAULT_NAME)) vty_out(vty, " vrf %s", vrfname); } else { - const char *ifname = yang_dnode_get_string(dnode, "./name"); + const char *ifname = yang_dnode_get_string(dnode, "name"); vty_out(vty, "interface %s", ifname); } @@ -1361,6 +1339,15 @@ static void cli_show_interface_end(struct vty *vty, vty_out(vty, "exit\n"); } +static int cli_cmp_interface(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) +{ + const char *ifname1 = yang_dnode_get_string(dnode1, "name"); + const char *ifname2 = yang_dnode_get_string(dnode2, "name"); + + return if_cmp_name_func(ifname1, ifname2); +} + void if_vty_config_start(struct vty *vty, struct interface *ifp) { vty_frame(vty, "!\n"); @@ -1477,17 +1464,6 @@ void if_cmd_init_default(void) if_cmd_init(if_nb_config_write); } -void if_zapi_callbacks(int (*create)(struct interface *ifp), - int (*up)(struct interface *ifp), - int (*down)(struct interface *ifp), - int (*destroy)(struct interface *ifp)) -{ - ifp_master.create_hook = create; - ifp_master.up_hook = up; - ifp_master.down_hook = down; - ifp_master.destroy_hook = destroy; -} - /* ------- Northbound callbacks ------- */ /* @@ -1498,7 +1474,7 @@ static int lib_interface_create(struct nb_cb_create_args *args) const char *ifname; struct interface *ifp; - ifname = yang_dnode_get_string(args->dnode, "./name"); + ifname = yang_dnode_get_string(args->dnode, "name"); switch (args->event) { case NB_EV_VALIDATE: @@ -1709,7 +1685,7 @@ lib_interface_state_mtu_get_elem(struct nb_cb_get_elem_args *args) { const struct interface *ifp = args->list_entry; - return yang_data_new_uint16(args->xpath, ifp->mtu); + return yang_data_new_uint32(args->xpath, ifp->mtu); } /* @@ -1780,6 +1756,8 @@ lib_interface_state_phy_address_get_elem(struct nb_cb_get_elem_args *args) } /* clang-format off */ + +/* cli_show callbacks are kept here for daemons not yet converted to mgmtd */ const struct frr_yang_module_info frr_interface_info = { .name = "frr-interface", .nodes = { @@ -1790,6 +1768,7 @@ const struct frr_yang_module_info frr_interface_info = { .destroy = lib_interface_destroy, .cli_show = cli_show_interface, .cli_show_end = cli_show_interface_end, + .cli_cmp = cli_cmp_interface, .get_next = lib_interface_get_next, .get_keys = lib_interface_get_keys, .lookup_entry = lib_interface_lookup_entry, @@ -1862,3 +1841,27 @@ const struct frr_yang_module_info frr_interface_info = { }, } }; + +const struct frr_yang_module_info frr_interface_cli_info = { + .name = "frr-interface", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-interface:lib/interface", + .cbs = { + .cli_show = cli_show_interface, + .cli_show_end = cli_show_interface_end, + .cli_cmp = cli_cmp_interface, + }, + }, + { + .xpath = "/frr-interface:lib/interface/description", + .cbs = { + .cli_show = cli_show_interface_desc, + }, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/if.h b/lib/if.h index 7b4415da45d4..0dc56bd21098 100644 --- a/lib/if.h +++ b/lib/if.h @@ -88,8 +88,6 @@ enum zebra_link_type { FreeBSD define value in /usr/include/net/if.h. #define IFNAMSIZ 16 */ - -#define INTERFACE_NAMSIZ IFNAMSIZ #define INTERFACE_HWADDR_MAX 20 typedef signed int ifindex_t; @@ -197,7 +195,7 @@ struct if_link_params { uint32_t min_delay; /* Link Min Delay */ uint32_t max_delay; /* Link Max Delay */ uint32_t delay_var; /* Link Delay Variation */ - float pkt_loss; /* Link Packet Loss */ + uint32_t pkt_loss; /* Link Packet Loss */ float res_bw; /* Residual Bandwidth */ float ava_bw; /* Available Bandwidth */ float use_bw; /* Utilized Bandwidth */ @@ -206,6 +204,8 @@ struct if_link_params { #define INTERFACE_LINK_PARAMS_SIZE sizeof(struct if_link_params) #define HAS_LINK_PARAMS(ifp) ((ifp)->link_params != NULL) +PREDECL_DLIST(if_connected); + /* Interface structure */ struct interface { RB_ENTRY(interface) name_entry, index_entry; @@ -218,7 +218,7 @@ struct interface { To delete, just set ifindex to IFINDEX_INTERNAL to indicate that the interface does not exist in the kernel. */ - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; /* Interface index (should be IFINDEX_INTERNAL for non-kernel or deleted interfaces). @@ -275,12 +275,8 @@ struct interface { /* description of the interface. */ char *desc; - /* Distribute list. */ - void *distribute_in; - void *distribute_out; - /* Connected address list. */ - struct list *connected; + struct if_connected_head connected[1]; /* Neighbor connected address list. */ struct list *nbr_connected; @@ -375,9 +371,6 @@ DECLARE_QOBJ_TYPE(interface); if (vrf) \ RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name) -#define FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) \ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) - /* called from the library code whenever interfaces are created/deleted * note: interfaces may not be fully realized at that point; also they * may not exist in the system (ifindex = IFINDEX_INTERNAL) @@ -386,13 +379,34 @@ DECLARE_QOBJ_TYPE(interface); * can use 1000+ so they run after the daemon has initialised daemon-specific * interface data */ -DECLARE_HOOK(if_add, (struct interface * ifp), (ifp)); -DECLARE_KOOH(if_del, (struct interface * ifp), (ifp)); +DECLARE_HOOK(if_add, (struct interface *ifp), (ifp)); +DECLARE_KOOH(if_del, (struct interface *ifp), (ifp)); + +/* called (in daemons) when ZAPI tells us the interface actually exists + * (ifindex != IFINDEX_INTERNAL) + * + * WARNING: these 2 hooks NEVER CALLED inside zebra! + */ +DECLARE_HOOK(if_real, (struct interface *ifp), (ifp)); +DECLARE_KOOH(if_unreal, (struct interface *ifp), (ifp)); + +/* called (in daemons) on state changes on interfaces. Whether this is admin + * state (= pure config) or carrier state (= hardware link plugged) depends on + * zebra's "link-detect" configuration. By default, it's carrier state, so + * this won't happen until the interface actually has a link. + * + * WARNING: these 2 hooks NEVER CALLED inside zebra! + */ +DECLARE_HOOK(if_up, (struct interface *ifp), (ifp)); +DECLARE_KOOH(if_down, (struct interface *ifp), (ifp)); + #define METRIC_MAX (~0) /* Connected address structure. */ struct connected { + struct if_connected_item item; + /* Attached interface. */ struct interface *ifp; @@ -420,6 +434,8 @@ struct connected { #define ZEBRA_IFA_SECONDARY (1 << 0) #define ZEBRA_IFA_PEER (1 << 1) #define ZEBRA_IFA_UNNUMBERED (1 << 2) +#define ZEBRA_IFA_NOPREFIXROUTE (1 << 3) + /* N.B. the ZEBRA_IFA_PEER flag should be set if and only if a peer address has been configured. If this flag is set, the destination field must contain the peer address. @@ -442,6 +458,8 @@ struct connected { uint32_t metric; }; +DECLARE_DLIST(if_connected, struct connected, item); + /* Nbr Connected address structure. */ struct nbr_connected { /* Attached interface. */ @@ -512,9 +530,9 @@ extern int if_cmp_name_func(const char *p1, const char *p2); * This is useful for vrf route-leaking. So more than anything * else think before you use VRF_UNKNOWN */ -extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id); +extern void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id); -extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id); +extern struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id); extern struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex, vrf_id_t vrf_id); extern struct interface *if_lookup_address_local(const void *matchaddr, @@ -545,7 +563,7 @@ extern int if_set_index(struct interface *ifp, ifindex_t ifindex); /* Delete the interface, but do not free the structure, and leave it in the interface list. It is often advisable to leave the pseudo interface structure because there may be configuration information attached. */ -extern void if_delete_retain(struct interface *); +extern void if_delete_retain(struct interface *ifp); /* Delete and free the interface structure: calls if_delete_retain and then deletes it from the interface list and frees the structure. */ @@ -563,13 +581,13 @@ extern int if_is_pointopoint(const struct interface *ifp); extern int if_is_multicast(const struct interface *ifp); extern void if_terminate(struct vrf *vrf); extern void if_dump_all(void); -extern const char *if_flag_dump(unsigned long); -extern const char *if_link_type_str(enum zebra_link_type); +extern const char *if_flag_dump(unsigned long flags); +extern const char *if_link_type_str(enum zebra_link_type zlt); /* Please use ifindex2ifname instead of if_indextoname where possible; ifindex2ifname uses internal interface info, whereas if_indextoname must make a system call. */ -extern const char *ifindex2ifname(ifindex_t, vrf_id_t vrf_id); +extern const char *ifindex2ifname(ifindex_t ifindex, vrf_id_t vrf_id); /* Please use ifname2ifindex instead of if_nametoindex where possible; ifname2ifindex uses internal interface info, whereas if_nametoindex must @@ -579,19 +597,20 @@ extern ifindex_t ifname2ifindex(const char *ifname, vrf_id_t vrf_id); /* Connected address functions. */ extern struct connected *connected_new(void); extern void connected_free(struct connected **connected); -extern void connected_add(struct interface *, struct connected *); -extern struct connected * -connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *); -extern struct connected *connected_delete_by_prefix(struct interface *, - struct prefix *); -extern struct connected *connected_lookup_prefix(struct interface *, - const struct prefix *); -extern struct connected *connected_lookup_prefix_exact(struct interface *, - const struct prefix *); -extern unsigned int connected_count_by_family(struct interface *, int family); +extern struct connected *connected_add_by_prefix(struct interface *ifp, + struct prefix *p, + struct prefix *dest); +extern struct connected *connected_delete_by_prefix(struct interface *ifp, + struct prefix *p); +extern struct connected *connected_lookup_prefix(struct interface *ifp, + const struct prefix *p); +extern struct connected *connected_lookup_prefix_exact(struct interface *ifp, + const struct prefix *p); +extern unsigned int connected_count_by_family(struct interface *ifp, int family); extern struct nbr_connected *nbr_connected_new(void); -extern void nbr_connected_free(struct nbr_connected *); -struct nbr_connected *nbr_connected_check(struct interface *, struct prefix *); +extern void nbr_connected_free(struct nbr_connected *connected); +struct nbr_connected *nbr_connected_check(struct interface *ifp, + struct prefix *p); struct connected *connected_get_linklocal(struct interface *ifp); /* link parameters */ @@ -599,10 +618,10 @@ bool if_link_params_cmp(struct if_link_params *iflp1, struct if_link_params *iflp2); void if_link_params_copy(struct if_link_params *dst, struct if_link_params *src); -struct if_link_params *if_link_params_get(struct interface *); +struct if_link_params *if_link_params_get(struct interface *ifp); struct if_link_params *if_link_params_enable(struct interface *ifp); struct if_link_params *if_link_params_init(struct interface *ifp); -void if_link_params_free(struct interface *); +void if_link_params_free(struct interface *ifp); /* Northbound. */ struct vty; @@ -610,10 +629,6 @@ extern void if_vty_config_start(struct vty *vty, struct interface *ifp); extern void if_vty_config_end(struct vty *vty); extern void if_cmd_init(int (*config_write)(struct vty *)); extern void if_cmd_init_default(void); -extern void if_zapi_callbacks(int (*create)(struct interface *ifp), - int (*up)(struct interface *ifp), - int (*down)(struct interface *ifp), - int (*destroy)(struct interface *ifp)); extern void if_new_via_zapi(struct interface *ifp); extern void if_up_via_zapi(struct interface *ifp); @@ -621,6 +636,7 @@ extern void if_down_via_zapi(struct interface *ifp); extern void if_destroy_via_zapi(struct interface *ifp); extern const struct frr_yang_module_info frr_interface_info; +extern const struct frr_yang_module_info frr_interface_cli_info; #ifdef __cplusplus } diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 42e162072ff3..5fe5061a3cb0 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -243,14 +243,14 @@ DEFPY_YANG(no_if_ipv6_route_map, no_if_ipv6_route_map_cmd, void cli_show_if_route_map(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - if (yang_dnode_exists(dnode, "./in-route-map")) + if (yang_dnode_exists(dnode, "in-route-map")) vty_out(vty, " route-map %s in %s\n", - yang_dnode_get_string(dnode, "./in-route-map"), - yang_dnode_get_string(dnode, "./interface")); - if (yang_dnode_exists(dnode, "./out-route-map")) + yang_dnode_get_string(dnode, "in-route-map"), + yang_dnode_get_string(dnode, "interface")); + if (yang_dnode_exists(dnode, "out-route-map")) vty_out(vty, " route-map %s out %s\n", - yang_dnode_get_string(dnode, "./out-route-map"), - yang_dnode_get_string(dnode, "./interface")); + yang_dnode_get_string(dnode, "out-route-map"), + yang_dnode_get_string(dnode, "interface")); } void if_rmap_yang_modify_cb(struct if_rmap_ctx *ctx, diff --git a/lib/imsg-buffer.c b/lib/imsg-buffer.c index 4f041ff66ef0..556e0cf90490 100644 --- a/lib/imsg-buffer.c +++ b/lib/imsg-buffer.c @@ -6,6 +6,7 @@ */ #include +#include #include "queue.h" #include "imsg.h" diff --git a/lib/ipaddr.h b/lib/ipaddr.h index c86e38c867c0..888955fba0ab 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -40,8 +40,9 @@ struct ipaddr { #define IS_IPADDR_V4(p) ((p)->ipa_type == IPADDR_V4) #define IS_IPADDR_V6(p) ((p)->ipa_type == IPADDR_V6) -#define SET_IPADDR_V4(p) (p)->ipa_type = IPADDR_V4 -#define SET_IPADDR_V6(p) (p)->ipa_type = IPADDR_V6 +#define SET_IPADDR_NONE(p) ((p)->ipa_type = IPADDR_NONE) +#define SET_IPADDR_V4(p) ((p)->ipa_type = IPADDR_V4) +#define SET_IPADDR_V6(p) ((p)->ipa_type = IPADDR_V6) #define IPADDRSZ(p) \ (IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr)) @@ -165,9 +166,17 @@ static inline bool ipaddr_is_zero(const struct ipaddr *ip) return true; } +static inline bool ipaddr_is_same(const struct ipaddr *ip1, + const struct ipaddr *ip2) +{ + return ipaddr_cmp(ip1, ip2) == 0; +} + +/* clang-format off */ #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pIA" (struct ipaddr *) #endif +/* clang-format on */ #ifdef __cplusplus } diff --git a/lib/jhash.c b/lib/jhash.c index 0d561ef3a4f2..4e02112e098f 100644 --- a/lib/jhash.c +++ b/lib/jhash.c @@ -86,34 +86,34 @@ uint32_t jhash(const void *key, uint32_t length, uint32_t initval) switch (len) { case 11: c += ((uint32_t)k[10] << 24); - /* fallthru */ + fallthrough; case 10: c += ((uint32_t)k[9] << 16); - /* fallthru */ + fallthrough; case 9: c += ((uint32_t)k[8] << 8); - /* fallthru */ + fallthrough; case 8: b += ((uint32_t)k[7] << 24); - /* fallthru */ + fallthrough; case 7: b += ((uint32_t)k[6] << 16); - /* fallthru */ + fallthrough; case 6: b += ((uint32_t)k[5] << 8); - /* fallthru */ + fallthrough; case 5: b += k[4]; - /* fallthru */ + fallthrough; case 4: a += ((uint32_t)k[3] << 24); - /* fallthru */ + fallthrough; case 3: a += ((uint32_t)k[2] << 16); - /* fallthru */ + fallthrough; case 2: a += ((uint32_t)k[1] << 8); - /* fallthru */ + fallthrough; case 1: a += k[0]; } @@ -148,7 +148,7 @@ uint32_t jhash2(const uint32_t *k, uint32_t length, uint32_t initval) switch (len) { case 2: b += k[1]; - /* fallthru */ + fallthrough; case 1: a += k[0]; } diff --git a/lib/keychain.c b/lib/keychain.c index 640746bb4194..1982220bc7e3 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -6,19 +6,19 @@ #include "config.h" #include -#include "command.h" -#include "memory.h" -#include "linklist.h" #include "keychain.h" +#include "linklist.h" +#include "memory.h" -DEFINE_MTYPE_STATIC(LIB, KEY, "Key"); -DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain"); +DEFINE_MTYPE(LIB, KEY, "Key"); +DEFINE_MTYPE(LIB, KEYCHAIN, "Key chain"); +DEFINE_MTYPE(LIB, KEYCHAIN_DESC, "Key chain description"); DEFINE_QOBJ_TYPE(keychain); DEFINE_QOBJ_TYPE(key); /* Master list of key chain. */ -static struct list *keychain_list; +struct list *keychain_list; static struct keychain *keychain_new(void) { @@ -37,6 +37,7 @@ static void keychain_free(struct keychain *keychain) static struct key *key_new(void) { struct key *key = XCALLOC(MTYPE_KEY, sizeof(struct key)); + QOBJ_REG(key, key); return key; } @@ -77,11 +78,11 @@ static int key_cmp_func(void *arg1, void *arg2) static void key_delete_func(struct key *key) { if (key->string) - free(key->string); + XFREE(MTYPE_KEY, key->string); key_free(key); } -static struct keychain *keychain_get(const char *name) +struct keychain *keychain_get(const char *name) { struct keychain *keychain; @@ -100,7 +101,7 @@ static struct keychain *keychain_get(const char *name) return keychain; } -static void keychain_delete(struct keychain *keychain) +void keychain_delete(struct keychain *keychain) { XFREE(MTYPE_KEYCHAIN, keychain->name); @@ -109,7 +110,7 @@ static void keychain_delete(struct keychain *keychain) keychain_free(keychain); } -static struct key *key_lookup(const struct keychain *keychain, uint32_t index) +struct key *key_lookup(const struct keychain *keychain, uint32_t index) { struct listnode *node; struct key *key; @@ -182,7 +183,7 @@ struct key *key_lookup_for_send(const struct keychain *keychain) return NULL; } -static struct key *key_get(const struct keychain *keychain, uint32_t index) +struct key *key_get(const struct keychain *keychain, uint32_t index) { struct key *key; @@ -199,7 +200,7 @@ static struct key *key_get(const struct keychain *keychain, uint32_t index) return key; } -static void key_delete(struct keychain *keychain, struct key *key) +void key_delete(struct keychain *keychain, struct key *key) { listnode_delete(keychain->key, key); @@ -207,122 +208,6 @@ static void key_delete(struct keychain *keychain, struct key *key) key_free(key); } -DEFUN_NOSH (key_chain, - key_chain_cmd, - "key chain WORD", - "Authentication key management\n" - "Key-chain management\n" - "Key-chain name\n") -{ - int idx_word = 2; - struct keychain *keychain; - - keychain = keychain_get(argv[idx_word]->arg); - VTY_PUSH_CONTEXT(KEYCHAIN_NODE, keychain); - - return CMD_SUCCESS; -} - -DEFUN (no_key_chain, - no_key_chain_cmd, - "no key chain WORD", - NO_STR - "Authentication key management\n" - "Key-chain management\n" - "Key-chain name\n") -{ - int idx_word = 3; - struct keychain *keychain; - - keychain = keychain_lookup(argv[idx_word]->arg); - - if (!keychain) { - vty_out(vty, "Can't find keychain %s\n", argv[idx_word]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - - keychain_delete(keychain); - - return CMD_SUCCESS; -} - -DEFUN_NOSH (key, - key_cmd, - "key (0-2147483647)", - "Configure a key\n" - "Key identifier number\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(keychain, keychain); - struct key *key; - uint32_t index; - - index = strtoul(argv[idx_number]->arg, NULL, 10); - key = key_get(keychain, index); - VTY_PUSH_CONTEXT_SUB(KEYCHAIN_KEY_NODE, key); - - return CMD_SUCCESS; -} - -DEFUN (no_key, - no_key_cmd, - "no key (0-2147483647)", - NO_STR - "Delete a key\n" - "Key identifier number\n") -{ - int idx_number = 2; - VTY_DECLVAR_CONTEXT(keychain, keychain); - struct key *key; - uint32_t index; - - index = strtoul(argv[idx_number]->arg, NULL, 10); - key = key_lookup(keychain, index); - if (!key) { - vty_out(vty, "Can't find key %d\n", index); - return CMD_WARNING_CONFIG_FAILED; - } - - key_delete(keychain, key); - - vty->node = KEYCHAIN_NODE; - - return CMD_SUCCESS; -} - -DEFUN (key_string, - key_string_cmd, - "key-string LINE", - "Set key string\n" - "The key\n") -{ - int idx_line = 1; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - if (key->string) - XFREE(MTYPE_KEY, key->string); - key->string = XSTRDUP(MTYPE_KEY, argv[idx_line]->arg); - - return CMD_SUCCESS; -} - -DEFUN (no_key_string, - no_key_string_cmd, - "no key-string [LINE]", - NO_STR - "Unset key string\n" - "The key\n") -{ - VTY_DECLVAR_CONTEXT_SUB(key, key); - - if (key->string) { - XFREE(MTYPE_KEY, key->string); - key->string = NULL; - } - - return CMD_SUCCESS; -} - const struct keychain_algo_info algo_info[] = { {KEYCHAIN_ALGO_NULL, "null", 0, 0, "NULL"}, {KEYCHAIN_ALGO_MD5, "md5", KEYCHAIN_MD5_HASH_SIZE, @@ -393,864 +278,39 @@ const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key) return algo_info[key].name; } -DEFUN(cryptographic_algorithm, cryptographic_algorithm_cmd, - "cryptographic-algorithm " - "", - "Cryptographic-algorithm\n" - "Use MD5 algorithm\n" - "Use HMAC-SHA-1 algorithm\n" - "Use HMAC-SHA-256 algorithm\n" - "Use HMAC-SHA-384 algorithm\n" - "Use HMAC-SHA-512 algorithm\n") -{ - int algo_idx = 1; - uint8_t hash_algo = KEYCHAIN_ALGO_NULL; - - VTY_DECLVAR_CONTEXT_SUB(key, key); - hash_algo = keychain_get_algo_id_by_name(argv[algo_idx]->arg); -#ifndef CRYPTO_OPENSSL - if (hash_algo == KEYCHAIN_ALGO_NULL) { - vty_out(vty, - "Hash algorithm not supported, compile with --with-crypto=openssl\n"); - return CMD_WARNING_CONFIG_FAILED; - } -#endif /* CRYPTO_OPENSSL */ - key->hash_algo = hash_algo; - return CMD_SUCCESS; -} - -DEFUN(no_cryptographic_algorithm, no_cryptographic_algorithm_cmd, - "no cryptographic-algorithm " - "[]", - NO_STR - "Cryptographic-algorithm\n" - "Use MD5 algorithm\n" - "Use HMAC-SHA-1 algorithm\n" - "Use HMAC-SHA-256 algorithm\n" - "Use HMAC-SHA-384 algorithm\n" - "Use HMAC-SHA-512 algorithm\n") -{ - int algo_idx = 2; - uint8_t hash_algo = KEYCHAIN_ALGO_NULL; - - VTY_DECLVAR_CONTEXT_SUB(key, key); - if (argc > algo_idx) { - hash_algo = keychain_get_algo_id_by_name(argv[algo_idx]->arg); - if (hash_algo == KEYCHAIN_ALGO_NULL) { - vty_out(vty, - "Hash algorithm not supported, try compiling with --with-crypto=openssl\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - if ((hash_algo != KEYCHAIN_ALGO_NULL) && (hash_algo != key->hash_algo)) - return CMD_SUCCESS; - - key->hash_algo = KEYCHAIN_ALGO_NULL; - return CMD_SUCCESS; -} - -/* Convert HH:MM:SS MON DAY YEAR to time_t value. -1 is returned when - given string is malformed. */ -static time_t key_str2time(const char *time_str, const char *day_str, - const char *month_str, const char *year_str) -{ - int i = 0; - char *colon; - struct tm tm; - time_t time; - unsigned int sec, min, hour; - unsigned int day, month, year; - - const char *month_name[] = { - "January", "February", "March", "April", "May", - "June", "July", "August", "September", "October", - "November", "December", NULL}; - -#define _GET_LONG_RANGE(V, STR, MMCOND) \ - { \ - unsigned long tmpl; \ - char *endptr = NULL; \ - tmpl = strtoul((STR), &endptr, 10); \ - if (*endptr != '\0' || tmpl == ULONG_MAX) \ - return -1; \ - if (MMCOND) \ - return -1; \ - (V) = tmpl; \ - } -#define GET_LONG_RANGE(V, STR, MIN, MAX) \ - _GET_LONG_RANGE(V, STR, tmpl<(MIN) || tmpl>(MAX)) -#define GET_LONG_RANGE0(V, STR, MAX) _GET_LONG_RANGE(V, STR, tmpl > (MAX)) - - /* Check hour field of time_str. */ - colon = strchr(time_str, ':'); - if (colon == NULL) - return -1; - *colon = '\0'; - - /* Hour must be between 0 and 23. */ - GET_LONG_RANGE0(hour, time_str, 23); - - /* Check min field of time_str. */ - time_str = colon + 1; - colon = strchr(time_str, ':'); - if (*time_str == '\0' || colon == NULL) - return -1; - *colon = '\0'; - - /* Min must be between 0 and 59. */ - GET_LONG_RANGE0(min, time_str, 59); - - /* Check sec field of time_str. */ - time_str = colon + 1; - if (*time_str == '\0') - return -1; - - /* Sec must be between 0 and 59. */ - GET_LONG_RANGE0(sec, time_str, 59); - - /* Check day_str. Day must be <1-31>. */ - GET_LONG_RANGE(day, day_str, 1, 31); - - /* Check month_str. Month must match month_name. */ - month = 0; - if (strlen(month_str) >= 3) - for (i = 0; month_name[i]; i++) - if (strncmp(month_str, month_name[i], strlen(month_str)) - == 0) { - month = i; - break; - } - if (!month_name[i]) - return -1; - - /* Check year_str. Year must be <1993-2035>. */ - GET_LONG_RANGE(year, year_str, 1993, 2035); - - memset(&tm, 0, sizeof(tm)); - tm.tm_sec = sec; - tm.tm_min = min; - tm.tm_hour = hour; - tm.tm_mon = month; - tm.tm_mday = day; - tm.tm_year = year - 1900; - - time = mktime(&tm); - - return time; -#undef GET_LONG_RANGE -} - -static int key_lifetime_set(struct vty *vty, struct key_range *krange, - const char *stime_str, const char *sday_str, - const char *smonth_str, const char *syear_str, - const char *etime_str, const char *eday_str, - const char *emonth_str, const char *eyear_str) -{ - time_t time_start; - time_t time_end; - - time_start = key_str2time(stime_str, sday_str, smonth_str, syear_str); - if (time_start < 0) { - vty_out(vty, "Malformed time value\n"); - return CMD_WARNING_CONFIG_FAILED; - } - time_end = key_str2time(etime_str, eday_str, emonth_str, eyear_str); - - if (time_end < 0) { - vty_out(vty, "Malformed time value\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (time_end <= time_start) { - vty_out(vty, "Expire time is not later than start time\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - krange->start = time_start; - krange->end = time_end; - - return CMD_SUCCESS; -} - -static int key_lifetime_duration_set(struct vty *vty, struct key_range *krange, - const char *stime_str, - const char *sday_str, - const char *smonth_str, - const char *syear_str, - const char *duration_str) -{ - time_t time_start; - uint32_t duration; - - time_start = key_str2time(stime_str, sday_str, smonth_str, syear_str); - if (time_start < 0) { - vty_out(vty, "Malformed time value\n"); - return CMD_WARNING_CONFIG_FAILED; - } - krange->start = time_start; - - duration = strtoul(duration_str, NULL, 10); - krange->duration = 1; - krange->end = time_start + duration; - - return CMD_SUCCESS; -} - -static int key_lifetime_infinite_set(struct vty *vty, struct key_range *krange, - const char *stime_str, - const char *sday_str, - const char *smonth_str, - const char *syear_str) -{ - time_t time_start; - - time_start = key_str2time(stime_str, sday_str, smonth_str, syear_str); - if (time_start < 0) { - vty_out(vty, "Malformed time value\n"); - return CMD_WARNING_CONFIG_FAILED; - } - krange->start = time_start; - - krange->end = -1; - - return CMD_SUCCESS; -} - -DEFUN (accept_lifetime_day_month_day_month, - accept_lifetime_day_month_day_month_cmd, - "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", - "Set accept lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Time to expire\n" - "Day of th month to expire\n" - "Month of the year to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_number_3 = 6; - int idx_month_2 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (accept_lifetime_day_month_month_day, - accept_lifetime_day_month_month_day_cmd, - "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", - "Set accept lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Time to expire\n" - "Month of the year to expire\n" - "Day of th month to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_month_2 = 6; - int idx_number_3 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (accept_lifetime_month_day_day_month, - accept_lifetime_month_day_day_month_cmd, - "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", - "Set accept lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Time to expire\n" - "Day of th month to expire\n" - "Month of the year to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_number_3 = 6; - int idx_month_2 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (accept_lifetime_month_day_month_day, - accept_lifetime_month_day_month_day_cmd, - "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", - "Set accept lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Time to expire\n" - "Month of the year to expire\n" - "Day of th month to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_month_2 = 6; - int idx_number_3 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (accept_lifetime_infinite_day_month, - accept_lifetime_infinite_day_month_cmd, - "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) infinite", - "Set accept lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Never expires\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_infinite_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg); -} - -DEFUN (accept_lifetime_infinite_month_day, - accept_lifetime_infinite_month_day_cmd, - "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) infinite", - "Set accept lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Never expires\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_infinite_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg); -} - -DEFUN (accept_lifetime_duration_day_month, - accept_lifetime_duration_day_month_cmd, - "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) duration (1-2147483646)", - "Set accept lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Duration of the key\n" - "Duration seconds\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - int idx_number_3 = 6; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_duration_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg); -} - -DEFUN (accept_lifetime_duration_month_day, - accept_lifetime_duration_month_day_cmd, - "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) duration (1-2147483646)", - "Set accept lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Duration of the key\n" - "Duration seconds\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - int idx_number_3 = 6; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_duration_set( - vty, &key->accept, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg); -} - -DEFUN (no_accept_lifetime, - no_accept_lifetime_cmd, - "no accept-lifetime", - NO_STR - "Unset accept-lifetime\n") -{ - VTY_DECLVAR_CONTEXT_SUB(key, key); - - if (key->accept.start) - key->accept.start = 0; - if (key->accept.end) - key->accept.end = 0; - if (key->accept.duration) - key->accept.duration = 0; - - return CMD_SUCCESS; -} - -DEFUN (send_lifetime_day_month_day_month, - send_lifetime_day_month_day_month_cmd, - "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", - "Set send lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Time to expire\n" - "Day of th month to expire\n" - "Month of the year to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_number_3 = 6; - int idx_month_2 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (send_lifetime_day_month_month_day, - send_lifetime_day_month_month_day_cmd, - "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", - "Set send lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Time to expire\n" - "Month of the year to expire\n" - "Day of th month to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_month_2 = 6; - int idx_number_3 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (send_lifetime_month_day_day_month, - send_lifetime_month_day_day_month_cmd, - "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", - "Set send lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Time to expire\n" - "Day of th month to expire\n" - "Month of the year to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_number_3 = 6; - int idx_month_2 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (send_lifetime_month_day_month_day, - send_lifetime_month_day_month_day_cmd, - "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", - "Set send lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Time to expire\n" - "Month of the year to expire\n" - "Day of th month to expire\n" - "Year to expire\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - int idx_hhmmss_2 = 5; - int idx_month_2 = 6; - int idx_number_3 = 7; - int idx_number_4 = 8; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_hhmmss_2]->arg, argv[idx_number_3]->arg, - argv[idx_month_2]->arg, argv[idx_number_4]->arg); -} - -DEFUN (send_lifetime_infinite_day_month, - send_lifetime_infinite_day_month_cmd, - "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) infinite", - "Set send lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Never expires\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_infinite_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg); -} - -DEFUN (send_lifetime_infinite_month_day, - send_lifetime_infinite_month_day_cmd, - "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) infinite", - "Set send lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Never expires\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_infinite_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg); -} - -DEFUN (send_lifetime_duration_day_month, - send_lifetime_duration_day_month_cmd, - "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) duration (1-2147483646)", - "Set send lifetime of the key\n" - "Time to start\n" - "Day of th month to start\n" - "Month of the year to start\n" - "Year to start\n" - "Duration of the key\n" - "Duration seconds\n") -{ - int idx_hhmmss = 1; - int idx_number = 2; - int idx_month = 3; - int idx_number_2 = 4; - int idx_number_3 = 6; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_duration_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg); -} - -DEFUN (send_lifetime_duration_month_day, - send_lifetime_duration_month_day_cmd, - "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) duration (1-2147483646)", - "Set send lifetime of the key\n" - "Time to start\n" - "Month of the year to start\n" - "Day of th month to start\n" - "Year to start\n" - "Duration of the key\n" - "Duration seconds\n") -{ - int idx_hhmmss = 1; - int idx_month = 2; - int idx_number = 3; - int idx_number_2 = 4; - int idx_number_3 = 6; - VTY_DECLVAR_CONTEXT_SUB(key, key); - - return key_lifetime_duration_set( - vty, &key->send, argv[idx_hhmmss]->arg, argv[idx_number]->arg, - argv[idx_month]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg); -} - -DEFUN (no_send_lifetime, - no_send_lifetime_cmd, - "no send-lifetime", - NO_STR - "Unset send-lifetime\n") -{ - VTY_DECLVAR_CONTEXT_SUB(key, key); - - if (key->send.start) - key->send.start = 0; - if (key->send.end) - key->send.end = 0; - if (key->send.duration) - key->send.duration = 0; - - return CMD_SUCCESS; -} - -static int keychain_config_write(struct vty *vty); -static struct cmd_node keychain_node = { - .name = "keychain", - .node = KEYCHAIN_NODE, - .parent_node = CONFIG_NODE, - .prompt = "%s(config-keychain)# ", - .config_write = keychain_config_write, -}; - -static struct cmd_node keychain_key_node = { - .name = "keychain key", - .node = KEYCHAIN_KEY_NODE, - .parent_node = KEYCHAIN_NODE, - .prompt = "%s(config-keychain-key)# ", -}; - -static int keychain_strftime(char *buf, int bufsiz, time_t *time) -{ - struct tm tm; - size_t len; - - localtime_r(time, &tm); - - len = strftime(buf, bufsiz, "%T %b %d %Y", &tm); - - return len; -} - -static int keychain_config_write(struct vty *vty) +void keychain_terminate(void) { struct keychain *keychain; - struct key *key; - struct listnode *node; - struct listnode *knode; - char buf[BUFSIZ]; - for (ALL_LIST_ELEMENTS_RO(keychain_list, node, keychain)) { - vty_out(vty, "key chain %s\n", keychain->name); - - for (ALL_LIST_ELEMENTS_RO(keychain->key, knode, key)) { - vty_out(vty, " key %d\n", key->index); - - if (key->string) - vty_out(vty, " key-string %s\n", key->string); - - if (key->hash_algo != KEYCHAIN_ALGO_NULL) - vty_out(vty, " cryptographic-algorithm %s\n", - keychain_get_algo_name_by_id( - key->hash_algo)); - - if (key->accept.start) { - keychain_strftime(buf, BUFSIZ, - &key->accept.start); - vty_out(vty, " accept-lifetime %s", buf); - - if (key->accept.end == -1) - vty_out(vty, " infinite"); - else if (key->accept.duration) - vty_out(vty, " duration %ld", - (long)(key->accept.end - - key->accept.start)); - else { - keychain_strftime(buf, BUFSIZ, - &key->accept.end); - vty_out(vty, " %s", buf); - } - vty_out(vty, "\n"); - } - - if (key->send.start) { - keychain_strftime(buf, BUFSIZ, - &key->send.start); - vty_out(vty, " send-lifetime %s", buf); + while (listcount(keychain_list)) { + keychain = listgetdata(listhead(keychain_list)); - if (key->send.end == -1) - vty_out(vty, " infinite"); - else if (key->send.duration) - vty_out(vty, " duration %ld", - (long)(key->send.end - - key->send.start)); - else { - keychain_strftime(buf, BUFSIZ, - &key->send.end); - vty_out(vty, " %s", buf); - } - vty_out(vty, "\n"); - } - - vty_out(vty, " exit\n"); - } - vty_out(vty, "exit\n"); - vty_out(vty, "!\n"); + listnode_delete(keychain_list, keychain); + keychain_delete(keychain); } - return 0; + list_delete(&keychain_list); } - -static void keychain_active_config(vector comps, struct cmd_token *token) +void keychain_init_new(bool in_backend) { - struct keychain *keychain; - struct listnode *node; + keychain_list = list_new(); - for (ALL_LIST_ELEMENTS_RO(keychain_list, node, keychain)) - vector_set(comps, XSTRDUP(MTYPE_COMPLETION, keychain->name)); + if (!in_backend) + keychain_cli_init(); } -static const struct cmd_variable_handler keychain_var_handlers[] = { - {.varname = "key_chain", .completions = keychain_active_config}, - {.tokenname = "KEYCHAIN_NAME", .completions = keychain_active_config}, - {.tokenname = "KCHAIN_NAME", .completions = keychain_active_config}, - {.completions = NULL} -}; - void keychain_init(void) { - keychain_list = list_new(); - - /* Register handler for keychain auto config support */ - cmd_variable_handler_register(keychain_var_handlers); - install_node(&keychain_node); - install_node(&keychain_key_node); - - install_default(KEYCHAIN_NODE); - install_default(KEYCHAIN_KEY_NODE); - - install_element(CONFIG_NODE, &key_chain_cmd); - install_element(CONFIG_NODE, &no_key_chain_cmd); - install_element(KEYCHAIN_NODE, &key_cmd); - install_element(KEYCHAIN_NODE, &no_key_cmd); - - install_element(KEYCHAIN_NODE, &key_chain_cmd); - install_element(KEYCHAIN_NODE, &no_key_chain_cmd); - - install_element(KEYCHAIN_KEY_NODE, &key_string_cmd); - install_element(KEYCHAIN_KEY_NODE, &no_key_string_cmd); - - install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); - install_element(KEYCHAIN_KEY_NODE, &no_key_chain_cmd); - - install_element(KEYCHAIN_KEY_NODE, &key_cmd); - install_element(KEYCHAIN_KEY_NODE, &no_key_cmd); - - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_day_month_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_day_month_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_month_day_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_month_day_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_infinite_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_infinite_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_duration_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &accept_lifetime_duration_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, &no_accept_lifetime_cmd); - - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_day_month_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_day_month_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_month_day_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_month_day_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_infinite_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_infinite_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_duration_day_month_cmd); - install_element(KEYCHAIN_KEY_NODE, - &send_lifetime_duration_month_day_cmd); - install_element(KEYCHAIN_KEY_NODE, &no_send_lifetime_cmd); - install_element(KEYCHAIN_KEY_NODE, &cryptographic_algorithm_cmd); - install_element(KEYCHAIN_KEY_NODE, &no_cryptographic_algorithm_cmd); + keychain_init_new(false); } + +const struct frr_yang_module_info ietf_key_chain_deviation_info = { + .name = "frr-deviations-ietf-key-chain", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = NULL, + }, + }, +}; diff --git a/lib/keychain.h b/lib/keychain.h index be93275a5d23..dc35c2ea392e 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -6,6 +6,8 @@ #ifndef _ZEBRA_KEYCHAIN_H #define _ZEBRA_KEYCHAIN_H +#include "memory.h" +#include "northbound.h" #include "qobj.h" #ifdef __cplusplus @@ -44,6 +46,10 @@ struct keychain_algo_info { const char *desc; }; +extern const struct frr_yang_module_info ietf_key_chain_info; +extern const struct frr_yang_module_info ietf_key_chain_cli_info; +extern const struct frr_yang_module_info ietf_key_chain_deviation_info; + extern const struct keychain_algo_info algo_info[]; uint16_t keychain_get_block_size(enum keychain_hash_algo key); uint16_t keychain_get_hash_len(enum keychain_hash_algo key); @@ -55,6 +61,8 @@ const char *keychain_get_algo_name_by_id(enum keychain_hash_algo key); struct keychain { char *name; + char *desc; + time_t last_touch; struct list *key; @@ -81,12 +89,43 @@ struct key { }; DECLARE_QOBJ_TYPE(key); +DECLARE_MTYPE(KEY); +DECLARE_MTYPE(KEYCHAIN); +DECLARE_MTYPE(KEYCHAIN_DESC); + +/* keychain implementation */ +extern struct list *keychain_list; +struct keychain *keychain_lookup(const char *name); +struct keychain *keychain_get(const char *name); +void keychain_delete(struct keychain *keychain); +struct key *key_lookup(const struct keychain *keychain, uint32_t index); +struct key *key_get(const struct keychain *keychain, uint32_t index); +void key_delete(struct keychain *keychain, struct key *key); + +void keychain_cli_init(void); +extern void key_chains_key_chain_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void key_chains_key_chain_cli_write_end(struct vty *vty, const struct lyd_node *dnode); +extern void key_chains_key_chain_description_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void key_chains_key_chain_key_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void key_chains_key_chain_key_cli_write_end(struct vty *vty, const struct lyd_node *dnode); +extern void key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void key_chains_key_chain_key_crypto_algorithm_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void key_chains_key_chain_key_key_string_keystring_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); + +/* keychain users */ extern void keychain_init(void); +extern void keychain_init_new(bool in_backend); +extern void keychain_terminate(void); extern struct keychain *keychain_lookup(const char *); extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t); extern struct key *key_match_for_accept(const struct keychain *, const char *); extern struct key *key_lookup_for_send(const struct keychain *); const char *keychain_algo_str(enum keychain_hash_algo hash_algo); + + + #ifdef __cplusplus } #endif diff --git a/lib/keychain_cli.c b/lib/keychain_cli.c new file mode 100644 index 000000000000..26f56f182ac4 --- /dev/null +++ b/lib/keychain_cli.c @@ -0,0 +1,1033 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * February 22 2024, Christian Hopps + * + * Copyright (C) 2024 LabN Consulting, L.L.C. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "command.h" +#include "keychain.h" +#include "northbound.h" +#include "northbound_cli.h" +#include "vty.h" + +#include "lib/keychain_cli_clippy.c" + +DEFPY_YANG_NOSH( + key_chain, + key_chain_cmd, + "key chain WORD", + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + char *xpath; + int ret; + + xpath = asprintfrr(MTYPE_TMP, + "/ietf-key-chain:key-chains/key-chain[name='%s']", + chain); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(KEYCHAIN_NODE, xpath); + XFREE(MTYPE_TMP, xpath); + return ret; +} + +DEFPY_YANG( + no_key_chain, + no_key_chain_cmd, + "no key chain WORD", + NO_STR + "Authentication key management\n" + "Key-chain management\n" + "Key-chain name\n") +{ + char *xpath; + + xpath = asprintfrr(MTYPE_TMP, + "/ietf-key-chain:key-chains/key-chain[name='%s']", + chain); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + XFREE(MTYPE_TMP, xpath); + return nb_cli_apply_changes_clear_pending(vty, NULL); +} + +DEFPY_YANG_NOSH( + key, + key_cmd, + "key (0-2147483647)", + "Configure a key\n" + "Key identifier number\n") +{ + char *xpath; + int ret; + + xpath = asprintfrr(MTYPE_TMP, "%s/key[key-id='%s']", VTY_CURR_XPATH, + key_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + VTY_PUSH_XPATH(KEYCHAIN_KEY_NODE, xpath); + XFREE(MTYPE_TMP, xpath); + return ret; +} + +DEFPY_YANG( + no_key, + no_key_cmd, + "no key (0-2147483647)", + NO_STR + "Delete a key\n" + "Key identifier number\n") +{ + char *xpath; + + xpath = asprintfrr(MTYPE_TMP, "%s/key[key-id='%s']", VTY_CURR_XPATH, + key_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + XFREE(MTYPE_TMP, xpath); + return nb_cli_apply_changes_clear_pending(vty, NULL); +} + +DEFPY_YANG( + key_string, + key_string_cmd, + "key-string LINE", + "Set key string\n" + "The key\n") +{ + nb_cli_enqueue_change(vty, "./key-string/keystring", NB_OP_CREATE, line); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_key_string, + no_key_string_cmd, + "no key-string [LINE]", + NO_STR + "Unset key string\n" + "The key\n") +{ + nb_cli_enqueue_change(vty, "./key-string/keystring", NB_OP_DESTROY, line); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + cryptographic_algorithm, + cryptographic_algorithm_cmd, + "cryptographic-algorithm " + "$algo", + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n") +{ + nb_cli_enqueue_change(vty, "./crypto-algorithm", NB_OP_CREATE, algo); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_cryptographic_algorithm, + no_cryptographic_algorithm_cmd, + "no cryptographic-algorithm " + "[$algo]", + NO_STR + "Cryptographic-algorithm\n" + "Use MD5 algorithm\n" + "Use HMAC-SHA-1 algorithm\n" + "Use HMAC-SHA-256 algorithm\n" + "Use HMAC-SHA-384 algorithm\n" + "Use HMAC-SHA-512 algorithm\n") +{ + nb_cli_enqueue_change(vty, "./crypto-algorithm", NB_OP_DESTROY, algo); + return nb_cli_apply_changes(vty, NULL); +} + +const char *month_name[] = { + "january", "february", "march", "april", "may", "june", "july", + "august", "september", "october", "november", "december", NULL +}; + +static int __get_month(const char *month_str) +{ + int i, len; + + len = strlen(month_str); + if (len < 3) + return -1; + for (i = 1; month_name[i-1]; i++) + if (strncasecmp(month_str, month_name[i-1], len) == 0) + return i; + return -1; +} + + +static long __timezone_offset(void) +{ + time_t now; + struct tm *tm_now; + + time(&now); + tm_now = localtime(&now); + return tm_now->tm_gmtoff; +} + +static int __lifetime_set(struct vty *vty, char timebuf[32], + const char *time_node, const char *leaf_node, + const char *time_str, const char *day_str, + const char *month_str, const char *year_str) +{ + char xpath[128]; + int month = __get_month(month_str); + int hoff, moff; + long offset; + + if (month < 1) { + vty_out(vty, "Bad month value: %s\n", month_str); + return -1; + } + + offset = __timezone_offset(); + hoff = offset / 3600; + if (offset < 0) + offset = -offset; + moff = (offset % 3600) / 60; + + snprintf(timebuf, 32, "%s-%02d-%02dT%s%+03d:%02d", year_str, month, + atoi(day_str), time_str, hoff, moff); + snprintf(xpath, sizeof(xpath), "./lifetime/%s/%s", time_node, leaf_node); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, timebuf); + return 0; +} + + +static int key_lifetime_set(struct vty *vty, const char *time_node, + const char *stime_str, const char *sday_str, + const char *smonth_str, const char *syear_str, + const char *etime_str, const char *eday_str, + const char *emonth_str, const char *eyear_str) +{ + char time1[32]; + char time2[32]; + + if (__lifetime_set(vty, time1, time_node, "start-date-time", stime_str, + sday_str, smonth_str, syear_str)) + return CMD_WARNING_CONFIG_FAILED; + + if (__lifetime_set(vty, time2, time_node, "end-date-time", etime_str, + eday_str, emonth_str, eyear_str)) + return CMD_WARNING_CONFIG_FAILED; + + return nb_cli_apply_changes(vty, NULL); +} + +static int key_lifetime_duration_set(struct vty *vty, const char *time_node, + const char *stime_str, const char *sday_str, + const char *smonth_str, + const char *syear_str, + const char *duration_str) +{ + char xpath[128]; + char time[32]; + + if (__lifetime_set(vty, time, time_node, "start-date-time", stime_str, + sday_str, smonth_str, syear_str)) + return CMD_WARNING_CONFIG_FAILED; + + /* End time. */ + snprintf(xpath, sizeof(xpath), "./lifetime/%s/duration", time_node); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, duration_str); + + return nb_cli_apply_changes(vty, NULL); +} + +static int key_lifetime_infinite_set(struct vty *vty, const char *time_node, + const char *stime_str, const char *sday_str, + const char *smonth_str, + const char *syear_str) +{ + char xpath[128]; + char time[32]; + + if (__lifetime_set(vty, time, time_node, "start-date-time", stime_str, + sday_str, smonth_str, syear_str)) + return CMD_WARNING_CONFIG_FAILED; + + /* End time. */ + snprintf(xpath, sizeof(xpath), "./lifetime/%s/no-end-time", time_node); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + accept_lifetime_day_month_day_month, + accept_lifetime_day_month_day_month_cmd, + "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_number_3 = 6; + int idx_month_2 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "accept-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(accept_lifetime_day_month_month_day, + accept_lifetime_day_month_month_day_cmd, + "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_month_2 = 6; + int idx_number_3 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "accept-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(accept_lifetime_month_day_day_month, + accept_lifetime_month_day_day_month_cmd, + "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_number_3 = 6; + int idx_month_2 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "accept-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(accept_lifetime_month_day_month_day, + accept_lifetime_month_day_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_month_2 = 6; + int idx_number_3 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "accept-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(accept_lifetime_infinite_day_month, + accept_lifetime_infinite_day_month_cmd, + "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + + return key_lifetime_infinite_set(vty, "accept-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg); +} + +DEFPY_YANG(accept_lifetime_infinite_month_day, + accept_lifetime_infinite_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) infinite", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + + return key_lifetime_infinite_set(vty, "accept-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg); +} + +DEFPY_YANG(accept_lifetime_duration_day_month, + accept_lifetime_duration_day_month_cmd, + "accept-lifetime HH:MM:SS (1-31) MONTH (1993-2035) duration (1-2147483646)", + "Set accept lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + int idx_number_3 = 6; + + return key_lifetime_duration_set(vty, "accept-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg, + argv[idx_number_3]->arg); +} + +DEFPY_YANG(accept_lifetime_duration_month_day, + accept_lifetime_duration_month_day_cmd, + "accept-lifetime HH:MM:SS MONTH (1-31) (1993-2035) duration (1-2147483646)", + "Set accept lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + int idx_number_3 = 6; + + return key_lifetime_duration_set(vty, "accept-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg, + argv[idx_number_3]->arg); +} + +DEFPY_YANG(no_accept_lifetime, + no_accept_lifetime_cmd, + "no accept-lifetime", + NO_STR + "Unset accept-lifetime\n") +{ + nb_cli_enqueue_change(vty, "accept-lifetime", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + send_lifetime_day_month_day_month, send_lifetime_day_month_day_month_cmd, + "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_number_3 = 6; + int idx_month_2 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "send-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(send_lifetime_day_month_month_day, + send_lifetime_day_month_month_day_cmd, + "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_month_2 = 6; + int idx_number_3 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "send-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(send_lifetime_month_day_day_month, + send_lifetime_month_day_day_month_cmd, + "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS (1-31) MONTH (1993-2035)", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Day of th month to expire\n" + "Month of the year to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_number_3 = 6; + int idx_month_2 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "send-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(send_lifetime_month_day_month_day, + send_lifetime_month_day_month_day_cmd, + "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) HH:MM:SS MONTH (1-31) (1993-2035)", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Time to expire\n" + "Month of the year to expire\n" + "Day of th month to expire\n" + "Year to expire\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + int idx_hhmmss_2 = 5; + int idx_month_2 = 6; + int idx_number_3 = 7; + int idx_number_4 = 8; + + return key_lifetime_set(vty, "send-lifetime", argv[idx_hhmmss]->arg, + argv[idx_number]->arg, argv[idx_month]->arg, + argv[idx_number_2]->arg, argv[idx_hhmmss_2]->arg, + argv[idx_number_3]->arg, argv[idx_month_2]->arg, + argv[idx_number_4]->arg); +} + +DEFPY_YANG(send_lifetime_infinite_day_month, + send_lifetime_infinite_day_month_cmd, + "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Never expires\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + + return key_lifetime_infinite_set(vty, "send-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg); +} + +DEFPY_YANG(send_lifetime_infinite_month_day, + send_lifetime_infinite_month_day_cmd, + "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) infinite", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Never expires\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + + return key_lifetime_infinite_set(vty, "send-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg); +} + +DEFPY_YANG(send_lifetime_duration_day_month, + send_lifetime_duration_day_month_cmd, + "send-lifetime HH:MM:SS (1-31) MONTH (1993-2035) duration (1-2147483646)", + "Set send lifetime of the key\n" + "Time to start\n" + "Day of th month to start\n" + "Month of the year to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + int idx_hhmmss = 1; + int idx_number = 2; + int idx_month = 3; + int idx_number_2 = 4; + int idx_number_3 = 6; + + return key_lifetime_duration_set(vty, "send-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg, + argv[idx_number_3]->arg); +} + +DEFPY_YANG(send_lifetime_duration_month_day, + send_lifetime_duration_month_day_cmd, + "send-lifetime HH:MM:SS MONTH (1-31) (1993-2035) duration (1-2147483646)", + "Set send lifetime of the key\n" + "Time to start\n" + "Month of the year to start\n" + "Day of th month to start\n" + "Year to start\n" + "Duration of the key\n" + "Duration seconds\n") +{ + int idx_hhmmss = 1; + int idx_month = 2; + int idx_number = 3; + int idx_number_2 = 4; + int idx_number_3 = 6; + + return key_lifetime_duration_set(vty, "send-lifetime", + argv[idx_hhmmss]->arg, + argv[idx_number]->arg, + argv[idx_month]->arg, + argv[idx_number_2]->arg, + argv[idx_number_3]->arg); +} + +DEFUN (no_send_lifetime, + no_send_lifetime_cmd, + "no send-lifetime", + NO_STR + "Unset send-lifetime\n") +{ + nb_cli_enqueue_change(vty, "send-lifetime", NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain + */ +void key_chains_key_chain_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, "key chain %s\n", yang_dnode_get_string(dnode, "name")); +} + +void key_chains_key_chain_cli_write_end(struct vty *vty, + const struct lyd_node *dnode) +{ + vty_out(vty, "exit\n"); + vty_out(vty, "!\n"); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/description + */ +void key_chains_key_chain_description_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + /* Implement CLI */ + /* vty_out(vty, " description %s\n", yang_dnode_get_string(dnode)); */ +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key + */ +void key_chains_key_chain_key_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vty_out(vty, " key %s\n", yang_dnode_get_string(dnode, "key-id")); +} + +void key_chains_key_chain_key_cli_write_end(struct vty *vty, + const struct lyd_node *dnode) +{ + vty_out(vty, " exit\n"); +} + +static const char *__dnode_to_key_strftime(char *buf, size_t bufsize, + const struct lyd_node *lt_start_dnode) +{ + const char *timestr; + struct lyd_node *end_node; + struct tm tm; + uint32_t duration; + time_t time; + int len, sz; + char *s; + + s = buf; + sz = bufsize; + + timestr = yang_dnode_get_string(lt_start_dnode, NULL); + (void)ly_time_str2time(timestr, &time, NULL); + localtime_r(&time, &tm); + len = strftime(s, sz, "%T %b %e %Y", &tm); + s += len; + sz -= len; + + if (yang_dnode_exists(lt_start_dnode, "../no-end-time")) { + strlcat(s, " infinite", sz); + return buf; + } + + end_node = yang_dnode_get(lt_start_dnode, "../duration"); + if (end_node) { + duration = yang_dnode_get_uint32(end_node, NULL); + snprintf(s, sz, " duration %u", (uint)duration); + return buf; + } + + timestr = yang_dnode_get_string(lt_start_dnode, "../end-date-time"); + (void)ly_time_str2time(timestr, &time, NULL); + localtime_r(&time, &tm); + strftime(s, sz, " %T %b %e %Y", &tm); + return buf; +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/start-date-time + */ +void key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + char s[256]; + + vty_out(vty, " send-lifetime %s\n", + __dnode_to_key_strftime(s, sizeof(s), dnode)); + vty_out(vty, " accept-lifetime %s\n", s); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/start-date-time + */ +void key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + char s[256]; + + vty_out(vty, " send-lifetime %s\n", + __dnode_to_key_strftime(s, sizeof(s), dnode)); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/start-date-time + */ +void key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + char s[256]; + + vty_out(vty, " accept-lifetime %s\n", + __dnode_to_key_strftime(s, sizeof(s), dnode)); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/crypto-algorithm + */ +void key_chains_key_chain_key_crypto_algorithm_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + static const char prefix[] = "ietf-key-chain:"; + static const int prefix_len = sizeof(prefix) - 1; + const char *name = yang_dnode_get_string(dnode, NULL); + + if (!strncmp(name, prefix, prefix_len)) + name += prefix_len; + vty_out(vty, " cryptographic-algorithm %s\n", name); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/key-string/keystring + */ +void key_chains_key_chain_key_key_string_keystring_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " key-string %s\n", yang_dnode_get_string(dnode, NULL)); +} + +static const char * const keychain_features[] = { + "independent-send-accept-lifetime", + NULL, +}; + +/* clang-format off */ +const struct frr_yang_module_info ietf_key_chain_cli_info = { + .name = "ietf-key-chain", + .features = (const char **)keychain_features, + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/ietf-key-chain:key-chains/key-chain", + .cbs = { + .cli_show = key_chains_key_chain_cli_write, + .cli_show_end = key_chains_key_chain_cli_write_end, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/description", + .cbs = { + .cli_show = key_chains_key_chain_description_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key", + .cbs = { + .cli_show = key_chains_key_chain_key_cli_write, + .cli_show_end = key_chains_key_chain_key_cli_write_end, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/start-date-time", + .cbs = { + .cli_show = key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/start-date-time", + .cbs = { + .cli_show = key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/start-date-time", + .cbs = { + .cli_show = key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/crypto-algorithm", + .cbs = { + .cli_show = key_chains_key_chain_key_crypto_algorithm_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/key-string/keystring", + .cbs = { + .cli_show = key_chains_key_chain_key_key_string_keystring_cli_write, + } + }, + { + .xpath = NULL, + }, + } +}; + +static int keychain_config_write(struct vty *vty) +{ + const struct lyd_node *dnode; + int written = 0; + + dnode = yang_dnode_get(running_config->dnode, + "/ietf-key-chain:key-chains"); + if (dnode) { + nb_cli_show_dnode_cmds(vty, dnode, false); + written = 1; + } + return written; +} + +static struct cmd_node keychain_node = { + .name = "keychain", + .node = KEYCHAIN_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-keychain)# ", + .config_write = keychain_config_write, +}; + +static struct cmd_node keychain_key_node = { + .name = "keychain key", + .node = KEYCHAIN_KEY_NODE, + .parent_node = KEYCHAIN_NODE, + .prompt = "%s(config-keychain-key)# ", +}; + +static const struct cmd_variable_handler keychain_var_handlers[] = { + {.varname = "key_chain", .xpath = "/ietf-key-chain:key-chains/key-chain/name" }, + {.tokenname = "KEYCHAIN_NAME", .xpath = "/ietf-key-chain:key-chains/key-chain/name" }, + {.completions = NULL} +}; + +void keychain_cli_init(void) +{ + /* Register handler for keychain auto config support */ + cmd_variable_handler_register(keychain_var_handlers); + install_node(&keychain_node); + install_node(&keychain_key_node); + + install_default(KEYCHAIN_NODE); + install_default(KEYCHAIN_KEY_NODE); + + install_element(CONFIG_NODE, &key_chain_cmd); + install_element(CONFIG_NODE, &no_key_chain_cmd); + install_element(KEYCHAIN_NODE, &key_cmd); + install_element(KEYCHAIN_NODE, &no_key_cmd); + + install_element(KEYCHAIN_NODE, &key_chain_cmd); + install_element(KEYCHAIN_NODE, &no_key_chain_cmd); + + install_element(KEYCHAIN_KEY_NODE, &key_string_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_key_string_cmd); + + install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_key_chain_cmd); + + install_element(KEYCHAIN_KEY_NODE, &key_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_key_cmd); + + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_day_month_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_day_month_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_month_day_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_month_day_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_infinite_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_infinite_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_duration_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &accept_lifetime_duration_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_accept_lifetime_cmd); + + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_day_month_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_day_month_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_month_day_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_month_day_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_infinite_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_infinite_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_duration_day_month_cmd); + install_element(KEYCHAIN_KEY_NODE, + &send_lifetime_duration_month_day_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_send_lifetime_cmd); + install_element(KEYCHAIN_KEY_NODE, &cryptographic_algorithm_cmd); + install_element(KEYCHAIN_KEY_NODE, &no_cryptographic_algorithm_cmd); +} diff --git a/lib/keychain_nb.c b/lib/keychain_nb.c new file mode 100644 index 000000000000..57967b30a516 --- /dev/null +++ b/lib/keychain_nb.c @@ -0,0 +1,898 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * February 22 2024, Christian Hopps + * + * Copyright (C) 2024 LabN Consulting, L.L.C. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "lib_errors.h" +#include "northbound.h" +#include "keychain.h" + +static void keychain_touch(struct keychain *keychain) +{ + keychain->last_touch = time(NULL); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain + */ +static int key_chains_key_chain_create(struct nb_cb_create_args *args) +{ + const char *name; + struct keychain *keychain; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "name"); + keychain = keychain_get(name); + keychain_touch(keychain); + return NB_OK; +} + +static int key_chains_key_chain_destroy(struct nb_cb_destroy_args *args) +{ + const char *name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "name"); + keychain_delete(keychain_lookup(name)); + return NB_OK; +} + +static const void *key_chains_key_chain_get_next(struct nb_cb_get_next_args *args) +{ + const struct listnode *prev = args->list_entry; + + return prev ? prev->next : keychain_list->head; +} + +static int key_chains_key_chain_get_keys(struct nb_cb_get_keys_args *args) +{ + const struct listnode *node = args->list_entry; + const struct keychain *keychain = node->data; + + args->keys->num = 1; + strlcpy(args->keys->key[0], keychain->name, sizeof(args->keys->key[0])); + return NB_OK; +} + +static const void *key_chains_key_chain_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + const char *name = args->keys->key[0]; + struct keychain *keychain; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(keychain_list, node, keychain)) { + if (strcmp(keychain->name, name) == 0) + return node; + } + return NULL; +} + + +static int __destroy_nop(struct nb_cb_destroy_args *args) +{ + /* modified by sibling or cleaned up by container destroy */ + return NB_OK; +} + +static struct key *__dnode_get_key2(const struct lyd_node *dnode, bool touch) +{ + struct keychain *keychain; + const char *name; + struct key *key; + uint32_t index; + + name = yang_dnode_get_string(dnode, "../../../name"); + keychain = keychain_lookup(name); + index = (uint32_t)yang_dnode_get_uint64(dnode, "../../key-id"); + key = key_lookup(keychain, index); + if (touch) + keychain_touch(keychain); + return key; +} + +static struct key *__dnode_get_key3(const struct lyd_node *dnode, bool touch) +{ + struct keychain *keychain; + const char *name; + struct key *key; + uint32_t index; + + name = yang_dnode_get_string(dnode, "../../../../name"); + keychain = keychain_lookup(name); + index = (uint32_t)yang_dnode_get_uint64(dnode, "../../../key-id"); + key = key_lookup(keychain, index); + if (touch) + keychain_touch(keychain); + return key; +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/description + */ +static int key_chains_key_chain_description_modify(struct nb_cb_modify_args *args) +{ + struct keychain *keychain; + const char *name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "../name"); + keychain = keychain_lookup(name); + XFREE(MTYPE_KEYCHAIN_DESC, keychain->desc); + keychain->desc = XSTRDUP(MTYPE_KEYCHAIN_DESC, + yang_dnode_get_string(args->dnode, NULL)); + + keychain_touch(keychain); + return NB_OK; +} + +static int key_chains_key_chain_description_destroy(struct nb_cb_destroy_args *args) +{ + struct keychain *keychain; + const char *name; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "../name"); + keychain = keychain_lookup(name); + XFREE(MTYPE_KEYCHAIN_DESC, keychain->desc); + + keychain_touch(keychain); + return NB_OK; +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/last-modified-timestamp + */ +static struct yang_data *key_chains_key_chain_last_modified_timestamp_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct listnode *kcnode = args->list_entry; + const struct keychain *keychain = kcnode->data; + + return yang_data_new_date_and_time(args->xpath, keychain->last_touch, + false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key + */ +static int key_chains_key_chain_key_create(struct nb_cb_create_args *args) +{ + struct keychain *keychain; + struct key *key; + const char *name; + uint64_t keyid; + + if (args->event != NB_EV_VALIDATE && args->event != NB_EV_APPLY) + return NB_OK; + + keyid = yang_dnode_get_uint64(args->dnode, "key-id"); + if (args->event == NB_EV_VALIDATE) { + if (keyid > UINT32_MAX) { + /* Warn most protocols can't use this value */ + flog_err(EC_LIB_NB_CB_CONFIG_VALIDATE, + "Protocols do not accept > 32-bit key-id values"); + return NB_EV_VALIDATE; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "../name"); + keychain = keychain_lookup(name); + assert(keyid <= UINT32_MAX); + key = key_get(keychain, (uint32_t)keyid); + assert(key); + + keychain_touch(keychain); + return NB_OK; +} + +static int key_chains_key_chain_key_destroy(struct nb_cb_destroy_args *args) +{ + struct keychain *keychain; + struct key *key; + const char *name; + uint64_t keyid; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + keyid = yang_dnode_get_uint64(args->dnode, "key-id"); + if (keyid > UINT32_MAX) + return NB_ERR_NOT_FOUND; + name = yang_dnode_get_string(args->dnode, "../name"); + keychain = keychain_lookup(name); + key = key_lookup(keychain, (uint32_t)keyid); + key_delete(keychain, key); + + keychain_touch(keychain); + return NB_OK; +} + +static const void *key_chains_key_chain_key_get_next(struct nb_cb_get_next_args *args) +{ + const struct listnode *kcnode = args->parent_list_entry; + const struct keychain *keychain = kcnode->data; + const struct listnode *prev = args->list_entry; + + return prev ? prev->next : keychain->key->head; +} + +static int key_chains_key_chain_key_get_keys(struct nb_cb_get_keys_args *args) +{ + const struct listnode *node = args->list_entry; + const struct key *key = node->data; + + args->keys->num = 1; + snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%" PRIu32, + key->index); + + return NB_OK; +} + +static const void *key_chains_key_chain_key_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + const struct listnode *kcnode = args->parent_list_entry; + const struct keychain *keychain = kcnode->data; + struct listnode *node; + struct key *key; + uint32_t index; + + index = strtoul(args->keys->key[0], NULL, 0); + for (ALL_LIST_ELEMENTS_RO(keychain->key, node, key)) + if (key->index == index) + return node; + return NULL; +} + +static int __lifetime_create(struct nb_cb_create_args *args, bool send, + bool accept, bool always) +{ + struct key *key; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + if (always) + key = __dnode_get_key3(args->dnode, true); + else + key = __dnode_get_key2(args->dnode, true); + if (send) { + key->send.start = 0; + key->send.end = -1; + key->send.duration = 0; + } + if (accept) { + key->accept.start = 0; + key->accept.end = -1; + key->accept.duration = 0; + } + return NB_OK; +} + +static int __lifetime_start_date_time_modify(struct nb_cb_modify_args *args, + bool send, bool accept) +{ + struct key *key; + time_t time; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + key = __dnode_get_key3(args->dnode, true); + time = yang_dnode_get_date_and_time(args->dnode, NULL); + + if (send) + key->send.start = time; + if (accept) + key->accept.start = time; + + return NB_OK; +} + +static int __lifetime_no_end_time_create(struct nb_cb_create_args *args, + bool send, bool accept) +{ + struct key *key; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + key = __dnode_get_key3(args->dnode, true); + if (send) + key->send.end = -1; + if (accept) + key->accept.end = -1; + return NB_OK; +} + +static int __lifetime_duration_modify(struct nb_cb_modify_args *args, bool send, + bool accept) +{ + struct key *key; + uint32_t duration; + time_t time; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + key = __dnode_get_key3(args->dnode, true); + time = yang_dnode_get_date_and_time(args->dnode, "../start-date-time"); + duration = yang_dnode_get_uint32(args->dnode, NULL); + + if (send) + key->send.end = time + duration; + if (accept) + key->accept.end = time + duration; + return NB_OK; +} + +static int __lifetime_end_date_time_modify(struct nb_cb_modify_args *args, + bool send, bool accept) +{ + struct key *key; + time_t time; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + key = __dnode_get_key3(args->dnode, true); + time = yang_dnode_get_date_and_time(args->dnode, NULL); + + if (send) + key->send.end = time; + if (accept) + key->accept.end = time; + return NB_OK; +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime + */ +static int key_chains_key_chain_key_lifetime_send_accept_lifetime_create( + struct nb_cb_create_args *args) +{ + + return __lifetime_create(args, true, true, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/always + */ +static int key_chains_key_chain_key_lifetime_send_accept_lifetime_always_create( + struct nb_cb_create_args *args) +{ + return __lifetime_create(args, true, true, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/start-date-time + */ +static int +key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_modify( + struct nb_cb_modify_args *args) +{ + return __lifetime_start_date_time_modify(args, true, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/no-end-time + */ +static int +key_chains_key_chain_key_lifetime_send_accept_lifetime_no_end_time_create( + struct nb_cb_create_args *args) +{ + return __lifetime_no_end_time_create(args, true, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/duration + */ +static int key_chains_key_chain_key_lifetime_send_accept_lifetime_duration_modify( + struct nb_cb_modify_args *args) +{ + return __lifetime_duration_modify(args, true, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/end-date-time + */ +static int +key_chains_key_chain_key_lifetime_send_accept_lifetime_end_date_time_modify( + struct nb_cb_modify_args *args) +{ + return __lifetime_end_date_time_modify(args, true, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime + */ +static int key_chains_key_chain_key_lifetime_send_lifetime_create( + struct nb_cb_create_args *args) +{ + + return __lifetime_create(args, true, false, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/always + */ +static int key_chains_key_chain_key_lifetime_send_lifetime_always_create( + struct nb_cb_create_args *args) +{ + return __lifetime_create(args, true, false, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/start-date-time + */ +static int key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_modify(struct nb_cb_modify_args *args) +{ + return __lifetime_start_date_time_modify(args, true, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/no-end-time + */ +static int key_chains_key_chain_key_lifetime_send_lifetime_no_end_time_create(struct nb_cb_create_args *args) +{ + return __lifetime_no_end_time_create(args, true, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/duration + */ +static int key_chains_key_chain_key_lifetime_send_lifetime_duration_modify(struct nb_cb_modify_args *args) +{ + return __lifetime_duration_modify(args, true, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/end-date-time + */ +static int key_chains_key_chain_key_lifetime_send_lifetime_end_date_time_modify(struct nb_cb_modify_args *args) +{ + return __lifetime_end_date_time_modify(args, true, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime + */ +static int key_chains_key_chain_key_lifetime_accept_lifetime_create( + struct nb_cb_create_args *args) +{ + + return __lifetime_create(args, false, true, false); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/always + */ +static int key_chains_key_chain_key_lifetime_accept_lifetime_always_create(struct nb_cb_create_args *args) +{ + return __lifetime_create(args, false, true, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/start-date-time + */ +static int key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_modify(struct nb_cb_modify_args *args) +{ + return __lifetime_start_date_time_modify(args, false, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/no-end-time + */ +static int key_chains_key_chain_key_lifetime_accept_lifetime_no_end_time_create(struct nb_cb_create_args *args) +{ + return __lifetime_no_end_time_create(args, false, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/duration + */ +static int key_chains_key_chain_key_lifetime_accept_lifetime_duration_modify(struct nb_cb_modify_args *args) +{ + return __lifetime_duration_modify(args, false, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/end-date-time + */ +static int key_chains_key_chain_key_lifetime_accept_lifetime_end_date_time_modify(struct nb_cb_modify_args *args) +{ + return __lifetime_end_date_time_modify(args, false, true); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/crypto-algorithm + */ +static int key_chains_key_chain_key_crypto_algorithm_modify(struct nb_cb_modify_args *args) +{ + static const char prefix[] = "ietf-key-chain:"; + static const int prefix_len = sizeof(prefix) - 1; + struct keychain *keychain; + const char *name; + struct key *key; + uint32_t index; + uint8_t hash_algo; + + if (args->event != NB_EV_VALIDATE && args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, NULL); + if (!strncmp(name, prefix, prefix_len)) + name += prefix_len; + hash_algo = keychain_get_algo_id_by_name(name); + + if (args->event == NB_EV_VALIDATE) { + if (!hash_algo) { + zlog_err("\"%s\" hash algo not supported", name); + return NB_ERR_VALIDATION; + } +#ifndef CRYPTO_OPENSSL + if (hash_algo == KEYCHAIN_ALGO_NULL) { + zlog_err("\"%s\" algo not supported, compile with --with-crypto=openssl", + name); + return NB_ERR_VALIDATION; + } +#endif /* CRYPTO_OPENSSL */ + return NB_OK; + } + + assert(args->event == NB_EV_APPLY); + name = yang_dnode_get_string(args->dnode, "../../name"); + keychain = keychain_lookup(name); + index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../key-id"); + key = key_lookup(keychain, index); + key->hash_algo = hash_algo; + + keychain_touch(keychain); + return NB_OK; +} + +static int key_chains_key_chain_key_crypto_algorithm_destroy( + struct nb_cb_destroy_args *args) +{ + struct keychain *keychain; + const char *name; + struct key *key; + uint32_t index; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "../../../name"); + keychain = keychain_lookup(name); + index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../../key-id"); + key = key_lookup(keychain, index); + key->hash_algo = KEYCHAIN_ALGO_NULL; + keychain_touch(keychain); + + return NB_OK; +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/key-string/keystring + */ +static int key_chains_key_chain_key_key_string_keystring_modify(struct nb_cb_modify_args *args) +{ + struct keychain *keychain; + const char *name; + struct key *key; + uint32_t index; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "../../../name"); + keychain = keychain_lookup(name); + index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../../key-id"); + key = key_lookup(keychain, index); + assert(key); + + + if (key->string) + XFREE(MTYPE_KEY, key->string); + key->string = XSTRDUP(MTYPE_KEY, + yang_dnode_get_string(args->dnode, NULL)); + + keychain_touch(keychain); + return NB_OK; +} + +static int key_chains_key_chain_key_key_string_keystring_destroy(struct nb_cb_destroy_args *args) +{ + struct keychain *keychain; + const char *name; + struct key *key; + uint32_t index; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + name = yang_dnode_get_string(args->dnode, "../../../name"); + keychain = keychain_lookup(name); + index = (uint32_t)yang_dnode_get_uint64(args->dnode, "../../key-id"); + key = key_lookup(keychain, index); + assert(key); + + XFREE(MTYPE_KEY, key->string); + keychain_touch(keychain); + + return NB_OK; +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/send-lifetime-active + */ +static struct yang_data *key_chains_key_chain_key_send_lifetime_active_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct listnode *node = args->list_entry; + const struct key *key = node->data; + time_t now = time(NULL); + bool active = false; + + if (key->send.start == 0) + active = true; + else if (key->send.start <= now) + if (key->send.end >= now || key->send.end == -1) + active = true; + + return yang_data_new_bool(args->xpath, active); +} + +/* + * XPath: /ietf-key-chain:key-chains/key-chain/key/accept-lifetime-active + */ +static struct yang_data *key_chains_key_chain_key_accept_lifetime_active_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct listnode *node = args->list_entry; + const struct key *key = node->data; + time_t now = time(NULL); + bool active = false; + + if (key->accept.start == 0) + active = true; + else if (key->accept.start <= now) + if (key->accept.end >= now || key->accept.end == -1) + active = true; + + return yang_data_new_bool(args->xpath, active); +} + +static const char * const keychain_features[] = { + "independent-send-accept-lifetime", + NULL, +}; + +/* clang-format off */ +const struct frr_yang_module_info ietf_key_chain_info = { + .name = "ietf-key-chain", + .features = (const char **)keychain_features, + .nodes = { + { + .xpath = "/ietf-key-chain:key-chains/key-chain", + .cbs = { + .create = key_chains_key_chain_create, + .destroy = key_chains_key_chain_destroy, + .get_next = key_chains_key_chain_get_next, + .get_keys = key_chains_key_chain_get_keys, + .lookup_entry = key_chains_key_chain_lookup_entry, + .cli_show = key_chains_key_chain_cli_write, + .cli_show_end = key_chains_key_chain_cli_write_end, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/description", + .cbs = { + .modify = key_chains_key_chain_description_modify, + .destroy = key_chains_key_chain_description_destroy, + .cli_show = key_chains_key_chain_description_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/last-modified-timestamp", + .cbs = { + .get_elem = key_chains_key_chain_last_modified_timestamp_get_elem, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key", + .cbs = { + .create = key_chains_key_chain_key_create, + .destroy = key_chains_key_chain_key_destroy, + .get_next = key_chains_key_chain_key_get_next, + .get_keys = key_chains_key_chain_key_get_keys, + .lookup_entry = key_chains_key_chain_key_lookup_entry, + .cli_show = key_chains_key_chain_key_cli_write, + .cli_show_end = key_chains_key_chain_key_cli_write_end, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime", + .cbs = { + .create = key_chains_key_chain_key_lifetime_send_accept_lifetime_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/always", + .cbs = { + .create = key_chains_key_chain_key_lifetime_send_accept_lifetime_always_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/start-date-time", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_modify, + .destroy = __destroy_nop, + .cli_show = key_chains_key_chain_key_lifetime_send_accept_lifetime_start_date_time_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/no-end-time", + .cbs = { + .create = key_chains_key_chain_key_lifetime_send_accept_lifetime_no_end_time_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/duration", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_send_accept_lifetime_duration_modify, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-accept-lifetime/end-date-time", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_send_accept_lifetime_end_date_time_modify, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime", + .cbs = { + .create = key_chains_key_chain_key_lifetime_send_lifetime_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/always", + .cbs = { + .create = key_chains_key_chain_key_lifetime_send_lifetime_always_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/start-date-time", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_modify, + .destroy = __destroy_nop, + .cli_show = key_chains_key_chain_key_lifetime_send_lifetime_start_date_time_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/no-end-time", + .cbs = { + .create = key_chains_key_chain_key_lifetime_send_lifetime_no_end_time_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/duration", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_send_lifetime_duration_modify, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/send-lifetime/end-date-time", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_send_lifetime_end_date_time_modify, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime", + .cbs = { + .create = key_chains_key_chain_key_lifetime_accept_lifetime_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/always", + .cbs = { + .create = key_chains_key_chain_key_lifetime_accept_lifetime_always_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/start-date-time", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_modify, + .destroy = __destroy_nop, + .cli_show = key_chains_key_chain_key_lifetime_accept_lifetime_start_date_time_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/no-end-time", + .cbs = { + .create = key_chains_key_chain_key_lifetime_accept_lifetime_no_end_time_create, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/duration", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_accept_lifetime_duration_modify, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/lifetime/accept-lifetime/end-date-time", + .cbs = { + .modify = key_chains_key_chain_key_lifetime_accept_lifetime_end_date_time_modify, + .destroy = __destroy_nop, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/crypto-algorithm", + .cbs = { + .modify = key_chains_key_chain_key_crypto_algorithm_modify, + .destroy = key_chains_key_chain_key_crypto_algorithm_destroy, + .cli_show = key_chains_key_chain_key_crypto_algorithm_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/key-string/keystring", + .cbs = { + .modify = key_chains_key_chain_key_key_string_keystring_modify, + .destroy = key_chains_key_chain_key_key_string_keystring_destroy, + .cli_show = key_chains_key_chain_key_key_string_keystring_cli_write, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/send-lifetime-active", + .cbs = { + .get_elem = key_chains_key_chain_key_send_lifetime_active_get_elem, + } + }, + { + .xpath = "/ietf-key-chain:key-chains/key-chain/key/accept-lifetime-active", + .cbs = { + .get_elem = key_chains_key_chain_key_accept_lifetime_active_get_elem, + } + }, + { + .xpath = NULL, + }, + }, +}; diff --git a/lib/ldp_sync.h b/lib/ldp_sync.h index f7601ebf9d2f..3a6ae5b3575a 100644 --- a/lib/ldp_sync.h +++ b/lib/ldp_sync.h @@ -59,7 +59,7 @@ struct ldp_igp_sync_if_state { struct ldp_igp_sync_if_state_req { int proto; ifindex_t ifindex; - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; }; #ifdef __cplusplus diff --git a/lib/lib_errors.c b/lib/lib_errors.c index a96fac9cd461..9d6c04325cc3 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -307,24 +307,6 @@ static struct log_ref ferr_lib_err[] = { .description = "The northbound subsystem, during initialization, has detected that a libyang plugin failed to be loaded", .suggestion = "Check if the FRR libyang plugins were installed correctly in the system", }, - { - .code = EC_LIB_CONFD_INIT, - .title = "ConfD initialization error", - .description = "Upon startup FRR failed to properly initialize and startup the ConfD northbound plugin", - .suggestion = "Check if ConfD is installed correctly in the system. Also, check if the confd daemon is running.", - }, - { - .code = EC_LIB_CONFD_DATA_CONVERT, - .title = "ConfD data conversion error", - .description = "An error has occurred while converting a ConfD data value (binary) to a string", - .suggestion = "Open an Issue with all relevant log files and restart FRR" - }, - { - .code = EC_LIB_LIBCONFD, - .title = "libconfd error", - .description = "The northbound subsystem has detected that the libconfd library returned an error", - .suggestion = "Open an Issue with all relevant log files and restart FRR" - }, { .code = EC_LIB_SYSREPO_INIT, .title = "Sysrepo initialization error", diff --git a/lib/lib_errors.h b/lib/lib_errors.h index 8cdfb166c706..9e0d539599ec 100644 --- a/lib/lib_errors.h +++ b/lib/lib_errors.h @@ -65,9 +65,6 @@ enum lib_log_refs { EC_LIB_NB_TRANSACTION_RECORD_FAILED, EC_LIB_LIBYANG, EC_LIB_LIBYANG_PLUGIN_LOAD, - EC_LIB_CONFD_INIT, - EC_LIB_CONFD_DATA_CONVERT, - EC_LIB_LIBCONFD, EC_LIB_SYSREPO_INIT, EC_LIB_SYSREPO_DATA_CONVERT, EC_LIB_LIBSYSREPO, diff --git a/lib/libagentx.c b/lib/libagentx.c new file mode 100644 index 000000000000..23826572ed11 --- /dev/null +++ b/lib/libagentx.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* SNMP cli support + * Copyright (C) 2024 Donald Sharp NVIDIA Corporation + */ +#include + +#include "lib/hook.h" +#include "lib/libagentx.h" +#include "command.h" + +DEFINE_HOOK(agentx_cli_enabled, (), ()); +DEFINE_HOOK(agentx_cli_disabled, (), ()); + +bool agentx_enabled; + +/* AgentX node. */ +static int config_write_agentx(struct vty *vty) +{ + if (agentx_enabled) + vty_out(vty, "agentx\n"); + return 1; +} + +static struct cmd_node agentx_node = { + .name = "smux", + .node = SMUX_NODE, + .prompt = "", + .config_write = config_write_agentx, +}; + +DEFUN(agentx_enable, agentx_enable_cmd, "agentx", + "SNMP AgentX protocol settings\n") +{ + if (!hook_have_hooks(agentx_cli_enabled)) { + zlog_info( + "agentx specified but the agentx Module is not loaded, is this intentional?"); + + return CMD_SUCCESS; + } + + hook_call(agentx_cli_enabled); + + return CMD_SUCCESS; +} + +DEFUN(no_agentx, no_agentx_cmd, "no agentx", + NO_STR "SNMP AgentX protocol settings\n") +{ + vty_out(vty, "SNMP AgentX support cannot be disabled once enabled\n"); + if (!hook_call(agentx_cli_disabled)) + return CMD_WARNING_CONFIG_FAILED; + + return CMD_SUCCESS; +} + +void libagentx_init(void) +{ + agentx_enabled = false; + + install_node(&agentx_node); + install_element(CONFIG_NODE, &agentx_enable_cmd); + install_element(CONFIG_NODE, &no_agentx_cmd); +} diff --git a/lib/libagentx.h b/lib/libagentx.h new file mode 100644 index 000000000000..c3246d975f14 --- /dev/null +++ b/lib/libagentx.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* SNMP cli support + * Copyright (C) 2024 Donald Sharp NVIDIA Corporation + */ +#ifndef __LIBAGENTX_H__ +#define __LIBAGENTX_H__ + +extern void libagentx_init(void); +extern bool agentx_enabled; + +DECLARE_HOOK(agentx_cli_enabled, (), ()); +DECLARE_HOOK(agentx_cli_disabled, (), ()); + +#endif diff --git a/lib/libfrr.c b/lib/libfrr.c index 33237df5fca3..07cd4a5306f1 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -6,7 +6,11 @@ */ #include + +#include +#include #include +#include #include #include @@ -33,6 +37,8 @@ #include "frrscript.h" #include "systemd.h" +#include "lib/config_paths.h" + DEFINE_HOOK(frr_early_init, (struct event_loop * tm), (tm)); DEFINE_HOOK(frr_late_init, (struct event_loop * tm), (tm)); DEFINE_HOOK(frr_config_pre, (struct event_loop * tm), (tm)); @@ -41,10 +47,8 @@ DEFINE_KOOH(frr_early_fini, (), ()); DEFINE_KOOH(frr_fini, (), ()); const char frr_sysconfdir[] = SYSCONFDIR; -char frr_vtydir[256]; -#ifdef HAVE_SQLITE3 -const char frr_dbdir[] = DAEMON_DB_DIR; -#endif +char frr_runstatedir[256] = FRR_RUNSTATE_PATH; +char frr_libstatedir[256] = FRR_LIBSTATE_PATH; const char frr_moduledir[] = MODULE_PATH; const char frr_scriptdir[] = SCRIPT_PATH; @@ -52,10 +56,10 @@ char frr_protoname[256] = "NONE"; char frr_protonameinst[256] = "NONE"; char config_default[512]; -char frr_zclientpath[256]; +char frr_zclientpath[512]; static char pidfile_default[1024]; #ifdef HAVE_SQLITE3 -static char dbfile_default[512]; +static char dbfile_default[1024]; #endif static char vtypath_default[512]; @@ -98,23 +102,25 @@ static void opt_extend(const struct optspec *os) #define OPTION_SCRIPTDIR 1009 static const struct option lo_always[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"daemon", no_argument, NULL, 'd'}, - {"module", no_argument, NULL, 'M'}, - {"profile", required_argument, NULL, 'F'}, - {"pathspace", required_argument, NULL, 'N'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, - {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, - {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, - {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, - {"log", required_argument, NULL, OPTION_LOG}, - {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"command-log-always", no_argument, NULL, OPTION_LOGGING}, - {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, - {NULL}}; + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, + { "profile", required_argument, NULL, 'F' }, + { "pathspace", required_argument, NULL, 'N' }, + { "vrfdefaultname", required_argument, NULL, 'o' }, + { "graceful_restart", optional_argument, NULL, 'K' }, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, + { "moduledir", required_argument, NULL, OPTION_MODULEDIR }, + { "scriptdir", required_argument, NULL, OPTION_SCRIPTDIR }, + { "log", required_argument, NULL, OPTION_LOG }, + { "log-level", required_argument, NULL, OPTION_LOGLEVEL }, + { "command-log-always", no_argument, NULL, OPTION_LOGGING }, + { "limit-fds", required_argument, NULL, OPTION_LIMIT_FDS }, + { NULL } +}; static const struct optspec os_always = { - "hvdM:F:N:o:", + "hvdM:F:N:o:K::", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" @@ -122,13 +128,15 @@ static const struct optspec os_always = { " -F, --profile Use specified configuration profile\n" " -N, --pathspace Insert prefix into config & socket paths\n" " -o, --vrfdefaultname Set default VRF name.\n" + " -K, --graceful_restart FRR starting in Graceful Restart mode, with optional route-cleanup timer\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" " --limit-fds Limit number of fds supported\n", - lo_always}; + lo_always +}; static bool logging_to_stdout = false; /* set when --log stdout specified */ @@ -204,7 +212,7 @@ bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) { /* note: this functionality is disabled at bottom */ int af; - int port = ZEBRA_PORT; + int port = ZEBRA_TCP_PORT; char *err = NULL; struct sockaddr_in *sin = NULL; struct sockaddr_in6 *sin6 = NULL; @@ -218,7 +226,8 @@ bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, break; case '6': path++; - /* fallthrough */ + af = AF_INET6; + break; default: af = AF_INET6; break; @@ -305,11 +314,6 @@ bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, static struct frr_daemon_info *di = NULL; -void frr_init_vtydir(void) -{ - snprintf(frr_vtydir, sizeof(frr_vtydir), DAEMON_VTY_DIR, "", ""); -} - void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) { di = daemon; @@ -319,7 +323,12 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) char *p = strrchr(argv[0], '/'); di->progname = p ? p + 1 : argv[0]; - umask(0027); + if (!getenv("GCOV_PREFIX")) + umask(0027); + else { + /* If we are profiling use a more generous umask */ + umask(0002); + } log_args_init(daemon->early_logging); @@ -339,22 +348,22 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) if (di->flags & FRR_DETACH_LATER) nodetach_daemon = true; - frr_init_vtydir(); snprintf(config_default, sizeof(config_default), "%s/%s.conf", frr_sysconfdir, di->name); snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid", - frr_vtydir, di->name); - snprintf(frr_zclientpath, sizeof(frr_zclientpath), - ZEBRA_SERV_PATH, "", ""); + frr_runstatedir, di->name); + snprintf(frr_zclientpath, sizeof(frr_zclientpath), ZAPI_SOCK_NAME); #ifdef HAVE_SQLITE3 snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s.db", - frr_dbdir, di->name); + frr_libstatedir, di->name); #endif strlcpy(frr_protoname, di->logname, sizeof(frr_protoname)); strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst)); di->cli_mode = FRR_CLI_CLASSIC; + di->graceful_restart = false; + di->gr_cleanup_time = 0; /* we may be starting with extra FDs open for whatever purpose, * e.g. logging, some module, etc. Recording them here allows later @@ -497,13 +506,15 @@ static int frr_opt(int opt) } di->pathspace = optarg; + snprintf(frr_runstatedir, sizeof(frr_runstatedir), + FRR_RUNSTATE_PATH "/%s", di->pathspace); + snprintf(frr_libstatedir, sizeof(frr_libstatedir), + FRR_LIBSTATE_PATH "/%s", di->pathspace); + snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid", + frr_runstatedir, di->name); if (!di->zpathspace) snprintf(frr_zclientpath, sizeof(frr_zclientpath), - ZEBRA_SERV_PATH, "/", di->pathspace); - snprintf(frr_vtydir, sizeof(frr_vtydir), DAEMON_VTY_DIR, "/", - di->pathspace); - snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid", - frr_vtydir, di->name); + ZAPI_SOCK_NAME); break; case 'o': vrf_set_default_name(optarg); @@ -515,6 +526,11 @@ static int frr_opt(int opt) di->db_file = optarg; break; #endif + case 'K': + di->graceful_restart = true; + if (optarg) + di->gr_cleanup_time = atoi(optarg); + break; case 'C': if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; @@ -724,10 +740,10 @@ struct event_loop *frr_init(void) snprintf(config_default, sizeof(config_default), "%s%s%s%s.conf", frr_sysconfdir, p_pathspace, di->name, p_instance); snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s%s.pid", - frr_vtydir, di->name, p_instance); + frr_runstatedir, di->name, p_instance); #ifdef HAVE_SQLITE3 snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s%s%s.db", - frr_dbdir, p_pathspace, di->name, p_instance); + frr_libstatedir, p_pathspace, di->name, p_instance); #endif zprivs_preinit(di->privs); @@ -756,8 +772,9 @@ struct event_loop *frr_init(void) /* don't mkdir these as root... */ if (!(di->flags & FRR_NO_PRIVSEP)) { + frr_mkdir(frr_libstatedir, false); if (!di->pid_file || !di->vty_path) - frr_mkdir(frr_vtydir, false); + frr_mkdir(frr_runstatedir, false); if (di->pid_file) frr_mkdir(di->pid_file, true); if (di->vty_path) @@ -956,8 +973,6 @@ static void frr_daemonize(void) } close(fds[1]); - nb_terminate(); - yang_terminate(); frr_daemon_wait(fds[0]); } @@ -1036,7 +1051,17 @@ void frr_config_fork(void) zlog_tls_buffer_init(); } -void frr_vty_serv_start(void) +static void frr_check_detach(void) +{ + if (nodetach_term || nodetach_daemon) + return; + + if (daemon_ctl_sock != -1) + close(daemon_ctl_sock); + daemon_ctl_sock = -1; +} + +void frr_vty_serv_start(bool check_detach) { /* allow explicit override of vty_path in the future * (not currently set anywhere) */ @@ -1044,7 +1069,7 @@ void frr_vty_serv_start(void) const char *dir; char defvtydir[256]; - snprintf(defvtydir, sizeof(defvtydir), "%s", frr_vtydir); + snprintf(defvtydir, sizeof(defvtydir), "%s", frr_runstatedir); dir = di->vty_sock_path ? di->vty_sock_path : defvtydir; @@ -1059,6 +1084,9 @@ void frr_vty_serv_start(void) } vty_serv_start(di->vty_addr, di->vty_port, di->vty_path); + + if (check_detach) + frr_check_detach(); } void frr_vty_serv_stop(void) @@ -1069,16 +1097,6 @@ void frr_vty_serv_stop(void) unlink(di->vty_path); } -static void frr_check_detach(void) -{ - if (nodetach_term || nodetach_daemon) - return; - - if (daemon_ctl_sock != -1) - close(daemon_ctl_sock); - daemon_ctl_sock = -1; -} - static void frr_terminal_close(int isexit) { int nullfd; @@ -1164,7 +1182,7 @@ void frr_run(struct event_loop *master) char instanceinfo[64] = ""; if (!(di->flags & FRR_MANUAL_VTY_START)) - frr_vty_serv_start(); + frr_vty_serv_start(false); if (di->instance) snprintf(instanceinfo, sizeof(instanceinfo), "instance %u ", @@ -1202,7 +1220,8 @@ void frr_run(struct event_loop *master) close(nullfd); } - frr_check_detach(); + if (!(di->flags & FRR_MANUAL_VTY_START)) + frr_check_detach(); } /* end fixed stderr startup logging */ @@ -1248,6 +1267,8 @@ void frr_fini(void) /* frrmod_init -> nothing needed / hooks */ rcu_shutdown(); + frrmod_terminate(); + /* also log memstats to stderr when stderr goes to a file*/ if (debug_memstats_at_exit || !isatty(STDERR_FILENO)) have_leftovers = log_memstats(stderr, di->name); @@ -1270,6 +1291,161 @@ void frr_fini(void) } } +struct json_object *frr_daemon_state_load(void) +{ + struct json_object *state; + char **state_path; + + assertf(di->state_paths, + "CODE BUG: daemon trying to load state, but no state path in frr_daemon_info"); + + for (state_path = di->state_paths; *state_path; state_path++) { + state = json_object_from_file(*state_path); + if (state) + return state; + } + + return json_object_new_object(); +} + +/* cross-reference file_write_config() in command.c + * the code there is similar but not identical (configs use a unique temporary + * name for writing and keep a backup of the previous config.) + */ +void frr_daemon_state_save(struct json_object **statep) +{ + struct json_object *state = *statep; + char *state_path, *slash, *temp_name, **other; + size_t name_len, json_len; + const char *json_str; + int dirfd, fd; + + assertf(di->state_paths, + "CODE BUG: daemon trying to save state, but no state path in frr_daemon_info"); + + state_path = di->state_paths[0]; + json_str = json_object_to_json_string_ext(state, + JSON_C_TO_STRING_PRETTY); + json_len = strlen(json_str); + + /* To correctly fsync() and ensure we have either consistent old state + * or consistent new state but no fs-damage garbage inbetween, we need + * to work with a directory fd. If we need that anyway we might as + * well use the dirfd with openat() & co in fd-relative operations. + */ + + slash = strrchr(state_path, '/'); + if (slash) { + char *state_dir; + + state_dir = XSTRDUP(MTYPE_TMP, state_path); + state_dir[slash - state_path] = '\0'; + dirfd = open(state_dir, O_DIRECTORY | O_RDONLY); + XFREE(MTYPE_TMP, state_dir); + + if (dirfd < 0) { + zlog_err("failed to open directory %pSQq for saving daemon state: %m", + state_dir); + return; + } + + /* skip to file name */ + slash++; + } else { + dirfd = open(".", O_DIRECTORY | O_RDONLY); + if (dirfd < 0) { + zlog_err( + "failed to open current directory for saving daemon state: %m"); + return; + } + + /* file name = path */ + slash = state_path; + } + + /* unlike saving configs, a temporary unique filename is unhelpful + * here as it might litter files on limited write-heavy storage + * (think switch with small NOR flash for frequently written data.) + * + * => always use filename with .sav suffix, worst case it litters one + * file. + */ + name_len = strlen(slash); + temp_name = XMALLOC(MTYPE_TMP, name_len + 5); + memcpy(temp_name, slash, name_len); + memcpy(temp_name + name_len, ".sav", 5); + + /* state file is always 0600, it's by and for FRR itself only */ + fd = openat(dirfd, temp_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) { + zlog_err("failed to open temporary daemon state save file for %pSQq: %m", + state_path); + goto out_closedir_free; + } + + while (json_len) { + ssize_t nwr = write(fd, json_str, json_len); + + if (nwr <= 0) { + zlog_err("failed to write temporary daemon state to %pSQq: %m", + state_path); + + close(fd); + unlinkat(dirfd, temp_name, 0); + goto out_closedir_free; + } + + json_str += nwr; + json_len -= nwr; + } + + /* fsync is theoretically implicit in close(), but... */ + if (fsync(fd) < 0) + zlog_warn("fsync for daemon state %pSQq failed: %m", state_path); + close(fd); + + /* this is the *actual* fsync that ensures we're consistent. The + * file fsync only syncs the inode, but not the directory entry + * referring to it. + */ + if (fsync(dirfd) < 0) + zlog_warn("directory fsync for daemon state %pSQq failed: %m", + state_path); + + /* atomic, hopefully. */ + if (renameat(dirfd, temp_name, dirfd, slash) < 0) { + zlog_err("renaming daemon state %pSQq to %pSQq failed: %m", + temp_name, state_path); + /* no unlink here, give the user a chance to investigate */ + goto out_closedir_free; + } + + /* and the rename needs to be synced too */ + if (fsync(dirfd) < 0) + zlog_warn("directory fsync for daemon state %pSQq failed after rename: %m", + state_path); + + /* daemon may specify other deprecated paths to load from; since we + * just saved successfully we should delete those. + */ + for (other = di->state_paths + 1; *other; other++) { + if (unlink(*other) == 0) + continue; + if (errno == ENOENT || errno == ENOTDIR) + continue; + + zlog_warn("failed to remove deprecated daemon state file %pSQq: %m", + *other); + } + +out_closedir_free: + XFREE(MTYPE_TMP, temp_name); + close(dirfd); + + json_object_free(state); + *statep = NULL; +} + #ifdef INTERP static const char interp[] __attribute__((section(".interp"), used)) = INTERP; @@ -1291,3 +1467,20 @@ void _libfrr_version(void) write(1, banner, sizeof(banner) - 1); _exit(0); } + +/* Render simple version tuple to string */ +const char *frr_vers2str(uint32_t version, char *buf, int buflen) +{ + snprintf(buf, buflen, "%d.%d.%d", MAJOR_FRRVERSION(version), + MINOR_FRRVERSION(version), SUB_FRRVERSION(version)); + + return buf; +} + +bool frr_is_daemon(void) +{ + if (di) + return true; + + return false; +} diff --git a/lib/libfrr.h b/lib/libfrr.h index b260a54dfeb1..7ed7be4d984d 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -22,6 +22,8 @@ extern "C" { #endif +#define ZAPI_SOCK_NAME "%s/zserv.api", frr_runstatedir + /* The following options disable specific command line options that * are not applicable for a particular daemon. */ @@ -53,6 +55,49 @@ struct log_arg { }; DECLARE_DLIST(log_args, struct log_arg, itm); +/* Registry of daemons' port defaults. Many of these are VTY ports; some + * daemons have default ports for other features such as ospfapi, or zebra's + * FPM. + */ + +/* default zebra TCP port for zapi; this is currently disabled for security + * reasons. + */ +#define ZEBRA_TCP_PORT 2600 + +#define ZEBRA_VTY_PORT 2601 +#define RIP_VTY_PORT 2602 +#define RIPNG_VTY_PORT 2603 +#define OSPF_VTY_PORT 2604 +#define BGP_VTY_PORT 2605 +#define OSPF6_VTY_PORT 2606 + +/* Default API server port to accept connection request from client-side. + * This value could be overridden by "ospfapi" entry in "/etc/services". + */ +#define OSPF_API_SYNC_PORT 2607 + +#define ISISD_VTY_PORT 2608 +#define BABEL_VTY_PORT 2609 +#define NHRP_VTY_PORT 2610 +#define PIMD_VTY_PORT 2611 +#define LDP_VTY_PORT 2612 +#define EIGRP_VTY_PORT 2613 +#define SHARP_VTY_PORT 2614 +#define PBR_VTY_PORT 2615 +#define STATIC_VTY_PORT 2616 +#define BFDD_VTY_PORT 2617 +#define FABRICD_VTY_PORT 2618 +#define VRRP_VTY_PORT 2619 + +/* default port for FPM connections */ +#define FPM_DEFAULT_PORT 2620 + +#define PATH_VTY_PORT 2621 +#define PIM6D_VTY_PORT 2622 +#define MGMTD_VTY_PORT 2623 +/* Registry of daemons' port defaults */ + enum frr_cli_mode { FRR_CLI_CLASSIC = 0, FRR_CLI_TRANSACTIONAL, @@ -73,6 +118,8 @@ struct frr_daemon_info { bool dryrun; bool daemon_mode; bool terminal; + bool graceful_restart; + int gr_cleanup_time; enum frr_cli_mode cli_mode; struct event *read_in; @@ -85,6 +132,7 @@ struct frr_daemon_info { const char *vty_path; const char *module_path; const char *script_path; + char **state_paths; const char *pathspace; bool zpathspace; @@ -130,7 +178,6 @@ struct frr_daemon_info { .version = FRR_VERSION, ); \ MACRO_REQUIRE_SEMICOLON() /* end */ -extern void frr_init_vtydir(void); extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv); extern void frr_opt_add(const char *optstr, const struct option *longopts, const char *helpstr); @@ -143,7 +190,7 @@ extern const char *frr_get_progname(void); extern enum frr_cli_mode frr_get_cli_mode(void); extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); - +extern bool frr_is_daemon(void); /* call order of these hooks is as ordered here */ DECLARE_HOOK(frr_early_init, (struct event_loop * tm), (tm)); DECLARE_HOOK(frr_late_init, (struct event_loop * tm), (tm)); @@ -155,12 +202,16 @@ extern void frr_config_fork(void); extern void frr_run(struct event_loop *master); extern void frr_detach(void); -extern void frr_vty_serv_start(void); +extern void frr_vty_serv_start(bool check_detach); extern void frr_vty_serv_stop(void); extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, const char *path); +struct json_object; +extern struct json_object *frr_daemon_state_load(void); +extern void frr_daemon_state_save(struct json_object **statep); + /* these two are before the protocol daemon does its own shutdown * it's named this way being the counterpart to frr_late_init */ DECLARE_KOOH(frr_early_fini, (), ()); @@ -170,10 +221,40 @@ DECLARE_KOOH(frr_fini, (), ()); extern void frr_fini(void); extern char config_default[512]; -extern char frr_zclientpath[256]; +extern char frr_zclientpath[512]; + +/* refer to lib/config_paths.h (generated during ./configure) for build config + * values of the following: + */ + +/* sysconfdir is generally /etc/frr/, some BSDs may use /usr/local/etc/frr/. + * Will NOT include "pathspace" (namespace) suffix from -N. (libfrr.c handles + * pathspace'ing config files.) Has a slash at the end for "historical" + * reasons. + */ extern const char frr_sysconfdir[]; -extern char frr_vtydir[256]; + +/* runstatedir is *ephemeral* across reboots. It may either be a ramdisk, + * or be wiped during boot. Use only for pid files, sockets, and the like, + * not state. Commonly /run/frr or /var/run/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ +extern char frr_runstatedir[256]; + +/* libstatedir is *persistent*. It's the place to put state like sequence + * numbers or databases. Commonly /var/lib/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ +extern char frr_libstatedir[256]; + +/* moduledir is something along the lines of /usr/lib/frr/modules or + * /usr/lib/x86_64-linux-gnu/frr/modules. It is not guaranteed to be a + * subdirectory of the directory that the daemon binaries reside in. (e.g. + * the "x86_64-linux-gnu" component will be absent from daemon paths.) + */ extern const char frr_moduledir[]; + +/* scriptdir is for Lua scripts, generally ${frr_sysconfdir}/scripts */ extern const char frr_scriptdir[]; extern char frr_protoname[]; @@ -183,6 +264,17 @@ extern bool frr_is_after_fork; extern bool debug_memstats_at_exit; +/* + * Version numbering: MAJOR (8) | MINOR (16) | SUB (8) + */ +#define MAKE_FRRVERSION(maj, min, sub) \ + ((((maj) & 0xff) << 24) | (((min) & 0xffff) << 8) | ((sub) & 0xff)) +#define MAJOR_FRRVERSION(v) (((v) >> 24) & 0xff) +#define MINOR_FRRVERSION(v) (((v) >> 8) & 0xffff) +#define SUB_FRRVERSION(v) ((v) & 0xff) + +const char *frr_vers2str(uint32_t version, char *buf, int buflen); + #ifdef __cplusplus } #endif diff --git a/lib/libfrr_trace.c b/lib/libfrr_trace.c index 59320322ca45..14f4a3cb20ac 100644 --- a/lib/libfrr_trace.c +++ b/lib/libfrr_trace.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE diff --git a/lib/libospf.h b/lib/libospf.h index 9a643256c23d..8a208beb3c33 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -58,10 +58,12 @@ extern "C" { #define OSPF_HELLO_DELAY_DEFAULT 10 #define OSPF_ROUTER_PRIORITY_DEFAULT 1 #define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */ #define OSPF_TRANSMIT_DELAY_DEFAULT 1 #define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */ +#define OSPF_ACK_DELAY_DEFAULT 1 -#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Mbps */ +#define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ #define OSPF_POLL_INTERVAL_DEFAULT 60 #define OSPF_NEIGHBOR_PRIORITY_DEFAULT 0 @@ -69,6 +71,7 @@ extern "C" { #define OSPF_MTU_IGNORE_DEFAULT 0 #define OSPF_FAST_HELLO_DEFAULT 0 #define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false +#define OSPF_P2MP_NON_BROADCAST_DEFAULT false #define OSPF_OPAQUE_CAPABLE_DEFAULT true #define OSPF_PREFIX_SUPPRESSION_DEFAULT false #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ diff --git a/lib/link_state.c b/lib/link_state.c index 105e3e28a96a..3d96c75f6d1e 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -140,6 +140,12 @@ int ls_node_same(struct ls_node *n1, struct ls_node *n2) if (CHECK_FLAG(n1->flags, LS_NODE_MSD) && (n1->msd != n2->msd)) return 0; } + if (CHECK_FLAG(n1->flags, LS_NODE_SRV6)) { + if (n1->srv6_cap_flags != n2->srv6_cap_flags) + return 0; + if (memcmp(&n1->srv6_msd, &n2->srv6_msd, sizeof(n1->srv6_msd))) + return 0; + } /* OK, n1 & n2 are equal */ return 1; @@ -320,6 +326,23 @@ int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2) &l2->adj_sid[i].neighbor.addr))) return 0; } + for (int i = 0; i < ADJ_SRV6_MAX; i++) { + if (!CHECK_FLAG(l1->flags, (LS_ATTR_ADJ_SRV6SID << i))) + continue; + if (memcmp(&l1->adj_srv6_sid[i].sid, &l2->adj_srv6_sid[i].sid, + sizeof(struct in6_addr)) || + (l1->adj_srv6_sid[i].flags != l2->adj_srv6_sid[i].flags) || + (l1->adj_srv6_sid[i].weight != l2->adj_srv6_sid[i].weight) || + (l1->adj_srv6_sid[i].endpoint_behavior != + l2->adj_srv6_sid[i].endpoint_behavior)) + return 0; + if (((l1->adv.origin == ISIS_L1) || + (l1->adv.origin == ISIS_L2)) && + (memcmp(&l1->adj_srv6_sid[i].neighbor.sysid, + &l2->adj_srv6_sid[i].neighbor.sysid, + ISO_SYS_ID_LEN) != 0)) + return 0; + } if (CHECK_FLAG(l1->flags, LS_ATTR_SRLG) && ((l1->srlg_len != l2->srlg_len) || memcmp(l1->srlgs, l2->srlgs, @@ -391,6 +414,13 @@ int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) || (p1->sr.sid_flag != p2->sr.sid_flag)) return 0; } + if (CHECK_FLAG(p1->flags, LS_PREF_SRV6)) { + if (memcmp(&p1->srv6.sid, &p2->srv6.sid, + sizeof(struct in6_addr)) || + (p1->srv6.flags != p2->srv6.flags) || + (p1->srv6.behavior != p2->srv6.behavior)) + return 0; + } /* OK, p1 & p2 are equal */ return 1; @@ -1298,6 +1328,26 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s) STREAM_GET(attr->adj_sid[ADJ_BCK_IPV6].neighbor.sysid, s, ISO_SYS_ID_LEN); } + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SRV6SID)) { + STREAM_GET(&attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].sid, s, + sizeof(struct in6_addr)); + STREAM_GETC(s, attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].flags); + STREAM_GETC(s, attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].weight); + STREAM_GETW(s, attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6] + .endpoint_behavior); + STREAM_GET(attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].neighbor.sysid, + s, ISO_SYS_ID_LEN); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SRV6SID)) { + STREAM_GET(&attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].sid, s, + sizeof(struct in6_addr)); + STREAM_GETC(s, attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].flags); + STREAM_GETC(s, attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].weight); + STREAM_GETW(s, attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6] + .endpoint_behavior); + STREAM_GET(attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].neighbor.sysid, + s, ISO_SYS_ID_LEN); + } if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { STREAM_GETC(s, len); attr->srlgs = XCALLOC(MTYPE_LS_DB, len*sizeof(uint32_t)); @@ -1345,6 +1395,11 @@ static struct ls_prefix *ls_parse_prefix(struct stream *s) STREAM_GETC(s, ls_pref->sr.sid_flag); STREAM_GETC(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + STREAM_GET(&ls_pref->srv6.sid, s, sizeof(struct in6_addr)); + STREAM_GETW(s, ls_pref->srv6.behavior); + STREAM_GETC(s, ls_pref->srv6.flags); + } return ls_pref; @@ -1532,6 +1587,28 @@ static int ls_format_attributes(struct stream *s, struct ls_attributes *attr) stream_put(s, attr->adj_sid[ADJ_BCK_IPV6].neighbor.sysid, ISO_SYS_ID_LEN); } + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SRV6SID)) { + stream_put(s, &attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].sid, + sizeof(struct in6_addr)); + stream_putc(s, attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].flags); + stream_putc(s, attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].weight); + stream_putw(s, attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6] + .endpoint_behavior); + stream_put(s, + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].neighbor.sysid, + ISO_SYS_ID_LEN); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SRV6SID)) { + stream_put(s, &attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].sid, + sizeof(struct in6_addr)); + stream_putc(s, attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].flags); + stream_putc(s, attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].weight); + stream_putw(s, attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6] + .endpoint_behavior); + stream_put(s, + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].neighbor.sysid, + ISO_SYS_ID_LEN); + } if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { stream_putc(s, attr->srlg_len); for (len = 0; len < attr->srlg_len; len++) @@ -1567,6 +1644,11 @@ static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref) stream_putc(s, ls_pref->sr.sid_flag); stream_putc(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + stream_put(s, &ls_pref->srv6.sid, sizeof(struct in6_addr)); + stream_putw(s, ls_pref->srv6.behavior); + stream_putc(s, ls_pref->srv6.flags); + } return 0; } @@ -1739,7 +1821,7 @@ struct ls_message *ls_subnet2msg(struct ls_message *msg, struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg, bool delete) { - struct ls_node *node = (struct ls_node *)msg->data.node; + struct ls_node *node = msg->data.node; struct ls_vertex *vertex = NULL; switch (msg->event) { @@ -1779,7 +1861,7 @@ struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg, struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, bool delete) { - struct ls_attributes *attr = (struct ls_attributes *)msg->data.attr; + struct ls_attributes *attr = msg->data.attr; struct ls_edge *edge = NULL; switch (msg->event) { @@ -1819,7 +1901,7 @@ struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, struct ls_subnet *ls_msg2subnet(struct ls_ted *ted, struct ls_message *msg, bool delete) { - struct ls_prefix *pref = (struct ls_prefix *)msg->data.prefix; + struct ls_prefix *pref = msg->data.prefix; struct ls_subnet *subnet = NULL; switch (msg->event) { @@ -2351,6 +2433,24 @@ static void ls_show_edge_vty(struct ls_edge *edge, struct vty *vty, attr->adj_sid[ADJ_BCK_IPV6].flags, attr->adj_sid[ADJ_BCK_IPV6].weight); } + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SRV6SID)) { + sbuf_push(&sbuf, 4, "IPv6 Adjacency-SRV6-SID: %pI6", + &attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].sid); + sbuf_push(&sbuf, 0, + "\tFlags: 0x%x\tWeight: 0x%x\tbehavior: 0x%x\n", + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].flags, + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].weight, + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].endpoint_behavior); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SRV6SID)) { + sbuf_push(&sbuf, 4, "IPv6 Bck. Adjacency-SRV6-SID: %pI6", + &attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].sid); + sbuf_push(&sbuf, 0, + "\tFlags: 0x%x\tWeight: 0x%x\tbehavior: 0x%x\n", + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].flags, + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].weight, + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].endpoint_behavior); + } if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { sbuf_push(&sbuf, 4, "SRLGs: %d", attr->srlg_len); for (int i = 1; i < attr->srlg_len; i++) { @@ -2372,7 +2472,7 @@ static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json) struct ls_attributes *attr; struct json_object *jte, *jbw, *jobj, *jsr = NULL, *jsrlg, *js_ext_ag, *js_ext_ag_arr_word, - *js_ext_ag_arr_bit; + *js_ext_ag_arr_bit, *jsrv6 = NULL; char buf[INET6_BUFSIZ]; char buf_ag[strlen("0xffffffff") + 1]; uint32_t bitmap; @@ -2557,6 +2657,45 @@ static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json) attr->adj_sid[ADJ_BCK_IPV6].weight); json_object_array_add(jsr, jobj); } + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SRV6SID)) { + jsrv6 = json_object_new_array(); + json_object_object_add(json, "segment-routing-ipv6", jsrv6); + jobj = json_object_new_object(); + snprintfrr(buf, INET6_BUFSIZ, "%pI6", + &attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].sid); + json_object_string_add(jobj, "adj-sid", buf); + snprintfrr(buf, 6, "0x%x", + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].flags); + json_object_string_add(jobj, "flags", buf); + json_object_int_add(jobj, "weight", + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6].weight); + snprintfrr(buf, 6, "0x%x", + attr->adj_srv6_sid[ADJ_SRV6_PRI_IPV6] + .endpoint_behavior); + json_object_string_add(jobj, "endpoint-behavior", buf); + json_object_array_add(jsr, jobj); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SRV6SID)) { + if (!jsrv6) { + jsrv6 = json_object_new_array(); + json_object_object_add(json, "segment-routing-ipv6", + jsrv6); + } + jobj = json_object_new_object(); + snprintfrr(buf, INET6_BUFSIZ, "%pI6", + &attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].sid); + json_object_string_add(jobj, "adj-sid", buf); + snprintfrr(buf, 6, "0x%x", + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].flags); + json_object_string_add(jobj, "flags", buf); + json_object_int_add(jobj, "weight", + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6].weight); + snprintfrr(buf, 6, "0x%x", + attr->adj_srv6_sid[ADJ_SRV6_BCK_IPV6] + .endpoint_behavior); + json_object_string_add(jobj, "endpoint-behavior", buf); + json_object_array_add(jsr, jobj); + } } void ls_show_edge(struct ls_edge *edge, struct vty *vty, @@ -2626,6 +2765,13 @@ static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty, sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n", pref->sr.sid, pref->sr.algo, pref->sr.sid_flag); + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) + sbuf_push(&sbuf, 4, + "SIDv6: %pI6\tEndpoint behavior: %s\tFlags: 0x%x\n", + &pref->srv6.sid, + seg6local_action2str(pref->srv6.behavior), + pref->srv6.flags); + end: vty_out(vty, "%s\n", sbuf_buf(&sbuf)); sbuf_free(&sbuf); @@ -2635,7 +2781,7 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, struct json_object *json) { struct ls_prefix *pref; - json_object *jsr; + json_object *jsr, *jsrv6; char buf[INET6_BUFSIZ]; pref = subnet->ls_pref; @@ -2665,6 +2811,16 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag); json_object_string_add(jsr, "flags", buf); } + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) { + jsrv6 = json_object_new_object(); + json_object_object_add(json, "segment-routing-ipv6", jsrv6); + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &pref->srv6.sid); + json_object_string_add(jsrv6, "sid", buf); + json_object_string_add(jsrv6, "behavior", + seg6local_action2str(pref->srv6.behavior)); + snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->srv6.flags); + json_object_string_add(jsrv6, "flags", buf); + } } void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, diff --git a/lib/link_state.h b/lib/link_state.h index d3a0ce39da99..c54e2ec6d904 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -106,6 +106,7 @@ extern int ls_node_id_same(struct ls_node_id i1, struct ls_node_id i2); #define LS_NODE_SR 0x0040 #define LS_NODE_SRLB 0x0080 #define LS_NODE_MSD 0x0100 +#define LS_NODE_SRV6 0x0200 /* Link State Node structure */ struct ls_node { @@ -128,6 +129,14 @@ struct ls_node { } srlb; uint8_t algo[LIB_LS_SR_ALGO_COUNT]; /* Segment Routing Algorithms */ uint8_t msd; /* Maximum Stack Depth */ + + uint16_t srv6_cap_flags; /* draft-ietf-idr-bgpls-srv6-ext, 3.1., flags field */ + struct ls_srv6_msd { /* draft-ietf-idr-bgpls-srv6-ext, 3.2. */ + uint8_t max_seg_left_msd; + uint8_t max_end_pop_msd; + uint8_t max_h_encaps_msd; + uint8_t max_end_d_msd; + } srv6_msd; }; /* Link State flags to indicate which Attribute parameters are valid */ @@ -161,6 +170,8 @@ struct ls_node { #define LS_ATTR_BCK_ADJ_SID6 0x08000000 #define LS_ATTR_SRLG 0x10000000 #define LS_ATTR_EXT_ADM_GRP 0x20000000 +#define LS_ATTR_ADJ_SRV6SID 0x40000000 +#define LS_ATTR_BCK_ADJ_SRV6SID 0x80000000 /* Link State Attributes */ struct ls_attributes { @@ -209,6 +220,18 @@ struct ls_attributes { uint8_t sysid[ISO_SYS_ID_LEN]; /* or Sys-ID for ISIS */ } neighbor; } adj_sid[4]; /* IPv4/IPv6 & Primary/Backup (LAN)-Adj. SID */ +#define ADJ_SRV6_PRI_IPV6 0 +#define ADJ_SRV6_BCK_IPV6 1 +#define ADJ_SRV6_MAX 2 + struct ls_srv6_adjacency { /* Adjacency SID for IS-IS */ + struct in6_addr sid; /* SID as IPv6 address */ + uint8_t flags; /* Flags */ + uint8_t weight; /* Administrative weight */ + uint16_t endpoint_behavior; /* Endpoint Behavior */ + union { + uint8_t sysid[ISO_SYS_ID_LEN]; /* Sys-ID for ISIS */ + } neighbor; + } adj_srv6_sid[2]; uint32_t *srlgs; /* List of Shared Risk Link Group */ uint8_t srlg_len; /* number of SRLG in the list */ }; @@ -220,6 +243,7 @@ struct ls_attributes { #define LS_PREF_EXTENDED_TAG 0x04 #define LS_PREF_METRIC 0x08 #define LS_PREF_SR 0x10 +#define LS_PREF_SRV6 0x20 /* Link State Prefix */ struct ls_prefix { @@ -235,6 +259,11 @@ struct ls_prefix { uint8_t sid_flag; /* Segment Routing Flags */ uint8_t algo; /* Algorithm for Segment Routing */ } sr; + struct ls_srv6_sid { + struct in6_addr sid; /* Segment Routing ID */ + uint16_t behavior; /* Endpoint behavior bound to the SID */ + uint8_t flags; /* Flags */ + } srv6; }; /** diff --git a/lib/linklist.h b/lib/linklist.h index fd953d0769b8..f922891df95f 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -10,6 +10,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new list structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ diff --git a/lib/log.c b/lib/log.c index df9b6c717633..880180ae5a94 100644 --- a/lib/log.c +++ b/lib/log.c @@ -8,6 +8,10 @@ #include +#ifdef HAVE_GLIBC_BACKTRACE +#include +#endif /* HAVE_GLIBC_BACKTRACE */ + #include "zclient.h" #include "log.h" #include "memory.h" @@ -351,7 +355,6 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_VRF_ADD), DESC_ENTRY(ZEBRA_VRF_DELETE), DESC_ENTRY(ZEBRA_VRF_LABEL), - DESC_ENTRY(ZEBRA_INTERFACE_VRF_UPDATE), DESC_ENTRY(ZEBRA_BFD_CLIENT_REGISTER), DESC_ENTRY(ZEBRA_BFD_CLIENT_DEREGISTER), DESC_ENTRY(ZEBRA_INTERFACE_ENABLE_RADV), @@ -433,6 +436,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_SRV6_LOCATOR_DELETE), DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK), DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_SRV6_SID), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID), DESC_ENTRY(ZEBRA_ERROR), DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES), DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE), @@ -441,11 +447,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_NEIGH_DISCOVER), DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST), DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY), - DESC_ENTRY(ZEBRA_NHRP_NEIGH_ADDED), - DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED), - DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET), - DESC_ENTRY(ZEBRA_NHRP_NEIGH_REGISTER), - DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER), + DESC_ENTRY(ZEBRA_NEIGH_ADDED), + DESC_ENTRY(ZEBRA_NEIGH_REMOVED), + DESC_ENTRY(ZEBRA_NEIGH_GET), + DESC_ENTRY(ZEBRA_NEIGH_REGISTER), + DESC_ENTRY(ZEBRA_NEIGH_UNREGISTER), DESC_ENTRY(ZEBRA_NEIGH_IP_ADD), DESC_ENTRY(ZEBRA_NEIGH_IP_DEL), DESC_ENTRY(ZEBRA_CONFIGURE_ARP), @@ -458,7 +464,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_TC_CLASS_DELETE), DESC_ENTRY(ZEBRA_TC_FILTER_ADD), DESC_ENTRY(ZEBRA_TC_FILTER_DELETE), - DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY) + DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY), + DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY) }; #undef DESC_ENTRY @@ -548,6 +555,8 @@ int proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_KERNEL; else if (strmatch(s, "connected")) return ZEBRA_ROUTE_CONNECT; + else if (strmatch(s, "local")) + return ZEBRA_ROUTE_LOCAL; else if (strmatch(s, "static")) return ZEBRA_ROUTE_STATIC; else if (strmatch(s, "rip")) @@ -574,12 +583,16 @@ int proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_SHARP; else if (strmatch(s, "openfabric")) return ZEBRA_ROUTE_OPENFABRIC; + else if (strmatch(s, "table-direct")) + return ZEBRA_ROUTE_TABLE_DIRECT; } if (afi == AFI_IP6) { if (strmatch(s, "kernel")) return ZEBRA_ROUTE_KERNEL; else if (strmatch(s, "connected")) return ZEBRA_ROUTE_CONNECT; + else if (strmatch(s, "local")) + return ZEBRA_ROUTE_LOCAL; else if (strmatch(s, "static")) return ZEBRA_ROUTE_STATIC; else if (strmatch(s, "ripng")) @@ -604,6 +617,8 @@ int proto_redistnum(int afi, const char *s) return ZEBRA_ROUTE_SHARP; else if (strmatch(s, "openfabric")) return ZEBRA_ROUTE_OPENFABRIC; + else if (strmatch(s, "table-direct")) + return ZEBRA_ROUTE_TABLE_DIRECT; } return -1; } diff --git a/lib/log_vty.c b/lib/log_vty.c index 26e608d16b9b..323b1b1d55a3 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -15,6 +15,7 @@ #include "lib/lib_errors.h" #include "lib/printfrr.h" #include "lib/systemd.h" +#include "lib/vtysh_daemons.h" #include "lib/log_vty_clippy.c" @@ -459,6 +460,70 @@ DEFUN (clear_log_cmdline, return CMD_SUCCESS; } +/* Per-daemon log file config */ +DEFUN (config_log_dmn_file, + config_log_dmn_file_cmd, + "log daemon " DAEMONS_LIST " file FILENAME [$levelarg]", + "Logging control\n" + "Specific daemon\n" + DAEMONS_STR + "Logging to file\n" + "Logging filename\n" + LOG_LEVEL_DESC) +{ + int level = log_default_lvl; + int idx = 0; + const char *d_str; + const char *filename; + const char *levelarg = NULL; + + d_str = argv[2]->text; + + /* Ignore if not for this daemon */ + if (!strmatch(d_str, frr_get_progname())) + return CMD_SUCCESS; + + if (argv_find(argv, argc, "file", &idx)) + filename = argv[idx + 1]->arg; + else + return CMD_SUCCESS; + + if (argc > 5) + levelarg = argv[5]->text; + + if (levelarg) { + level = log_level_match(levelarg); + if (level == ZLOG_DISABLED) + return CMD_ERR_NO_MATCH; + } + return set_log_file(&zt_file, vty, filename, level); +} + +/* Per-daemon no log file */ +DEFUN (no_config_log_dmn_file, + no_config_log_dmn_file_cmd, + "no log daemon " DAEMONS_LIST " file [FILENAME [LEVEL]]", + NO_STR + "Logging control\n" + "Specific daemon\n" + DAEMONS_STR + "Cancel logging to file\n" + "Logging file name\n" + "Logging level\n") +{ + const char *d_str; + + d_str = argv[3]->text; + + /* Ignore if not for this daemon */ + if (!strmatch(d_str, frr_get_progname())) + return CMD_SUCCESS; + + zt_file.prio_min = ZLOG_DISABLED; + zlog_file_set_other(&zt_file); + return CMD_SUCCESS; +} + DEFPY (config_log_file, config_log_file_cmd, "log file FILENAME [$levelarg]", @@ -837,6 +902,8 @@ void log_config_write(struct vty *vty) vty_out(vty, "no log error-category\n"); if (!zlog_get_prefix_xid()) vty_out(vty, "no log unique-id\n"); + if (zlog_get_immediate_mode()) + vty_out(vty, "log immediate-mode\n"); if (logmsgs_with_persist_bt) { struct xrefdata *xrd; @@ -857,12 +924,24 @@ void log_config_write(struct vty *vty) } } +static int log_vty_fini(void) +{ + if (zt_file_cmdline.filename) + zlog_file_fini(&zt_file_cmdline); + if (zt_file.filename) + zlog_file_fini(&zt_file); + return 0; +} + + static int log_vty_init(const char *progname, const char *protoname, unsigned short instance, uid_t uid, gid_t gid) { zlog_progname = progname; zlog_protoname = protoname; + hook_register(zlog_fini, log_vty_fini); + zlog_set_prefix_ec(true); zlog_set_prefix_xid(true); @@ -892,6 +971,8 @@ void log_cmd_init(void) install_element(CONFIG_NODE, &config_log_monitor_cmd); install_element(CONFIG_NODE, &no_config_log_monitor_cmd); install_element(CONFIG_NODE, &config_log_file_cmd); + install_element(CONFIG_NODE, &config_log_dmn_file_cmd); + install_element(CONFIG_NODE, &no_config_log_dmn_file_cmd); install_element(CONFIG_NODE, &no_config_log_file_cmd); install_element(CONFIG_NODE, &config_log_syslog_cmd); install_element(CONFIG_NODE, &no_config_log_syslog_cmd); diff --git a/lib/memory.h b/lib/memory.h index ba437ebd0ed9..65b99a5fc945 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -69,14 +69,12 @@ struct memgroup { #define DECLARE_MGROUP(name) extern struct memgroup _mg_##name #define _DEFINE_MGROUP(mname, desc, ...) \ - struct memgroup _mg_##mname \ - __attribute__((section(".data.mgroups"))) = { \ - .name = desc, \ - .types = NULL, \ - .next = NULL, \ - .insert = NULL, \ - .ref = NULL, \ - __VA_ARGS__ \ + struct memgroup _mg_##mname _DATA_SECTION("mgroups") = { \ + .name = desc, \ + .types = NULL, \ + .next = NULL, \ + .insert = NULL, \ + .ref = NULL, \ }; \ static void _mginit_##mname(void) __attribute__((_CONSTRUCTOR(1000))); \ static void _mginit_##mname(void) \ @@ -105,13 +103,12 @@ struct memgroup { /* end */ #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \ - attr struct memtype MTYPE_##mname[1] \ - __attribute__((section(".data.mtypes"))) = { { \ - .name = desc, \ - .next = NULL, \ - .n_alloc = 0, \ - .size = 0, \ - .ref = NULL, \ + attr struct memtype MTYPE_##mname[1] _DATA_SECTION("mtypes") = { { \ + .name = desc, \ + .next = NULL, \ + .n_alloc = 0, \ + .size = 0, \ + .ref = NULL, \ } }; \ static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \ static void _mtinit_##mname(void) \ diff --git a/lib/mgmt.proto b/lib/mgmt.proto index 9e4b39abe4d2..c95301118bab 100644 --- a/lib/mgmt.proto +++ b/lib/mgmt.proto @@ -55,7 +55,10 @@ message YangData { enum CfgDataReqType { REQ_TYPE_NONE = 0; SET_DATA = 1; - DELETE_DATA = 2; + REMOVE_DATA = 2; + CREATE_DATA = 3; + DELETE_DATA = 4; + REPLACE_DATA = 5; } message YangCfgDataReq { @@ -73,8 +76,10 @@ message YangGetDataReq { // message BeSubscribeReq { required string client_name = 1; - required bool subscribe_xpaths = 2; - repeated string xpath_reg = 3; + repeated string config_xpaths = 2; + repeated string oper_xpaths = 3; + repeated string notif_xpaths = 4; + repeated string rpc_xpaths = 5; } message BeSubscribeReply { @@ -94,16 +99,14 @@ message BeTxnReply { message BeCfgDataCreateReq { required uint64 txn_id = 1; - required uint64 batch_id = 2; - repeated YangCfgDataReq data_req = 3; - required bool end_of_data = 4; + repeated YangCfgDataReq data_req = 2; + required bool end_of_data = 3; } message BeCfgDataCreateReply { required uint64 txn_id = 1; - required uint64 batch_id = 2; - required bool success = 3; - optional string error_if_any = 4; + required bool success = 2; + optional string error_if_any = 3; } message BeCfgDataApplyReq { @@ -112,15 +115,8 @@ message BeCfgDataApplyReq { message BeCfgDataApplyReply { required uint64 txn_id = 1; - repeated uint64 batch_ids = 2; - required bool success = 3; - optional string error_if_any = 4; -} - -message BeOperDataGetReq { - required uint64 txn_id = 1; - required uint64 batch_id = 2; - repeated YangGetDataReq data = 3; + required bool success = 2; + optional string error_if_any = 3; } message YangDataReply { @@ -128,14 +124,6 @@ message YangDataReply { required int64 next_indx = 2; } -message BeOperDataGetReply { - required uint64 txn_id = 1; - required uint64 batch_id = 2; - required bool success = 3; - optional string error = 4; - optional YangDataReply data = 5; -} - // // Any message on the MGMTD Backend Interface. // @@ -149,8 +137,6 @@ message BeMessage { BeCfgDataCreateReply cfg_data_reply = 7; BeCfgDataApplyReq cfg_apply_req = 8; BeCfgDataApplyReply cfg_apply_reply = 9; - BeOperDataGetReq get_req = 10; - BeOperDataGetReply get_reply = 11; } } diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c index 7bd9980357d5..49879f3f5334 100644 --- a/lib/mgmt_be_client.c +++ b/lib/mgmt_be_client.c @@ -8,15 +8,18 @@ #include #include "debug.h" #include "compiler.h" +#include "darr.h" #include "libfrr.h" -#include "mgmtd/mgmt.h" +#include "lib_errors.h" #include "mgmt_be_client.h" #include "mgmt_msg.h" +#include "mgmt_msg_native.h" #include "mgmt_pb.h" #include "network.h" #include "northbound.h" #include "stream.h" #include "sockopt.h" +#include "northbound_cli.h" #include "lib/mgmt_be_client_clippy.c" @@ -24,11 +27,11 @@ DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_CLIENT, "backend client"); DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_CLIENT_NAME, "backend client name"); DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_BATCH, "backend transaction batch data"); DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_TXN, "backend transaction data"); +DEFINE_MTYPE_STATIC(LIB, MGMTD_BE_GT_CB_ARGS, "backend get-tree cb args"); enum mgmt_be_txn_event { MGMTD_BE_TXN_PROC_SETCFG = 1, MGMTD_BE_TXN_PROC_GETCFG, - MGMTD_BE_TXN_PROC_GETDATA }; struct mgmt_be_set_cfg_req { @@ -36,24 +39,20 @@ struct mgmt_be_set_cfg_req { uint16_t num_cfg_changes; }; -struct mgmt_be_get_data_req { - char *xpaths[MGMTD_MAX_NUM_DATA_REQ_IN_BATCH]; - uint16_t num_xpaths; -}; - struct mgmt_be_txn_req { enum mgmt_be_txn_event event; union { struct mgmt_be_set_cfg_req set_cfg; - struct mgmt_be_get_data_req get_data; } req; }; +struct be_oper_iter_arg { + struct lyd_node *root; /* the tree we are building */ + struct lyd_node *hint; /* last node added */ +}; + PREDECL_LIST(mgmt_be_batches); struct mgmt_be_batch_ctx { - /* Batch-Id as assigned by MGMTD */ - uint64_t batch_id; - struct mgmt_be_txn_req txn_req; uint32_t flags; @@ -116,15 +115,22 @@ struct mgmt_be_client { #define FOREACH_BE_TXN_IN_LIST(client_ctx, txn) \ frr_each_safe (mgmt_be_txns, &(client_ctx)->txn_head, (txn)) -struct debug mgmt_dbg_be_client = {0, "Management backend client operations"}; - -const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = { -#ifdef HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = "staticd", -#endif - [MGMTD_BE_CLIENT_ID_MAX] = "Unknown/Invalid", +struct debug mgmt_dbg_be_client = { + .desc = "Management backend client operations" }; +/* NOTE: only one client per proc for now. */ +static struct mgmt_be_client *__be_client; + +static int be_client_send_native_msg(struct mgmt_be_client *client_ctx, + void *msg, size_t len, + bool short_circuit_ok) +{ + return msg_conn_send_msg(&client_ctx->client.conn, + MGMT_MSG_VERSION_NATIVE, msg, len, NULL, + short_circuit_ok); +} + static int mgmt_be_client_send_msg(struct mgmt_be_client *client_ctx, Mgmtd__BeMessage *be_msg) { @@ -135,37 +141,15 @@ static int mgmt_be_client_send_msg(struct mgmt_be_client *client_ctx, } static struct mgmt_be_batch_ctx * -mgmt_be_find_batch_by_id(struct mgmt_be_txn_ctx *txn, - uint64_t batch_id) +mgmt_be_batch_create(struct mgmt_be_txn_ctx *txn) { struct mgmt_be_batch_ctx *batch = NULL; - FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) { - if (batch->batch_id == batch_id) - return batch; - } - - return NULL; -} + batch = XCALLOC(MTYPE_MGMTD_BE_BATCH, sizeof(struct mgmt_be_batch_ctx)); -static struct mgmt_be_batch_ctx * -mgmt_be_batch_create(struct mgmt_be_txn_ctx *txn, uint64_t batch_id) -{ - struct mgmt_be_batch_ctx *batch = NULL; - - batch = mgmt_be_find_batch_by_id(txn, batch_id); - if (!batch) { - batch = XCALLOC(MTYPE_MGMTD_BE_BATCH, - sizeof(struct mgmt_be_batch_ctx)); - assert(batch); - - batch->batch_id = batch_id; - mgmt_be_batches_add_tail(&txn->cfg_batches, batch); + mgmt_be_batches_add_tail(&txn->cfg_batches, batch); - MGMTD_BE_CLIENT_DBG("Added new batch-id: %" PRIu64 - " to transaction", - batch_id); - } + debug_be_client("Added new batch to transaction"); return batch; } @@ -218,7 +202,8 @@ mgmt_be_find_txn_by_id(struct mgmt_be_client *client_ctx, uint64_t txn_id, if (txn->txn_id == txn_id) return txn; if (warn) - MGMTD_BE_CLIENT_ERR("Unknown txn-id: %" PRIu64, txn_id); + log_err_be_client("client %s unkonwn txn-id: %" PRIu64, + client_ctx->name, txn_id); return NULL; } @@ -230,8 +215,8 @@ mgmt_be_txn_create(struct mgmt_be_client *client_ctx, uint64_t txn_id) txn = mgmt_be_find_txn_by_id(client_ctx, txn_id, false); if (txn) { - MGMTD_BE_CLIENT_ERR("Can't create existing txn-id: %" PRIu64, - txn_id); + log_err_be_client("Can't create existing txn-id: %" PRIu64, + txn_id); return NULL; } @@ -242,7 +227,7 @@ mgmt_be_txn_create(struct mgmt_be_client *client_ctx, uint64_t txn_id) mgmt_be_batches_init(&txn->apply_cfgs); mgmt_be_txns_add_tail(&client_ctx->txn_head, txn); - MGMTD_BE_CLIENT_DBG("Created new txn-id: %" PRIu64, txn_id); + debug_be_client("Created new txn-id: %" PRIu64, txn_id); return txn; } @@ -291,6 +276,84 @@ static void mgmt_be_cleanup_all_txns(struct mgmt_be_client *client_ctx) } } + +/** + * Send an error back to MGMTD using native messaging. + * + * Args: + * client: the BE client. + * txn_id: the txn_id this error pertains to. + * short_circuit_ok: True if OK to short-circuit the call. + * error: An integer error value. + * errfmt: An error format string (i.e., printfrr) + * ...: args for use by the `errfmt` format string. + * + * Return: + * the return value from the underlying send message function. + */ +static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) + PRINTFRR(6, 7); + +static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, errfmt); + ret = vmgmt_msg_native_send_error(&client->client.conn, txn_id, req_id, + short_circuit_ok, error, errfmt, ap); + va_end(ap); + + return ret; +} + +static int mgmt_be_send_notification(void *__be_client, const char *xpath, + const struct lyd_node *tree) +{ + struct mgmt_be_client *client = __be_client; + struct mgmt_msg_notify_data *msg = NULL; + LYD_FORMAT format = LYD_JSON; + uint8_t **darrp; + LY_ERR err; + int ret = 0; + + assert(tree); + + debug_be_client("%s: sending YANG notification: %s", __func__, + tree->schema->name); + /* + * Allocate a message and append the data to it using `format` + */ + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_notify_data, 0, + MTYPE_MSG_NATIVE_NOTIFY); + msg->code = MGMT_MSG_CODE_NOTIFY; + msg->result_type = format; + + mgmt_msg_native_xpath_encode(msg, xpath); + + darrp = mgmt_msg_native_get_darrp(msg); + err = yang_print_tree_append(darrp, tree, format, + (LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT | + LYD_PRINT_WITHSIBLINGS)); + if (err) { + flog_err(EC_LIB_LIBYANG, + "%s: error creating notification data: %s", __func__, + ly_strerrcode(err)); + ret = 1; + goto done; + } + + (void)be_client_send_native_msg(client, msg, + mgmt_msg_native_get_msg_len(msg), false); +done: + mgmt_msg_native_free_msg(msg); + return ret; +} + static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx, uint64_t txn_id, bool create) { @@ -306,7 +369,7 @@ static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY; be_msg.txn_reply = &txn_reply; - MGMTD_BE_CLIENT_DBG("Sending TXN_REPLY txn-id %" PRIu64, txn_id); + debug_be_client("Sending TXN_REPLY txn-id %" PRIu64, txn_id); return mgmt_be_client_send_msg(client_ctx, &be_msg); } @@ -317,7 +380,7 @@ static int mgmt_be_process_txn_req(struct mgmt_be_client *client_ctx, struct mgmt_be_txn_ctx *txn; if (create) { - MGMTD_BE_CLIENT_DBG("Creating new txn-id %" PRIu64, txn_id); + debug_be_client("Creating new txn-id %" PRIu64, txn_id); txn = mgmt_be_txn_create(client_ctx, txn_id); if (!txn) @@ -328,7 +391,7 @@ static int mgmt_be_process_txn_req(struct mgmt_be_client *client_ctx, client_ctx->user_data, &txn->client_data, false); } else { - MGMTD_BE_CLIENT_DBG("Deleting txn-id: %" PRIu64, txn_id); + debug_be_client("Deleting txn-id: %" PRIu64, txn_id); txn = mgmt_be_find_txn_by_id(client_ctx, txn_id, false); if (txn) mgmt_be_txn_delete(client_ctx, &txn); @@ -342,8 +405,7 @@ static int mgmt_be_process_txn_req(struct mgmt_be_client *client_ctx, } static int mgmt_be_send_cfgdata_create_reply(struct mgmt_be_client *client_ctx, - uint64_t txn_id, uint64_t batch_id, - bool success, + uint64_t txn_id, bool success, const char *error_if_any) { Mgmtd__BeMessage be_msg; @@ -351,7 +413,6 @@ static int mgmt_be_send_cfgdata_create_reply(struct mgmt_be_client *client_ctx, mgmtd__be_cfg_data_create_reply__init(&cfgdata_reply); cfgdata_reply.txn_id = (uint64_t)txn_id; - cfgdata_reply.batch_id = (uint64_t)batch_id; cfgdata_reply.success = success; if (error_if_any) cfgdata_reply.error_if_any = (char *)error_if_any; @@ -360,9 +421,7 @@ static int mgmt_be_send_cfgdata_create_reply(struct mgmt_be_client *client_ctx, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY; be_msg.cfg_data_reply = &cfgdata_reply; - MGMTD_BE_CLIENT_DBG("Sending CFGDATA_CREATE_REPLY txn-id: %" PRIu64 - " batch-id: %" PRIu64, - txn_id, batch_id); + debug_be_client("Sending CFGDATA_CREATE_REPLY txn-id: %" PRIu64, txn_id); return mgmt_be_client_send_msg(client_ctx, &be_msg); } @@ -373,9 +432,8 @@ static void mgmt_be_txn_cfg_abort(struct mgmt_be_txn_ctx *txn) assert(txn && txn->client); if (txn->nb_txn) { - MGMTD_BE_CLIENT_ERR( - "Aborting configs after prep for txn-id: %" PRIu64, - txn->txn_id); + log_err_be_client("Aborting configs after prep for txn-id: %" PRIu64, + txn->txn_id); nb_candidate_commit_abort(txn->nb_txn, errmsg, sizeof(errmsg)); txn->nb_txn = 0; } @@ -386,9 +444,8 @@ static void mgmt_be_txn_cfg_abort(struct mgmt_be_txn_ctx *txn) * This is one txn ctx but the candidate_config is per client ctx, how * does that work? */ - MGMTD_BE_CLIENT_DBG( - "Reset candidate configurations after abort of txn-id: %" PRIu64, - txn->txn_id); + debug_be_client("Reset candidate configurations after abort of txn-id: %" PRIu64, + txn->txn_id); nb_config_replace(txn->client->candidate_config, txn->client->running_config, true); } @@ -433,15 +490,12 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn) client_ctx->candidate_config, txn_req->req.set_cfg.cfg_changes, (size_t)txn_req->req.set_cfg.num_cfg_changes, - NULL, NULL, 0, err_buf, sizeof(err_buf), - &error); + NULL, true, err_buf, sizeof(err_buf), &error); if (error) { err_buf[sizeof(err_buf) - 1] = 0; - MGMTD_BE_CLIENT_ERR( - "Failed to update configs for txn-id: %" PRIu64 - " batch-id: %" PRIu64 - " to candidate, err: '%s'", - txn->txn_id, batch->batch_id, err_buf); + log_err_be_client("Failed to update configs for txn-id: %" PRIu64 + " to candidate, err: '%s'", + txn->txn_id, err_buf); return -1; } gettimeofday(&edit_nb_cfg_end, NULL); @@ -479,21 +533,19 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn) if (err != NB_OK) { err_buf[sizeof(err_buf) - 1] = 0; if (err == NB_ERR_VALIDATION) - MGMTD_BE_CLIENT_ERR( - "Failed to validate configs txn-id: %" PRIu64 - " %zu batches, err: '%s'", - txn->txn_id, num_processed, err_buf); + log_err_be_client("Failed to validate configs txn-id: %" PRIu64 + " %zu batches, err: '%s'", + txn->txn_id, num_processed, err_buf); else - MGMTD_BE_CLIENT_ERR( - "Failed to prepare configs for txn-id: %" PRIu64 - " %zu batches, err: '%s'", - txn->txn_id, num_processed, err_buf); + log_err_be_client("Failed to prepare configs for txn-id: %" PRIu64 + " %zu batches, err: '%s'", + txn->txn_id, num_processed, err_buf); error = true; SET_FLAG(txn->flags, MGMTD_BE_TXN_FLAGS_CFGPREP_FAILED); } else - MGMTD_BE_CLIENT_DBG("Prepared configs for txn-id: %" PRIu64 - " %zu batches", - txn->txn_id, num_processed); + debug_be_client("Prepared configs for txn-id: %" PRIu64 + " %zu batches", + txn->txn_id, num_processed); gettimeofday(&prep_nb_cfg_end, NULL); prep_nb_cfg_tm = timeval_elapsed(prep_nb_cfg_end, prep_nb_cfg_start); @@ -504,9 +556,6 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn) client_ctx->num_prep_nb_cfg++; FOREACH_BE_TXN_BATCH_IN_LIST (txn, batch) { - mgmt_be_send_cfgdata_create_reply( - client_ctx, txn->txn_id, batch->batch_id, - error ? false : true, error ? err_buf : NULL); if (!error) { SET_FLAG(batch->flags, MGMTD_BE_BATCH_FLAGS_CFG_PREPARED); @@ -515,10 +564,12 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn) } } - MGMTD_BE_CLIENT_DBG( - "Avg-nb-edit-duration %lu uSec, nb-prep-duration %lu (avg: %lu) uSec, batch size %u", - client_ctx->avg_edit_nb_cfg_tm, prep_nb_cfg_tm, - client_ctx->avg_prep_nb_cfg_tm, (uint32_t)num_processed); + mgmt_be_send_cfgdata_create_reply(client_ctx, txn->txn_id, + error ? false : true, error ? err_buf : NULL); + + debug_be_client("Avg-nb-edit-duration %lu uSec, nb-prep-duration %lu (avg: %lu) uSec, batch size %u", + client_ctx->avg_edit_nb_cfg_tm, prep_nb_cfg_tm, + client_ctx->avg_prep_nb_cfg_tm, (uint32_t)num_processed); if (error) mgmt_be_txn_cfg_abort(txn); @@ -531,7 +582,6 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn) */ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx, struct mgmt_be_txn_ctx *txn, - uint64_t batch_id, Mgmtd__YangCfgDataReq *cfg_req[], int num_req) { @@ -540,27 +590,39 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx, int index; struct nb_cfg_change *cfg_chg; - batch = mgmt_be_batch_create(txn, batch_id); - if (!batch) { - MGMTD_BE_CLIENT_ERR("Batch create failed!"); - return -1; - } + batch = mgmt_be_batch_create(txn); + assert(batch); txn_req = &batch->txn_req; txn_req->event = MGMTD_BE_TXN_PROC_SETCFG; - MGMTD_BE_CLIENT_DBG("Created SETCFG request for batch-id: %" PRIu64 - " txn-id: %" PRIu64 " cfg-items:%d", - batch_id, txn->txn_id, num_req); + debug_be_client("Created SETCFG request for txn-id: %" PRIu64 + " cfg-items:%d", + txn->txn_id, num_req); txn_req->req.set_cfg.num_cfg_changes = num_req; for (index = 0; index < num_req; index++) { cfg_chg = &txn_req->req.set_cfg.cfg_changes[index]; - if (cfg_req[index]->req_type - == MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA) + /* + * Treat all operations as destroy or modify, because we don't + * need additional existence checks on the backend. Everything + * is already checked by mgmtd. + */ + switch (cfg_req[index]->req_type) { + case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA: + case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA: cfg_chg->operation = NB_OP_DESTROY; - else - cfg_chg->operation = NB_OP_CREATE; + break; + case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA: + case MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA: + case MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA: + cfg_chg->operation = NB_OP_MODIFY; + break; + case MGMTD__CFG_DATA_REQ_TYPE__REQ_TYPE_NONE: + case _MGMTD__CFG_DATA_REQ_TYPE_IS_INT_SIZE: + default: + continue; + } strlcpy(cfg_chg->xpath, cfg_req[index]->data->xpath, sizeof(cfg_chg->xpath)); @@ -584,7 +646,7 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx, } static int mgmt_be_process_cfgdata_req(struct mgmt_be_client *client_ctx, - uint64_t txn_id, uint64_t batch_id, + uint64_t txn_id, Mgmtd__YangCfgDataReq *cfg_req[], int num_req, bool end_of_data) { @@ -594,11 +656,10 @@ static int mgmt_be_process_cfgdata_req(struct mgmt_be_client *client_ctx, if (!txn) goto failed; - mgmt_be_update_setcfg_in_batch(client_ctx, txn, batch_id, cfg_req, - num_req); + mgmt_be_update_setcfg_in_batch(client_ctx, txn, cfg_req, num_req); if (txn && end_of_data) { - MGMTD_BE_CLIENT_DBG("End of data; CFG_PREPARE_REQ processing"); + debug_be_client("End of data; CFG_PREPARE_REQ processing"); if (mgmt_be_txn_cfg_prepare(txn)) goto failed; } @@ -610,8 +671,7 @@ static int mgmt_be_process_cfgdata_req(struct mgmt_be_client *client_ctx, } static int mgmt_be_send_apply_reply(struct mgmt_be_client *client_ctx, - uint64_t txn_id, uint64_t batch_ids[], - size_t num_batch_ids, bool success, + uint64_t txn_id, bool success, const char *error_if_any) { Mgmtd__BeMessage be_msg; @@ -620,8 +680,6 @@ static int mgmt_be_send_apply_reply(struct mgmt_be_client *client_ctx, mgmtd__be_cfg_data_apply_reply__init(&apply_reply); apply_reply.success = success; apply_reply.txn_id = txn_id; - apply_reply.batch_ids = (uint64_t *)batch_ids; - apply_reply.n_batch_ids = num_batch_ids; if (error_if_any) apply_reply.error_if_any = (char *)error_if_any; @@ -630,12 +688,7 @@ static int mgmt_be_send_apply_reply(struct mgmt_be_client *client_ctx, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY; be_msg.cfg_apply_reply = &apply_reply; - MGMTD_BE_CLIENT_DBG( - "Sending CFG_APPLY_REPLY txn-id %" PRIu64 - " %zu batch ids %" PRIu64 " - %" PRIu64, - txn_id, num_batch_ids, - success && num_batch_ids ? batch_ids[0] : 0, - success && num_batch_ids ? batch_ids[num_batch_ids - 1] : 0); + debug_be_client("Sending CFG_APPLY_REPLY txn-id %" PRIu64, txn_id); return mgmt_be_client_send_msg(client_ctx, &be_msg); } @@ -648,14 +701,11 @@ static int mgmt_be_txn_proc_cfgapply(struct mgmt_be_txn_ctx *txn) unsigned long apply_nb_cfg_tm; struct mgmt_be_batch_ctx *batch; char err_buf[BUFSIZ]; - size_t num_processed; - static uint64_t batch_ids[MGMTD_BE_MAX_BATCH_IDS_IN_REQ]; assert(txn && txn->client); client_ctx = txn->client; assert(txn->nb_txn); - num_processed = 0; /* * Now apply all the batches we have applied in one go. @@ -673,9 +723,6 @@ static int mgmt_be_txn_proc_cfgapply(struct mgmt_be_txn_ctx *txn) client_ctx->num_apply_nb_cfg++; txn->nb_txn = NULL; - /* - * Send back CFG_APPLY_REPLY for all batches applied. - */ FOREACH_BE_APPLY_BATCH_IN_LIST (txn, batch) { /* * No need to delete the batch yet. Will be deleted during @@ -684,22 +731,12 @@ static int mgmt_be_txn_proc_cfgapply(struct mgmt_be_txn_ctx *txn) SET_FLAG(batch->flags, MGMTD_BE_TXN_FLAGS_CFG_APPLIED); mgmt_be_batches_del(&txn->apply_cfgs, batch); mgmt_be_batches_add_tail(&txn->cfg_batches, batch); - - batch_ids[num_processed] = batch->batch_id; - num_processed++; - if (num_processed == MGMTD_BE_MAX_BATCH_IDS_IN_REQ) { - mgmt_be_send_apply_reply(client_ctx, txn->txn_id, - batch_ids, num_processed, - true, NULL); - num_processed = 0; - } } - mgmt_be_send_apply_reply(client_ctx, txn->txn_id, batch_ids, - num_processed, true, NULL); + mgmt_be_send_apply_reply(client_ctx, txn->txn_id, true, NULL); - MGMTD_BE_CLIENT_DBG("Nb-apply-duration %lu (avg: %lu) uSec", - apply_nb_cfg_tm, client_ctx->avg_apply_nb_cfg_tm); + debug_be_client("Nb-apply-duration %lu (avg: %lu) uSec", + apply_nb_cfg_tm, client_ctx->avg_apply_nb_cfg_tm); return 0; } @@ -713,7 +750,7 @@ static int mgmt_be_process_cfg_apply(struct mgmt_be_client *client_ctx, if (!txn) goto failed; - MGMTD_BE_CLIENT_DBG("Trigger CFG_APPLY_REQ processing"); + debug_be_client("Trigger CFG_APPLY_REQ processing"); if (mgmt_be_txn_proc_cfgapply(txn)) goto failed; @@ -736,50 +773,45 @@ static int mgmt_be_client_handle_msg(struct mgmt_be_client *client_ctx, */ switch ((int)be_msg->message_case) { case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY: - MGMTD_BE_CLIENT_DBG("Got SUBSCR_REPLY success %u", - be_msg->subscr_reply->success); + debug_be_client("Got SUBSCR_REPLY success %u", + be_msg->subscr_reply->success); + + if (client_ctx->cbs.subscr_done) + (*client_ctx->cbs.subscr_done)(client_ctx, + client_ctx->user_data, + be_msg->subscr_reply + ->success); break; case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ: - MGMTD_BE_CLIENT_DBG("Got TXN_REQ %s txn-id: %" PRIu64, - be_msg->txn_req->create ? "Create" - : "Delete", - be_msg->txn_req->txn_id); + debug_be_client("Got TXN_REQ %s txn-id: %" PRIu64, + be_msg->txn_req->create ? "Create" : "Delete", + be_msg->txn_req->txn_id); mgmt_be_process_txn_req(client_ctx, be_msg->txn_req->txn_id, be_msg->txn_req->create); break; case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ: - MGMTD_BE_CLIENT_DBG("Got CFG_DATA_REQ txn-id: %" PRIu64 - " batch-id: %" PRIu64 " end-of-data %u", - be_msg->cfg_data_req->txn_id, - be_msg->cfg_data_req->batch_id, - be_msg->cfg_data_req->end_of_data); + debug_be_client("Got CFG_DATA_REQ txn-id: %" PRIu64 + " end-of-data %u", + be_msg->cfg_data_req->txn_id, + be_msg->cfg_data_req->end_of_data); mgmt_be_process_cfgdata_req( client_ctx, be_msg->cfg_data_req->txn_id, - be_msg->cfg_data_req->batch_id, be_msg->cfg_data_req->data_req, be_msg->cfg_data_req->n_data_req, be_msg->cfg_data_req->end_of_data); break; case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ: - MGMTD_BE_CLIENT_DBG("Got CFG_APPLY_REQ txn-id: %" PRIu64, - be_msg->cfg_data_req->txn_id); + debug_be_client("Got CFG_APPLY_REQ txn-id: %" PRIu64, + be_msg->cfg_data_req->txn_id); mgmt_be_process_cfg_apply( client_ctx, (uint64_t)be_msg->cfg_apply_req->txn_id); break; - case MGMTD__BE_MESSAGE__MESSAGE_GET_REQ: - MGMTD_BE_CLIENT_ERR("Got unhandled message type %u", - be_msg->message_case); - /* - * TODO: Add handling code in future. - */ - break; /* * NOTE: The following messages are always sent from Backend * clients to MGMTd only and/or need not be handled here. */ case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ: - case MGMTD__BE_MESSAGE__MESSAGE_GET_REPLY: case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY: case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY: case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY: @@ -797,6 +829,307 @@ static int mgmt_be_client_handle_msg(struct mgmt_be_client *client_ctx, return 0; } +struct be_client_tree_data_batch_args { + struct mgmt_be_client *client; + uint64_t txn_id; + uint64_t req_id; + LYD_FORMAT result_type; +}; + +/* + * Process the get-tree request on our local oper state + */ +static enum nb_error be_client_send_tree_data_batch(const struct lyd_node *tree, + void *arg, enum nb_error ret) +{ + struct be_client_tree_data_batch_args *args = arg; + struct mgmt_be_client *client = args->client; + struct mgmt_msg_tree_data *tree_msg = NULL; + bool more = false; + uint8_t **darrp; + LY_ERR err; + + if (ret == NB_YIELD) { + more = true; + ret = NB_OK; + } + if (ret != NB_OK) + goto done; + + tree_msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_tree_data, 0, + MTYPE_MSG_NATIVE_TREE_DATA); + tree_msg->refer_id = args->txn_id; + tree_msg->req_id = args->req_id; + tree_msg->code = MGMT_MSG_CODE_TREE_DATA; + tree_msg->result_type = args->result_type; + tree_msg->more = more; + + darrp = mgmt_msg_native_get_darrp(tree_msg); + err = yang_print_tree_append(darrp, tree, args->result_type, + (LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT | + LYD_PRINT_WITHSIBLINGS)); + if (err) { + ret = NB_ERR; + goto done; + } + (void)be_client_send_native_msg(client, tree_msg, + mgmt_msg_native_get_msg_len(tree_msg), + false); +done: + mgmt_msg_native_free_msg(tree_msg); + if (ret) + be_client_send_error(client, args->txn_id, args->req_id, false, + -EINVAL, + "BE client %s txn-id %" PRIu64 + " error fetching oper state %d", + client->name, args->txn_id, ret); + if (ret != NB_OK || !more) + XFREE(MTYPE_MGMTD_BE_GT_CB_ARGS, args); + return ret; +} + +/* + * Process the get-tree request on our local oper state + */ +static void be_client_handle_get_tree(struct mgmt_be_client *client, + uint64_t txn_id, void *msgbuf, + size_t msg_len) +{ + struct mgmt_msg_get_tree *get_tree_msg = msgbuf; + struct be_client_tree_data_batch_args *args; + + debug_be_client("Received get-tree request for client %s txn-id %" PRIu64 + " req-id %" PRIu64, + client->name, txn_id, get_tree_msg->req_id); + + /* NOTE: removed the translator, if put back merge with northbound_cli + * code + */ + + args = XMALLOC(MTYPE_MGMTD_BE_GT_CB_ARGS, sizeof(*args)); + args->client = client; + args->txn_id = get_tree_msg->refer_id; + args->req_id = get_tree_msg->req_id; + args->result_type = get_tree_msg->result_type; + nb_oper_walk(get_tree_msg->xpath, NULL, 0, true, NULL, NULL, + be_client_send_tree_data_batch, args); +} + +static void be_client_send_rpc_reply(struct mgmt_be_client *client, + uint64_t txn_id, uint64_t req_id, + uint8_t result_type, + struct lyd_node *output) +{ + struct mgmt_msg_rpc_reply *rpc_reply_msg; + uint8_t **darrp; + LY_ERR err; + int ret = NB_OK; + + rpc_reply_msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_rpc_reply, 0, + MTYPE_MSG_NATIVE_RPC_REPLY); + rpc_reply_msg->refer_id = txn_id; + rpc_reply_msg->req_id = req_id; + rpc_reply_msg->code = MGMT_MSG_CODE_RPC_REPLY; + rpc_reply_msg->result_type = result_type; + + if (output) { + darrp = mgmt_msg_native_get_darrp(rpc_reply_msg); + err = yang_print_tree_append(darrp, output, result_type, + LYD_PRINT_SHRINK); + lyd_free_all(output); + if (err) { + ret = NB_ERR; + goto done; + } + } + + (void)be_client_send_native_msg(client, rpc_reply_msg, + mgmt_msg_native_get_msg_len( + rpc_reply_msg), + false); +done: + mgmt_msg_native_free_msg(rpc_reply_msg); + if (ret != NB_OK) + be_client_send_error(client, txn_id, req_id, false, -EINVAL, + "Can't format RPC reply"); +} + +/* + * Process the RPC request. + */ +static void be_client_handle_rpc(struct mgmt_be_client *client, uint64_t txn_id, + void *msgbuf, size_t msg_len) +{ + struct mgmt_msg_rpc *rpc_msg = msgbuf; + struct nb_node *nb_node; + struct lyd_node *input, *output; + const char *xpath; + const char *data; + char errmsg[BUFSIZ] = { 0 }; + LY_ERR err; + int ret; + + debug_be_client("Received RPC request for client %s txn-id %" PRIu64 + " req-id %" PRIu64, + client->name, txn_id, rpc_msg->req_id); + + xpath = mgmt_msg_native_xpath_data_decode(rpc_msg, msg_len, data); + if (!xpath) { + be_client_send_error(client, txn_id, rpc_msg->req_id, false, + -EINVAL, "Corrupt RPC message"); + return; + } + + nb_node = nb_node_find(xpath); + if (!nb_node) { + be_client_send_error(client, txn_id, rpc_msg->req_id, false, + -EINVAL, "No schema found for RPC: %s", + xpath); + return; + } + + if (!nb_node->cbs.rpc) { + be_client_send_error(client, txn_id, rpc_msg->req_id, false, + -EINVAL, "No RPC callback for: %s", xpath); + return; + } + + if (data) { + err = yang_parse_rpc(xpath, rpc_msg->request_type, data, false, + &input); + if (err) { + be_client_send_error(client, txn_id, rpc_msg->req_id, + false, -EINVAL, + "Can't parse RPC data for: %s", + xpath); + return; + } + } else { + /* + * If there's no input data, create an empty input container. + * It is especially needed for actions, because their parents + * may hold necessary information. + */ + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, 0, + NULL, &input); + if (err) { + be_client_send_error(client, txn_id, rpc_msg->req_id, + false, -EINVAL, + "Can't create input node for RPC: %s", + xpath); + return; + } + } + + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, 0, NULL, + &output); + if (err) { + lyd_free_all(input); + be_client_send_error(client, txn_id, rpc_msg->req_id, false, + -EINVAL, + "Can't create output node for RPC: %s", + xpath); + return; + } + + ret = nb_callback_rpc(nb_node, xpath, input, output, errmsg, + sizeof(errmsg)); + if (ret != NB_OK) { + lyd_free_all(input); + lyd_free_all(output); + be_client_send_error(client, txn_id, rpc_msg->req_id, false, + -EINVAL, "%s", errmsg); + return; + } + + lyd_free_all(input); + if (!lyd_child(output)) { + lyd_free_all(output); + output = NULL; + } + + be_client_send_rpc_reply(client, txn_id, rpc_msg->req_id, + rpc_msg->request_type, output); +} + +/* + * Process the notification. + */ +static void be_client_handle_notify(struct mgmt_be_client *client, void *msgbuf, + size_t msg_len) +{ + struct mgmt_msg_notify_data *notif_msg = msgbuf; + struct nb_node *nb_node; + struct lyd_node *dnode; + const char *data = NULL; + const char *notif; + LY_ERR err; + + debug_be_client("Received notification for client %s", client->name); + + notif = mgmt_msg_native_xpath_data_decode(notif_msg, msg_len, data); + if (!notif || !data) { + log_err_be_client("Corrupt notify msg"); + return; + } + + nb_node = nb_node_find(notif); + if (!nb_node) { + log_err_be_client("No schema found for notification: %s", notif); + return; + } + + if (!nb_node->cbs.notify) { + debug_be_client("No notification callback for: %s", notif); + return; + } + + err = yang_parse_notification(notif, notif_msg->result_type, data, + &dnode); + if (err) { + log_err_be_client("Can't parse notification data for: %s", + notif); + return; + } + + nb_callback_notify(nb_node, notif, dnode); + + lyd_free_all(dnode); +} + +/* + * Handle a native encoded message + * + * We don't create transactions with native messaging. + */ +static void be_client_handle_native_msg(struct mgmt_be_client *client, + struct mgmt_msg_header *msg, + size_t msg_len) +{ + uint64_t txn_id = msg->refer_id; + + switch (msg->code) { + case MGMT_MSG_CODE_GET_TREE: + be_client_handle_get_tree(client, txn_id, msg, msg_len); + break; + case MGMT_MSG_CODE_RPC: + be_client_handle_rpc(client, txn_id, msg, msg_len); + break; + case MGMT_MSG_CODE_NOTIFY: + be_client_handle_notify(client, msg, msg_len); + break; + default: + log_err_be_client("unknown native message txn-id %" PRIu64 + " req-id %" PRIu64 " code %u to client %s", + txn_id, msg->req_id, msg->code, client->name); + be_client_send_error(client, msg->refer_id, msg->req_id, false, + -1, + "BE client %s recv msg unknown txn-id %" PRIu64, + client->name, txn_id); + break; + } +} + static void mgmt_be_client_process_msg(uint8_t version, uint8_t *data, size_t len, struct msg_conn *conn) { @@ -807,43 +1140,56 @@ static void mgmt_be_client_process_msg(uint8_t version, uint8_t *data, client = container_of(conn, struct msg_client, conn); client_ctx = container_of(client, struct mgmt_be_client, client); + if (version == MGMT_MSG_VERSION_NATIVE) { + struct mgmt_msg_header *msg = (typeof(msg))data; + + if (len >= sizeof(*msg)) + be_client_handle_native_msg(client_ctx, msg, len); + else + log_err_be_client("native message to client %s too short %zu", + client_ctx->name, len); + return; + } + be_msg = mgmtd__be_message__unpack(NULL, len, data); if (!be_msg) { - MGMTD_BE_CLIENT_DBG("Failed to decode %zu bytes from server", - len); + debug_be_client("Failed to decode %zu bytes from server", len); return; } - MGMTD_BE_CLIENT_DBG( - "Decoded %zu bytes of message(msg: %u/%u) from server", len, - be_msg->message_case, be_msg->message_case); + debug_be_client("Decoded %zu bytes of message(msg: %u/%u) from server", + len, be_msg->message_case, be_msg->message_case); (void)mgmt_be_client_handle_msg(client_ctx, be_msg); mgmtd__be_message__free_unpacked(be_msg, NULL); } int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx, - bool subscr_xpaths, int num_xpaths, - char **reg_xpaths) + int n_config_xpaths, char **config_xpaths, + int n_oper_xpaths, char **oper_xpaths) { Mgmtd__BeMessage be_msg; Mgmtd__BeSubscribeReq subscr_req; mgmtd__be_subscribe_req__init(&subscr_req); subscr_req.client_name = client_ctx->name; - subscr_req.n_xpath_reg = num_xpaths; - if (num_xpaths) - subscr_req.xpath_reg = reg_xpaths; - else - subscr_req.xpath_reg = NULL; - subscr_req.subscribe_xpaths = subscr_xpaths; + subscr_req.n_config_xpaths = n_config_xpaths; + subscr_req.config_xpaths = config_xpaths; + subscr_req.n_oper_xpaths = n_oper_xpaths; + subscr_req.oper_xpaths = oper_xpaths; + + /* See if we should register for notifications */ + subscr_req.n_notif_xpaths = client_ctx->cbs.nnotif_xpaths; + subscr_req.notif_xpaths = (char **)client_ctx->cbs.notif_xpaths; + + subscr_req.n_rpc_xpaths = client_ctx->cbs.nrpc_xpaths; + subscr_req.rpc_xpaths = (char **)client_ctx->cbs.rpc_xpaths; mgmtd__be_message__init(&be_msg); be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ; be_msg.subscr_req = &subscr_req; - MGMTD_FE_CLIENT_DBG( - "Sending SUBSCR_REQ name: %s subscr_xpaths: %u num_xpaths: %zu", - subscr_req.client_name, subscr_req.subscribe_xpaths, - subscr_req.n_xpath_reg); + debug_be_client("Sending SUBSCR_REQ name: %s xpaths: config %zu oper: %zu notif: %zu", + subscr_req.client_name, subscr_req.n_config_xpaths, + subscr_req.n_oper_xpaths, subscr_req.n_notif_xpaths); return mgmt_be_client_send_msg(client_ctx, &be_msg); } @@ -857,15 +1203,16 @@ static int _notify_conenct_disconnect(struct msg_client *msg_client, if (connected) { assert(msg_client->conn.fd != -1); - ret = mgmt_be_send_subscr_req(client, false, 0, NULL); + ret = mgmt_be_send_subscr_req(client, 0, NULL, 0, NULL); if (ret) return ret; } /* Notify BE client through registered callback (if any) */ if (client->cbs.client_connect_notify) - (void)(*client->cbs.client_connect_notify)( - client, client->user_data, connected); + (void)(*client->cbs.client_connect_notify)(client, + client->user_data, + connected); /* Cleanup any in-progress TXN on disconnect */ if (!connected) @@ -890,44 +1237,48 @@ static int mgmt_be_client_notify_disconenct(struct msg_conn *conn) * Debug Flags */ -DEFPY(debug_mgmt_client_be, debug_mgmt_client_be_cmd, - "[no] debug mgmt client backend", - NO_STR DEBUG_STR MGMTD_STR - "client\n" - "backend\n") +static void mgmt_debug_client_be_set(uint32_t flags, bool set) { - uint32_t mode = DEBUG_NODE2MODE(vty->node); + DEBUG_FLAGS_SET(&mgmt_dbg_be_client, flags, set); - DEBUG_MODE_SET(&mgmt_dbg_be_client, mode, !no); + if (!__be_client) + return; - return CMD_SUCCESS; + __be_client->client.conn.debug = DEBUG_MODE_CHECK(&mgmt_dbg_be_client, + DEBUG_MODE_ALL); } -static void mgmt_debug_client_be_set_all(uint32_t flags, bool set) +DEFPY(debug_mgmt_client_be, debug_mgmt_client_be_cmd, + "[no] debug mgmt client backend", + NO_STR DEBUG_STR MGMTD_STR "client\n" + "backend\n") { - DEBUG_FLAGS_SET(&mgmt_dbg_be_client, flags, set); + mgmt_debug_client_be_set(DEBUG_NODE2MODE(vty->node), !no); + + return CMD_SUCCESS; } static int mgmt_debug_be_client_config_write(struct vty *vty) { if (DEBUG_MODE_CHECK(&mgmt_dbg_be_client, DEBUG_MODE_CONF)) - vty_out(vty, "debug mgmt client frontend\n"); + vty_out(vty, "debug mgmt client backend\n"); return 1; } void mgmt_debug_be_client_show_debug(struct vty *vty) { - if (MGMTD_DBG_BE_CLIENT_CHECK()) + if (debug_check_be_client()) vty_out(vty, "debug mgmt client backend\n"); } static struct debug_callbacks mgmt_dbg_be_client_cbs = { - .debug_set_all = mgmt_debug_client_be_set_all}; + .debug_set_all = mgmt_debug_client_be_set +}; static struct cmd_node mgmt_dbg_node = { - .name = "mgmt backend client", - .node = DEBUG_NODE, + .name = "debug mgmt client backend", + .node = MGMT_BE_DEBUG_NODE, .prompt = "", .config_write = mgmt_debug_be_client_config_write, }; @@ -937,26 +1288,39 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name, uintptr_t user_data, struct event_loop *event_loop) { - struct mgmt_be_client *client = - XCALLOC(MTYPE_MGMTD_BE_CLIENT, sizeof(*client)); + struct mgmt_be_client *client; + char server_path[MAXPATHLEN]; + + if (__be_client) + return NULL; + + client = XCALLOC(MTYPE_MGMTD_BE_CLIENT, sizeof(*client)); + __be_client = client; /* Only call after frr_init() */ assert(running_config); client->name = XSTRDUP(MTYPE_MGMTD_BE_CLIENT_NAME, client_name); client->running_config = running_config; - client->candidate_config = nb_config_new(NULL); + client->candidate_config = vty_shared_candidate_config; if (cbs) client->cbs = *cbs; mgmt_be_txns_init(&client->txn_head); - msg_client_init(&client->client, event_loop, MGMTD_BE_SERVER_PATH, + + snprintf(server_path, sizeof(server_path), MGMTD_BE_SOCK_NAME); + + msg_client_init(&client->client, event_loop, server_path, mgmt_be_client_notify_conenct, mgmt_be_client_notify_disconenct, mgmt_be_client_process_msg, MGMTD_BE_MAX_NUM_MSG_PROC, - MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MSG_MAX_LEN, false, - "BE-client", MGMTD_DBG_BE_CLIENT_CHECK()); + MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MAX_MSG_LEN, false, + "BE-client", debug_check_be_client()); + + /* Hook to receive notifications */ + hook_register_arg(nb_notification_tree_send, mgmt_be_send_notification, + client); - MGMTD_BE_CLIENT_DBG("Initialized client '%s'", client_name); + debug_be_client("Initialized client '%s'", client_name); return client; } @@ -972,14 +1336,17 @@ void mgmt_be_client_lib_vty_init(void) void mgmt_be_client_destroy(struct mgmt_be_client *client) { - MGMTD_BE_CLIENT_DBG("Destroying MGMTD Backend Client '%s'", - client->name); + assert(client == __be_client); + debug_be_client("Destroying MGMTD Backend Client '%s'", client->name); + + nb_oper_cancel_all_walks(); msg_client_cleanup(&client->client); mgmt_be_cleanup_all_txns(client); mgmt_be_txns_fini(&client->txn_head); - nb_config_free(client->candidate_config); XFREE(MTYPE_MGMTD_BE_CLIENT_NAME, client->name); XFREE(MTYPE_MGMTD_BE_CLIENT, client); + + __be_client = NULL; } diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h index 4ad5ca5957cd..7ad0589bdbcb 100644 --- a/lib/mgmt_be_client.h +++ b/lib/mgmt_be_client.h @@ -14,52 +14,18 @@ extern "C" { #include "northbound.h" #include "mgmt_pb.h" -#include "mgmtd/mgmt_defines.h" - -/*************************************************************** - * Client IDs - ***************************************************************/ - -/* - * Add enum value for each supported component, wrap with - * #ifdef HAVE_COMPONENT - */ -enum mgmt_be_client_id { - MGMTD_BE_CLIENT_ID_MIN = 0, - MGMTD_BE_CLIENT_ID_INIT = -1, -#ifdef HAVE_STATICD - MGMTD_BE_CLIENT_ID_STATICD, -#endif - MGMTD_BE_CLIENT_ID_MAX -}; - -#define FOREACH_MGMTD_BE_CLIENT_ID(id) \ - for ((id) = MGMTD_BE_CLIENT_ID_MIN; \ - (id) < MGMTD_BE_CLIENT_ID_MAX; (id)++) +#include "mgmt_defines.h" /*************************************************************** * Constants ***************************************************************/ -#define MGMTD_BE_CLIENT_ERROR_STRING_MAX_LEN 32 - -#define MGMTD_BE_DEFAULT_CONN_RETRY_INTVL_SEC 5 - -#define MGMTD_BE_MSG_PROC_DELAY_USEC 10 -#define MGMTD_BE_MAX_NUM_MSG_PROC 500 - -#define MGMTD_BE_MSG_WRITE_DELAY_MSEC 1 +#define MGMTD_BE_MAX_NUM_MSG_PROC 500 #define MGMTD_BE_MAX_NUM_MSG_WRITE 1000 +#define MGMTD_BE_MAX_MSG_LEN (64 * 1024) -#define GMGD_BE_MAX_NUM_REQ_ITEMS 64 - -#define MGMTD_BE_MSG_MAX_LEN 16384 - -#define MGMTD_SOCKET_BE_SEND_BUF_SIZE 65535 -#define MGMTD_SOCKET_BE_RECV_BUF_SIZE MGMTD_SOCKET_BE_SEND_BUF_SIZE - -#define MGMTD_MAX_CFG_CHANGES_IN_BATCH \ - ((10 * MGMTD_BE_MSG_MAX_LEN) / \ +#define MGMTD_MAX_CFG_CHANGES_IN_BATCH \ + ((10 * MGMTD_BE_MAX_MSG_LEN) / \ (MGMTD_MAX_XPATH_LEN + MGMTD_MAX_YANG_VALUE_LEN)) /* @@ -68,11 +34,11 @@ enum mgmt_be_client_id { * that gets added to sent message */ #define MGMTD_BE_CFGDATA_PACKING_EFFICIENCY 0.8 -#define MGMTD_BE_CFGDATA_MAX_MSG_LEN \ - (MGMTD_BE_MSG_MAX_LEN * MGMTD_BE_CFGDATA_PACKING_EFFICIENCY) +#define MGMTD_BE_CFGDATA_MAX_MSG_LEN \ + (MGMTD_BE_MAX_MSG_LEN * MGMTD_BE_CFGDATA_PACKING_EFFICIENCY) -#define MGMTD_BE_MAX_BATCH_IDS_IN_REQ \ - (MGMTD_BE_MSG_MAX_LEN - 128) / sizeof(uint64_t) +#define MGMTD_BE_MAX_BATCH_IDS_IN_REQ \ + (MGMTD_BE_MAX_MSG_LEN - 128) / sizeof(uint64_t) #define MGMTD_BE_CONTAINER_NODE_VAL "<>" @@ -94,55 +60,41 @@ struct mgmt_be_client_txn_ctx { * Callbacks: * client_connect_notify: called when connection is made/lost to mgmtd. * txn_notify: called when a txn has been created + * notify_cbs: callbacks for notifications. + * nnotify_cbs: number of notification callbacks. + * */ struct mgmt_be_client_cbs { void (*client_connect_notify)(struct mgmt_be_client *client, uintptr_t usr_data, bool connected); - + void (*subscr_done)(struct mgmt_be_client *client, uintptr_t usr_data, + bool success); void (*txn_notify)(struct mgmt_be_client *client, uintptr_t usr_data, struct mgmt_be_client_txn_ctx *txn_ctx, bool destroyed); + + const char **notif_xpaths; + uint nnotif_xpaths; + const char **rpc_xpaths; + uint nrpc_xpaths; }; /*************************************************************** * Global data exported ***************************************************************/ -extern const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1]; - -static inline const char *mgmt_be_client_id2name(enum mgmt_be_client_id id) -{ - if (id > MGMTD_BE_CLIENT_ID_MAX) - id = MGMTD_BE_CLIENT_ID_MAX; - return mgmt_be_client_names[id]; -} - -static inline enum mgmt_be_client_id -mgmt_be_client_name2id(const char *name) -{ - enum mgmt_be_client_id id; - - FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (!strncmp(mgmt_be_client_names[id], name, - MGMTD_CLIENT_NAME_MAX_LEN)) - return id; - } - - return MGMTD_BE_CLIENT_ID_MAX; -} - extern struct debug mgmt_dbg_be_client; /*************************************************************** * API prototypes ***************************************************************/ -#define MGMTD_BE_CLIENT_DBG(fmt, ...) \ +#define debug_be_client(fmt, ...) \ DEBUGD(&mgmt_dbg_be_client, "BE-CLIENT: %s: " fmt, __func__, \ ##__VA_ARGS__) -#define MGMTD_BE_CLIENT_ERR(fmt, ...) \ +#define log_err_be_client(fmt, ...) \ zlog_err("BE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_DBG_BE_CLIENT_CHECK() \ +#define debug_check_be_client() \ DEBUG_MODE_CHECK(&mgmt_dbg_be_client, DEBUG_MODE_ALL) /** @@ -181,7 +133,7 @@ extern void mgmt_debug_be_client_show_debug(struct vty *vty); * The client object. * * reg_yang_xpaths - * Yang xpath(s) that needs to be [un]-subscribed from/to + * Yang xpath(s) that needs to be subscribed to * * num_xpaths * Number of xpaths @@ -189,9 +141,9 @@ extern void mgmt_debug_be_client_show_debug(struct vty *vty); * Returns: * MGMTD_SUCCESS on success, MGMTD_* otherwise. */ -extern int mgmt_be_send_subscr_req(struct mgmt_be_client *client, - bool subscr_xpaths, int num_xpaths, - char **reg_xpaths); +extern int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx, + int n_config_xpaths, char **config_xpaths, + int n_oper_xpaths, char **oper_xpaths); /* * Destroy backend client and cleanup everything. diff --git a/mgmtd/mgmt_defines.h b/lib/mgmt_defines.h similarity index 63% rename from mgmtd/mgmt_defines.h rename to lib/mgmt_defines.h index 40fa67075d0e..b02341ea4ecf 100644 --- a/mgmtd/mgmt_defines.h +++ b/lib/mgmt_defines.h @@ -11,6 +11,9 @@ #include "yang.h" +#define MGMTD_FE_SOCK_NAME "%s/mgmtd_fe.sock", frr_runstatedir +#define MGMTD_BE_SOCK_NAME "%s/mgmtd_be.sock", frr_runstatedir + #define MGMTD_CLIENT_NAME_MAX_LEN 32 #define MGMTD_MAX_XPATH_LEN XPATH_MAXLEN @@ -32,27 +35,4 @@ enum mgmt_result { MGMTD_UNKNOWN_FAILURE }; -enum mgmt_fe_event { - MGMTD_FE_SERVER = 1, - MGMTD_FE_CONN_READ, - MGMTD_FE_CONN_WRITE, - MGMTD_FE_PROC_MSG -}; - -enum mgmt_be_event { - MGMTD_BE_SERVER = 1, - MGMTD_BE_CONN_INIT, - MGMTD_BE_CONN_READ, - MGMTD_BE_CONN_WRITE, - MGMTD_BE_PROC_MSG, - MGMTD_BE_SCHED_CFG_PREPARE, - MGMTD_BE_RESCHED_CFG_PREPARE, - MGMTD_BE_SCHED_CFG_APPLY, - MGMTD_BE_RESCHED_CFG_APPLY, -}; - -#define MGMTD_TXN_ID_NONE 0 - -#define MGMTD_TXN_BATCH_ID_NONE 0 - #endif /* _FRR_MGMTD_DEFINES_H */ diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c index 7e42e1c09e5e..8cfb025f7225 100644 --- a/lib/mgmt_fe_client.c +++ b/lib/mgmt_fe_client.c @@ -12,6 +12,7 @@ #include "libfrr.h" #include "mgmt_fe_client.h" #include "mgmt_msg.h" +#include "mgmt_msg_native.h" #include "mgmt_pb.h" #include "network.h" #include "stream.h" @@ -47,8 +48,12 @@ struct mgmt_fe_client { #define FOREACH_SESSION_IN_LIST(client, session) \ frr_each_safe (mgmt_sessions, &(client)->sessions, (session)) -struct debug mgmt_dbg_fe_client = {0, "Management frontend client operations"}; +struct debug mgmt_dbg_fe_client = { + .desc = "Management frontend client operations" +}; +/* NOTE: only one client per proc for now. */ +static struct mgmt_fe_client *__fe_client; static inline const char *dsid2name(Mgmtd__DatastoreId id) { @@ -74,14 +79,13 @@ mgmt_fe_find_session_by_client_id(struct mgmt_fe_client *client, FOREACH_SESSION_IN_LIST (client, session) { if (session->client_id == client_id) { - MGMTD_FE_CLIENT_DBG("Found session-id %" PRIu64 - " using client-id %" PRIu64, - session->session_id, client_id); + debug_fe_client("Found session-id %" PRIu64 + " using client-id %" PRIu64, + session->session_id, client_id); return session; } } - MGMTD_FE_CLIENT_DBG("Session not found using client-id %" PRIu64, - client_id); + debug_fe_client("Session not found using client-id %" PRIu64, client_id); return NULL; } @@ -93,15 +97,14 @@ mgmt_fe_find_session_by_session_id(struct mgmt_fe_client *client, FOREACH_SESSION_IN_LIST (client, session) { if (session->session_id == session_id) { - MGMTD_FE_CLIENT_DBG( - "Found session of client-id %" PRIu64 - " using session-id %" PRIu64, - session->client_id, session_id); + debug_fe_client("Found session of client-id %" PRIu64 + " using session-id %" PRIu64, + session->client_id, session_id); return session; } } - MGMTD_FE_CLIENT_DBG("Session not found using session-id %" PRIu64, - session_id); + debug_fe_client("Session not found using session-id %" PRIu64, + session_id); return NULL; } @@ -128,8 +131,7 @@ static int mgmt_fe_send_register_req(struct mgmt_fe_client *client) fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ; fe_msg.register_req = &rgstr_req; - MGMTD_FE_CLIENT_DBG( - "Sending REGISTER_REQ message to MGMTD Frontend server"); + debug_fe_client("Sending REGISTER_REQ message to MGMTD Frontend server"); return mgmt_fe_client_send_msg(client, &fe_msg, true); } @@ -155,9 +157,8 @@ static int mgmt_fe_send_session_req(struct mgmt_fe_client *client, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ; fe_msg.session_req = &sess_req; - MGMTD_FE_CLIENT_DBG( - "Sending SESSION_REQ %s message for client-id %" PRIu64, - create ? "create" : "destroy", session->client_id); + debug_fe_client("Sending SESSION_REQ %s message for client-id %" PRIu64, + create ? "create" : "destroy", session->client_id); return mgmt_fe_client_send_msg(client, &fe_msg, true); } @@ -180,9 +181,8 @@ int mgmt_fe_send_lockds_req(struct mgmt_fe_client *client, uint64_t session_id, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ; fe_msg.lockds_req = &lockds_req; - MGMTD_FE_CLIENT_DBG( - "Sending LOCKDS_REQ (%sLOCK) message for DS:%s session-id %" PRIu64, - lock ? "" : "UN", dsid2name(ds_id), session_id); + debug_fe_client("Sending LOCKDS_REQ (%sLOCK) message for DS:%s session-id %" PRIu64, + lock ? "" : "UN", dsid2name(ds_id), session_id); return mgmt_fe_client_send_msg(client, &fe_msg, scok); @@ -210,10 +210,9 @@ int mgmt_fe_send_setcfg_req(struct mgmt_fe_client *client, uint64_t session_id, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ; fe_msg.setcfg_req = &setcfg_req; - MGMTD_FE_CLIENT_DBG( - "Sending SET_CONFIG_REQ message for DS:%s session-id %" PRIu64 - " (#xpaths:%d)", - dsid2name(ds_id), session_id, num_data_reqs); + debug_fe_client("Sending SET_CONFIG_REQ message for DS:%s session-id %" PRIu64 + " (#xpaths:%d)", + dsid2name(ds_id), session_id, num_data_reqs); return mgmt_fe_client_send_msg(client, &fe_msg, false); } @@ -240,9 +239,8 @@ int mgmt_fe_send_commitcfg_req(struct mgmt_fe_client *client, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ; fe_msg.commcfg_req = &commitcfg_req; - MGMTD_FE_CLIENT_DBG( - "Sending COMMIT_CONFIG_REQ message for Src-DS:%s, Dst-DS:%s session-id %" PRIu64, - dsid2name(src_ds_id), dsid2name(dest_ds_id), session_id); + debug_fe_client("Sending COMMIT_CONFIG_REQ message for Src-DS:%s, Dst-DS:%s session-id %" PRIu64, + dsid2name(src_ds_id), dsid2name(dest_ds_id), session_id); return mgmt_fe_client_send_msg(client, &fe_msg, false); } @@ -268,10 +266,9 @@ int mgmt_fe_send_get_req(struct mgmt_fe_client *client, uint64_t session_id, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GET_REQ; fe_msg.get_req = &getcfg_req; - MGMTD_FE_CLIENT_DBG("Sending GET_REQ (iscfg %d) message for DS:%s session-id %" PRIu64 - " (#xpaths:%d)", - is_config, dsid2name(ds_id), session_id, - num_data_reqs); + debug_fe_client("Sending GET_REQ (iscfg %d) message for DS:%s session-id %" PRIu64 + " (#xpaths:%d)", + is_config, dsid2name(ds_id), session_id, num_data_reqs); return mgmt_fe_client_send_msg(client, &fe_msg, false); } @@ -300,6 +297,96 @@ int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client, return mgmt_fe_client_send_msg(client, &fe_msg, false); } +/* + * Send get-data request. + */ +int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, + uint64_t session_id, uint64_t req_id, + uint8_t datastore, LYD_FORMAT result_type, + uint8_t flags, uint8_t defaults, const char *xpath) +{ + struct mgmt_msg_get_data *msg; + size_t xplen = strlen(xpath); + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_get_data, xplen + 1, + MTYPE_MSG_NATIVE_GET_DATA); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_GET_DATA; + msg->result_type = result_type; + msg->flags = flags; + msg->defaults = defaults; + msg->datastore = datastore; + strlcpy(msg->xpath, xpath, xplen + 1); + + debug_fe_client("Sending GET_DATA_REQ session-id %" PRIu64 + " req-id %" PRIu64 " xpath: %s", + session_id, req_id, xpath); + + ret = mgmt_msg_native_send_msg(&client->client.conn, msg, false); + mgmt_msg_native_free_msg(msg); + return ret; +} + +int mgmt_fe_send_edit_req(struct mgmt_fe_client *client, uint64_t session_id, + uint64_t req_id, uint8_t datastore, + LYD_FORMAT request_type, uint8_t flags, + uint8_t operation, const char *xpath, const char *data) +{ + struct mgmt_msg_edit *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_edit, 0, + MTYPE_MSG_NATIVE_EDIT); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_EDIT; + msg->request_type = request_type; + msg->flags = flags; + msg->datastore = datastore; + msg->operation = operation; + + mgmt_msg_native_xpath_encode(msg, xpath); + if (data) + mgmt_msg_native_append(msg, data, strlen(data) + 1); + + debug_fe_client("Sending EDIT_REQ session-id %" PRIu64 + " req-id %" PRIu64 " xpath: %s", + session_id, req_id, xpath); + + ret = mgmt_msg_native_send_msg(&client->client.conn, msg, false); + mgmt_msg_native_free_msg(msg); + return ret; +} + +int mgmt_fe_send_rpc_req(struct mgmt_fe_client *client, uint64_t session_id, + uint64_t req_id, LYD_FORMAT request_type, + const char *xpath, const char *data) +{ + struct mgmt_msg_rpc *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_rpc, 0, + MTYPE_MSG_NATIVE_RPC); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_RPC; + msg->request_type = request_type; + + mgmt_msg_native_xpath_encode(msg, xpath); + if (data) + mgmt_msg_native_append(msg, data, strlen(data) + 1); + + debug_fe_client("Sending RPC_REQ session-id %" PRIu64 " req-id %" PRIu64 + " xpath: %s", + session_id, req_id, xpath); + + ret = mgmt_msg_native_send_msg(&client->client.conn, msg, false); + mgmt_msg_native_free_msg(msg); + return ret; +} + static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, Mgmtd__FeMessage *fe_msg) { @@ -313,30 +400,28 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY: if (fe_msg->session_reply->create && fe_msg->session_reply->has_client_conn_id) { - MGMTD_FE_CLIENT_DBG( - "Got SESSION_REPLY (create) for client-id %" PRIu64 - " with session-id: %" PRIu64, - fe_msg->session_reply->client_conn_id, - fe_msg->session_reply->session_id); + debug_fe_client("Got SESSION_REPLY (create) for client-id %" PRIu64 + " with session-id: %" PRIu64, + fe_msg->session_reply->client_conn_id, + fe_msg->session_reply->session_id); session = mgmt_fe_find_session_by_client_id( client, fe_msg->session_reply->client_conn_id); if (session && fe_msg->session_reply->success) { - MGMTD_FE_CLIENT_DBG( - "Session Created for client-id %" PRIu64, - fe_msg->session_reply->client_conn_id); + debug_fe_client("Session Created for client-id %" PRIu64, + fe_msg->session_reply + ->client_conn_id); session->session_id = fe_msg->session_reply->session_id; } else { - MGMTD_FE_CLIENT_ERR( + log_err_fe_client( "Session Create failed for client-id %" PRIu64, fe_msg->session_reply->client_conn_id); } } else if (!fe_msg->session_reply->create) { - MGMTD_FE_CLIENT_DBG( - "Got SESSION_REPLY (destroy) for session-id %" PRIu64, - fe_msg->session_reply->session_id); + debug_fe_client("Got SESSION_REPLY (destroy) for session-id %" PRIu64, + fe_msg->session_reply->session_id); session = mgmt_fe_find_session_by_session_id( client, fe_msg->session_req->session_id); @@ -353,8 +438,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, session->user_ctx); break; case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY: - MGMTD_FE_CLIENT_DBG("Got LOCKDS_REPLY for session-id %" PRIu64, - fe_msg->lockds_reply->session_id); + debug_fe_client("Got LOCKDS_REPLY for session-id %" PRIu64, + fe_msg->lockds_reply->session_id); session = mgmt_fe_find_session_by_session_id( client, fe_msg->lockds_reply->session_id); @@ -370,8 +455,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, fe_msg->lockds_reply->error_if_any); break; case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY: - MGMTD_FE_CLIENT_DBG("Got SETCFG_REPLY for session-id %" PRIu64, - fe_msg->setcfg_reply->session_id); + debug_fe_client("Got SETCFG_REPLY for session-id %" PRIu64, + fe_msg->setcfg_reply->session_id); session = mgmt_fe_find_session_by_session_id( client, fe_msg->setcfg_reply->session_id); @@ -388,8 +473,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, fe_msg->setcfg_reply->error_if_any); break; case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY: - MGMTD_FE_CLIENT_DBG("Got COMMCFG_REPLY for session-id %" PRIu64, - fe_msg->commcfg_reply->session_id); + debug_fe_client("Got COMMCFG_REPLY for session-id %" PRIu64, + fe_msg->commcfg_reply->session_id); session = mgmt_fe_find_session_by_session_id( client, fe_msg->commcfg_reply->session_id); @@ -408,8 +493,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, fe_msg->commcfg_reply->error_if_any); break; case MGMTD__FE_MESSAGE__MESSAGE_GET_REPLY: - MGMTD_FE_CLIENT_DBG("Got GET_REPLY for session-id %" PRIu64, - fe_msg->get_reply->session_id); + debug_fe_client("Got GET_REPLY for session-id %" PRIu64, + fe_msg->get_reply->session_id); session = mgmt_fe_find_session_by_session_id(client, @@ -465,6 +550,152 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client, return 0; } +/* + * Handle a native encoded message + */ +static void fe_client_handle_native_msg(struct mgmt_fe_client *client, + struct mgmt_msg_header *msg, + size_t msg_len) +{ + struct mgmt_fe_client_session *session = NULL; + struct mgmt_msg_notify_data *notify_msg; + struct mgmt_msg_tree_data *tree_msg; + struct mgmt_msg_edit_reply *edit_msg; + struct mgmt_msg_rpc_reply *rpc_msg; + struct mgmt_msg_error *err_msg; + const char *xpath = NULL; + const char *data = NULL; + size_t dlen; + + debug_fe_client("Got native message for session-id %" PRIu64, + msg->refer_id); + + session = mgmt_fe_find_session_by_session_id(client, msg->refer_id); + if (!session || !session->client) { + log_err_fe_client("No session for received native msg session-id %" PRIu64, + msg->refer_id); + return; + } + + switch (msg->code) { + case MGMT_MSG_CODE_ERROR: + if (!session->client->cbs.error_notify) + return; + + err_msg = (typeof(err_msg))msg; + if (!MGMT_MSG_VALIDATE_NUL_TERM(err_msg, msg_len)) { + log_err_fe_client("Corrupt error msg recv"); + return; + } + session->client->cbs.error_notify(client, client->user_data, + session->client_id, + msg->refer_id, + session->user_ctx, + msg->req_id, err_msg->error, + err_msg->errstr); + break; + case MGMT_MSG_CODE_TREE_DATA: + if (!session->client->cbs.get_tree_notify) + return; + + tree_msg = (typeof(tree_msg))msg; + if (msg_len < sizeof(*tree_msg)) { + log_err_fe_client("Corrupt tree-data msg recv"); + return; + } + session->client->cbs.get_tree_notify(client, client->user_data, + session->client_id, + msg->refer_id, + session->user_ctx, + msg->req_id, + MGMTD_DS_OPERATIONAL, + tree_msg->result_type, + tree_msg->result, + msg_len - sizeof(*tree_msg), + tree_msg->partial_error); + break; + case MGMT_MSG_CODE_EDIT_REPLY: + if (!session->client->cbs.edit_notify) + return; + + edit_msg = (typeof(edit_msg))msg; + if (msg_len < sizeof(*edit_msg)) { + log_err_fe_client("Corrupt edit-reply msg recv"); + return; + } + + xpath = mgmt_msg_native_xpath_decode(edit_msg, msg_len); + if (!xpath) { + log_err_fe_client("Corrupt edit-reply msg recv"); + return; + } + + session->client->cbs.edit_notify(client, client->user_data, + session->client_id, + msg->refer_id, + session->user_ctx, msg->req_id, + xpath); + break; + case MGMT_MSG_CODE_RPC_REPLY: + if (!session->client->cbs.rpc_notify) + return; + + rpc_msg = (typeof(rpc_msg))msg; + if (msg_len < sizeof(*rpc_msg)) { + log_err_fe_client("Corrupt rpc-reply msg recv"); + return; + } + dlen = msg_len - sizeof(*rpc_msg); + + session->client->cbs.rpc_notify(client, client->user_data, + session->client_id, + msg->refer_id, + session->user_ctx, msg->req_id, + dlen ? rpc_msg->data : NULL); + break; + case MGMT_MSG_CODE_NOTIFY: + if (!session->client->cbs.async_notification) + return; + + notify_msg = (typeof(notify_msg))msg; + if (msg_len < sizeof(*notify_msg)) { + log_err_fe_client("Corrupt notify-data msg recv"); + return; + } + + data = mgmt_msg_native_data_decode(notify_msg, msg_len); + if (!data) { + log_err_fe_client("Corrupt error msg recv"); + return; + } + dlen = mgmt_msg_native_data_len_decode(notify_msg, msg_len); + if (notify_msg->result_type != LYD_JSON) + data = yang_convert_lyd_format(data, dlen, + notify_msg->result_type, + LYD_JSON, true); + if (!data) { + log_err_fe_client("Can't convert format %d to JSON", + notify_msg->result_type); + return; + } + + session->client->cbs.async_notification(client, + client->user_data, + session->client_id, + msg->refer_id, + session->user_ctx, data); + + if (notify_msg->result_type != LYD_JSON) + darr_free(data); + break; + default: + log_err_fe_client("unknown native message session-id %" PRIu64 + " req-id %" PRIu64 " code %u", + msg->refer_id, msg->req_id, msg->code); + break; + } +} + static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data, size_t len, struct msg_conn *conn) { @@ -475,15 +706,24 @@ static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data, msg_client = container_of(conn, struct msg_client, conn); client = container_of(msg_client, struct mgmt_fe_client, client); + if (version == MGMT_MSG_VERSION_NATIVE) { + struct mgmt_msg_header *msg = (typeof(msg))data; + + if (len >= sizeof(*msg)) + fe_client_handle_native_msg(client, msg, len); + else + log_err_fe_client("native message to FE client %s too short %zu", + client->name, len); + return; + } + fe_msg = mgmtd__fe_message__unpack(NULL, len, data); if (!fe_msg) { - MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.", - len); + debug_fe_client("Failed to decode %zu bytes from server.", len); return; } - MGMTD_FE_CLIENT_DBG( - "Decoded %zu bytes of message(msg: %u/%u) from server", len, - fe_msg->message_case, fe_msg->message_case); + debug_fe_client("Decoded %zu bytes of message(msg: %u/%u) from server", + len, fe_msg->message_case, fe_msg->message_case); (void)mgmt_fe_client_handle_msg(client, fe_msg); mgmtd__fe_message__free_unpacked(fe_msg, NULL); } @@ -504,7 +744,7 @@ static int _notify_connect_disconnect(struct msg_client *msg_client, /* Walk list of sessions for this FE client deleting them */ if (!connected && mgmt_sessions_count(&client->sessions)) { - MGMTD_FE_CLIENT_DBG("Cleaning up existing sessions"); + debug_fe_client("Cleaning up existing sessions"); FOREACH_SESSION_IN_LIST (client, session) { assert(session->client); @@ -543,6 +783,16 @@ static int mgmt_fe_client_notify_disconnect(struct msg_conn *conn) return _notify_connect_disconnect(client, false); } +static void mgmt_debug_client_fe_set(uint32_t mode, bool set) +{ + DEBUG_FLAGS_SET(&mgmt_dbg_fe_client, mode, set); + + if (!__fe_client) + return; + + __fe_client->client.conn.debug = DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, + DEBUG_MODE_ALL); +} DEFPY(debug_mgmt_client_fe, debug_mgmt_client_fe_cmd, "[no] debug mgmt client frontend", @@ -550,18 +800,11 @@ DEFPY(debug_mgmt_client_fe, debug_mgmt_client_fe_cmd, "client\n" "frontend\n") { - uint32_t mode = DEBUG_NODE2MODE(vty->node); - - DEBUG_MODE_SET(&mgmt_dbg_fe_client, mode, !no); + mgmt_debug_client_fe_set(DEBUG_NODE2MODE(vty->node), !no); return CMD_SUCCESS; } -static void mgmt_debug_client_fe_set_all(uint32_t flags, bool set) -{ - DEBUG_FLAGS_SET(&mgmt_dbg_fe_client, flags, set); -} - static int mgmt_debug_fe_client_config_write(struct vty *vty) { if (DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_CONF)) @@ -572,16 +815,17 @@ static int mgmt_debug_fe_client_config_write(struct vty *vty) void mgmt_debug_fe_client_show_debug(struct vty *vty) { - if (MGMTD_DBG_FE_CLIENT_CHECK()) + if (debug_check_fe_client()) vty_out(vty, "debug mgmt client frontend\n"); } static struct debug_callbacks mgmt_dbg_fe_client_cbs = { - .debug_set_all = mgmt_debug_client_fe_set_all}; + .debug_set_all = mgmt_debug_client_fe_set +}; static struct cmd_node mgmt_dbg_node = { - .name = "mgmt client frontend", - .node = DEBUG_NODE, + .name = "debug mgmt client frontend", + .node = MGMT_FE_DEBUG_NODE, .prompt = "", .config_write = mgmt_debug_fe_client_config_write, }; @@ -594,8 +838,14 @@ struct mgmt_fe_client *mgmt_fe_client_create(const char *client_name, uintptr_t user_data, struct event_loop *event_loop) { - struct mgmt_fe_client *client = - XCALLOC(MTYPE_MGMTD_FE_CLIENT, sizeof(*client)); + struct mgmt_fe_client *client; + char server_path[MAXPATHLEN]; + + if (__fe_client) + return NULL; + + client = XCALLOC(MTYPE_MGMTD_FE_CLIENT, sizeof(*client)); + __fe_client = client; client->name = XSTRDUP(MTYPE_MGMTD_FE_CLIENT_NAME, client_name); client->user_data = user_data; @@ -604,14 +854,16 @@ struct mgmt_fe_client *mgmt_fe_client_create(const char *client_name, mgmt_sessions_init(&client->sessions); - msg_client_init(&client->client, event_loop, MGMTD_FE_SERVER_PATH, + snprintf(server_path, sizeof(server_path), MGMTD_FE_SOCK_NAME); + + msg_client_init(&client->client, event_loop, server_path, mgmt_fe_client_notify_connect, mgmt_fe_client_notify_disconnect, mgmt_fe_client_process_msg, MGMTD_FE_MAX_NUM_MSG_PROC, - MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN, true, - "FE-client", MGMTD_DBG_FE_CLIENT_CHECK()); + MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MAX_MSG_LEN, true, + "FE-client", debug_check_fe_client()); - MGMTD_FE_CLIENT_DBG("Initialized client '%s'", client_name); + debug_fe_client("Initialized client '%s'", client_name); return client; } @@ -634,6 +886,11 @@ bool mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client) return client->client.conn.is_short_circuit; } +const char *mgmt_fe_client_name(struct mgmt_fe_client *client) +{ + return client->name; +} + /* * Create a new Session for a Frontend Client connection. */ @@ -675,9 +932,8 @@ enum mgmt_result mgmt_fe_destroy_client_session(struct mgmt_fe_client *client, if (session->session_id && mgmt_fe_send_session_req(client, session, false) != 0) - MGMTD_FE_CLIENT_ERR( - "Failed to send session destroy request for the session-id %" PRIu64, - session->session_id); + log_err_fe_client("Failed to send session destroy request for the session-id %" PRIu64, + session->session_id); mgmt_sessions_del(&client->sessions, session); XFREE(MTYPE_MGMTD_FE_SESSION, session); @@ -692,8 +948,9 @@ void mgmt_fe_client_destroy(struct mgmt_fe_client *client) { struct mgmt_fe_client_session *session; - MGMTD_FE_CLIENT_DBG("Destroying MGMTD Frontend Client '%s'", - client->name); + assert(client == __fe_client); + + debug_fe_client("Destroying MGMTD Frontend Client '%s'", client->name); FOREACH_SESSION_IN_LIST (client, session) mgmt_fe_destroy_client_session(client, session->client_id); @@ -702,4 +959,6 @@ void mgmt_fe_client_destroy(struct mgmt_fe_client *client) XFREE(MTYPE_MGMTD_FE_CLIENT_NAME, client->name); XFREE(MTYPE_MGMTD_FE_CLIENT, client); + + __fe_client = NULL; } diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h index 349b7e4cf415..20c87044a5e4 100644 --- a/lib/mgmt_fe_client.h +++ b/lib/mgmt_fe_client.h @@ -14,7 +14,8 @@ extern "C" { #include "mgmt_pb.h" #include "frrevent.h" -#include "mgmtd/mgmt_defines.h" +#include "mgmt_defines.h" +#include "mgmt_msg_native.h" /*************************************************************** * Macros @@ -25,22 +26,11 @@ extern "C" { * connections. */ -#define MGMTD_FE_CLIENT_ERROR_STRING_MAX_LEN 32 - -#define MGMTD_FE_DEFAULT_CONN_RETRY_INTVL_SEC 5 - #define MGMTD_FE_MSG_PROC_DELAY_USEC 10 -#define MGMTD_FE_MAX_NUM_MSG_PROC 500 -#define MGMTD_FE_MSG_WRITE_DELAY_MSEC 1 +#define MGMTD_FE_MAX_NUM_MSG_PROC 500 #define MGMTD_FE_MAX_NUM_MSG_WRITE 100 - -#define GMGD_FE_MAX_NUM_REQ_ITEMS 64 - -#define MGMTD_FE_MSG_MAX_LEN 9000 - -#define MGMTD_SOCKET_FE_SEND_BUF_SIZE 65535 -#define MGMTD_SOCKET_FE_RECV_BUF_SIZE MGMTD_SOCKET_FE_SEND_BUF_SIZE +#define MGMTD_FE_MAX_MSG_LEN (64 * 1024) /*************************************************************** * Data-structures @@ -115,6 +105,38 @@ struct mgmt_fe_client_cbs { uintptr_t user_data, uint64_t req_id, Mgmtd__DatastoreId ds_id, Mgmtd__YangData **yang_data, size_t num_data); + + /* Called when get-tree result is returned */ + int (*get_tree_notify)(struct mgmt_fe_client *client, + uintptr_t user_data, uint64_t client_id, + uint64_t session_id, uintptr_t session_ctx, + uint64_t req_id, Mgmtd__DatastoreId ds_id, + LYD_FORMAT result_type, void *result, size_t len, + int partial_error); + + /* Called when edit result is returned */ + int (*edit_notify)(struct mgmt_fe_client *client, uintptr_t user_data, + uint64_t client_id, uint64_t session_id, + uintptr_t session_ctx, uint64_t req_id, + const char *xpath); + + /* Called when RPC result is returned */ + int (*rpc_notify)(struct mgmt_fe_client *client, uintptr_t user_data, + uint64_t client_id, uint64_t session_id, + uintptr_t session_ctx, uint64_t req_id, + const char *result); + + /* Called with asynchronous notifications from backends */ + int (*async_notification)(struct mgmt_fe_client *client, + uintptr_t user_data, uint64_t client_id, + uint64_t session_id, uintptr_t session_ctx, + const char *result); + + /* Called when new native error is returned */ + int (*error_notify)(struct mgmt_fe_client *client, uintptr_t user_data, + uint64_t client_id, uint64_t session_id, + uintptr_t session_ctx, uint64_t req_id, int error, + const char *errstr); }; extern struct debug mgmt_dbg_fe_client; @@ -123,12 +145,12 @@ extern struct debug mgmt_dbg_fe_client; * API prototypes ***************************************************************/ -#define MGMTD_FE_CLIENT_DBG(fmt, ...) \ +#define debug_fe_client(fmt, ...) \ DEBUGD(&mgmt_dbg_fe_client, "FE-CLIENT: %s: " fmt, __func__, \ ##__VA_ARGS__) -#define MGMTD_FE_CLIENT_ERR(fmt, ...) \ +#define log_err_fe_client(fmt, ...) \ zlog_err("FE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_DBG_FE_CLIENT_CHECK() \ +#define debug_check_fe_client() \ DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_ALL) /* @@ -363,6 +385,110 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client, Mgmtd__YangDataXPath **data_req, int num_reqs); +/* + * Send GET-DATA to MGMTD daemon. + * + * client + * Client object. + * + * session_id + * Client session ID. + * + * req_id + * Client request ID. + * + * datastore + * Datastore for getting data. + * + * result_type + * The LYD_FORMAT of the result. + * + * flags + * Flags to control the behavior of the request. + * + * defaults + * Options to control the reporting of default values. + * + * xpath + * the xpath to get. + * + * Returns: + * 0 on success, otherwise msg_conn_send_msg() return values. + */ +extern int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, + uint64_t session_id, uint64_t req_id, + uint8_t datastore, LYD_FORMAT result_type, + uint8_t flags, uint8_t defaults, + const char *xpath); + +/* + * Send EDIT to MGMTD daemon. + * + * client + * Client object. + * + * session_id + * Client session ID. + * + * req_id + * Client request ID. + * + * datastore + * Datastore for editing. + * + * request_type + * The LYD_FORMAT of the request. + * + * flags + * Flags to control the behavior of the request. + * + * operation + * NB_OP_* operation to perform. + * + * xpath + * the xpath to edit. + * + * data + * the data tree. + * + * Returns: + * 0 on success, otherwise msg_conn_send_msg() return values. + */ +extern int mgmt_fe_send_edit_req(struct mgmt_fe_client *client, + uint64_t session_id, uint64_t req_id, + uint8_t datastore, LYD_FORMAT request_type, + uint8_t flags, uint8_t operation, + const char *xpath, const char *data); + +/* + * Send RPC request to MGMTD daemon. + * + * client + * Client object. + * + * session_id + * Client session ID. + * + * req_id + * Client request ID. + * + * result_type + * The LYD_FORMAT of the result. + * + * xpath + * the xpath of the RPC. + * + * data + * the data tree. + * + * Returns: + * 0 on success, otherwise msg_conn_send_msg() return values. + */ +extern int mgmt_fe_send_rpc_req(struct mgmt_fe_client *client, + uint64_t session_id, uint64_t req_id, + LYD_FORMAT request_type, const char *xpath, + const char *data); + /* * Destroy library and cleanup everything. */ @@ -379,6 +505,17 @@ extern uint mgmt_fe_client_session_count(struct mgmt_fe_client *client); extern bool mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client); +/** + * Get the name of the client + * + * Args: + * The client object. + * + * Return: + * The name of the client. + */ +extern const char *mgmt_fe_client_name(struct mgmt_fe_client *client); + #ifdef __cplusplus } #endif diff --git a/lib/mgmt_msg.c b/lib/mgmt_msg.c index ee5c1008bd0c..aff9af7e8460 100644 --- a/lib/mgmt_msg.c +++ b/lib/mgmt_msg.c @@ -7,12 +7,15 @@ * Copyright (c) 2023, LabN Consulting, L.L.C. */ #include +#include + #include "debug.h" #include "network.h" #include "sockopt.h" #include "stream.h" #include "frrevent.h" #include "mgmt_msg.h" +#include "mgmt_msg_native.h" #define MGMT_MSG_DBG(dbgtag, fmt, ...) \ @@ -84,7 +87,7 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd, */ assert(stream_get_getp(ms->ins) == 0); left = stream_get_endp(ms->ins); - while (left > (long)sizeof(struct mgmt_msg_hdr)) { + while (left > (ssize_t)sizeof(struct mgmt_msg_hdr)) { mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(ms->ins) + total); if (!MGMT_MSG_IS_MARKER(mhdr->marker)) { MGMT_MSG_DBG(dbgtag, "recv corrupt buffer, disconnect"); @@ -99,8 +102,30 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd, mcount++; } - if (!mcount) + if (!mcount) { + /* Didn't manage to read a full message */ + if (mhdr && avail == 0) { + struct stream *news; + /* + * Message was longer than what was left and we have no + * available space to read more in. B/c mcount == 0 the + * message starts at the beginning of the stream so + * therefor the stream is too small to fit the message.. + * Resize the stream to fit. + */ + if (mhdr->len > MGMT_MSG_MAX_MSG_ALLOC_LEN) { + MGMT_MSG_ERR(ms, "corrupt msg len rcvd %u", + mhdr->len); + return MSR_DISCONNECT; + } + news = stream_new(mhdr->len); + stream_put(news, mhdr, left); + stream_set_endp(news, left); + stream_free(ms->ins); + ms->ins = news; + } return MSR_SCHED_STREAM; + } /* * We have read at least one message into the stream, queue it up. @@ -108,7 +133,11 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd, mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(ms->ins) + total); stream_set_endp(ms->ins, total); stream_fifo_push(&ms->inq, ms->ins); - ms->ins = stream_new(ms->max_msg_sz); + if (left < (ssize_t)sizeof(struct mgmt_msg_hdr)) + ms->ins = stream_new(ms->max_msg_sz); + else + /* handle case where message is greater than max */ + ms->ins = stream_new(MAX(ms->max_msg_sz, mhdr->len)); if (left) { stream_put(ms->ins, mhdr, left); stream_set_endp(ms->ins, left); @@ -180,7 +209,7 @@ bool mgmt_msg_procbufs(struct mgmt_msg_state *ms, } /** - * Write data from a onto the socket, using streams that have been queued for + * Write data onto the socket, using streams that have been queued for * sending by mgmt_msg_send_msg. This function should be reschedulable. * * Args: @@ -292,23 +321,26 @@ int mgmt_msg_send_msg(struct mgmt_msg_state *ms, uint8_t version, void *msg, size_t endp, n; size_t mlen = len + sizeof(*mhdr); - if (mlen > ms->max_msg_sz) { - MGMT_MSG_ERR(ms, "Message %zu > max size %zu, dropping", mlen, - ms->max_msg_sz); - return -1; - } + if (mlen > ms->max_msg_sz) + MGMT_MSG_DBG(dbgtag, "Sending large msg size %zu > max size %zu", + mlen, ms->max_msg_sz); if (!ms->outs) { - MGMT_MSG_DBG(dbgtag, "creating new stream for msg len %zu", - len); - ms->outs = stream_new(ms->max_msg_sz); + MGMT_MSG_DBG(dbgtag, "creating new stream for msg len %zu", mlen); + ms->outs = stream_new(MAX(ms->max_msg_sz, mlen)); + } else if (mlen > ms->max_msg_sz && ms->outs->endp == 0) { + /* msg is larger than stream max size get a fit-to-size stream */ + MGMT_MSG_DBG(dbgtag, + "replacing old stream with fit-to-size for msg len %zu", + mlen); + stream_free(ms->outs); + ms->outs = stream_new(mlen); } else if (STREAM_WRITEABLE(ms->outs) < mlen) { - MGMT_MSG_DBG( - dbgtag, - "enq existing stream len %zu and creating new stream for msg len %zu", - STREAM_WRITEABLE(ms->outs), mlen); + MGMT_MSG_DBG(dbgtag, + "enq existing stream len %zu and creating new stream for msg len %zu", + STREAM_WRITEABLE(ms->outs), mlen); stream_fifo_push(&ms->outq, ms->outs); - ms->outs = stream_new(ms->max_msg_sz); + ms->outs = stream_new(MAX(ms->max_msg_sz, mlen)); } else { MGMT_MSG_DBG( dbgtag, @@ -317,6 +349,16 @@ int mgmt_msg_send_msg(struct mgmt_msg_state *ms, uint8_t version, void *msg, } s = ms->outs; + if (dbgtag && version == MGMT_MSG_VERSION_NATIVE) { + struct mgmt_msg_header *native_msg = msg; + + MGMT_MSG_DBG( + dbgtag, + "Sending native msg sess/txn-id %"PRIu64" req-id %"PRIu64" code %u", + native_msg->refer_id, native_msg->req_id, native_msg->code); + + } + /* We have a stream with space, pack the message into it. */ mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(s) + s->endp); mhdr->marker = MGMT_MSG_MARKER(version); @@ -427,6 +469,8 @@ void mgmt_msg_destroy(struct mgmt_msg_state *ms) mgmt_msg_reset_writes(ms); if (ms->ins) stream_free(ms->ins); + if (ms->outs) + stream_free(ms->outs); free(ms->idtag); } @@ -634,13 +678,13 @@ static void msg_client_sched_connect(struct msg_client *client, &client->conn_retry_tmr); } -static bool msg_client_connect_short_circuit(struct msg_client *client) +static int msg_client_connect_short_circuit(struct msg_client *client) { struct msg_conn *server_conn; struct msg_server *server; const char *dbgtag = client->conn.debug ? client->conn.mstate.idtag : NULL; - union sockunion su = {0}; + union sockunion su = {}; int sockets[2]; frr_each (msg_server_list, &msg_servers, server) @@ -648,10 +692,9 @@ static bool msg_client_connect_short_circuit(struct msg_client *client) break; if (!server) { MGMT_MSG_DBG(dbgtag, - "no short-circuit connection available for %s", + "no short-circuit server available yet for %s", client->sopath); - - return false; + return -1; } if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { @@ -659,7 +702,7 @@ static bool msg_client_connect_short_circuit(struct msg_client *client) &client->conn.mstate, "socketpair failed trying to short-circuit connection on %s: %s", client->sopath, safe_strerror(errno)); - return false; + return -1; } /* client side */ @@ -671,6 +714,9 @@ static bool msg_client_connect_short_circuit(struct msg_client *client) /* server side */ memset(&su, 0, sizeof(union sockunion)); server_conn = server->create(sockets[1], &su); + server_conn->debug = DEBUG_MODE_CHECK(server->debug, DEBUG_MODE_ALL) + ? true + : false; client->conn.remote_conn = server_conn; server_conn->remote_conn = &client->conn; @@ -687,7 +733,7 @@ static bool msg_client_connect_short_circuit(struct msg_client *client) client->sopath, client->conn.mstate.idtag, client->conn.fd, server_conn->mstate.idtag, server_conn->fd); - return true; + return 0; } @@ -697,11 +743,12 @@ static void msg_client_connect(struct msg_client *client) struct msg_conn *conn = &client->conn; const char *dbgtag = conn->debug ? conn->mstate.idtag : NULL; - if (!client->short_circuit_ok || - !msg_client_connect_short_circuit(client)) + if (!client->short_circuit_ok) conn->fd = mgmt_msg_connect(client->sopath, MSG_CONN_SEND_BUF_SIZE, MSG_CONN_RECV_BUF_SIZE, dbgtag); + else if (msg_client_connect_short_circuit(client)) + conn->fd = -1; if (conn->fd == -1) /* retry the connection */ @@ -741,7 +788,6 @@ void msg_client_init(struct msg_client *client, struct event_loop *tm, mgmt_msg_init(&conn->mstate, max_read_buf, max_write_buf, max_msg_sz, idtag); - /* XXX maybe just have client kick this off */ /* Start trying to connect to server */ msg_client_sched_connect(client, 0); } @@ -764,8 +810,9 @@ void msg_client_cleanup(struct msg_client *client) static void msg_server_accept(struct event *event) { struct msg_server *server = EVENT_ARG(event); - int fd; + struct msg_conn *conn; union sockunion su; + int fd; if (server->fd < 0) return; @@ -788,7 +835,11 @@ static void msg_server_accept(struct event *event) DEBUGD(server->debug, "Accepted new %s connection", server->idtag); - server->create(fd, &su); + conn = server->create(fd, &su); + if (conn) + conn->debug = DEBUG_MODE_CHECK(server->debug, DEBUG_MODE_ALL) + ? true + : false; } int msg_server_init(struct msg_server *server, const char *sopath, diff --git a/lib/mgmt_msg.h b/lib/mgmt_msg.h index dd7ae59f9162..6bdc9a6cfc3a 100644 --- a/lib/mgmt_msg.h +++ b/lib/mgmt_msg.h @@ -24,6 +24,8 @@ DECLARE_MTYPE(MSG_CONN); #define MGMT_MSG_VERSION_PROTOBUF 0 #define MGMT_MSG_VERSION_NATIVE 1 +/* The absolute maximum message size (16MB) */ +#define MGMT_MSG_MAX_MSG_ALLOC_LEN (16 * 1024 * 1024) struct mgmt_msg_state { struct stream *ins; @@ -136,6 +138,10 @@ struct msg_client { extern void msg_client_cleanup(struct msg_client *client); /* + * If `short_circuit_ok` is true, then the client-server connection will use a + * socketpair() rather than a unix-domain socket. This must be passed true if + * you wish to send messages short-circuit later. + * * `notify_disconnect` is not called when the user `msg_client_cleanup` is * called for a client which is currently connected. The socket is closed * but there is no notification. diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c new file mode 100644 index 000000000000..b85c7d1b6182 --- /dev/null +++ b/lib/mgmt_msg_native.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * June 29 2023, Christian Hopps + * + * Copyright (c) 2023, LabN Consulting, L.L.C. + * + */ +#include +#include "darr.h" +#include "mgmt_msg_native.h" + +DEFINE_MGROUP(MSG_NATIVE, "Native message allocations"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_ERROR, "native error msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_GET_TREE, "native get tree msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_TREE_DATA, "native tree data msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_GET_DATA, "native get data msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_NOTIFY, "native get data msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT, "native edit msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT_REPLY, "native edit reply msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC, "native RPC msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC_REPLY, "native RPC reply msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REQ, "native session-req msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REPLY, "native session-reply msg"); + + +size_t mgmt_msg_min_sizes[] = { + [MGMT_MSG_CODE_ERROR] = sizeof(struct mgmt_msg_error), + [MGMT_MSG_CODE_GET_TREE] = sizeof(struct mgmt_msg_get_tree), + [MGMT_MSG_CODE_TREE_DATA] = sizeof(struct mgmt_msg_tree_data), + [MGMT_MSG_CODE_GET_DATA] = sizeof(struct mgmt_msg_get_data), + [MGMT_MSG_CODE_NOTIFY] = sizeof(struct mgmt_msg_notify_data), + [MGMT_MSG_CODE_EDIT] = sizeof(struct mgmt_msg_edit), + [MGMT_MSG_CODE_EDIT_REPLY] = sizeof(struct mgmt_msg_edit_reply), + [MGMT_MSG_CODE_RPC] = sizeof(struct mgmt_msg_rpc), + [MGMT_MSG_CODE_RPC_REPLY] = sizeof(struct mgmt_msg_rpc_reply), + [MGMT_MSG_CODE_NOTIFY_SELECT] = sizeof(struct mgmt_msg_notify_select), + [MGMT_MSG_CODE_SESSION_REQ] = sizeof(struct mgmt_msg_session_req), + [MGMT_MSG_CODE_SESSION_REPLY] = sizeof(struct mgmt_msg_session_reply), +}; +size_t nmgmt_msg_min_sizes = sizeof(mgmt_msg_min_sizes) / + sizeof(*mgmt_msg_min_sizes); + +size_t mgmt_msg_get_min_size(uint code) +{ + if (code >= nmgmt_msg_min_sizes) + return 0; + return mgmt_msg_min_sizes[code]; +} + +int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, va_list ap) +{ + struct mgmt_msg_error *msg; + char *errstr; + ssize_t slen; + int ret; + + errstr = darr_vsprintf(errfmt, ap); + slen = strlen(errstr); + + msg = mgmt_msg_native_alloc_msg(typeof(*msg), slen + 1, + MTYPE_MSG_NATIVE_ERROR); + msg->refer_id = sess_or_txn_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_ERROR; + msg->error = error; + strlcpy(msg->errstr, errstr, slen + 1); + darr_free(errstr); + + if (conn->debug) + zlog_debug("Sending error %d session-id %" PRIu64 + " req-id %" PRIu64 " scok %d errstr: %s", + error, sess_or_txn_id, req_id, short_circuit_ok, + msg->errstr); + + ret = mgmt_msg_native_send_msg(conn, msg, short_circuit_ok); + mgmt_msg_native_free_msg(msg); + return ret; +} + +const char **_mgmt_msg_native_strings_decode(const void *_sdata, int sdlen) +{ + const char *sdata = _sdata; + const char **strings = NULL; + int len; + + if (sdata[sdlen - 1] != 0) + return NULL; + + for (; sdlen; sdata += len, sdlen -= len) { + *darr_append(strings) = darr_strdup(sdata); + len = 1 + darr_strlen(strings[darr_lasti(strings)]); + } + + return strings; +} diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h new file mode 100644 index 000000000000..76a52658cdee --- /dev/null +++ b/lib/mgmt_msg_native.h @@ -0,0 +1,801 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * June 29 2023, Christian Hopps + * + * Copyright (c) 2023, LabN Consulting, L.L.C. + * + * Public APIs: + * + * The message type codes and corresponding message data definitions for + * front-end client messages represent a public API, as such any changes should + * only be made according to backward compatible principles (basically never, + * just use a new message type). Back-end clients being always compiled with FRR + * can be updated (although one should take care in modifying BE messages as it + * could impact private back-end client implementations which will then need to + * be updated by their owners). + */ + +#ifndef _FRR_MGMT_MSG_NATIVE_H_ +#define _FRR_MGMT_MSG_NATIVE_H_ + +#ifdef __cplusplus +extern "C" { +#elif 0 +} +#endif + +#include +#include "compiler.h" +#include "darr.h" +#include "memory.h" +#include "mgmt_msg.h" +#include "mgmt_defines.h" +#include "northbound.h" + +#include + +/* + * ================== + * Native Message API + * ================== + * + * ----------------------- + * Defining A New Message: + * ----------------------- + * + * 1) Start with `struct mgmt_msg_header` as the first (unnamed) field. + * + * 2) Add fixed-width fields. Add on natural aligned boundaries (*) + * + * 3) [Optional] Add a zero-length variable field. Add aligned on a 64-bit + * boundary, this is done so that: `value = (HDR + 1)` works. + * + * 4) Define a new MTYPE for the new message type (see DECLARE_MTYPE below + * as well as the paired DEFINE_MTYPE in mgmt_msg_native.c) + * + * These rules are so the messages may be read from and written directly to + * "the wire", easily, using common programming languages (e.g., C, rust, go, + * python, ...) + * + * (*) Natrual aligned boundaries, i.e., uint16_t on 2-byte boundary, uint64_t + * on 8-byte boundaries, ...) + * + * ------------------------------ + * Allocating New Native Messages + * ------------------------------ + * + * For fixed-length and variable length messages one should allocate new + * messages with the mgmt_msg_native_alloc_msg() passing in the newly defined + * MTYPE. Likewise, to free the message one should use + * mgmt_msg_native_free_msg(). + * + * Unknown Variable Length Messages: + * --------------------------------- + * + * If using a zero-length variable length field and the length is not known at + * message creation time, you can use the `native` API function + * mgmt_msg_native_append() to add data to the end of the message, or if a more + * full set of operations are required, the darr_xxxx() API is also available as + * in the Advanced section below. + * + * Notable API Functions: + * --------------------------------- + * + * mgmt_msg_native_alloc_msg() - Allocate a native msg. + * mgmt_msg_native_free_msg() - Free a native msg. + * mgmt_msg_native_append() - Append data to the end of the msg. + * mgmt_msg_native_get_msg_len() - Get the total length of the msg. + * mgmt_msg_native_send_msg() - Send the message. + * + * mgmt_msg_native_xpath_encode() - Encode xpath in xpath, data format message. + * mgmt_msg_native_xpath_data_decode() - Decode xpath, data format message. + * mgmt_msg_native_xpath_decode() - Get the xpath, from xpath, data format message. + * mgmt_msg_native_data_decode() - Get the secondary data from xpath, data message. + * mgmt_msg_native_data_len_decode() - Get length of secondary data. + * + * ------------------------------------- + * [Advanced Use] Dynamic Array Messages + * ------------------------------------- + * + * NOTE: Most users can simply use mgmt_msg_native_append() and skip this + * section. + * + * This section is only important to understand if you wish to utilize the fact + * that native messages allocated with mgmt_msg_native_alloc_msg are + * actually allocated as uint8_t dynamic arrays (`darr`). + * + * You can utilize all the darr_xxxx() API to manipulate the variable length + * message data in a native message. To do so you simply need to understand that + * the native message is actually a `uint8_t *` darr. So, for example, to append + * data to the end of a message one could do the following: + * + * void append_metric_path(struct mgmt_msg_my_msg *msg) + * { + * msg = (struct mggm_msg_my_msg *) + * darr_strcat((uint8_t *)msg, "/metric"); + * + * // ... + * } + * + * NOTE: If reallocs happen the original passed in pointer will be updated; + * however, any other pointers into the message will become invalid, and so they + * should always be discarded or reinitialized after using any reallocating + * darr_xxx() API functions. + * + * void append_metric_path(struct mgmt_msg_my_msg *msg) + * { + * char *xpath = msg->xpath; // pointer into message + * + * darr_in_strcat((uint8_t *)msg, "/metric"); + * // msg may have been updated to point at new memory + * + * xpath = NULL; // now invalid + * xpath = msg->xpath; // reinitialize + * // ... + * } + * + * Rather than worry about this, it's typical when using dynamic arrays to always + * work from the main pointer to the dynamic array, rather than caching multiple + * pointers into the data. Modern compilers will optimize the code so that it + * adds no extra execution cost. + * + * void append_metric_path(struct mgmt_msg_my_msg *msg) + * { + * darr_in_strcat((uint8_t *)msg, "/metric"); + * + * // Use `msg->xpath` directly rather creating and using an + * // `xpath = msg->xpath` local variable. + * + * if (strcmp(msg->xpath, "foobar/metric")) { + * // ... + * } + * } + * + */ + +DECLARE_MTYPE(MSG_NATIVE_MSG); +DECLARE_MTYPE(MSG_NATIVE_ERROR); +DECLARE_MTYPE(MSG_NATIVE_GET_TREE); +DECLARE_MTYPE(MSG_NATIVE_TREE_DATA); +DECLARE_MTYPE(MSG_NATIVE_GET_DATA); +DECLARE_MTYPE(MSG_NATIVE_NOTIFY); +DECLARE_MTYPE(MSG_NATIVE_EDIT); +DECLARE_MTYPE(MSG_NATIVE_EDIT_REPLY); +DECLARE_MTYPE(MSG_NATIVE_RPC); +DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REQ); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REPLY); + +/* + * Native message codes + */ +#define MGMT_MSG_CODE_ERROR 0 /* Public API */ +#define MGMT_MSG_CODE_GET_TREE 1 /* BE only, non-public API */ +#define MGMT_MSG_CODE_TREE_DATA 2 /* Public API */ +#define MGMT_MSG_CODE_GET_DATA 3 /* Public API */ +#define MGMT_MSG_CODE_NOTIFY 4 /* Public API */ +#define MGMT_MSG_CODE_EDIT 5 /* Public API */ +#define MGMT_MSG_CODE_EDIT_REPLY 6 /* Public API */ +#define MGMT_MSG_CODE_RPC 7 /* Public API */ +#define MGMT_MSG_CODE_RPC_REPLY 8 /* Public API */ +#define MGMT_MSG_CODE_NOTIFY_SELECT 9 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REQ 10 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REPLY 11 /* Public API */ + +/* + * Datastores + */ +#define MGMT_MSG_DATASTORE_STARTUP 0 +#define MGMT_MSG_DATASTORE_CANDIDATE 1 +#define MGMT_MSG_DATASTORE_RUNNING 2 +#define MGMT_MSG_DATASTORE_OPERATIONAL 3 + +/* + * Formats + */ +#define MGMT_MSG_FORMAT_XML 1 +#define MGMT_MSG_FORMAT_JSON 2 +#define MGMT_MSG_FORMAT_BINARY 3 /* non-standard libyang internal format */ + +/* + * Now we're using LYD_FORMAT directly to avoid mapping code, but having our + * own definitions allows us to create such a mapping in the future if libyang + * makes a backwards incompatible change. + */ +_Static_assert(MGMT_MSG_FORMAT_XML == LYD_XML, "Format mismatch"); +_Static_assert(MGMT_MSG_FORMAT_JSON == LYD_JSON, "Format mismatch"); +_Static_assert(MGMT_MSG_FORMAT_BINARY == LYD_LYB, "Format mismatch"); + +/** + * struct mgmt_msg_header - Header common to all native messages. + * + * @code: the actual type of the message. + * @resv: Set to zero, ignore on receive. + * @vsplit: If a variable section is split in 2, the length of first part. + * @refer_id: the session, txn, conn, etc, this message is associated with. + * @req_id: the request this message is for. + */ +struct mgmt_msg_header { + uint16_t code; + uint16_t resv; + uint32_t vsplit; + uint64_t refer_id; + uint64_t req_id; +}; +_Static_assert(sizeof(struct mgmt_msg_header) == 3 * 8, "Bad padding"); +_Static_assert(sizeof(struct mgmt_msg_header) == + offsetof(struct mgmt_msg_header, req_id) + + sizeof(((struct mgmt_msg_header *)0)->req_id), + "Size mismatch"); + +/** + * struct mgmt_msg_error - Common error message. + * + * @error: An error value. + * @errst: Description of error can be 0 length. + * + * This common error message can be used for replies for many msg requests + * (req_id). + */ +struct mgmt_msg_error { + struct mgmt_msg_header; + int16_t error; + uint8_t resv2[6]; + + alignas(8) char errstr[]; +}; +_Static_assert(sizeof(struct mgmt_msg_error) == + offsetof(struct mgmt_msg_error, errstr), + "Size mismatch"); + +/** + * struct mgmt_msg_get_tree - backend oper data request. + * + * @result_type: ``LYD_FORMAT`` for the returned result. + * @xpath: the query for the data to return. + */ +struct mgmt_msg_get_tree { + struct mgmt_msg_header; + uint8_t result_type; + uint8_t resv2[7]; + + alignas(8) char xpath[]; +}; +_Static_assert(sizeof(struct mgmt_msg_get_tree) == + offsetof(struct mgmt_msg_get_tree, xpath), + "Size mismatch"); + +/** + * struct mgmt_msg_tree_data - Message carrying tree data. + * + * @partial_error: If the full result could not be returned do to this error. + * @result_type: ``LYD_FORMAT`` for format of the @result value. + * @more: if this is a partial return and there will be more coming. + * @result: The tree data in @result_type format. + * + */ +struct mgmt_msg_tree_data { + struct mgmt_msg_header; + int8_t partial_error; + uint8_t result_type; + uint8_t more; + uint8_t resv2[5]; + + alignas(8) uint8_t result[]; +}; +_Static_assert(sizeof(struct mgmt_msg_tree_data) == + offsetof(struct mgmt_msg_tree_data, result), + "Size mismatch"); + +/* Flags for get-data request */ +#define GET_DATA_FLAG_STATE 0x01 /* include "config false" data */ +#define GET_DATA_FLAG_CONFIG 0x02 /* include "config true" data */ +#define GET_DATA_FLAG_EXACT 0x04 /* get exact data node instead of the full tree */ + +/* + * Modes of reporting default values. Non-default values are always reported. + * These options reflect "with-defaults" modes as defined in RFC 6243. + */ +#define GET_DATA_DEFAULTS_EXPLICIT 0 /* "explicit" */ +#define GET_DATA_DEFAULTS_TRIM 1 /* "trim" */ +#define GET_DATA_DEFAULTS_ALL 2 /* "report-all" */ +#define GET_DATA_DEFAULTS_ALL_ADD_TAG 3 /* "report-all-tagged" */ + +/** + * struct mgmt_msg_get_data - frontend get-data request. + * + * @result_type: ``LYD_FORMAT`` for the returned result. + * @flags: combination of ``GET_DATA_FLAG_*`` flags. + * @defaults: one of ``GET_DATA_DEFAULTS_*`` values. + * @xpath: the query for the data to return. + */ +struct mgmt_msg_get_data { + struct mgmt_msg_header; + uint8_t result_type; + uint8_t flags; + uint8_t defaults; + uint8_t datastore; + uint8_t resv2[4]; + + alignas(8) char xpath[]; +}; +_Static_assert(sizeof(struct mgmt_msg_get_data) == + offsetof(struct mgmt_msg_get_data, xpath), + "Size mismatch"); + +/** + * struct mgmt_msg_notify_data - Message carrying notification data. + * + * @result_type: ``LYD_FORMAT`` for format of the @result value. + * @data: The xpath string of the notification followed by the tree data in + * @result_type format. + */ +struct mgmt_msg_notify_data { + struct mgmt_msg_header; + uint8_t result_type; + uint8_t resv2[7]; + + alignas(8) char data[]; +}; +_Static_assert(sizeof(struct mgmt_msg_notify_data) == + offsetof(struct mgmt_msg_notify_data, data), + "Size mismatch"); + +#define EDIT_FLAG_IMPLICIT_LOCK 0x01 +#define EDIT_FLAG_IMPLICIT_COMMIT 0x02 + +#define EDIT_OP_CREATE 0 +#define EDIT_OP_DELETE 4 +#define EDIT_OP_MERGE 2 +#define EDIT_OP_REPLACE 5 +#define EDIT_OP_REMOVE 3 + +_Static_assert(EDIT_OP_CREATE == NB_OP_CREATE_EXCL, "Operation mismatch"); +_Static_assert(EDIT_OP_DELETE == NB_OP_DELETE, "Operation mismatch"); +_Static_assert(EDIT_OP_MERGE == NB_OP_MODIFY, "Operation mismatch"); +_Static_assert(EDIT_OP_REPLACE == NB_OP_REPLACE, "Operation mismatch"); +_Static_assert(EDIT_OP_REMOVE == NB_OP_DESTROY, "Operation mismatch"); + +/** + * struct mgmt_msg_edit - frontend edit request. + * + * @request_type: ``LYD_FORMAT`` for the @data. + * @flags: combination of ``EDIT_FLAG_*`` flags. + * @datastore: the datastore to edit. + * @operation: one of ``EDIT_OP_*`` operations. + * @data: the xpath followed by the tree data for the operation. + * for CREATE, xpath points to the parent node. + */ +struct mgmt_msg_edit { + struct mgmt_msg_header; + uint8_t request_type; + uint8_t flags; + uint8_t datastore; + uint8_t operation; + uint8_t resv2[4]; + + alignas(8) char data[]; +}; +_Static_assert(sizeof(struct mgmt_msg_edit) == + offsetof(struct mgmt_msg_edit, data), + "Size mismatch"); + +/** + * struct mgmt_msg_edit_reply - frontend edit reply. + * + * @data: the xpath of the data node that was created. + */ +struct mgmt_msg_edit_reply { + struct mgmt_msg_header; + uint8_t resv2[8]; + + alignas(8) char data[]; +}; +_Static_assert(sizeof(struct mgmt_msg_edit_reply) == + offsetof(struct mgmt_msg_edit_reply, data), + "Size mismatch"); + +/** + * struct mgmt_msg_rpc - RPC/action request. + * + * @request_type: ``LYD_FORMAT`` for the @data. + * @data: the xpath followed by the tree data for the operation. + */ +struct mgmt_msg_rpc { + struct mgmt_msg_header; + uint8_t request_type; + uint8_t resv2[7]; + + alignas(8) char data[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_rpc) == + offsetof(struct mgmt_msg_rpc, data), + "Size mismatch"); + +/** + * struct mgmt_msg_rpc_reply - RPC/action reply. + * + * @result_type: ``LYD_FORMAT`` for the @data. + * @data: the tree data for the reply. + */ +struct mgmt_msg_rpc_reply { + struct mgmt_msg_header; + uint8_t result_type; + uint8_t resv2[7]; + + alignas(8) char data[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_rpc_reply) == + offsetof(struct mgmt_msg_rpc_reply, data), + "Size mismatch"); + +/** + * struct mgmt_msg_notify_select - Add notification selectors for FE client. + * + * Add xpath prefix notification selectors to limit the notifications sent + * to the front-end client. + * + * @selectors: the xpath prefixes to selectors notifications through. + * @replace: if true replace existing selectors with `selectors`. + */ +struct mgmt_msg_notify_select { + struct mgmt_msg_header; + uint8_t replace; + uint8_t resv2[7]; + + alignas(8) char selectors[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_notify_select) == + offsetof(struct mgmt_msg_notify_select, selectors), + "Size mismatch"); + +/** + * struct mgmt_msg_session_req - Create or delete a front-end session. + * + * @refer_id: Zero for create, otherwise the session-id to delete. + * @req_id: For create will use as client-id. + * @client_name: For first session request the client name, otherwise empty. + */ +struct mgmt_msg_session_req { + struct mgmt_msg_header; + uint8_t resv2[8]; /* bug in compiler produces error w/o this */ + + alignas(8) char client_name[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_session_req) == + offsetof(struct mgmt_msg_session_req, client_name), + "Size mismatch"); + +/** + * struct mgmt_msg_session_reply - Reply to session request message. + * + * @created: true if this is a reply to a create request, otherwise 0. + * @refer_id: The session-id for the action (create or delete) just taken. + */ +struct mgmt_msg_session_reply { + struct mgmt_msg_header; + uint8_t created; + uint8_t resv2[7]; +}; + +/* + * Validate that the message ends in a NUL terminating byte + */ +#define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len) \ + ((len) >= sizeof(*msgp) + 1 && ((char *)msgp)[(len)-1] == 0) + +/** + * mgmt_msg_get_min_size() - Get minimum message size given the type + * @code: The type of the message (MGMT_MSG_CODE_*) + * + * Return: + * The minimum size of a message of the given type or 0 if the message + * code is unknown. + */ +size_t mgmt_msg_get_min_size(uint code); + +/** + * Send a native message error to the other end of the connection. + * + * This function is normally used by the server-side to indicate a failure to + * process a client request. For this server side handling of client messages + * which expect a reply, either that reply or this error should be returned, as + * closing the connection is not allowed during message handling. + * + * Args: + * conn: the connection. + * sess_or_txn_id: Session ID (to FE client) or Txn ID (from BE client) + * req_id: which req_id this error is associated with. + * short_circuit_ok: if short circuit sending is OK. + * error: the error value + * errfmt: vprintfrr style format string + * ap: the variable args for errfmt. + * + * Return: + * The return value of ``msg_conn_send_msg``. + */ +extern int vmgmt_msg_native_send_error(struct msg_conn *conn, + uint64_t sess_or_txn_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errfmt, va_list ap) + PRINTFRR(6, 0); + +/** + * mgmt_msg_native_alloc_msg() - Create a native appendable msg. + * @msg_type: The message structure type. + * @var_len: The initial additional length to add to the message. + * @mem_type: The initial additional length to add to the message. + * + * This function takes a C type (e.g., `struct mgmt_msg_get_tree`) as an + * argument and returns a new native message. The newly allocated message + * can be used with the other `native` functions. + * + * Importantly the mgmt_msg_native_append() function can be used to add data + * to the end of the message, and mgmt_msg_get_native_msg_len() can be used + * to obtain the total length of the message (i.e., the fixed sized header plus + * the variable length data that has been appended). + * + * Additionally, a dynamic array (darr) pointer can be obtained using + * mgmt_msg_get_native_darr() which allows adding and manipulating the + * variable data that follows the fixed sized header. + * + * Return: A `msg_type` object created using a dynamic_array. + */ +#define mgmt_msg_native_alloc_msg(msg_type, var_len, mem_type) \ + ({ \ + uint8_t *buf = NULL; \ + (msg_type *)darr_append_nz_mt(buf, \ + sizeof(msg_type) + (var_len), \ + mem_type); \ + }) + +/** + * mgmt_msg_free_native_msg() - Free a native msg. + * @msg - pointer to message allocated by mgmt_msg_create_native_msg(). + */ +#define mgmt_msg_native_free_msg(msg) darr_free(msg) + +/** + * mgmt_msg_native_get_msg_len() - Get the total length of the msg. + * @msg: the native message. + * + * Return: the total length of the message, fixed + variable length. + */ +#define mgmt_msg_native_get_msg_len(msg) (darr_len((uint8_t *)(msg))) + +/** + * mgmt_msg_native_append() - Append data to the end of the msg. + * @msg: (IN/OUT) Pointer to the native message, variable may be updated. + * @data: data to append. + * @len: length of data to append. + * + * Append @data of length @len to the native message @msg. + * + * NOTE: Be aware @msg pointer may change as a result of reallocating the + * message to fit the new data. Any other pointers into the old message should + * be discarded. + * + * Return: a pointer to the newly appended data. + */ +#define mgmt_msg_native_append(msg, data, len) \ + ({ \ + uint8_t **darrp = mgmt_msg_native_get_darrp(msg); \ + uint8_t *p = darr_append_n(*darrp, len); \ + memcpy(p, data, len); \ + p; \ + }) + +/** + * mgmt_msg_native_add_str() - Append [another] string to the msg. + * @msg: (IN/OUT) Pointer to the native message, variable may be updated. + * @s: string to append. + * + * Append string @s to the native message @msg. @msg is assumed to have a + * sequence of NUL-terminated strings at the end of it. This function appends + * the string @s and it's NUL terminating octet to the message. + * + * NOTE: Be aware @msg pointer may change as a result of reallocating the + * message to fit the new data. Any other pointers into the old message should + * be discarded. + */ +#define mgmt_msg_native_add_str(msg, s) \ + do { \ + int __len = strlen(s) + 1; \ + mgmt_msg_native_append(msg, s, __len); \ + } while (0) + +/** + * mgmt_msg_native_send_msg(msg, short_circuit_ok) - Send a native msg. + * @conn: the mgmt_msg connection. + * @msg: the native message. + * @short_circuit_ok: True if short-circuit sending is required. + * + * Return: The error return value of msg_conn_send_msg(). + */ +#define mgmt_msg_native_send_msg(conn, msg, short_circuit_ok) \ + msg_conn_send_msg(conn, MGMT_MSG_VERSION_NATIVE, msg, \ + mgmt_msg_native_get_msg_len(msg), NULL, \ + short_circuit_ok) + +/** + * mgmt_msg_native_get_darrp() - Return a ptr to the dynamic array ptr. + * @msg: Pointer to the native message. + * + * NOTE: Most users can simply use mgmt_msg_native_append() instead of this. + * + * This function obtains a pointer to the dynamic byte array for this message, + * this array actually includes the message header if one is going to look at + * the length value. With that in mind any of the `darr_*()` functions/API may + * be used to manipulate the variable data at the end of the message. + * + * NOTE: The pointer returned is actually a pointer to the message pointer + * passed in to this function. This pointer to pointer is required so that + * realloc can be done inside the darr API. + * + * NOTE: If reallocs happen the original passed in pointer will be updated; + * however, any other pointers into the message will become invalid and so they + * should always be discarded after using the returned value. + * + * Example: + * + * void append_metric_path(struct mgmt_msg_my_msg *msg) + * { + * char *xpath = msg->xpath; // pointer into message + * uint8_t **darp; + * + * darrp = mgmt_msg_native_get_darrp(msg); + * darr_in_strcat(*darrp, "/metric"); + * + * xpath = NULL; // now invalid + * xpath = msg->xpath; + * } + * + * + * Return: A pointer to the first argument -- which is a pointer to a pointer to + * a dynamic array. + */ +#define mgmt_msg_native_get_darrp(msg) ((uint8_t **)&(msg)) + +/* ------------------------- */ +/* Encode and Decode Helpers */ +/* ------------------------- */ + +/** + * mgmt_msg_native_xpath_encode() - encode an xpath in a xpath, data message. + * @msg: Pointer to the native message. + * @xpath: The xpath string to encode. + * + * This function starts the encoding of a message that can be decoded with + * `mgmt_msg_native_xpath_data_decode()`. The variable length data is comprised + * of a NUL terminated string followed by some data of any format. This starts + * the first half of the encoding, after which one can simply append the + * secondary data to the message. + */ +#define mgmt_msg_native_xpath_encode(msg, xpath) \ + do { \ + size_t __slen = strlen(xpath) + 1; \ + mgmt_msg_native_append(msg, xpath, __slen); \ + (msg)->vsplit = __slen; \ + } while (0) + +/** + * mgmt_msg_native_xpath_data_decode() - decode an xpath, data format message. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * @data: [OUT] Pointer to the data section of the variable data + * + * This function decodes a message that was encoded with + * `mgmt_msg_native_xpath_encode()`. The variable length data is comprised of a + * NUL terminated string followed by some data of any format. + * + * Return: + * The xpath string or NULL if there was an error decoding (i.e., the + * message is corrupt). + */ +#define mgmt_msg_native_xpath_data_decode(msg, msglen, __data) \ + ({ \ + size_t __len = (msglen) - sizeof(*msg); \ + const char *__s = NULL; \ + if (msg->vsplit && msg->vsplit <= __len && \ + msg->data[msg->vsplit - 1] == 0) { \ + if (msg->vsplit < __len) \ + (__data) = msg->data + msg->vsplit; \ + else \ + (__data) = NULL; \ + __s = msg->data; \ + } \ + __s; \ + }) + +/** + * mgmt_msg_native_xpath_decode() - return the xpath from xpath, data message. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * + * This function decodes the xpath from a message that was encoded with + * `mgmt_msg_native_xpath_encode()`. The variable length data is comprised of a + * NUL terminated string followed by some data of any format. + * + * Return: + * The xpath string or NULL if there was an error decoding (i.e., the + * message is corrupt). + */ +#define mgmt_msg_native_xpath_decode(msg, msglen) \ + ({ \ + size_t __len = (msglen) - sizeof(*msg); \ + const char *__s = msg->data; \ + if (!msg->vsplit || msg->vsplit > __len || \ + __s[msg->vsplit - 1] != 0) \ + __s = NULL; \ + __s; \ + }) + +/** + * mgmt_msg_native_data_decode() - return the data from xpath, data message. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * + * This function decodes the secondary data from a message that was encoded with + * `mgmt_msg_native_xpath_encode()`. The variable length data is comprised of a + * NUL terminated string followed by some data of any format. + * + * Return: + * The secondary data or NULL if there was an error decoding (i.e., the + * message is corrupt). + */ +#define mgmt_msg_native_data_decode(msg, msglen) \ + ({ \ + size_t __len = (msglen) - sizeof(*msg); \ + const char *__data = msg->data + msg->vsplit; \ + if (!msg->vsplit || msg->vsplit > __len || __data[-1] != 0) \ + __data = NULL; \ + __data; \ + }) + +/** + * mgmt_msg_native_data_len_decode() - len of data in xpath, data format message. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * + * This function returns the length of the secondary variable data from a + * message that was encoded with `mgmt_msg_native_xpath_encode()`. The variable + * length data is comprised of a NUL terminated string followed by some data of + * any format. + * + * Return: + * The length of the secondary variable data. The message is assumed to be + * validated as not corrupt already. + */ +#define mgmt_msg_native_data_len_decode(msg, msglen) \ + ((msglen) - sizeof(*msg) - msg->vsplit) + +/** + * mgmt_msg_native_strings_decode() - Get dynamic array of str ptrs from the msg. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * @sdata: pointer to the variable length string data at end of @msg. + * + * Given a pointer to a sequence of NUL-terminated strings allocate + * and return a dynamic array of dynamic array strings. This function + * can be used to decode a message that was built using + * mgmt_msg_native_add_str(). + * + * Return: a dynamic array (darr) of string pointers, or NULL if the message + * is corrupt. + */ +#define mgmt_msg_native_strings_decode(msg, msg_len, sdata) \ + _mgmt_msg_native_strings_decode(sdata, \ + (msg_len) - ((sdata) - (char *)(msg))) + +extern const char **_mgmt_msg_native_strings_decode(const void *sdata, + int sdlen); + +#ifdef __cplusplus +} +#endif + +#endif /* _FRR_MGMT_MSG_NATIVE_H_ */ diff --git a/lib/mlag.c b/lib/mlag.c index a370bf8924a2..62d00ff9a4fe 100644 --- a/lib/mlag.c +++ b/lib/mlag.c @@ -92,7 +92,7 @@ int mlag_lib_decode_mlag_hdr(struct stream *s, struct mlag_msg *msg, } #define MLAG_MROUTE_ADD_LENGTH \ - (VRF_NAMSIZ + INTERFACE_NAMSIZ + 4 + 4 + 4 + 4 + 1 + 1 + 4) + (VRF_NAMSIZ + IFNAMSIZ + 4 + 4 + 4 + 4 + 1 + 1 + 4) int mlag_lib_decode_mroute_add(struct stream *s, struct mlag_mroute_add *msg, size_t *length) @@ -108,14 +108,14 @@ int mlag_lib_decode_mroute_add(struct stream *s, struct mlag_mroute_add *msg, STREAM_GETC(s, msg->am_i_dr); STREAM_GETC(s, msg->am_i_dual_active); STREAM_GETL(s, msg->vrf_id); - STREAM_GET(msg->intf_name, s, INTERFACE_NAMSIZ); + STREAM_GET(msg->intf_name, s, IFNAMSIZ); return 0; stream_failure: return -1; } -#define MLAG_MROUTE_DEL_LENGTH (VRF_NAMSIZ + INTERFACE_NAMSIZ + 4 + 4 + 4 + 4) +#define MLAG_MROUTE_DEL_LENGTH (VRF_NAMSIZ + IFNAMSIZ + 4 + 4 + 4 + 4) int mlag_lib_decode_mroute_del(struct stream *s, struct mlag_mroute_del *msg, size_t *length) @@ -128,7 +128,7 @@ int mlag_lib_decode_mroute_del(struct stream *s, struct mlag_mroute_del *msg, STREAM_GETL(s, msg->group_ip); STREAM_GETL(s, msg->owner_id); STREAM_GETL(s, msg->vrf_id); - STREAM_GET(msg->intf_name, s, INTERFACE_NAMSIZ); + STREAM_GET(msg->intf_name, s, IFNAMSIZ); return 0; stream_failure: @@ -140,7 +140,7 @@ int mlag_lib_decode_mlag_status(struct stream *s, struct mlag_status *msg) if (s == NULL || msg == NULL) return -1; - STREAM_GET(msg->peerlink_rif, s, INTERFACE_NAMSIZ); + STREAM_GET(msg->peerlink_rif, s, IFNAMSIZ); STREAM_GETL(s, msg->my_role); STREAM_GETL(s, msg->peer_state); return 0; diff --git a/lib/mlag.h b/lib/mlag.h index 3aef0d77a8f4..91c550b07c28 100644 --- a/lib/mlag.h +++ b/lib/mlag.h @@ -65,7 +65,7 @@ struct mlag_frr_status { }; struct mlag_status { - char peerlink_rif[INTERFACE_NAMSIZ]; + char peerlink_rif[IFNAMSIZ]; enum mlag_role my_role; enum mlag_state peer_state; }; @@ -86,7 +86,7 @@ struct mlag_mroute_add { bool am_i_dr; bool am_i_dual_active; vrf_id_t vrf_id; - char intf_name[INTERFACE_NAMSIZ]; + char intf_name[IFNAMSIZ]; }; struct mlag_mroute_del { @@ -95,7 +95,7 @@ struct mlag_mroute_del { uint32_t group_ip; enum mlag_owner owner_id; vrf_id_t vrf_id; - char intf_name[INTERFACE_NAMSIZ]; + char intf_name[IFNAMSIZ]; }; struct mlag_msg { diff --git a/lib/module.c b/lib/module.c index af7d20c3da39..9d178bb0e4a6 100644 --- a/lib/module.c +++ b/lib/module.c @@ -202,3 +202,15 @@ void frrmod_unload(struct frrmod_runtime *module) { } #endif + +void frrmod_terminate(void) +{ + struct frrmod_runtime *rtinfo = frrmod_list; + + while (rtinfo) { + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + + rtinfo = rtinfo->next; + } +} diff --git a/lib/module.h b/lib/module.h index cd2be474e7f4..1810b335f6f6 100644 --- a/lib/module.h +++ b/lib/module.h @@ -79,6 +79,7 @@ extern union _frrmod_runtime_u _frrmod_this_module; extern struct frrmod_runtime *frrmod_list; extern void frrmod_init(struct frrmod_runtime *modinfo); +extern void frrmod_terminate(void); extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, void (*pFerrlog)(const void *, const char *), diff --git a/lib/netns_linux.c b/lib/netns_linux.c index 297e2c5952df..8fa4bc6fe0f7 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -5,6 +5,7 @@ */ #include +#include #ifdef HAVE_NETNS #undef _GNU_SOURCE @@ -502,12 +503,19 @@ void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns) void ns_terminate(void) { struct ns *ns; + struct ns_map_nsid *ns_map; while (!RB_EMPTY(ns_head, &ns_tree)) { ns = RB_ROOT(ns_head, &ns_tree); ns_delete(ns); } + + while (!RB_EMPTY(ns_map_nsid_head, &ns_map_nsid_list)) { + ns_map = RB_ROOT(ns_map_nsid_head, &ns_map_nsid_list); + RB_REMOVE(ns_map_nsid_head, &ns_map_nsid_list, ns_map); + XFREE(MTYPE_NS, ns_map); + } } int ns_switch_to_netns(const char *name) diff --git a/lib/netns_other.c b/lib/netns_other.c index 30218409dd8b..545a962b5584 100644 --- a/lib/netns_other.c +++ b/lib/netns_other.c @@ -13,10 +13,6 @@ #include "log.h" #include "memory.h" -DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context"); -DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name"); - - static inline int ns_compare(const struct ns *ns, const struct ns *ns2); RB_GENERATE(ns_head, ns, entry, ns_compare) @@ -39,7 +35,6 @@ void ns_init_management(ns_id_t ns_id) { } - /* * NS utilities */ diff --git a/lib/network.c b/lib/network.c index af1c7db443e9..b76869388952 100644 --- a/lib/network.c +++ b/lib/network.c @@ -5,6 +5,7 @@ */ #include +#include #include "log.h" #include "network.h" #include "lib_errors.h" diff --git a/lib/nexthop.c b/lib/nexthop.c index 8df57e36a201..65c12c1e6931 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -173,7 +173,7 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, ret = _nexthop_gateway_cmp(next1, next2); if (ret != 0) return ret; - /* Intentional Fall-Through */ + fallthrough; case NEXTHOP_TYPE_IFINDEX: if (next1->ifindex < next2->ifindex) return -1; @@ -295,7 +295,7 @@ int nexthop_cmp_basic(const struct nexthop *nh1, ret = nexthop_g_addr_cmp(nh1->type, &nh1->gate, &nh2->gate); if (ret != 0) return ret; - /* Intentional Fall-Through */ + fallthrough; case NEXTHOP_TYPE_IFINDEX: if (nh1->ifindex < nh2->ifindex) return -1; @@ -1150,11 +1150,359 @@ static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea, return -1; } -bool nexthop_is_ifindex_type(const struct nexthop *nh) +bool nexthop_is_blackhole(const struct nexthop *nh) { - if (nh->type == NEXTHOP_TYPE_IFINDEX || - nh->type == NEXTHOP_TYPE_IPV4_IFINDEX || - nh->type == NEXTHOP_TYPE_IPV6_IFINDEX) - return true; - return false; + return nh->type == NEXTHOP_TYPE_BLACKHOLE; +} + +/* + * Render a nexthop into a json object; the caller allocates and owns + * the json object memory. + */ +void nexthop_json_helper(json_object *json_nexthop, + const struct nexthop *nexthop, bool display_vrfid, + uint8_t rn_family) +{ + json_object *json_labels = NULL; + json_object *json_backups = NULL; + json_object *json_seg6local = NULL; + json_object *json_seg6local_context = NULL; + json_object *json_seg6 = NULL; + json_object *json_segs = NULL; + int i; + + json_object_int_add(json_nexthop, "flags", nexthop->flags); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + json_object_boolean_true_add(json_nexthop, "duplicate"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) + json_object_boolean_true_add(json_nexthop, "fib"); + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + json_object_string_addf(json_nexthop, "ip", "%pI4", + &nexthop->gate.ipv4); + json_object_string_add(json_nexthop, "afi", "ipv4"); + + if (nexthop->ifindex) { + json_object_int_add(json_nexthop, "interfaceIndex", + nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + json_object_string_addf(json_nexthop, "ip", "%pI6", + &nexthop->gate.ipv6); + json_object_string_add(json_nexthop, "afi", "ipv6"); + + if (nexthop->ifindex) { + json_object_int_add(json_nexthop, "interfaceIndex", + nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + } + break; + + case NEXTHOP_TYPE_IFINDEX: + json_object_boolean_true_add(json_nexthop, "directlyConnected"); + json_object_int_add(json_nexthop, "interfaceIndex", + nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + json_object_boolean_true_add(json_nexthop, "unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + json_object_boolean_true_add(json_nexthop, "reject"); + break; + case BLACKHOLE_ADMINPROHIB: + json_object_boolean_true_add(json_nexthop, + "adminProhibited"); + break; + case BLACKHOLE_NULL: + json_object_boolean_true_add(json_nexthop, "blackhole"); + break; + case BLACKHOLE_UNSPEC: + break; + } + break; + } + + /* This nexthop is a resolver for the parent nexthop. + * Set resolver flag for better clarity and delimiter + * in flat list of nexthops in json. + */ + if (nexthop->rparent) + json_object_boolean_true_add(json_nexthop, "resolver"); + + if (display_vrfid) + json_object_string_add(json_nexthop, "vrf", + vrf_id_to_name(nexthop->vrf_id)); + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + json_object_boolean_true_add(json_nexthop, "duplicate"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + json_object_boolean_true_add(json_nexthop, "active"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + json_object_boolean_true_add(json_nexthop, "onLink"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN)) + json_object_boolean_true_add(json_nexthop, "linkDown"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + json_object_boolean_true_add(json_nexthop, "recursive"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + json_backups = json_object_new_array(); + for (i = 0; i < nexthop->backup_num; i++) { + json_object_array_add(json_backups, + json_object_new_int( + nexthop->backup_idx[i])); + } + + json_object_object_add(json_nexthop, "backupIndex", + json_backups); + } + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->rmap_src.ipv4.s_addr) + json_object_string_addf(json_nexthop, "rmapSource", + "%pI4", &nexthop->rmap_src.ipv4); + else if (nexthop->src.ipv4.s_addr) + json_object_string_addf(json_nexthop, "source", "%pI4", + &nexthop->src.ipv4); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + /* Allow for 5549 ipv4 prefix with ipv6 nexthop */ + if (rn_family == AF_INET && nexthop->rmap_src.ipv4.s_addr) + json_object_string_addf(json_nexthop, "rmapSource", + "%pI4", &nexthop->rmap_src.ipv4); + else if (!IPV6_ADDR_SAME(&nexthop->rmap_src.ipv6, &in6addr_any)) + json_object_string_addf(json_nexthop, "rmapSource", + "%pI6", &nexthop->rmap_src.ipv6); + else if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) + json_object_string_addf(json_nexthop, "source", "%pI6", + &nexthop->src.ipv6); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + break; + } + + if (nexthop->nh_label && nexthop->nh_label->num_labels) { + json_labels = json_object_new_array(); + + for (int label_index = 0; + label_index < nexthop->nh_label->num_labels; label_index++) + json_object_array_add( + json_labels, + json_object_new_int(( + (nexthop->nh_label_type == ZEBRA_LSP_EVPN) + ? label2vni( + &nexthop->nh_label->label + [label_index]) + : nexthop->nh_label + ->label[label_index]))); + + json_object_object_add(json_nexthop, "labels", json_labels); + } + + if (nexthop->weight) + json_object_int_add(json_nexthop, "weight", nexthop->weight); + + if (nexthop->srte_color) + json_object_int_add(json_nexthop, "srteColor", + nexthop->srte_color); + + if (nexthop->nh_srv6) { + json_seg6local = json_object_new_object(); + json_object_string_add(json_seg6local, "action", + seg6local_action2str( + nexthop->nh_srv6 + ->seg6local_action)); + json_seg6local_context = json_object_new_object(); + json_object_object_add(json_nexthop, "seg6local", + json_seg6local); + + seg6local_context2json(&nexthop->nh_srv6->seg6local_ctx, + nexthop->nh_srv6->seg6local_action, + json_seg6local_context); + json_object_object_add(json_nexthop, "seg6localContext", + json_seg6local_context); + + if (nexthop->nh_srv6->seg6_segs && + nexthop->nh_srv6->seg6_segs->num_segs == 1) { + json_seg6 = json_object_new_object(); + json_object_string_addf(json_seg6, "segs", "%pI6", + &nexthop->nh_srv6->seg6_segs + ->seg[0]); + json_object_object_add(json_nexthop, "seg6", json_seg6); + } else { + if (nexthop->nh_srv6->seg6_segs) { + json_segs = json_object_new_array(); + for (int seg_idx = 0; + seg_idx < + nexthop->nh_srv6->seg6_segs->num_segs; + seg_idx++) + json_object_array_add( + json_segs, + json_object_new_stringf( + "%pI6", + &nexthop->nh_srv6 + ->seg6_segs + ->seg[seg_idx])); + json_object_object_add(json_nexthop, "seg6", + json_segs); + } + } + } +} + +/* + * Helper for nexthop output + */ +void nexthop_vty_helper(struct vty *vty, const struct nexthop *nexthop, + bool display_vrfid, uint8_t rn_family) +{ + char buf[MPLS_LABEL_STRLEN]; + char seg_buf[SRV6_SEG_STRLEN]; + struct seg6_segs segs; + uint8_t i; + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, " via %pI4", &nexthop->gate.ipv4); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " via %s", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, + sizeof(buf))); + if (nexthop->ifindex) + vty_out(vty, ", %s", + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); + break; + + case NEXTHOP_TYPE_IFINDEX: + vty_out(vty, " is directly connected, %s", + ifindex2ifname(nexthop->ifindex, nexthop->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out(vty, " unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + vty_out(vty, " (ICMP unreachable)"); + break; + case BLACKHOLE_ADMINPROHIB: + vty_out(vty, " (ICMP admin-prohibited)"); + break; + case BLACKHOLE_NULL: + vty_out(vty, " (blackhole)"); + break; + case BLACKHOLE_UNSPEC: + break; + } + break; + } + + if (display_vrfid) + vty_out(vty, " (vrf %s)", vrf_id_to_name(nexthop->vrf_id)); + + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + vty_out(vty, " inactive"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + vty_out(vty, " onlink"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN)) + vty_out(vty, " linkdown"); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + vty_out(vty, " (recursive)"); + + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->rmap_src.ipv4.s_addr) + vty_out(vty, ", rmapsrc %pI4", &nexthop->rmap_src.ipv4); + else if (nexthop->src.ipv4.s_addr) + vty_out(vty, ", src %pI4", &nexthop->src.ipv4); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + /* Allow for 5549 ipv4 prefix with ipv6 nexthop */ + if (rn_family == AF_INET && nexthop->rmap_src.ipv4.s_addr) + vty_out(vty, ", rmapsrc %pI4", &nexthop->rmap_src.ipv4); + else if (!IPV6_ADDR_SAME(&nexthop->rmap_src.ipv6, &in6addr_any)) + vty_out(vty, ", rmapsrc %pI6", &nexthop->rmap_src.ipv6); + else if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) + vty_out(vty, ", src %pI6", &nexthop->src.ipv6); + break; + case NEXTHOP_TYPE_IFINDEX: + case NEXTHOP_TYPE_BLACKHOLE: + break; + } + + /* SR-TE information */ + if (nexthop->srte_color) + vty_out(vty, ", SR-TE color %u", nexthop->srte_color); + + /* Label information */ + if (nexthop->nh_label && nexthop->nh_label->num_labels) { + vty_out(vty, ", label %s", + mpls_label2str(nexthop->nh_label->num_labels, + nexthop->nh_label->label, buf, + sizeof(buf), nexthop->nh_label_type, 1)); + } + + if (nexthop->nh_srv6) { + seg6local_context2str(buf, sizeof(buf), + &nexthop->nh_srv6->seg6local_ctx, + nexthop->nh_srv6->seg6local_action); + if (nexthop->nh_srv6->seg6local_action != + ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) + vty_out(vty, ", seg6local %s %s", + seg6local_action2str( + nexthop->nh_srv6->seg6local_action), + buf); + if (nexthop->nh_srv6->seg6_segs && + IPV6_ADDR_CMP(&nexthop->nh_srv6->seg6_segs->seg[0], + &in6addr_any)) { + segs.num_segs = nexthop->nh_srv6->seg6_segs->num_segs; + for (i = 0; i < segs.num_segs; i++) + memcpy(&segs.segs[i], + &nexthop->nh_srv6->seg6_segs->seg[i], + sizeof(struct in6_addr)); + snprintf_seg6_segs(seg_buf, SRV6_SEG_STRLEN, &segs); + vty_out(vty, ", seg6 %s", seg_buf); + } + } + + if (nexthop->weight) + vty_out(vty, ", weight %u", nexthop->weight); + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + vty_out(vty, ", backup %d", nexthop->backup_idx[0]); + + for (i = 1; i < nexthop->backup_num; i++) + vty_out(vty, ",%d", nexthop->backup_idx[i]); + } } diff --git a/lib/nexthop.h b/lib/nexthop.h index bed6447d49ed..27073b948dea 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -240,8 +240,8 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop, extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop, struct nexthop *rparent); -/* Check nexthop of IFINDEX type */ -extern bool nexthop_is_ifindex_type(const struct nexthop *nh); +/* Is this nexthop a blackhole? */ +extern bool nexthop_is_blackhole(const struct nexthop *nh); /* * Parse one or more backup index values, as comma-separated numbers, @@ -252,6 +252,12 @@ extern bool nexthop_is_ifindex_type(const struct nexthop *nh); int nexthop_str2backups(const char *str, int *num_backups, uint8_t *backups); +void nexthop_json_helper(json_object *json_nexthop, + const struct nexthop *nexthop, bool display_vrfid, + uint8_t rn_family); +void nexthop_vty_helper(struct vty *vty, const struct nexthop *nexthop, + bool display_vrfid, uint8_t rn_family); + #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pNH" (struct nexthop *) #endif diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 25370eba4828..3f408e0a71f9 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -81,7 +81,8 @@ uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg) return num; } -uint8_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg) +static uint8_t +nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg) { struct nexthop *nhop; uint8_t num = 0; @@ -105,20 +106,6 @@ uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg) return num; } -uint8_t -nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg) -{ - struct nexthop *nhop; - uint8_t num = 0; - - for (nhop = nhg->nexthop; nhop; nhop = nhop->next) { - if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE)) - num++; - } - - return num; -} - bool nexthop_group_has_label(const struct nexthop_group *nhg) { struct nexthop *nhop; @@ -180,7 +167,7 @@ static struct nexthop *nhg_nh_find(const struct nexthop_group *nhg, &nexthop->gate, &nh->gate); if (ret != 0) continue; - /* Intentional Fall-Through */ + fallthrough; case NEXTHOP_TYPE_IFINDEX: if (nexthop->ifindex != nh->ifindex) continue; @@ -1248,9 +1235,9 @@ void nexthop_group_disable_vrf(struct vrf *vrf) struct nexthop_hold *nhh; RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) { - struct listnode *node; + struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) { + for (ALL_LIST_ELEMENTS(nhgc->nhg_list, node, nnode, nhh)) { struct nexthop nhop; struct nexthop *nh; @@ -1271,6 +1258,10 @@ void nexthop_group_disable_vrf(struct vrf *vrf) nhg_hooks.del_nexthop(nhgc, nh); nexthop_free(nh); + + list_delete_node(nhgc->nhg_list, node); + + nhgl_delete(nhh); } } } diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 78237e464fd9..822a35439cc0 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -151,11 +151,7 @@ extern void nexthop_group_json_nexthop(json_object *j, /* Return the number of nexthops in this nhg */ extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg); extern uint8_t -nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg); -extern uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg); -extern uint8_t -nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg); extern bool nexthop_group_has_label(const struct nexthop_group *nhg); diff --git a/lib/northbound.c b/lib/northbound.c index 69b96d365693..0bc79d027740 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -6,6 +6,7 @@ #include +#include "darr.h" #include "libfrr.h" #include "log.h" #include "lib_errors.h" @@ -70,12 +71,6 @@ static int nb_transaction_process(enum nb_event event, char *errmsg, size_t errmsg_len); static void nb_transaction_apply_finish(struct nb_transaction *transaction, char *errmsg, size_t errmsg_len); -static int nb_oper_data_iter_node(const struct lysc_node *snode, - const char *xpath, const void *list_entry, - const struct yang_list_keys *list_keys, - struct yang_translator *translator, - bool first, uint32_t flags, - nb_oper_data_cb cb, void *arg); static int nb_node_check_config_only(const struct lysc_node *snode, void *arg) { @@ -130,8 +125,8 @@ static int nb_node_new_cb(const struct lysc_node *snode, void *arg) assert(snode->priv == NULL); ((struct lysc_node *)snode)->priv = nb_node; - if (module && module->ignore_cbs) - SET_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS); + if (module && module->ignore_cfg_cbs) + SET_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS); return YANG_ITER_CONTINUE; } @@ -162,18 +157,45 @@ void nb_nodes_delete(void) struct nb_node *nb_node_find(const char *path) { const struct lysc_node *snode; + uint32_t llopts = 0; /* * Use libyang to find the schema node associated to the path and get - * the northbound node from there (snode private pointer). + * the northbound node from there (snode private pointer). We need to + * disable logging temporarily to avoid libyang from logging an error + * message when the node is not found. */ + ly_temp_log_options(&llopts); + snode = yang_find_snode(ly_native_ctx, path, 0); + + ly_temp_log_options(NULL); if (!snode) return NULL; return snode->priv; } +struct nb_node **nb_nodes_find(const char *xpath) +{ + struct lysc_node **snodes = NULL; + struct nb_node **nb_nodes = NULL; + bool simple; + LY_ERR err; + uint i; + + err = yang_resolve_snode_xpath(ly_native_ctx, xpath, &snodes, &simple); + if (err) + return NULL; + + darr_ensure_i(nb_nodes, darr_lasti(snodes)); + darr_foreach_i (snodes, i) + nb_nodes[i] = snodes[i]->priv; + darr_free(snodes); + return nb_nodes; +} + + void nb_node_set_dependency_cbs(const char *dependency_xpath, const char *dependant_xpath, struct nb_dependency_callbacks *cbs) @@ -194,12 +216,12 @@ bool nb_node_has_dependency(struct nb_node *node) } static int nb_node_validate_cb(const struct nb_node *nb_node, - enum nb_operation operation, + enum nb_cb_operation operation, int callback_implemented, bool optional) { bool valid; - valid = nb_operation_is_valid(operation, nb_node->snode); + valid = nb_cb_operation_is_valid(operation, nb_node->snode); /* * Add an exception for operational data callbacks. A rw list usually @@ -211,15 +233,15 @@ static int nb_node_validate_cb(const struct nb_node *nb_node, * depends on context (e.g. some daemons might augment "frr-interface" * while others don't). */ - if (!valid && callback_implemented && operation != NB_OP_GET_NEXT - && operation != NB_OP_GET_KEYS && operation != NB_OP_LOOKUP_ENTRY) + if (!valid && callback_implemented && operation != NB_CB_GET_NEXT + && operation != NB_CB_GET_KEYS && operation != NB_CB_LOOKUP_ENTRY) flog_warn(EC_LIB_NB_CB_UNNEEDED, "unneeded '%s' callback for '%s'", - nb_operation_name(operation), nb_node->xpath); + nb_cb_operation_name(operation), nb_node->xpath); if (!optional && valid && !callback_implemented) { flog_err(EC_LIB_NB_CB_MISSING, "missing '%s' callback for '%s'", - nb_operation_name(operation), nb_node->xpath); + nb_cb_operation_name(operation), nb_node->xpath); return 1; } @@ -235,31 +257,33 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node) { unsigned int error = 0; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return error; - error += nb_node_validate_cb(nb_node, NB_OP_CREATE, + error += nb_node_validate_cb(nb_node, NB_CB_CREATE, !!nb_node->cbs.create, false); - error += nb_node_validate_cb(nb_node, NB_OP_MODIFY, + error += nb_node_validate_cb(nb_node, NB_CB_MODIFY, !!nb_node->cbs.modify, false); - error += nb_node_validate_cb(nb_node, NB_OP_DESTROY, + error += nb_node_validate_cb(nb_node, NB_CB_DESTROY, !!nb_node->cbs.destroy, false); - error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move, + error += nb_node_validate_cb(nb_node, NB_CB_MOVE, !!nb_node->cbs.move, false); - error += nb_node_validate_cb(nb_node, NB_OP_PRE_VALIDATE, + error += nb_node_validate_cb(nb_node, NB_CB_PRE_VALIDATE, !!nb_node->cbs.pre_validate, true); - error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH, + error += nb_node_validate_cb(nb_node, NB_CB_APPLY_FINISH, !!nb_node->cbs.apply_finish, true); - error += nb_node_validate_cb(nb_node, NB_OP_GET_ELEM, + error += nb_node_validate_cb(nb_node, NB_CB_GET_ELEM, !!nb_node->cbs.get_elem, false); - error += nb_node_validate_cb(nb_node, NB_OP_GET_NEXT, + error += nb_node_validate_cb(nb_node, NB_CB_GET_NEXT, !!nb_node->cbs.get_next, false); - error += nb_node_validate_cb(nb_node, NB_OP_GET_KEYS, + error += nb_node_validate_cb(nb_node, NB_CB_GET_KEYS, !!nb_node->cbs.get_keys, false); - error += nb_node_validate_cb(nb_node, NB_OP_LOOKUP_ENTRY, + error += nb_node_validate_cb(nb_node, NB_CB_LOOKUP_ENTRY, !!nb_node->cbs.lookup_entry, false); - error += nb_node_validate_cb(nb_node, NB_OP_RPC, !!nb_node->cbs.rpc, + error += nb_node_validate_cb(nb_node, NB_CB_RPC, !!nb_node->cbs.rpc, false); + error += nb_node_validate_cb(nb_node, NB_CB_NOTIFY, + !!nb_node->cbs.notify, true); return error; } @@ -305,8 +329,6 @@ struct nb_config *nb_config_new(struct lyd_node *dnode) config->dnode = yang_dnode_new(ly_native_ctx, true); config->version = 0; - RB_INIT(nb_config_cbs, &config->cfg_chgs); - return config; } @@ -314,7 +336,7 @@ void nb_config_free(struct nb_config *config) { if (config->dnode) yang_dnode_free(config->dnode); - nb_config_diff_del_changes(&config->cfg_chgs); + XFREE(MTYPE_NB_CONFIG, config); } @@ -326,8 +348,6 @@ struct nb_config *nb_config_dup(const struct nb_config *config) dup->dnode = yang_dnode_dup(config->dnode); dup->version = config->version; - RB_INIT(nb_config_cbs, &dup->cfg_chgs); - return dup; } @@ -369,12 +389,28 @@ void nb_config_replace(struct nb_config *config_dst, static inline int nb_config_cb_compare(const struct nb_config_cb *a, const struct nb_config_cb *b) { - /* Sort by priority first. */ - if (a->nb_node->priority < b->nb_node->priority) + bool a_destroy = a->operation == NB_CB_DESTROY; + bool b_destroy = b->operation == NB_CB_DESTROY; + + /* + * Sort by operation first. All "destroys" must come first, to correctly + * process the change of a "case" inside a "choice". The old "case" must + * be deleted before the new "case" is created. + */ + if (a_destroy && !b_destroy) return -1; - if (a->nb_node->priority > b->nb_node->priority) + if (!a_destroy && b_destroy) return 1; + /* + * Then sort by priority. If the operation is "destroy", reverse the + * order, so that the dependants are deleted before the dependencies. + */ + if (a->nb_node->priority < b->nb_node->priority) + return !a_destroy ? -1 : 1; + if (a->nb_node->priority > b->nb_node->priority) + return !a_destroy ? 1 : -1; + /* * Preserve the order of the configuration changes as told by libyang. */ @@ -397,10 +433,9 @@ static inline int nb_config_cb_compare(const struct nb_config_cb *a, } RB_GENERATE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare); -static void nb_config_diff_add_change(struct nb_config_cbs *changes, - enum nb_operation operation, - uint32_t *seq, - const struct lyd_node *dnode) +void nb_config_diff_add_change(struct nb_config_cbs *changes, + enum nb_cb_operation operation, uint32_t *seq, + const struct lyd_node *dnode) { struct nb_config_change *change; @@ -438,7 +473,7 @@ void nb_config_diff_del_changes(struct nb_config_cbs *changes) void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq, struct nb_config_cbs *changes) { - enum nb_operation operation; + enum nb_cb_operation operation; struct lyd_node *child; /* Ignore unimplemented nodes. */ @@ -451,10 +486,10 @@ void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq, if (lyd_is_default(dnode)) break; - if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) - operation = NB_OP_CREATE; - else if (nb_operation_is_valid(NB_OP_MODIFY, dnode->schema)) - operation = NB_OP_MODIFY; + if (nb_cb_operation_is_valid(NB_CB_CREATE, dnode->schema)) + operation = NB_CB_CREATE; + else if (nb_cb_operation_is_valid(NB_CB_MODIFY, dnode->schema)) + operation = NB_CB_MODIFY; else return; @@ -462,8 +497,8 @@ void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq, break; case LYS_CONTAINER: case LYS_LIST: - if (nb_operation_is_valid(NB_OP_CREATE, dnode->schema)) - nb_config_diff_add_change(changes, NB_OP_CREATE, seq, + if (nb_cb_operation_is_valid(NB_CB_CREATE, dnode->schema)) + nb_config_diff_add_change(changes, NB_CB_CREATE, seq, dnode); /* Process child nodes recursively. */ @@ -483,8 +518,8 @@ static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq, if (!dnode->schema->priv) return; - if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema)) - nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode); + if (nb_cb_operation_is_valid(NB_CB_DESTROY, dnode->schema)) + nb_config_diff_add_change(changes, NB_CB_DESTROY, seq, dnode); else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) { struct lyd_node *child; @@ -633,7 +668,7 @@ void nb_config_diff(const struct nb_config *config1, /* either moving an entry or changing a value */ target = yang_dnode_get(config2->dnode, path); assert(target); - nb_config_diff_add_change(changes, NB_OP_MODIFY, + nb_config_diff_add_change(changes, NB_CB_MODIFY, &seq, target); break; case 'n': /* none */ @@ -648,44 +683,54 @@ void nb_config_diff(const struct nb_config *config1, lyd_free_all(diff); } -int nb_candidate_edit(struct nb_config *candidate, - const struct nb_node *nb_node, +static int dnode_create(struct nb_config *candidate, const char *xpath, + const char *value, uint32_t options, + struct lyd_node **new_dnode) +{ + struct lyd_node *dnode; + LY_ERR err; + + err = lyd_new_path(candidate->dnode, ly_native_ctx, xpath, value, + options, &dnode); + if (err) { + flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path(%s) failed: %d", + __func__, xpath, err); + return NB_ERR; + } else if (dnode) { + err = lyd_new_implicit_tree(dnode, LYD_IMPLICIT_NO_STATE, NULL); + if (err) { + flog_warn(EC_LIB_LIBYANG, + "%s: lyd_new_implicit_all failed: %d", + __func__, err); + } + } + if (new_dnode) + *new_dnode = dnode; + return NB_OK; +} + +int nb_candidate_edit(struct nb_config *candidate, const struct nb_node *nb_node, enum nb_operation operation, const char *xpath, const struct yang_data *previous, const struct yang_data *data) { - struct lyd_node *dnode, *dep_dnode; - char xpath_edit[XPATH_MAXLEN]; + struct lyd_node *dnode, *dep_dnode, *old_dnode; char dep_xpath[XPATH_MAXLEN]; + struct lyd_node *parent = NULL; + uint32_t options = 0; LY_ERR err; - /* Use special notation for leaf-lists (RFC 6020, section 9.13.5). */ - if (nb_node->snode->nodetype == LYS_LEAFLIST) - snprintf(xpath_edit, sizeof(xpath_edit), "%s[.='%s']", xpath, - data->value); - else - strlcpy(xpath_edit, xpath, sizeof(xpath_edit)); - switch (operation) { case NB_OP_CREATE: case NB_OP_MODIFY: - err = lyd_new_path(candidate->dnode, ly_native_ctx, xpath_edit, - (void *)data->value, LYD_NEW_PATH_UPDATE, + options = LYD_NEW_PATH_UPDATE; + fallthrough; + case NB_OP_CREATE_EXCL: + err = dnode_create(candidate, xpath, data->value, options, &dnode); if (err) { - flog_warn(EC_LIB_LIBYANG, - "%s: lyd_new_path(%s) failed: %d", __func__, - xpath_edit, err); - return NB_ERR; + return err; } else if (dnode) { - /* Create default nodes */ - LY_ERR err = lyd_new_implicit_tree( - dnode, LYD_IMPLICIT_NO_STATE, NULL); - if (err) { - flog_warn(EC_LIB_LIBYANG, - "%s: lyd_new_implicit_all failed: %d", - __func__, err); - } /* * create dependency * @@ -697,33 +742,24 @@ int nb_candidate_edit(struct nb_config *candidate, nb_node->dep_cbs.get_dependency_xpath( dnode, dep_xpath); - err = lyd_new_path(candidate->dnode, - ly_native_ctx, dep_xpath, - NULL, LYD_NEW_PATH_UPDATE, - &dep_dnode); - /* Create default nodes */ - if (!err && dep_dnode) - err = lyd_new_implicit_tree( - dep_dnode, - LYD_IMPLICIT_NO_STATE, NULL); + err = dnode_create(candidate, dep_xpath, NULL, + LYD_NEW_PATH_UPDATE, NULL); if (err) { - flog_warn( - EC_LIB_LIBYANG, - "%s: dependency: lyd_new_path(%s) failed: %d", - __func__, dep_xpath, err); - return NB_ERR; + lyd_free_tree(dnode); + return err; } } } break; case NB_OP_DESTROY: - dnode = yang_dnode_get(candidate->dnode, xpath_edit); - if (!dnode) - /* - * Return a special error code so the caller can choose - * whether to ignore it or not. - */ - return NB_ERR_NOT_FOUND; + case NB_OP_DELETE: + dnode = yang_dnode_get(candidate->dnode, xpath); + if (!dnode) { + if (operation == NB_OP_DELETE) + return NB_ERR; + else + return NB_OK; + } /* destroy dependant */ if (nb_node->dep_cbs.get_dependant_xpath) { nb_node->dep_cbs.get_dependant_xpath(dnode, dep_xpath); @@ -734,103 +770,313 @@ int nb_candidate_edit(struct nb_config *candidate, } lyd_free_tree(dnode); break; + case NB_OP_REPLACE: + old_dnode = yang_dnode_get(candidate->dnode, xpath); + if (old_dnode) { + parent = lyd_parent(old_dnode); + lyd_unlink_tree(old_dnode); + } + err = dnode_create(candidate, xpath, data->value, options, + &dnode); + if (!err && dnode && !old_dnode) { + /* create dependency if the node didn't exist */ + nb_node = dnode->schema->priv; + if (nb_node->dep_cbs.get_dependency_xpath) { + nb_node->dep_cbs.get_dependency_xpath( + dnode, dep_xpath); + + err = dnode_create(candidate, dep_xpath, NULL, + LYD_NEW_PATH_UPDATE, NULL); + if (err) + lyd_free_tree(dnode); + } + } + if (old_dnode) { + /* restore original node on error, free it otherwise */ + if (err) { + if (parent) + lyd_insert_child(parent, old_dnode); + else + lyd_insert_sibling(candidate->dnode, + old_dnode, NULL); + return err; + } + + lyd_free_tree(old_dnode); + } + break; case NB_OP_MOVE: /* TODO: update configuration. */ break; - case NB_OP_PRE_VALIDATE: - case NB_OP_APPLY_FINISH: - case NB_OP_GET_ELEM: - case NB_OP_GET_NEXT: - case NB_OP_GET_KEYS: - case NB_OP_LOOKUP_ENTRY: - case NB_OP_RPC: - flog_warn(EC_LIB_DEVELOPMENT, - "%s: unknown operation (%u) [xpath %s]", __func__, - operation, xpath_edit); - return NB_ERR; } return NB_OK; } -static void nb_update_candidate_changes(struct nb_config *candidate, - struct nb_cfg_change *change, - uint32_t *seq) +static int nb_candidate_edit_tree_add(struct nb_config *candidate, + enum nb_operation operation, + LYD_FORMAT format, const char *xpath, + const char *data, char *xpath_created, + char *errmsg, size_t errmsg_len) +{ + struct lyd_node *tree = NULL; + struct lyd_node *parent = NULL; + struct lyd_node *dnode = NULL; + struct lyd_node *existing = NULL; + struct lyd_node *ex_parent = NULL; + char *parent_xpath = NULL; + struct ly_in *in; + LY_ERR err; + bool root; + int ret; + + ly_in_new_memory(data, &in); + + root = xpath[0] == 0 || (xpath[0] == '/' && xpath[1] == 0); + + /* get parent xpath if xpath is not root */ + if (!root) { + /* NB_OP_CREATE_EXCT already expects parent xpath */ + parent_xpath = XSTRDUP(MTYPE_TMP, xpath); + + /* for other operations - pop one level */ + if (operation != NB_OP_CREATE_EXCL) { + ret = yang_xpath_pop_node(parent_xpath); + if (ret) { + snprintf(errmsg, errmsg_len, "Invalid xpath"); + goto done; + } + + /* root is not actually a parent */ + if (parent_xpath[0] == 0) + XFREE(MTYPE_TMP, parent_xpath); + } + } + + /* + * Create parent if it's not root. We're creating a new tree here to be + * merged later with candidate. + */ + if (parent_xpath) { + err = lyd_new_path2(NULL, ly_native_ctx, parent_xpath, NULL, 0, + 0, 0, &tree, &parent); + if (err) { + yang_print_errors(ly_native_ctx, errmsg, errmsg_len); + ret = NB_ERR; + goto done; + } + assert(parent); + } + + /* parse data */ + err = yang_lyd_parse_data(ly_native_ctx, parent, in, format, + LYD_PARSE_ONLY | LYD_PARSE_STRICT | + LYD_PARSE_NO_STATE, + 0, &dnode); + if (err) { + yang_print_errors(ly_native_ctx, errmsg, errmsg_len); + ret = NB_ERR; + goto done; + } + + /* set the tree if we created a top-level node */ + if (!parent) + tree = dnode; + + /* save xpath of the created node */ + lyd_path(dnode, LYD_PATH_STD, xpath_created, XPATH_MAXLEN); + + /* verify that list keys are the same in the xpath and the data tree */ + if (!root && (operation == NB_OP_REPLACE || operation == NB_OP_MODIFY)) { + if (lyd_find_path(tree, xpath, 0, NULL)) { + snprintf(errmsg, errmsg_len, + "List keys in xpath and data tree are different"); + ret = NB_ERR; + goto done; + } + } + + /* check if the node already exists in candidate */ + if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) { + existing = yang_dnode_get(candidate->dnode, xpath_created); + + /* if the existing node is implicit default, ignore */ + if (existing && (existing->flags & LYD_DEFAULT)) + existing = NULL; + + if (existing) { + if (operation == NB_OP_CREATE_EXCL) { + snprintf(errmsg, errmsg_len, + "Data already exists"); + ret = NB_ERR; + goto done; + } + + if (root) { + candidate->dnode = NULL; + } else { + /* if it's the first top-level node, update candidate */ + if (candidate->dnode == existing) + candidate->dnode = + candidate->dnode->next; + + ex_parent = lyd_parent(existing); + lyd_unlink_tree(existing); + } + } + } + + err = lyd_merge_siblings(&candidate->dnode, tree, + LYD_MERGE_DESTRUCT | LYD_MERGE_WITH_FLAGS); + if (err) { + /* if replace failed, restore the original node */ + if (existing) { + if (root) { + /* Restoring the whole config. */ + candidate->dnode = existing; + } else if (ex_parent) { + /* + * Restoring a nested node. Insert it as a + * child. + */ + lyd_insert_child(ex_parent, existing); + } else { + /* + * Restoring a top-level node. Insert it as a + * sibling to candidate->dnode to make sure + * the linkage is correct. + */ + lyd_insert_sibling(candidate->dnode, existing, + &candidate->dnode); + } + } + yang_print_errors(ly_native_ctx, errmsg, errmsg_len); + ret = NB_ERR; + goto done; + } else { + /* + * Free existing node after replace. + * We're using `lyd_free_siblings` here to free the whole + * tree if we replaced the root node. It won't affect other + * siblings if it wasn't root, because the existing node + * was unlinked from the tree. + */ + if (existing) + lyd_free_siblings(existing); + + tree = NULL; /* LYD_MERGE_DESTRUCT deleted the tree */ + } + + ret = NB_OK; +done: + if (tree) + lyd_free_all(tree); + XFREE(MTYPE_TMP, parent_xpath); + ly_in_free(in, 0); + + return ret; +} + +static int nb_candidate_edit_tree_del(struct nb_config *candidate, + enum nb_operation operation, + const char *xpath, char *errmsg, + size_t errmsg_len) { - enum nb_operation oper = change->operation; - char *xpath = change->xpath; - struct lyd_node *root = NULL; struct lyd_node *dnode; - struct nb_config_cbs *cfg_chgs = &candidate->cfg_chgs; - int op; - switch (oper) { + /* deleting root - remove the whole config */ + if (xpath[0] == 0 || (xpath[0] == '/' && xpath[1] == 0)) { + lyd_free_all(candidate->dnode); + candidate->dnode = NULL; + return NB_OK; + } + + dnode = yang_dnode_get(candidate->dnode, xpath); + if (!dnode || (dnode->flags & LYD_DEFAULT)) { + if (operation == NB_OP_DELETE) { + snprintf(errmsg, errmsg_len, "Data missing"); + return NB_ERR; + } else + return NB_OK; + } + + /* if it's the first top-level node, update candidate */ + if (candidate->dnode == dnode) + candidate->dnode = candidate->dnode->next; + + lyd_free_tree(dnode); + + return NB_OK; +} + +int nb_candidate_edit_tree(struct nb_config *candidate, + enum nb_operation operation, LYD_FORMAT format, + const char *xpath, const char *data, + char *xpath_created, char *errmsg, size_t errmsg_len) +{ + int ret = NB_ERR; + + switch (operation) { + case NB_OP_CREATE_EXCL: case NB_OP_CREATE: case NB_OP_MODIFY: - root = yang_dnode_get(candidate->dnode, xpath); + case NB_OP_REPLACE: + ret = nb_candidate_edit_tree_add(candidate, operation, format, + xpath, data, xpath_created, + errmsg, errmsg_len); break; case NB_OP_DESTROY: - root = yang_dnode_get(running_config->dnode, xpath); - /* code */ + case NB_OP_DELETE: + ret = nb_candidate_edit_tree_del(candidate, operation, xpath, + errmsg, errmsg_len); break; case NB_OP_MOVE: - case NB_OP_PRE_VALIDATE: - case NB_OP_APPLY_FINISH: - case NB_OP_GET_ELEM: - case NB_OP_GET_NEXT: - case NB_OP_GET_KEYS: - case NB_OP_LOOKUP_ENTRY: - case NB_OP_RPC: + /* not supported yet */ break; - default: - assert(!"non-enum value, invalid"); } - if (!root) - return; + return ret; +} - LYD_TREE_DFS_BEGIN (root, dnode) { - op = nb_lyd_diff_get_op(dnode); - switch (op) { - case 'c': /* create */ - nb_config_diff_created(dnode, seq, cfg_chgs); - LYD_TREE_DFS_continue = 1; - break; - case 'd': /* delete */ - nb_config_diff_deleted(dnode, seq, cfg_chgs); - LYD_TREE_DFS_continue = 1; - break; - case 'r': /* replace */ - nb_config_diff_add_change(cfg_chgs, NB_OP_MODIFY, seq, - dnode); - break; - case 'n': /* none */ - default: - break; - } - LYD_TREE_DFS_END(root, dnode); +const char *nb_operation_name(enum nb_operation operation) +{ + switch (operation) { + case NB_OP_CREATE_EXCL: + return "create exclusive"; + case NB_OP_CREATE: + return "create"; + case NB_OP_MODIFY: + return "modify"; + case NB_OP_DESTROY: + return "destroy"; + case NB_OP_DELETE: + return "delete"; + case NB_OP_REPLACE: + return "replace"; + case NB_OP_MOVE: + return "move"; } + + assert(!"Reached end of function we should never hit"); } -static bool nb_is_operation_allowed(struct nb_node *nb_node, - struct nb_cfg_change *change) +bool nb_is_operation_allowed(struct nb_node *nb_node, enum nb_operation oper) { - enum nb_operation oper = change->operation; - if (lysc_is_key(nb_node->snode)) { - if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY) + if (oper == NB_OP_MODIFY || oper == NB_OP_DESTROY + || oper == NB_OP_DELETE || oper == NB_OP_REPLACE) return false; } return true; } -void nb_candidate_edit_config_changes( - struct nb_config *candidate_config, struct nb_cfg_change cfg_changes[], - size_t num_cfg_changes, const char *xpath_base, const char *curr_xpath, - int xpath_index, char *err_buf, int err_bufsize, bool *error) +void nb_candidate_edit_config_changes(struct nb_config *candidate_config, + struct nb_cfg_change cfg_changes[], + size_t num_cfg_changes, + const char *xpath_base, bool in_backend, + char *err_buf, int err_bufsize, + bool *error) { - uint32_t seq = 0; - if (error) *error = false; @@ -841,37 +1087,38 @@ void nb_candidate_edit_config_changes( for (size_t i = 0; i < num_cfg_changes; i++) { struct nb_cfg_change *change = &cfg_changes[i]; struct nb_node *nb_node; + char *change_xpath = change->xpath; char xpath[XPATH_MAXLEN]; + const char *value; struct yang_data *data; int ret; - /* Handle relative XPaths. */ memset(xpath, 0, sizeof(xpath)); - if (xpath_index > 0 && - (xpath_base[0] == '.' || change->xpath[0] == '.')) - strlcpy(xpath, curr_xpath, sizeof(xpath)); - if (xpath_base[0]) { - if (xpath_base[0] == '.') - strlcat(xpath, xpath_base + 1, sizeof(xpath)); - else - strlcat(xpath, xpath_base, sizeof(xpath)); + /* If change xpath is relative, prepend base xpath. */ + if (change_xpath[0] == '.') { + strlcpy(xpath, xpath_base, sizeof(xpath)); + change_xpath++; /* skip '.' */ } - if (change->xpath[0] == '.') - strlcat(xpath, change->xpath + 1, sizeof(xpath)); - else - strlcpy(xpath, change->xpath, sizeof(xpath)); + strlcat(xpath, change_xpath, sizeof(xpath)); /* Find the northbound node associated to the data path. */ nb_node = nb_node_find(xpath); if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - if (error) - *error = true; + if (in_backend) + DEBUGD(&nb_dbg_cbs_config, + "%s: ignoring non-handled path: %s", + __func__, xpath); + else { + flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, + xpath); + if (error) + *error = true; + } continue; } /* Find if the node to be edited is not a key node */ - if (!nb_is_operation_allowed(nb_node, change)) { + if (!nb_is_operation_allowed(nb_node, change->operation)) { zlog_err(" Xpath %s points to key node", xpath); if (error) *error = true; @@ -879,9 +1126,10 @@ void nb_candidate_edit_config_changes( } /* If the value is not set, get the default if it exists. */ - if (change->value == NULL) - change->value = yang_snode_get_default(nb_node->snode); - data = yang_data_new(xpath, change->value); + value = change->value; + if (value == NULL) + value = yang_snode_get_default(nb_node->snode); + data = yang_data_new(xpath, value); /* * Ignore "not found" errors when editing the candidate @@ -890,7 +1138,7 @@ void nb_candidate_edit_config_changes( ret = nb_candidate_edit(candidate_config, nb_node, change->operation, xpath, NULL, data); yang_data_free(data); - if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) { + if (ret != NB_OK) { flog_warn( EC_LIB_NB_CANDIDATE_EDIT_ERROR, "%s: failed to edit candidate configuration: operation [%s] xpath [%s]", @@ -900,17 +1148,11 @@ void nb_candidate_edit_config_changes( *error = true; continue; } - nb_update_candidate_changes(candidate_config, change, &seq); } if (error && *error) { char buf[BUFSIZ]; - /* - * Failure to edit the candidate configuration should never - * happen in practice, unless there's a bug in the code. When - * that happens, log the error but otherwise ignore it. - */ snprintf(err_buf, err_bufsize, "%% Failed to edit configuration.\n\n%s", yang_print_errors(ly_native_ctx, buf, sizeof(buf))); @@ -947,9 +1189,19 @@ int nb_candidate_update(struct nb_config *candidate) int nb_candidate_validate_yang(struct nb_config *candidate, bool no_state, char *errmsg, size_t errmsg_len) { - if (lyd_validate_all(&candidate->dnode, ly_native_ctx, - no_state ? LYD_VALIDATE_NO_STATE - : LYD_VALIDATE_PRESENT, + uint32_t options = 0; + +#ifdef LYD_VALIDATE_MULTI_ERROR + /* libyang 2.1.36+ */ + options |= LYD_VALIDATE_MULTI_ERROR; +#endif + + if (no_state) + SET_FLAG(options, LYD_VALIDATE_NO_STATE); + else + SET_FLAG(options, LYD_VALIDATE_PRESENT); + + if (lyd_validate_all(&candidate->dnode, ly_native_ctx, options, NULL) != 0) { yang_print_errors(ly_native_ctx, errmsg, errmsg_len); return NB_ERR_VALIDATION; @@ -1191,7 +1443,7 @@ int nb_running_lock_check(enum nb_client client, const void *user) } static void nb_log_config_callback(const enum nb_event event, - enum nb_operation operation, + enum nb_cb_operation operation, const struct lyd_node *dnode) { const char *value; @@ -1208,7 +1460,7 @@ static void nb_log_config_callback(const enum nb_event event, zlog_debug( "northbound callback: event [%s] op [%s] xpath [%s] value [%s]", - nb_event_name(event), nb_operation_name(operation), xpath, + nb_event_name(event), nb_cb_operation_name(operation), xpath, value); } @@ -1222,9 +1474,9 @@ static int nb_callback_create(struct nb_context *context, bool unexpected_error = false; int ret; - assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)); + assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)); - nb_log_config_callback(event, NB_OP_CREATE, dnode); + nb_log_config_callback(event, NB_CB_CREATE, dnode); args.context = context; args.event = event; @@ -1273,9 +1525,9 @@ static int nb_callback_modify(struct nb_context *context, bool unexpected_error = false; int ret; - assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)); + assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)); - nb_log_config_callback(event, NB_OP_MODIFY, dnode); + nb_log_config_callback(event, NB_CB_MODIFY, dnode); args.context = context; args.event = event; @@ -1324,9 +1576,9 @@ static int nb_callback_destroy(struct nb_context *context, bool unexpected_error = false; int ret; - assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)); + assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)); - nb_log_config_callback(event, NB_OP_DESTROY, dnode); + nb_log_config_callback(event, NB_CB_DESTROY, dnode); args.context = context; args.event = event; @@ -1369,9 +1621,9 @@ static int nb_callback_move(struct nb_context *context, bool unexpected_error = false; int ret; - assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)); + assert(!CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)); - nb_log_config_callback(event, NB_OP_MOVE, dnode); + nb_log_config_callback(event, NB_CB_MOVE, dnode); args.context = context; args.event = event; @@ -1414,10 +1666,10 @@ static int nb_callback_pre_validate(struct nb_context *context, bool unexpected_error = false; int ret; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return 0; - nb_log_config_callback(NB_EV_VALIDATE, NB_OP_PRE_VALIDATE, dnode); + nb_log_config_callback(NB_EV_VALIDATE, NB_CB_PRE_VALIDATE, dnode); args.dnode = dnode; args.errmsg = errmsg; @@ -1448,10 +1700,10 @@ static void nb_callback_apply_finish(struct nb_context *context, { struct nb_cb_apply_finish_args args = {}; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return; - nb_log_config_callback(NB_EV_APPLY, NB_OP_APPLY_FINISH, dnode); + nb_log_config_callback(NB_EV_APPLY, NB_CB_APPLY_FINISH, dnode); args.context = context; args.dnode = dnode; @@ -1466,7 +1718,7 @@ struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node, { struct nb_cb_get_elem_args args = {}; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return NULL; DEBUGD(&nb_dbg_cbs_state, @@ -1484,7 +1736,7 @@ const void *nb_callback_get_next(const struct nb_node *nb_node, { struct nb_cb_get_next_args args = {}; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return NULL; DEBUGD(&nb_dbg_cbs_state, @@ -1501,7 +1753,7 @@ int nb_callback_get_keys(const struct nb_node *nb_node, const void *list_entry, { struct nb_cb_get_keys_args args = {}; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return 0; DEBUGD(&nb_dbg_cbs_state, @@ -1519,7 +1771,7 @@ const void *nb_callback_lookup_entry(const struct nb_node *nb_node, { struct nb_cb_lookup_entry_args args = {}; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return NULL; DEBUGD(&nb_dbg_cbs_state, @@ -1531,15 +1783,56 @@ const void *nb_callback_lookup_entry(const struct nb_node *nb_node, return nb_node->cbs.lookup_entry(&args); } +const void *nb_callback_lookup_node_entry(struct lyd_node *node, + const void *parent_list_entry) +{ + struct yang_list_keys keys; + struct nb_cb_lookup_entry_args args = {}; + const struct nb_node *nb_node = node->schema->priv; + + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) + return NULL; + + if (yang_get_node_keys(node, &keys)) { + flog_warn(EC_LIB_LIBYANG, + "%s: can't get keys for lookup from existing data node %s", + __func__, node->schema->name); + return NULL; + } + + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (lookup_node_entry): node [%s] parent_list_entry [%p]", + nb_node->xpath, parent_list_entry); + + args.parent_list_entry = parent_list_entry; + args.keys = &keys; + return nb_node->cbs.lookup_entry(&args); +} + +const void *nb_callback_lookup_next(const struct nb_node *nb_node, + const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + struct nb_cb_lookup_entry_args args = {}; + + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) + return NULL; + + DEBUGD(&nb_dbg_cbs_state, + "northbound callback (lookup_entry): node [%s] parent_list_entry [%p]", + nb_node->xpath, parent_list_entry); + + args.parent_list_entry = parent_list_entry; + args.keys = keys; + return nb_node->cbs.lookup_next(&args); +} + int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, - const struct list *input, struct list *output, char *errmsg, - size_t errmsg_len) + const struct lyd_node *input, struct lyd_node *output, + char *errmsg, size_t errmsg_len) { struct nb_cb_rpc_args args = {}; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) - return 0; - DEBUGD(&nb_dbg_cbs_rpc, "northbound RPC: %s", xpath); args.xpath = xpath; @@ -1550,6 +1843,18 @@ int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, return nb_node->cbs.rpc(&args); } +void nb_callback_notify(const struct nb_node *nb_node, const char *xpath, + struct lyd_node *dnode) +{ + struct nb_cb_notify_args args = {}; + + DEBUGD(&nb_dbg_cbs_notify, "northbound notify: %s", xpath); + + args.xpath = xpath; + args.dnode = dnode; + nb_node->cbs.notify(&args); +} + /* * Call the northbound configuration callback associated to a given * configuration change. @@ -1559,14 +1864,14 @@ static int nb_callback_configuration(struct nb_context *context, struct nb_config_change *change, char *errmsg, size_t errmsg_len) { - enum nb_operation operation = change->cb.operation; + enum nb_cb_operation operation = change->cb.operation; char xpath[XPATH_MAXLEN]; const struct nb_node *nb_node = change->cb.nb_node; const struct lyd_node *dnode = change->cb.dnode; union nb_resource *resource; int ret = NB_ERR; - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CBS)) + if (CHECK_FLAG(nb_node->flags, F_NB_NODE_IGNORE_CFG_CBS)) return NB_OK; if (event == NB_EV_VALIDATE) @@ -1575,29 +1880,30 @@ static int nb_callback_configuration(struct nb_context *context, resource = &change->resource; switch (operation) { - case NB_OP_CREATE: + case NB_CB_CREATE: ret = nb_callback_create(context, nb_node, event, dnode, resource, errmsg, errmsg_len); break; - case NB_OP_MODIFY: + case NB_CB_MODIFY: ret = nb_callback_modify(context, nb_node, event, dnode, resource, errmsg, errmsg_len); break; - case NB_OP_DESTROY: + case NB_CB_DESTROY: ret = nb_callback_destroy(context, nb_node, event, dnode, errmsg, errmsg_len); break; - case NB_OP_MOVE: + case NB_CB_MOVE: ret = nb_callback_move(context, nb_node, event, dnode, errmsg, errmsg_len); break; - case NB_OP_PRE_VALIDATE: - case NB_OP_APPLY_FINISH: - case NB_OP_GET_ELEM: - case NB_OP_GET_NEXT: - case NB_OP_GET_KEYS: - case NB_OP_LOOKUP_ENTRY: - case NB_OP_RPC: + case NB_CB_PRE_VALIDATE: + case NB_CB_APPLY_FINISH: + case NB_CB_GET_ELEM: + case NB_CB_GET_NEXT: + case NB_CB_GET_KEYS: + case NB_CB_LOOKUP_ENTRY: + case NB_CB_RPC: + case NB_CB_NOTIFY: yang_dnode_get_path(dnode, xpath, sizeof(xpath)); flog_err(EC_LIB_DEVELOPMENT, "%s: unknown operation (%u) [xpath %s]", __func__, @@ -1613,28 +1919,28 @@ static int nb_callback_configuration(struct nb_context *context, flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath, + nb_cb_operation_name(operation), xpath, errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_PREPARE: flog_warn(EC_LIB_NB_CB_CONFIG_PREPARE, "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath, + nb_cb_operation_name(operation), xpath, errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_ABORT: flog_warn(EC_LIB_NB_CB_CONFIG_ABORT, "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath, + nb_cb_operation_name(operation), xpath, errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_APPLY: flog_err(EC_LIB_NB_CB_CONFIG_APPLY, "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath, + nb_cb_operation_name(operation), xpath, errmsg[0] ? " message: " : "", errmsg); break; default: @@ -1741,6 +2047,7 @@ nb_apply_finish_cb_new(struct nb_config_cbs *cbs, const struct nb_node *nb_node, struct nb_config_cb *cb; cb = XCALLOC(MTYPE_TMP, sizeof(*cb)); + cb->operation = NB_CB_APPLY_FINISH; cb->nb_node = nb_node; cb->dnode = dnode; RB_INSERT(nb_config_cbs, cbs, cb); @@ -1755,6 +2062,7 @@ nb_apply_finish_cb_find(struct nb_config_cbs *cbs, { struct nb_config_cb s; + s.operation = NB_CB_APPLY_FINISH; s.seq = 0; s.nb_node = nb_node; s.dnode = dnode; @@ -1782,12 +2090,12 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction, * (the 'apply_finish' callbacks from the node ancestors should * be called though). */ - if (change->cb.operation == NB_OP_DESTROY) { + if (change->cb.operation == NB_CB_DESTROY) { char xpath[XPATH_MAXLEN]; dnode = lyd_parent(dnode); if (!dnode) - break; + continue; /* * The dnode from 'delete' callbacks point to elements @@ -1833,394 +2141,15 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction, } } -static int nb_oper_data_iter_children(const struct lysc_node *snode, - const char *xpath, const void *list_entry, - const struct yang_list_keys *list_keys, - struct yang_translator *translator, - bool first, uint32_t flags, - nb_oper_data_cb cb, void *arg) -{ - const struct lysc_node *child; - - LY_LIST_FOR (lysc_node_child(snode), child) { - int ret; - - ret = nb_oper_data_iter_node(child, xpath, list_entry, - list_keys, translator, false, - flags, cb, arg); - if (ret != NB_OK) - return ret; - } - - return NB_OK; -} - -static int nb_oper_data_iter_leaf(const struct nb_node *nb_node, - const char *xpath, const void *list_entry, - const struct yang_list_keys *list_keys, - struct yang_translator *translator, - uint32_t flags, nb_oper_data_cb cb, void *arg) -{ - struct yang_data *data; - - if (CHECK_FLAG(nb_node->snode->flags, LYS_CONFIG_W)) - return NB_OK; - - /* Ignore list keys. */ - if (lysc_is_key(nb_node->snode)) - return NB_OK; - - data = nb_callback_get_elem(nb_node, xpath, list_entry); - if (data == NULL) - /* Leaf of type "empty" is not present. */ - return NB_OK; - - return (*cb)(nb_node->snode, translator, data, arg); -} - -static int nb_oper_data_iter_container(const struct nb_node *nb_node, - const char *xpath, - const void *list_entry, - const struct yang_list_keys *list_keys, - struct yang_translator *translator, - uint32_t flags, nb_oper_data_cb cb, - void *arg) -{ - const struct lysc_node *snode = nb_node->snode; - - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) - return NB_OK; - - /* Read-only presence containers. */ - if (nb_node->cbs.get_elem) { - struct yang_data *data; - int ret; - - data = nb_callback_get_elem(nb_node, xpath, list_entry); - if (data == NULL) - /* Presence container is not present. */ - return NB_OK; - - ret = (*cb)(snode, translator, data, arg); - if (ret != NB_OK) - return ret; - } - - /* Read-write presence containers. */ - if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) { - struct lysc_node_container *scontainer; - - scontainer = (struct lysc_node_container *)snode; - if (CHECK_FLAG(scontainer->flags, LYS_PRESENCE) - && !yang_dnode_get(running_config->dnode, xpath)) - return NB_OK; - } - - /* Iterate over the child nodes. */ - return nb_oper_data_iter_children(snode, xpath, list_entry, list_keys, - translator, false, flags, cb, arg); -} - -static int -nb_oper_data_iter_leaflist(const struct nb_node *nb_node, const char *xpath, - const void *parent_list_entry, - const struct yang_list_keys *parent_list_keys, - struct yang_translator *translator, uint32_t flags, - nb_oper_data_cb cb, void *arg) -{ - const void *list_entry = NULL; - - if (CHECK_FLAG(nb_node->snode->flags, LYS_CONFIG_W)) - return NB_OK; - - do { - struct yang_data *data; - int ret; - - list_entry = nb_callback_get_next(nb_node, parent_list_entry, - list_entry); - if (!list_entry) - /* End of the list. */ - break; - - data = nb_callback_get_elem(nb_node, xpath, list_entry); - if (data == NULL) - continue; - - ret = (*cb)(nb_node->snode, translator, data, arg); - if (ret != NB_OK) - return ret; - } while (list_entry); - - return NB_OK; -} - -static int nb_oper_data_iter_list(const struct nb_node *nb_node, - const char *xpath_list, - const void *parent_list_entry, - const struct yang_list_keys *parent_list_keys, - struct yang_translator *translator, - uint32_t flags, nb_oper_data_cb cb, void *arg) -{ - const struct lysc_node *snode = nb_node->snode; - const void *list_entry = NULL; - uint32_t position = 1; - - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) - return NB_OK; - - /* Iterate over all list entries. */ - do { - const struct lysc_node_leaf *skey; - struct yang_list_keys list_keys = {}; - char xpath[XPATH_MAXLEN * 2]; - int ret; - - /* Obtain list entry. */ - list_entry = nb_callback_get_next(nb_node, parent_list_entry, - list_entry); - if (!list_entry) - /* End of the list. */ - break; - - if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) { - /* Obtain the list entry keys. */ - if (nb_callback_get_keys(nb_node, list_entry, - &list_keys) - != NB_OK) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: failed to get list keys", - __func__); - return NB_ERR; - } - - /* Build XPath of the list entry. */ - strlcpy(xpath, xpath_list, sizeof(xpath)); - unsigned int i = 0; - LY_FOR_KEYS (snode, skey) { - assert(i < list_keys.num); - snprintf(xpath + strlen(xpath), - sizeof(xpath) - strlen(xpath), - "[%s='%s']", skey->name, - list_keys.key[i]); - i++; - } - assert(i == list_keys.num); - } else { - /* - * Keyless list - build XPath using a positional index. - */ - snprintf(xpath, sizeof(xpath), "%s[%u]", xpath_list, - position); - position++; - } - - /* Iterate over the child nodes. */ - ret = nb_oper_data_iter_children( - nb_node->snode, xpath, list_entry, &list_keys, - translator, false, flags, cb, arg); - if (ret != NB_OK) - return ret; - } while (list_entry); - - return NB_OK; -} - -static int nb_oper_data_iter_node(const struct lysc_node *snode, - const char *xpath_parent, - const void *list_entry, - const struct yang_list_keys *list_keys, - struct yang_translator *translator, - bool first, uint32_t flags, - nb_oper_data_cb cb, void *arg) -{ - struct nb_node *nb_node; - char xpath[XPATH_MAXLEN]; - int ret = NB_OK; - - if (!first && CHECK_FLAG(flags, NB_OPER_DATA_ITER_NORECURSE) - && CHECK_FLAG(snode->nodetype, LYS_CONTAINER | LYS_LIST)) - return NB_OK; - - /* Update XPath. */ - strlcpy(xpath, xpath_parent, sizeof(xpath)); - if (!first && snode->nodetype != LYS_USES) { - struct lysc_node *parent; - - /* Get the real parent. */ - parent = snode->parent; - - /* - * When necessary, include the namespace of the augmenting - * module. - */ - if (parent && parent->module != snode->module) - snprintf(xpath + strlen(xpath), - sizeof(xpath) - strlen(xpath), "/%s:%s", - snode->module->name, snode->name); - else - snprintf(xpath + strlen(xpath), - sizeof(xpath) - strlen(xpath), "/%s", - snode->name); - } - - nb_node = snode->priv; - switch (snode->nodetype) { - case LYS_CONTAINER: - ret = nb_oper_data_iter_container(nb_node, xpath, list_entry, - list_keys, translator, flags, - cb, arg); - break; - case LYS_LEAF: - ret = nb_oper_data_iter_leaf(nb_node, xpath, list_entry, - list_keys, translator, flags, cb, - arg); - break; - case LYS_LEAFLIST: - ret = nb_oper_data_iter_leaflist(nb_node, xpath, list_entry, - list_keys, translator, flags, - cb, arg); - break; - case LYS_LIST: - ret = nb_oper_data_iter_list(nb_node, xpath, list_entry, - list_keys, translator, flags, cb, - arg); - break; - case LYS_USES: - ret = nb_oper_data_iter_children(snode, xpath, list_entry, - list_keys, translator, false, - flags, cb, arg); - break; - default: - break; - } - - return ret; -} - -int nb_oper_data_iterate(const char *xpath, struct yang_translator *translator, - uint32_t flags, nb_oper_data_cb cb, void *arg) -{ - struct nb_node *nb_node; - const void *list_entry = NULL; - struct yang_list_keys list_keys; - struct list *list_dnodes; - struct lyd_node *dnode, *dn; - struct listnode *ln; - int ret; - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - return NB_ERR; - } - - /* For now this function works only with containers and lists. */ - if (!CHECK_FLAG(nb_node->snode->nodetype, LYS_CONTAINER | LYS_LIST)) { - flog_warn( - EC_LIB_NB_OPERATIONAL_DATA, - "%s: can't iterate over YANG leaf or leaf-list [xpath %s]", - __func__, xpath); - return NB_ERR; - } - - /* - * Create a data tree from the XPath so that we can parse the keys of - * all YANG lists (if any). - */ - - LY_ERR err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, - LYD_NEW_PATH_UPDATE, NULL, &dnode); - if (err || !dnode) { - const char *errmsg = - err ? ly_errmsg(ly_native_ctx) : "node not found"; - flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed %s", - __func__, errmsg); - return NB_ERR; - } - - /* - * Create a linked list to sort the data nodes starting from the root. - */ - list_dnodes = list_new(); - for (dn = dnode; dn; dn = lyd_parent(dn)) { - if (dn->schema->nodetype != LYS_LIST || !lyd_child(dn)) - continue; - listnode_add_head(list_dnodes, dn); - } - /* - * Use the northbound callbacks to find list entry pointer corresponding - * to the given XPath. - */ - for (ALL_LIST_ELEMENTS_RO(list_dnodes, ln, dn)) { - struct lyd_node *child; - struct nb_node *nn; - unsigned int n = 0; - - /* Obtain the list entry keys. */ - memset(&list_keys, 0, sizeof(list_keys)); - LY_LIST_FOR (lyd_child(dn), child) { - if (!lysc_is_key(child->schema)) - break; - strlcpy(list_keys.key[n], - yang_dnode_get_string(child, NULL), - sizeof(list_keys.key[n])); - n++; - } - list_keys.num = n; - if (list_keys.num != yang_snode_num_keys(dn->schema)) { - list_delete(&list_dnodes); - yang_dnode_free(dnode); - return NB_ERR_NOT_FOUND; - } - - /* Find the list entry pointer. */ - nn = dn->schema->priv; - if (!nn->cbs.lookup_entry) { - flog_warn( - EC_LIB_NB_OPERATIONAL_DATA, - "%s: data path doesn't support iteration over operational data: %s", - __func__, xpath); - list_delete(&list_dnodes); - yang_dnode_free(dnode); - return NB_ERR; - } - - list_entry = - nb_callback_lookup_entry(nn, list_entry, &list_keys); - if (list_entry == NULL) { - list_delete(&list_dnodes); - yang_dnode_free(dnode); - return NB_ERR_NOT_FOUND; - } - } - - /* If a list entry was given, iterate over that list entry only. */ - if (dnode->schema->nodetype == LYS_LIST && lyd_child(dnode)) - ret = nb_oper_data_iter_children( - nb_node->snode, xpath, list_entry, &list_keys, - translator, true, flags, cb, arg); - else - ret = nb_oper_data_iter_node(nb_node->snode, xpath, list_entry, - &list_keys, translator, true, - flags, cb, arg); - - list_delete(&list_dnodes); - yang_dnode_free(dnode); - - return ret; -} - -bool nb_operation_is_valid(enum nb_operation operation, - const struct lysc_node *snode) +bool nb_cb_operation_is_valid(enum nb_cb_operation operation, + const struct lysc_node *snode) { struct nb_node *nb_node = snode->priv; struct lysc_node_container *scontainer; struct lysc_node_leaf *sleaf; switch (operation) { - case NB_OP_CREATE: + case NB_CB_CREATE: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -2231,6 +2160,8 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; break; case LYS_CONTAINER: + if (snode->parent && snode->parent->nodetype == LYS_CASE) + return true; scontainer = (struct lysc_node_container *)snode; if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE)) return false; @@ -2242,7 +2173,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_MODIFY: + case NB_CB_MODIFY: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -2260,7 +2191,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_DESTROY: + case NB_CB_DESTROY: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -2285,6 +2216,8 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; break; case LYS_CONTAINER: + if (snode->parent && snode->parent->nodetype == LYS_CASE) + return true; scontainer = (struct lysc_node_container *)snode; if (!CHECK_FLAG(scontainer->flags, LYS_PRESENCE)) return false; @@ -2296,7 +2229,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_MOVE: + case NB_CB_MOVE: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; @@ -2310,12 +2243,12 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_PRE_VALIDATE: - case NB_OP_APPLY_FINISH: + case NB_CB_PRE_VALIDATE: + case NB_CB_APPLY_FINISH: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W)) return false; return true; - case NB_OP_GET_ELEM: + case NB_CB_GET_ELEM: if (!CHECK_FLAG(snode->flags, LYS_CONFIG_R)) return false; @@ -2332,7 +2265,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_GET_NEXT: + case NB_CB_GET_NEXT: switch (snode->nodetype) { case LYS_LIST: if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) @@ -2346,8 +2279,8 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_GET_KEYS: - case NB_OP_LOOKUP_ENTRY: + case NB_CB_GET_KEYS: + case NB_CB_LOOKUP_ENTRY: switch (snode->nodetype) { case LYS_LIST: if (CHECK_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY)) @@ -2359,7 +2292,7 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; - case NB_OP_RPC: + case NB_CB_RPC: if (CHECK_FLAG(snode->flags, LYS_CONFIG_W | LYS_CONFIG_R)) return false; @@ -2371,6 +2304,10 @@ bool nb_operation_is_valid(enum nb_operation operation, return false; } return true; + case NB_CB_NOTIFY: + if (snode->nodetype != LYS_NOTIF) + return false; + return true; default: return false; } @@ -2381,17 +2318,81 @@ DEFINE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments), int nb_notification_send(const char *xpath, struct list *arguments) { + struct lyd_node *root = NULL; + struct lyd_node *dnode; + struct yang_data *data; + struct listnode *ln; + LY_ERR err; int ret; DEBUGD(&nb_dbg_notif, "northbound notification: %s", xpath); + /* + * Call old hook functions + */ ret = hook_call(nb_notification_send, xpath, arguments); + + if (!hook_have_hooks(nb_notification_tree_send)) + goto done; + /* + * Convert yang data arguments list to a libyang data tree for new hook + * functions. + */ + for (ALL_LIST_ELEMENTS_RO(arguments, ln, data)) { + err = lyd_new_path(root, ly_native_ctx, data->xpath, + data->value, LYD_NEW_PATH_UPDATE, &dnode); + if (err != LY_SUCCESS) + goto lyerr; + if (!root) { + root = dnode; + while (root->parent) + root = lyd_parent(root); + } + } + + if (!root) { + err = lyd_new_path(NULL, ly_native_ctx, xpath, "", 0, &root); + if (err) { +lyerr: + flog_err(EC_LIB_LIBYANG, + "%s: error creating notification data: %s", + __func__, ly_strerrcode(err)); + ret += 1; + goto done; + } + } + + /* + * Call new hook functions + */ + ret += nb_notification_tree_send(xpath, root); + +done: + if (root) + lyd_free_all(root); if (arguments) list_delete(&arguments); return ret; } +DEFINE_HOOK(nb_notification_tree_send, + (const char *xpath, const struct lyd_node *tree), (xpath, tree)); + +int nb_notification_tree_send(const char *xpath, const struct lyd_node *tree) +{ + int ret; + + assert(tree); + + DEBUGD(&nb_dbg_notif, "northbound tree notification: %s", + tree->schema->name); + + ret = hook_call(nb_notification_tree_send, xpath, tree); + + return ret; +} + /* Running configuration user pointers management. */ struct nb_config_entry { char xpath[XPATH_MAXLEN]; @@ -2561,31 +2562,33 @@ const char *nb_event_name(enum nb_event event) assert(!"Reached end of function we should never hit"); } -const char *nb_operation_name(enum nb_operation operation) +const char *nb_cb_operation_name(enum nb_cb_operation operation) { switch (operation) { - case NB_OP_CREATE: + case NB_CB_CREATE: return "create"; - case NB_OP_MODIFY: + case NB_CB_MODIFY: return "modify"; - case NB_OP_DESTROY: + case NB_CB_DESTROY: return "destroy"; - case NB_OP_MOVE: + case NB_CB_MOVE: return "move"; - case NB_OP_PRE_VALIDATE: + case NB_CB_PRE_VALIDATE: return "pre_validate"; - case NB_OP_APPLY_FINISH: + case NB_CB_APPLY_FINISH: return "apply_finish"; - case NB_OP_GET_ELEM: + case NB_CB_GET_ELEM: return "get_elem"; - case NB_OP_GET_NEXT: + case NB_CB_GET_NEXT: return "get_next"; - case NB_OP_GET_KEYS: + case NB_CB_GET_KEYS: return "get_keys"; - case NB_OP_LOOKUP_ENTRY: + case NB_CB_LOOKUP_ENTRY: return "lookup_entry"; - case NB_OP_RPC: + case NB_CB_RPC: return "rpc"; + case NB_CB_NOTIFY: + return "notify"; } assert(!"Reached end of function we should never hit"); @@ -2610,6 +2613,8 @@ const char *nb_err_name(enum nb_error error) return "failed to allocate resource"; case NB_ERR_INCONSISTENCY: return "internal inconsistency"; + case NB_YIELD: + return "should yield"; } assert(!"Reached end of function we should never hit"); @@ -2620,8 +2625,6 @@ const char *nb_client_name(enum nb_client client) switch (client) { case NB_CLIENT_CLI: return "CLI"; - case NB_CLIENT_CONFD: - return "ConfD"; case NB_CLIENT_SYSREPO: return "Sysrepo"; case NB_CLIENT_GRPC: @@ -2641,10 +2644,6 @@ const char *nb_client_name(enum nb_client client) static void nb_load_callbacks(const struct frr_yang_module_info *module) { - - if (module->ignore_cbs) - return; - for (size_t i = 0; module->nodes[i].xpath; i++) { struct nb_node *nb_node; uint32_t priority; @@ -2710,7 +2709,8 @@ void nb_init(struct event_loop *tm, for (size_t i = 0; i < nmodules; i++) { DEBUGD(&nb_dbg_events, "northbound: loading %s.yang", modules[i]->name); - *loadedp++ = yang_module_load(modules[i]->name); + *loadedp++ = yang_module_load(modules[i]->name, + modules[i]->features); } if (explicit_compile) @@ -2735,10 +2735,15 @@ void nb_init(struct event_loop *tm, /* Initialize the northbound CLI. */ nb_cli_init(tm); + + /* Initialize oper-state */ + nb_oper_init(tm); } void nb_terminate(void) { + nb_oper_terminate(); + /* Terminate the northbound CLI. */ nb_cli_terminate(); diff --git a/lib/northbound.h b/lib/northbound.h index 1723a87e4e75..34d17a587caa 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -83,28 +83,23 @@ enum nb_event { }; /* - * Northbound operations. + * Northbound callback operations. * * Refer to the documentation comments of nb_callbacks for more details. */ -enum nb_operation { - NB_OP_CREATE, - NB_OP_MODIFY, - NB_OP_DESTROY, - NB_OP_MOVE, - NB_OP_PRE_VALIDATE, - NB_OP_APPLY_FINISH, - NB_OP_GET_ELEM, - NB_OP_GET_NEXT, - NB_OP_GET_KEYS, - NB_OP_LOOKUP_ENTRY, - NB_OP_RPC, -}; - -struct nb_cfg_change { - char xpath[XPATH_MAXLEN]; - enum nb_operation operation; - const char *value; +enum nb_cb_operation { + NB_CB_CREATE, + NB_CB_MODIFY, + NB_CB_DESTROY, + NB_CB_MOVE, + NB_CB_PRE_VALIDATE, + NB_CB_APPLY_FINISH, + NB_CB_GET_ELEM, + NB_CB_GET_NEXT, + NB_CB_GET_KEYS, + NB_CB_LOOKUP_ENTRY, + NB_CB_RPC, + NB_CB_NOTIFY, }; union nb_resource { @@ -279,11 +274,11 @@ struct nb_cb_rpc_args { /* XPath of the YANG RPC or action. */ const char *xpath; - /* Read-only list of input parameters. */ - const struct list *input; + /* Read-only "input" tree of the RPC/action. */ + const struct lyd_node *input; - /* List of output parameters to be populated by the callback. */ - struct list *output; + /* The "output" tree of the RPC/action to be populated by the callback. */ + struct lyd_node *output; /* Buffer to store human-readable error message in case of error. */ char *errmsg; @@ -292,6 +287,18 @@ struct nb_cb_rpc_args { size_t errmsg_len; }; +struct nb_cb_notify_args { + /* XPath of the notification. */ + const char *xpath; + + /* + * libyang data node representing the notification. If the notification + * is not top-level, it still points to the notification node, but it's + * part of the full data tree with all its parents. + */ + struct lyd_node *dnode; +}; + /* * Set of configuration callbacks that can be associated to a northbound node. */ @@ -484,6 +491,22 @@ struct nb_callbacks { */ const void *(*lookup_entry)(struct nb_cb_lookup_entry_args *args); + /* + * Operational data callback for YANG lists. + * + * The callback function should return the next list entry that would + * follow a list entry with the keys given as a parameter. Keyless + * lists don't need to implement this callback. + * + * args + * Refer to the documentation comments of nb_cb_lookup_entry_args for + * details. + * + * Returns: + * Pointer to the list entry if found, or NULL if not found. + */ + const void *(*lookup_next)(struct nb_cb_lookup_entry_args *args); + /* * RPC and action callback. * @@ -499,6 +522,17 @@ struct nb_callbacks { */ int (*rpc)(struct nb_cb_rpc_args *args); + /* + * Notification callback. + * + * The callback is called when a YANG notification is received. + * + * args + * Refer to the documentation comments of nb_cb_notify_args for + * details. + */ + void (*notify)(struct nb_cb_notify_args *args); + /* * Optional callback to compare the data nodes when printing * the CLI commands associated with them. @@ -587,18 +621,13 @@ struct nb_node { /* Flags. */ uint8_t flags; - -#ifdef HAVE_CONFD - /* ConfD hash value corresponding to this YANG path. */ - int confd_hash; -#endif }; /* The YANG container or list contains only config data. */ #define F_NB_NODE_CONFIG_ONLY 0x01 /* The YANG list doesn't contain key leafs. */ #define F_NB_NODE_KEYLESS_LIST 0x02 -/* Ignore callbacks for this node */ -#define F_NB_NODE_IGNORE_CBS 0x04 +/* Ignore config callbacks for this node */ +#define F_NB_NODE_IGNORE_CFG_CBS 0x04 /* * HACK: old gcc versions (< 5.x) have a bug that prevents C99 flexible arrays @@ -612,10 +641,19 @@ struct frr_yang_module_info { const char *name; /* - * Ignore callbacks for this module. Set this to true to - * load module without any callbacks. + * Ignore configuration callbacks for this module. Set this to true to + * load module with only CLI-related callbacks. This is useful for + * modules loaded in mgmtd. + */ + bool ignore_cfg_cbs; + + /* + * The NULL-terminated list of supported features. + * Features are defined with "feature" statements in the YANG model. + * Use ["*", NULL] to enable all features. + * Use NULL to disable all features. */ - bool ignore_cbs; + const char **features; /* Northbound callbacks. */ const struct { @@ -644,6 +682,7 @@ enum nb_error { NB_ERR_VALIDATION, NB_ERR_RESOURCE, NB_ERR_INCONSISTENCY, + NB_YIELD, }; /* Default priority. */ @@ -656,7 +695,6 @@ enum nb_error { enum nb_client { NB_CLIENT_NONE = 0, NB_CLIENT_CLI, - NB_CLIENT_CONFD, NB_CLIENT_SYSREPO, NB_CLIENT_GRPC, NB_CLIENT_PCEP, @@ -676,7 +714,7 @@ struct nb_context { /* Northbound configuration callback. */ struct nb_config_cb { RB_ENTRY(nb_config_cb) entry; - enum nb_operation operation; + enum nb_cb_operation operation; uint32_t seq; const struct nb_node *nb_node; const struct lyd_node *dnode; @@ -703,7 +741,26 @@ struct nb_transaction { struct nb_config { struct lyd_node *dnode; uint32_t version; - struct nb_config_cbs cfg_chgs; +}; + +/* + * Northbound operations. The semantics of operations is explained in RFC 8072, + * section 2.5: https://datatracker.ietf.org/doc/html/rfc8072#section-2.5. + */ +enum nb_operation { + NB_OP_CREATE_EXCL, /* "create" */ + NB_OP_CREATE, /* "merge" - kept for backward compatibility */ + NB_OP_MODIFY, /* "merge" */ + NB_OP_DESTROY, /* "remove" */ + NB_OP_DELETE, /* "delete" */ + NB_OP_REPLACE, /* "replace" */ + NB_OP_MOVE, /* "move" */ +}; + +struct nb_cfg_change { + char xpath[XPATH_MAXLEN]; + enum nb_operation operation; + const char *value; }; /* Callback function used by nb_oper_data_iterate(). */ @@ -711,12 +768,37 @@ typedef int (*nb_oper_data_cb)(const struct lysc_node *snode, struct yang_translator *translator, struct yang_data *data, void *arg); +/** + * nb_oper_data_finish_cb() - finish a portion or all of a oper data walk. + * @tree - r/o copy of the tree created during this portion of the walk. + * @arg - finish arg passed to nb_op_iterate_yielding. + * @ret - NB_OK if done with walk, NB_YIELD if done with portion, otherwise an + * error. + * + * If nb_op_iterate_yielding() was passed with @should_batch set then this + * callback will be invoked during each portion (batch) of the walk. + * + * The @tree is read-only and should not be modified or freed. + * + * If this function returns anything but NB_OK then the walk will be terminated. + * and this function will not be called again regardless of if @ret was + * `NB_YIELD` or not. + * + * Return: NB_OK to continue or complete the walk normally, otherwise an error + * to immediately terminate the walk. + */ +/* Callback function used by nb_oper_data_iter_yielding(). */ +typedef enum nb_error (*nb_oper_data_finish_cb)(const struct lyd_node *tree, + void *arg, enum nb_error ret); + /* Iterate over direct child nodes only. */ #define NB_OPER_DATA_ITER_NORECURSE 0x0001 /* Hooks. */ DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments), (xpath, arguments)); +DECLARE_HOOK(nb_notification_tree_send, + (const char *xpath, const struct lyd_node *tree), (xpath, tree)); DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty)); DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set)); @@ -724,6 +806,7 @@ DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set)); extern struct debug nb_dbg_cbs_config; extern struct debug nb_dbg_cbs_state; extern struct debug nb_dbg_cbs_rpc; +extern struct debug nb_dbg_cbs_notify; extern struct debug nb_dbg_notif; extern struct debug nb_dbg_events; extern struct debug nb_dbg_libyang; @@ -744,9 +827,16 @@ extern int nb_callback_get_keys(const struct nb_node *nb_node, extern const void *nb_callback_lookup_entry(const struct nb_node *nb_node, const void *parent_list_entry, const struct yang_list_keys *keys); +extern const void *nb_callback_lookup_node_entry(struct lyd_node *node, + const void *parent_list_entry); +extern const void *nb_callback_lookup_next(const struct nb_node *nb_node, + const void *parent_list_entry, + const struct yang_list_keys *keys); extern int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath, - const struct list *input, struct list *output, + const struct lyd_node *input, struct lyd_node *output, char *errmsg, size_t errmsg_len); +extern void nb_callback_notify(const struct nb_node *nb_node, const char *xpath, + struct lyd_node *dnode); /* * Create a northbound node for all YANG schema nodes. @@ -769,6 +859,14 @@ void nb_nodes_delete(void); */ extern struct nb_node *nb_node_find(const char *xpath); +/** + * nb_nodes_find() - find the NB nodes corresponding to complex xpath. + * @xpath: XPath to search for (with or without predicates). + * + * Return: a dynamic array (darr) of `struct nb_node *`s. + */ +extern struct nb_node **nb_nodes_find(const char *xpath); + extern void nb_node_set_dependency_cbs(const char *dependency_xpath, const char *dependant_xpath, struct nb_dependency_callbacks *cbs); @@ -842,6 +940,32 @@ extern void nb_config_replace(struct nb_config *config_dst, struct nb_config *config_src, bool preserve_source); +/* + * Return a human-readable string representing a northbound operation. + * + * operation + * Northbound operation. + * + * Returns: + * String representation of the given northbound operation. + */ +extern const char *nb_operation_name(enum nb_operation operation); + +/* + * Validate if the northbound operation is allowed for the given node. + * + * nb_node + * Northbound node. + * + * operation + * Operation we want to check. + * + * Returns: + * true if the operation is allowed, false otherwise. + */ +extern bool nb_is_operation_allowed(struct nb_node *nb_node, + enum nb_operation oper); + /* * Edit a candidate configuration. * @@ -866,7 +990,6 @@ extern void nb_config_replace(struct nb_config *config_dst, * * Returns: * - NB_OK on success. - * - NB_ERR_NOT_FOUND when the element to be deleted was not found. * - NB_ERR for other errors. */ extern int nb_candidate_edit(struct nb_config *candidate, @@ -875,6 +998,44 @@ extern int nb_candidate_edit(struct nb_config *candidate, const struct yang_data *previous, const struct yang_data *data); +/* + * Edit a candidate configuration. Value is given as JSON/XML. + * + * candidate + * Candidate configuration to edit. + * + * operation + * Operation to apply. + * + * format + * LYD_FORMAT of the value. + * + * xpath + * XPath of the configuration node being edited. + * For create, it must be the parent. + * + * data + * New data tree for the node. + * + * xpath_created + * XPath of the created node if operation is "create". + * + * errmsg + * Buffer to store human-readable error message in case of error. + * + * errmsg_len + * Size of errmsg. + * + * Returns: + * - NB_OK on success. + * - NB_ERR for other errors. + */ +extern int nb_candidate_edit_tree(struct nb_config *candidate, + enum nb_operation operation, + LYD_FORMAT format, const char *xpath, + const char *data, char *xpath_created, + char *errmsg, size_t errmsg_len); + /* * Create diff for configuration. * @@ -917,11 +1078,8 @@ extern bool nb_candidate_needs_update(const struct nb_config *candidate); * xpath_base * Base xpath for config. * - * curr_xpath - * Current xpath for config. - * - * xpath_index - * Index of xpath being processed. + * in_backend + * Specify whether the changes are being applied in the backend or not. * * err_buf * Buffer to store human-readable error message in case of error. @@ -932,11 +1090,18 @@ extern bool nb_candidate_needs_update(const struct nb_config *candidate); * error * TRUE on error, FALSE on success */ -extern void nb_candidate_edit_config_changes( - struct nb_config *candidate_config, struct nb_cfg_change cfg_changes[], - size_t num_cfg_changes, const char *xpath_base, const char *curr_xpath, - int xpath_index, char *err_buf, int err_bufsize, bool *error); - +extern void nb_candidate_edit_config_changes(struct nb_config *candidate_config, + struct nb_cfg_change cfg_changes[], + size_t num_cfg_changes, + const char *xpath_base, + bool in_backend, char *err_buf, + int err_bufsize, bool *error); + + +extern void nb_config_diff_add_change(struct nb_config_cbs *changes, + enum nb_cb_operation operation, + uint32_t *seq, + const struct lyd_node *dnode); /* * Delete candidate configuration changes. * @@ -1258,7 +1423,7 @@ extern int nb_running_unlock(enum nb_client client, const void *user); extern int nb_running_lock_check(enum nb_client client, const void *user); /* - * Iterate over operational data. + * Iterate over operational data -- deprecated. * * xpath * Data path of the YANG data we want to iterate over. @@ -1269,21 +1434,60 @@ extern int nb_running_lock_check(enum nb_client client, const void *user); * flags * NB_OPER_DATA_ITER_ flags to control how the iteration is performed. * + * should_batch + * Should call finish cb with partial results (i.e., creating batches) + * * cb * Function to call with each data node. * * arg * Arbitrary argument passed as the fourth parameter in each call to 'cb'. * + * tree + * If non-NULL will contain the data tree built from the walk. + * * Returns: * NB_OK on success, NB_ERR otherwise. */ -extern int nb_oper_data_iterate(const char *xpath, - struct yang_translator *translator, - uint32_t flags, nb_oper_data_cb cb, void *arg); +extern enum nb_error nb_oper_iterate_legacy(const char *xpath, + struct yang_translator *translator, + uint32_t flags, nb_oper_data_cb cb, + void *arg, struct lyd_node **tree); + +/** + * nb_oper_walk() - walk the schema building operational state. + * @xpath - + * @translator - + * @flags - + * @should_batch - should allow yielding and processing portions of the tree. + * @cb - callback invoked for each non-list, non-container node. + * @arg - arg to pass to @cb. + * @finish - function to call when done with portion or all of walk. + * @finish_arg - arg to pass to @finish. + * + * Return: walk - a cookie that can be used to cancel the walk. + */ +extern void *nb_oper_walk(const char *xpath, struct yang_translator *translator, + uint32_t flags, bool should_batch, nb_oper_data_cb cb, + void *arg, nb_oper_data_finish_cb finish, + void *finish_arg); + +/** + * nb_oper_cancel_walk() - cancel the in progress walk. + * @walk - value returned from nb_op_iterate_yielding() + * + * Should only be called on an in-progress walk. It is invalid to cancel and + * already finished walk. The walks `finish` callback will not be called. + */ +extern void nb_oper_cancel_walk(void *walk); + +/** + * nb_op_cancel_all_walks() - cancel all in progress walks. + */ +extern void nb_oper_cancel_all_walks(void); /* - * Validate if the northbound operation is valid for the given node. + * Validate if the northbound callback operation is valid for the given node. * * operation * Operation we want to check. @@ -1294,10 +1498,14 @@ extern int nb_oper_data_iterate(const char *xpath, * Returns: * true if the operation is valid, false otherwise. */ -extern bool nb_operation_is_valid(enum nb_operation operation, - const struct lysc_node *snode); +extern bool nb_cb_operation_is_valid(enum nb_cb_operation operation, + const struct lysc_node *snode); /* + * DEPRECATED: This call and infra should no longer be used. Instead, + * the mgmtd supported tree based call `nb_notification_tree_send` should be + * used instead + * * Send a YANG notification. This is a no-op unless the 'nb_notification_send' * hook was registered by a northbound plugin. * @@ -1313,6 +1521,22 @@ extern bool nb_operation_is_valid(enum nb_operation operation, */ extern int nb_notification_send(const char *xpath, struct list *arguments); +/* + * Send a YANG notification from a backend . This is a no-op unless th + * 'nb_notification_tree_send' hook was registered by a northbound plugin. + * + * xpath + * XPath of the YANG notification. + * + * tree + * The libyang tree for the notification. + * + * Returns: + * NB_OK on success, NB_ERR otherwise. + */ +extern int nb_notification_tree_send(const char *xpath, + const struct lyd_node *tree); + /* * Associate a user pointer to a configuration node. * @@ -1419,15 +1643,15 @@ extern void *nb_running_get_entry_non_rec(const struct lyd_node *dnode, extern const char *nb_event_name(enum nb_event event); /* - * Return a human-readable string representing a northbound operation. + * Return a human-readable string representing a northbound callback operation. * * operation - * Northbound operation. + * Northbound callback operation. * * Returns: - * String representation of the given northbound operation. + * String representation of the given northbound callback operation. */ -extern const char *nb_operation_name(enum nb_operation operation); +extern const char *nb_cb_operation_name(enum nb_cb_operation operation); /* * Return a human-readable string representing a northbound error. @@ -1488,6 +1712,9 @@ extern void nb_init(struct event_loop *tm, */ extern void nb_terminate(void); +extern void nb_oper_init(struct event_loop *loop); +extern void nb_oper_terminate(void); + #ifdef __cplusplus } #endif diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 8003679ed57b..4f962cda5c1d 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -5,6 +5,7 @@ */ #include +#include #include "libfrr.h" #include "lib/version.h" @@ -24,6 +25,7 @@ struct debug nb_dbg_cbs_config = {0, "Northbound callbacks: configuration"}; struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"}; struct debug nb_dbg_cbs_rpc = {0, "Northbound callbacks: RPCs"}; +struct debug nb_dbg_cbs_notify = {0, "Northbound callbacks: notifications"}; struct debug nb_dbg_notif = {0, "Northbound notifications"}; struct debug nb_dbg_events = {0, "Northbound events"}; struct debug nb_dbg_libyang = {0, "libyang debugging"}; @@ -145,10 +147,9 @@ static int nb_cli_apply_changes_internal(struct vty *vty, VTY_CHECK_XPATH; - nb_candidate_edit_config_changes( - vty->candidate_config, vty->cfg_changes, vty->num_cfg_changes, - xpath_base, VTY_CURR_XPATH, vty->xpath_index, buf, sizeof(buf), - &error); + nb_candidate_edit_config_changes(vty->candidate_config, vty->cfg_changes, + vty->num_cfg_changes, xpath_base, + false, buf, sizeof(buf), &error); if (error) { /* * Failure to edit the candidate configuration should never @@ -180,8 +181,26 @@ static int nb_cli_apply_changes_internal(struct vty *vty, return CMD_SUCCESS; } +static void create_xpath_base_abs(struct vty *vty, char *xpath_base_abs, + size_t xpath_base_abs_size, + const char *xpath_base) +{ + memset(xpath_base_abs, 0, xpath_base_abs_size); + + if (xpath_base[0] == 0) + xpath_base = "."; + + /* If base xpath is relative, prepend current vty xpath. */ + if (vty->xpath_index > 0 && xpath_base[0] == '.') { + strlcpy(xpath_base_abs, VTY_CURR_XPATH, xpath_base_abs_size); + xpath_base++; /* skip '.' */ + } + strlcat(xpath_base_abs, xpath_base, xpath_base_abs_size); +} + int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) { + char xpath_base_abs[XPATH_MAXLEN] = {}; char xpath_base[XPATH_MAXLEN] = {}; bool implicit_commit; int ret; @@ -195,6 +214,9 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) va_end(ap); } + create_xpath_base_abs(vty, xpath_base_abs, sizeof(xpath_base_abs), + xpath_base); + if (vty_mgmt_should_process_cli_apply_changes(vty)) { VTY_CHECK_XPATH; @@ -202,18 +224,20 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) return CMD_SUCCESS; implicit_commit = vty_needs_implicit_commit(vty); - ret = vty_mgmt_send_config_data(vty, implicit_commit); + ret = vty_mgmt_send_config_data(vty, xpath_base_abs, + implicit_commit); if (ret >= 0 && !implicit_commit) vty->mgmt_num_pending_setcfg++; return ret; } - return nb_cli_apply_changes_internal(vty, xpath_base, false); + return nb_cli_apply_changes_internal(vty, xpath_base_abs, false); } int nb_cli_apply_changes_clear_pending(struct vty *vty, const char *xpath_base_fmt, ...) { + char xpath_base_abs[XPATH_MAXLEN] = {}; char xpath_base[XPATH_MAXLEN] = {}; bool implicit_commit; int ret; @@ -227,6 +251,9 @@ int nb_cli_apply_changes_clear_pending(struct vty *vty, va_end(ap); } + create_xpath_base_abs(vty, xpath_base_abs, sizeof(xpath_base_abs), + xpath_base); + if (vty_mgmt_should_process_cli_apply_changes(vty)) { VTY_CHECK_XPATH; /* @@ -238,19 +265,41 @@ int nb_cli_apply_changes_clear_pending(struct vty *vty, * conversions to mgmtd require full proper implementations. */ implicit_commit = vty_needs_implicit_commit(vty); - ret = vty_mgmt_send_config_data(vty, implicit_commit); + ret = vty_mgmt_send_config_data(vty, xpath_base_abs, + implicit_commit); if (ret >= 0 && !implicit_commit) vty->mgmt_num_pending_setcfg++; return ret; } - return nb_cli_apply_changes_internal(vty, xpath_base, true); + return nb_cli_apply_changes_internal(vty, xpath_base_abs, true); +} + +int nb_cli_rpc_enqueue(struct vty *vty, const char *xpath, const char *value) +{ + struct nb_cfg_change *param; + + if (vty->num_rpc_params == VTY_MAXCFGCHANGES) { + /* Not expected to happen. */ + vty_out(vty, + "%% Exceeded the maximum number of params (%u) for a single command\n\n", + VTY_MAXCFGCHANGES); + return CMD_WARNING; + } + + param = &vty->rpc_params[vty->num_rpc_params++]; + strlcpy(param->xpath, xpath, sizeof(param->xpath)); + param->value = value; + + return CMD_SUCCESS; } -int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input, - struct list *output) +int nb_cli_rpc(struct vty *vty, const char *xpath, struct lyd_node **output_p) { struct nb_node *nb_node; + struct lyd_node *input = NULL; + struct lyd_node *output = NULL; + LY_ERR err; int ret; char errmsg[BUFSIZ] = {0}; @@ -261,12 +310,62 @@ int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input, return CMD_WARNING; } + /* create input tree */ + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, 0, NULL, + &input); + assert(err == LY_SUCCESS); + + for (size_t i = 0; i < vty->num_rpc_params; i++) { + err = lyd_new_path(input, ly_native_ctx, + vty->rpc_params[i].xpath, + vty->rpc_params[i].value, 0, NULL); + assert(err == LY_SUCCESS); + } + + if (vty_mgmt_fe_enabled()) { + char *data = NULL; + + err = lyd_print_mem(&data, input, LYD_JSON, LYD_PRINT_SHRINK); + assert(err == LY_SUCCESS); + + ret = vty_mgmt_send_rpc_req(vty, LYD_JSON, xpath, data); + + free(data); + lyd_free_all(input); + + if (ret < 0) + return CMD_WARNING; + return CMD_SUCCESS; + } + + /* validate input tree to create implicit defaults */ + err = lyd_validate_op(input, NULL, LYD_TYPE_RPC_YANG, NULL); + assert(err == LY_SUCCESS); + + /* create output tree root for population in the callback */ + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, 0, NULL, + &output); + assert(err == LY_SUCCESS); + ret = nb_callback_rpc(nb_node, xpath, input, output, errmsg, sizeof(errmsg)); + + /* validate output tree to create implicit defaults */ + err = lyd_validate_op(output, NULL, LYD_TYPE_REPLY_YANG, NULL); + assert(err == LY_SUCCESS); + + lyd_free_all(input); + vty->num_rpc_params = 0; + switch (ret) { case NB_OK: + if (output_p) + *output_p = output; + else + lyd_free_all(output); return CMD_SUCCESS; default: + lyd_free_all(output); if (strlen(errmsg)) vty_show_nb_errors(vty, ret, errmsg); return CMD_WARNING; @@ -1411,11 +1510,9 @@ static int nb_cli_oper_data_cb(const struct lysc_node *snode, } exit: - yang_data_free(data); return NB_OK; error: - yang_data_free(data); return NB_ERR; } @@ -1464,9 +1561,14 @@ DEFPY (show_yang_operational_data, ly_ctx = ly_native_ctx; /* Obtain data. */ - dnode = yang_dnode_new(ly_ctx, false); - ret = nb_oper_data_iterate(xpath, translator, 0, nb_cli_oper_data_cb, - dnode); + if (translator) { + dnode = yang_dnode_new(ly_ctx, false); + ret = nb_oper_iterate_legacy(xpath, translator, 0, + nb_cli_oper_data_cb, dnode, NULL); + } else { + dnode = NULL; + ret = nb_oper_iterate_legacy(xpath, NULL, 0, NULL, NULL, &dnode); + } if (ret != NB_OK) { if (format == LYD_JSON) vty_out(vty, "{}\n"); @@ -1474,7 +1576,8 @@ DEFPY (show_yang_operational_data, /* embed ly_last_errmsg() when we get newer libyang */ vty_out(vty, "\n"); } - yang_dnode_free(dnode); + if (dnode) + yang_dnode_free(dnode); return CMD_WARNING; } @@ -1741,13 +1844,15 @@ DEFPY (rollback_config, /* Debug CLI commands. */ static struct debug *nb_debugs[] = { &nb_dbg_cbs_config, &nb_dbg_cbs_state, &nb_dbg_cbs_rpc, - &nb_dbg_notif, &nb_dbg_events, &nb_dbg_libyang, + &nb_dbg_cbs_notify, &nb_dbg_notif, &nb_dbg_events, + &nb_dbg_libyang, }; static const char *const nb_debugs_conflines[] = { "debug northbound callbacks configuration", "debug northbound callbacks state", "debug northbound callbacks rpc", + "debug northbound callbacks notify", "debug northbound notifications", "debug northbound events", "debug northbound libyang", @@ -1772,7 +1877,7 @@ DEFPY (debug_nb, debug_nb_cmd, "[no] debug northbound\ [<\ - callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc}]\ + callbacks$cbs [{configuration$cbs_cfg|state$cbs_state|rpc$cbs_rpc|notify$cbs_notify}]\ |notifications$notifications\ |events$events\ |libyang$libyang\ @@ -1785,13 +1890,14 @@ DEFPY (debug_nb, "State\n" "RPC\n" "Notifications\n" + "Notifications\n" "Events\n" "libyang debugging\n") { uint32_t mode = DEBUG_NODE2MODE(vty->node); if (cbs) { - bool none = (!cbs_cfg && !cbs_state && !cbs_rpc); + bool none = (!cbs_cfg && !cbs_state && !cbs_rpc && !cbs_notify); if (none || cbs_cfg) DEBUG_MODE_SET(&nb_dbg_cbs_config, mode, !no); @@ -1799,6 +1905,8 @@ DEFPY (debug_nb, DEBUG_MODE_SET(&nb_dbg_cbs_state, mode, !no); if (none || cbs_rpc) DEBUG_MODE_SET(&nb_dbg_cbs_rpc, mode, !no); + if (none || cbs_notify) + DEBUG_MODE_SET(&nb_dbg_cbs_notify, mode, !no); } if (notifications) DEBUG_MODE_SET(&nb_dbg_notif, mode, !no); diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index c8f8a8481ab7..4c8dc50bd232 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -32,7 +32,7 @@ extern struct nb_config *vty_shared_candidate_config; * XPath (absolute or relative) of the configuration option being edited. * * operation - * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DELETE). + * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DESTROY). * * value * New value of the configuration option. Should be NULL for typeless YANG @@ -80,7 +80,23 @@ extern int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) PRINTFRR(2, 3); /* - * Execute a YANG RPC or Action. + * Add an input child node for an RPC or an action. + * + * vty + * The vty context. + * + * xpath + * XPath of the child being added, relative to the input container. + * + * value + * Value of the child being added. Can be NULL for containers and leafs of + * type 'empty'. + */ +extern int nb_cli_rpc_enqueue(struct vty *vty, const char *xpath, + const char *value); + +/* + * Execute a YANG RPC or Action using the enqueued input parameters. * * vty * The vty terminal to dump any error. @@ -88,20 +104,16 @@ extern int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, * xpath * XPath of the YANG RPC or Action node. * - * input - * List of 'yang_data' structures containing the RPC input parameters. It - * can be set to NULL when there are no input parameters. - * - * output - * List of 'yang_data' structures used to retrieve the RPC output parameters. - * It can be set to NULL when it's known that the given YANG RPC or Action - * doesn't have any output parameters. + * output_p + * A pointer to the libyang data node that will hold the output data tree. + * It can be set to NULL if the caller is not interested in processing the + * output. The caller is responsible for freeing the output data tree. * * Returns: * CMD_SUCCESS on success, CMD_WARNING otherwise. */ -extern int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input, - struct list *output); +extern int nb_cli_rpc(struct vty *vty, const char *xpath, + struct lyd_node **output_p); /* * Show CLI commands associated to the given YANG data node. diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c deleted file mode 100644 index 34406a110b9e..000000000000 --- a/lib/northbound_confd.c +++ /dev/null @@ -1,1494 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 NetDEF, Inc. - * Renato Westphal - */ - -#include - -#include "log.h" -#include "lib_errors.h" -#include "command.h" -#include "debug.h" -#include "libfrr.h" -#include "lib/version.h" -#include "northbound.h" - -#include -#include -#include -#include - -DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module"); - -static struct debug nb_dbg_client_confd = {0, "Northbound client: ConfD"}; - -static struct event_loop *master; -static struct sockaddr confd_addr; -static int cdb_sub_sock, dp_ctl_sock, dp_worker_sock; -static struct event *t_cdb_sub, *t_dp_ctl, *t_dp_worker; -static struct confd_daemon_ctx *dctx; -static struct confd_notification_ctx *live_ctx; -static bool confd_connected; -static struct list *confd_spoints; -static struct nb_transaction *transaction; - -static void frr_confd_finish_cdb(void); -static void frr_confd_finish_dp(void); -static int frr_confd_finish(void); - -#define flog_err_confd(funcname) \ - flog_err(EC_LIB_LIBCONFD, "%s: %s() failed: %s (%d): %s", __func__, \ - (funcname), confd_strerror(confd_errno), confd_errno, \ - confd_lasterr()) - - -/* ------------ Utils ------------ */ - -/* Get XPath string from ConfD hashed keypath. */ -static void frr_confd_get_xpath(const confd_hkeypath_t *kp, char *xpath, - size_t len) -{ - char *p; - - confd_xpath_pp_kpath(xpath, len, 0, kp); - - /* - * Replace double quotes by single quotes (the format accepted by the - * northbound API). - */ - p = xpath; - while ((p = strchr(p, '"')) != NULL) - *p++ = '\''; -} - -/* Convert ConfD binary value to a string. */ -static int frr_confd_val2str(const char *xpath, const confd_value_t *value, - char *string, size_t string_size) -{ - struct confd_cs_node *csp; - - csp = confd_cs_node_cd(NULL, xpath); - if (!csp) { - flog_err_confd("confd_cs_node_cd"); - return -1; - } - if (confd_val2str(csp->info.type, value, string, string_size) - == CONFD_ERR) { - flog_err_confd("confd_val2str"); - return -1; - } - - return 0; -} - -/* Obtain list entry from ConfD hashed keypath. */ -static int frr_confd_hkeypath_get_list_entry(const confd_hkeypath_t *kp, - struct nb_node *nb_node, - const void **list_entry) -{ - struct nb_node *nb_node_list; - int parent_lists = 0; - int curr_list = 0; - - *list_entry = NULL; - - /* - * Count the number of YANG lists in the path, disconsidering the - * last element. - */ - nb_node_list = nb_node; - while (nb_node_list->parent_list) { - nb_node_list = nb_node_list->parent_list; - parent_lists++; - } - if (nb_node->snode->nodetype != LYS_LIST && parent_lists == 0) - return 0; - - /* Start from the beginning and move down the tree. */ - for (int i = kp->len; i >= 0; i--) { - struct yang_list_keys keys; - - /* Not a YANG list. */ - if (kp->v[i][0].type != C_BUF) - continue; - - /* Obtain list keys. */ - memset(&keys, 0, sizeof(keys)); - for (int j = 0; kp->v[i][j].type != C_NOEXISTS; j++) { - strlcpy(keys.key[keys.num], - (char *)kp->v[i][j].val.buf.ptr, - sizeof(keys.key[keys.num])); - keys.num++; - } - - /* Obtain northbound node associated to the YANG list. */ - nb_node_list = nb_node; - for (int j = curr_list; j < parent_lists; j++) - nb_node_list = nb_node_list->parent_list; - - /* Obtain list entry. */ - if (!CHECK_FLAG(nb_node_list->flags, F_NB_NODE_KEYLESS_LIST)) { - *list_entry = nb_callback_lookup_entry( - nb_node, *list_entry, &keys); - if (*list_entry == NULL) - return -1; - } else { - unsigned long ptr_ulong; - - /* Retrieve list entry from pseudo-key (string). */ - if (sscanf(keys.key[0], "%lu", &ptr_ulong) != 1) - return -1; - *list_entry = (const void *)ptr_ulong; - } - - curr_list++; - } - - return 0; -} - -/* Fill the current date and time into a confd_datetime structure. */ -static void getdatetime(struct confd_datetime *datetime) -{ - struct tm tm; - struct timeval tv; - - gettimeofday(&tv, NULL); - gmtime_r(&tv.tv_sec, &tm); - - memset(datetime, 0, sizeof(*datetime)); - datetime->year = 1900 + tm.tm_year; - datetime->month = tm.tm_mon + 1; - datetime->day = tm.tm_mday; - datetime->sec = tm.tm_sec; - datetime->micro = tv.tv_usec; - datetime->timezone = 0; - datetime->timezone_minutes = 0; - datetime->hour = tm.tm_hour; - datetime->min = tm.tm_min; -} - -/* ------------ CDB code ------------ */ - -struct cdb_iter_args { - struct nb_config *candidate; - bool error; -}; - -static enum cdb_iter_ret -frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op, - confd_value_t *oldv, confd_value_t *newv, void *args) -{ - char xpath[XPATH_MAXLEN]; - struct nb_node *nb_node; - enum nb_operation nb_op; - struct cdb_iter_args *iter_args = args; - char value_str[YANG_VALUE_MAXLEN]; - struct yang_data *data; - char *sb1, *sb2; - int ret; - - frr_confd_get_xpath(kp, xpath, sizeof(xpath)); - - /* - * HACK: obtain value of leaf-list elements from the XPath due to - * a bug in the ConfD API. - */ - value_str[0] = '\0'; - sb1 = strrchr(xpath, '['); - sb2 = strrchr(xpath, ']'); - if (sb1 && sb2 && !strchr(sb1, '=')) { - *sb2 = '\0'; - strlcpy(value_str, sb1 + 1, sizeof(value_str)); - *sb1 = '\0'; - } - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - iter_args->error = true; - return ITER_STOP; - } - - /* Map operation values. */ - switch (cdb_op) { - case MOP_CREATED: - nb_op = NB_OP_CREATE; - break; - case MOP_DELETED: - nb_op = NB_OP_DESTROY; - break; - case MOP_VALUE_SET: - if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode)) - nb_op = NB_OP_MODIFY; - else - /* Ignore list keys modifications. */ - return ITER_RECURSE; - break; - case MOP_MOVED_AFTER: - nb_op = NB_OP_MOVE; - break; - case MOP_MODIFIED: - /* We're not interested on this. */ - return ITER_RECURSE; - default: - flog_err(EC_LIB_DEVELOPMENT, - "%s: unexpected operation %u [xpath %s]", __func__, - cdb_op, xpath); - iter_args->error = true; - return ITER_STOP; - } - - /* Convert ConfD value to a string. */ - if (nb_node->snode->nodetype != LYS_LEAFLIST && newv - && frr_confd_val2str(nb_node->xpath, newv, value_str, - sizeof(value_str)) - != 0) { - flog_err(EC_LIB_CONFD_DATA_CONVERT, - "%s: failed to convert ConfD value to a string", - __func__); - iter_args->error = true; - return ITER_STOP; - } - - /* Edit the candidate configuration. */ - data = yang_data_new(xpath, value_str); - ret = nb_candidate_edit(iter_args->candidate, nb_node, nb_op, xpath, - NULL, data); - yang_data_free(data); - if (ret != NB_OK) { - flog_warn( - EC_LIB_NB_CANDIDATE_EDIT_ERROR, - "%s: failed to edit candidate configuration: operation [%s] xpath [%s]", - __func__, nb_operation_name(nb_op), xpath); - iter_args->error = true; - return ITER_STOP; - } - - return ITER_RECURSE; -} - -static void frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) -{ - struct nb_context context = {}; - struct nb_config *candidate; - struct cdb_iter_args iter_args; - char errmsg[BUFSIZ] = {0}; - int ret; - - candidate = nb_config_dup(running_config); - - /* Iterate over all configuration changes. */ - iter_args.candidate = candidate; - iter_args.error = false; - for (int i = 0; i < reslen; i++) { - if (cdb_diff_iterate(fd, subp[i], frr_confd_cdb_diff_iter, - ITER_WANT_PREV, &iter_args) - != CONFD_OK) { - flog_err_confd("cdb_diff_iterate"); - } - } - free(subp); - - if (iter_args.error) { - nb_config_free(candidate); - - if (cdb_sub_abort_trans( - cdb_sub_sock, CONFD_ERRCODE_APPLICATION_INTERNAL, 0, - 0, "Couldn't apply configuration changes") - != CONFD_OK) { - flog_err_confd("cdb_sub_abort_trans"); - return; - } - return; - } - - /* - * Validate the configuration changes and allocate all resources - * required to apply them. - */ - transaction = NULL; - context.client = NB_CLIENT_CONFD; - ret = nb_candidate_commit_prepare(context, candidate, NULL, - &transaction, false, false, errmsg, - sizeof(errmsg)); - if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { - enum confd_errcode errcode; - - switch (ret) { - case NB_ERR_LOCKED: - errcode = CONFD_ERRCODE_IN_USE; - break; - case NB_ERR_RESOURCE: - errcode = CONFD_ERRCODE_RESOURCE_DENIED; - break; - default: - errcode = CONFD_ERRCODE_APPLICATION; - break; - } - - /* Reject the configuration changes. */ - if (cdb_sub_abort_trans(cdb_sub_sock, errcode, 0, 0, "%s", - errmsg) - != CONFD_OK) { - flog_err_confd("cdb_sub_abort_trans"); - return; - } - } else { - /* Acknowledge the notification. */ - if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) - != CONFD_OK) { - flog_err_confd("cdb_sync_subscription_socket"); - return; - } - - /* No configuration changes. */ - if (!transaction) - nb_config_free(candidate); - } -} - -static void frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen) -{ - /* - * No need to process the configuration changes again as we're already - * keeping track of them in the "transaction" variable. - */ - free(subp); - - /* Apply the transaction. */ - if (transaction) { - struct nb_config *candidate = transaction->config; - char errmsg[BUFSIZ] = {0}; - - nb_candidate_commit_apply(transaction, true, NULL, errmsg, - sizeof(errmsg)); - nb_config_free(candidate); - } - - /* Acknowledge the notification. */ - if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) { - flog_err_confd("cdb_sync_subscription_socket"); - return; - } -} - -static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen) -{ - /* - * No need to process the configuration changes again as we're already - * keeping track of them in the "transaction" variable. - */ - free(subp); - - /* Abort the transaction. */ - if (transaction) { - struct nb_config *candidate = transaction->config; - char errmsg[BUFSIZ] = {0}; - - nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg)); - nb_config_free(candidate); - } - - /* Acknowledge the notification. */ - if (cdb_sync_subscription_socket(fd, CDB_DONE_PRIORITY) != CONFD_OK) { - flog_err_confd("cdb_sync_subscription_socket"); - return -1; - } - - return 0; -} - -static void frr_confd_cdb_read_cb(struct event *thread) -{ - int fd = EVENT_FD(thread); - enum cdb_sub_notification cdb_ev; - int flags; - int *subp = NULL; - int reslen = 0; - - event_add_read(master, frr_confd_cdb_read_cb, NULL, fd, &t_cdb_sub); - - if (cdb_read_subscription_socket2(fd, &cdb_ev, &flags, &subp, &reslen) - != CONFD_OK) { - flog_err_confd("cdb_read_subscription_socket2"); - return; - } - - switch (cdb_ev) { - case CDB_SUB_PREPARE: - frr_confd_cdb_read_cb_prepare(fd, subp, reslen); - break; - case CDB_SUB_COMMIT: - frr_confd_cdb_read_cb_commit(fd, subp, reslen); - break; - case CDB_SUB_ABORT: - frr_confd_cdb_read_cb_abort(fd, subp, reslen); - break; - default: - flog_err_confd("unknown CDB event"); - break; - } -} - -/* Trigger CDB subscriptions to read the startup configuration. */ -static void *thread_cdb_trigger_subscriptions(void *data) -{ - int sock; - int *sub_points = NULL, len = 0; - struct listnode *node; - int *spoint; - int i = 0; - - /* Create CDB data socket. */ - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) { - flog_err(EC_LIB_SOCKET, "%s: failed to create socket: %s", - __func__, safe_strerror(errno)); - return NULL; - } - - if (cdb_connect(sock, CDB_DATA_SOCKET, &confd_addr, - sizeof(struct sockaddr_in)) - != CONFD_OK) { - flog_err_confd("cdb_connect"); - return NULL; - } - - /* - * Fill array containing the subscription point of all loaded YANG - * modules. - */ - len = listcount(confd_spoints); - sub_points = XCALLOC(MTYPE_CONFD, len * sizeof(int)); - for (ALL_LIST_ELEMENTS_RO(confd_spoints, node, spoint)) - sub_points[i++] = *spoint; - - if (cdb_trigger_subscriptions(sock, sub_points, len) != CONFD_OK) { - flog_err_confd("cdb_trigger_subscriptions"); - return NULL; - } - - /* Cleanup and exit thread. */ - XFREE(MTYPE_CONFD, sub_points); - cdb_close(sock); - - return NULL; -} - -static int frr_confd_subscribe(const struct lysc_node *snode, void *arg) -{ - struct yang_module *module = arg; - struct nb_node *nb_node; - int *spoint; - int ret; - - switch (snode->nodetype) { - case LYS_CONTAINER: - case LYS_LEAF: - case LYS_LEAFLIST: - case LYS_LIST: - break; - default: - return YANG_ITER_CONTINUE; - } - - if (CHECK_FLAG(snode->flags, LYS_CONFIG_R)) - return YANG_ITER_CONTINUE; - - nb_node = snode->priv; - if (!nb_node) - return YANG_ITER_CONTINUE; - - DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'", __func__, - nb_node->xpath); - - spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint)); - ret = cdb_subscribe2(cdb_sub_sock, CDB_SUB_RUNNING_TWOPHASE, - CDB_SUB_WANT_ABORT_ON_ABORT, 3, spoint, - module->confd_hash, nb_node->xpath); - if (ret != CONFD_OK) { - flog_err_confd("cdb_subscribe2"); - XFREE(MTYPE_CONFD, spoint); - return YANG_ITER_CONTINUE; - } - - listnode_add(confd_spoints, spoint); - return YANG_ITER_CONTINUE; -} - -static int frr_confd_init_cdb(void) -{ - struct yang_module *module; - pthread_t cdb_trigger_thread; - - /* Create CDB subscription socket. */ - cdb_sub_sock = socket(PF_INET, SOCK_STREAM, 0); - if (cdb_sub_sock < 0) { - flog_err(EC_LIB_SOCKET, "%s: failed to create socket: %s", - __func__, safe_strerror(errno)); - return -1; - } - - if (cdb_connect(cdb_sub_sock, CDB_SUBSCRIPTION_SOCKET, &confd_addr, - sizeof(struct sockaddr_in)) - != CONFD_OK) { - flog_err_confd("cdb_connect"); - goto error; - } - - /* Subscribe to all loaded YANG data modules. */ - confd_spoints = list_new(); - RB_FOREACH (module, yang_modules, &yang_modules) { - module->confd_hash = confd_str2hash(module->info->ns); - if (module->confd_hash == 0) { - flog_err( - EC_LIB_LIBCONFD, - "%s: failed to find hash value for namespace %s", - __func__, module->info->ns); - goto error; - } - - /* - * The CDB API doesn't provide a mechanism to subscribe to an - * entire YANG module. So we have to find the top level - * nodes ourselves and subscribe to their paths. - */ - yang_snodes_iterate(module->info, frr_confd_subscribe, 0, - module); - } - - if (cdb_subscribe_done(cdb_sub_sock) != CONFD_OK) { - flog_err_confd("cdb_subscribe_done"); - goto error; - } - - /* Create short lived pthread to trigger the CDB subscriptions. */ - if (pthread_create(&cdb_trigger_thread, NULL, - thread_cdb_trigger_subscriptions, NULL)) { - flog_err(EC_LIB_SYSTEM_CALL, "%s: error creating pthread: %s", - __func__, safe_strerror(errno)); - goto error; - } - pthread_detach(cdb_trigger_thread); - - event_add_read(master, frr_confd_cdb_read_cb, NULL, cdb_sub_sock, - &t_cdb_sub); - - return 0; - -error: - frr_confd_finish_cdb(); - - return -1; -} - -static void frr_confd_finish_cdb(void) -{ - if (cdb_sub_sock > 0) { - EVENT_OFF(t_cdb_sub); - cdb_close(cdb_sub_sock); - } -} - -/* ------------ DP code ------------ */ - -static int frr_confd_transaction_init(struct confd_trans_ctx *tctx) -{ - confd_trans_set_fd(tctx, dp_worker_sock); - - return CONFD_OK; -} - -#define CONFD_MAX_CHILD_NODES 32 - -static int frr_confd_data_get_elem(struct confd_trans_ctx *tctx, - confd_hkeypath_t *kp) -{ - struct nb_node *nb_node; - char xpath[XPATH_MAXLEN]; - struct yang_data *data; - confd_value_t v; - const void *list_entry = NULL; - - frr_confd_get_xpath(kp, xpath, sizeof(xpath)); - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - confd_data_reply_not_found(tctx); - return CONFD_OK; - } - - if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &list_entry) != 0) { - confd_data_reply_not_found(tctx); - return CONFD_OK; - } - - data = nb_callback_get_elem(nb_node, xpath, list_entry); - if (data) { - if (data->value) { - CONFD_SET_STR(&v, data->value); - confd_data_reply_value(tctx, &v); - } else - confd_data_reply_found(tctx); - yang_data_free(data); - } else - confd_data_reply_not_found(tctx); - - return CONFD_OK; -} - -static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, - confd_hkeypath_t *kp, long next) -{ - struct nb_node *nb_node; - char xpath[XPATH_MAXLEN]; - struct yang_data *data; - const void *parent_list_entry, *nb_next; - confd_value_t v[LIST_MAXKEYS]; - - frr_confd_get_xpath(kp, xpath, sizeof(xpath)); - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - confd_data_reply_next_key(tctx, NULL, -1, -1); - return CONFD_OK; - } - - if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &parent_list_entry) - != 0) { - /* List entry doesn't exist anymore. */ - confd_data_reply_next_key(tctx, NULL, -1, -1); - return CONFD_OK; - } - - nb_next = nb_callback_get_next(nb_node, parent_list_entry, - (next == -1) ? NULL : (void *)next); - if (!nb_next) { - /* End of the list or leaf-list. */ - confd_data_reply_next_key(tctx, NULL, -1, -1); - return CONFD_OK; - } - - switch (nb_node->snode->nodetype) { - case LYS_LIST: - if (!CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) { - struct yang_list_keys keys; - - memset(&keys, 0, sizeof(keys)); - if (nb_callback_get_keys(nb_node, nb_next, &keys) - != NB_OK) { - flog_warn(EC_LIB_NB_CB_STATE, - "%s: failed to get list keys", - __func__); - confd_data_reply_next_key(tctx, NULL, -1, -1); - return CONFD_OK; - } - - /* Feed keys to ConfD. */ - for (size_t i = 0; i < keys.num; i++) - CONFD_SET_STR(&v[i], keys.key[i]); - confd_data_reply_next_key(tctx, v, keys.num, - (long)nb_next); - } else { - char pointer_str[32]; - - /* - * ConfD 6.6 user guide, chapter 6.11 (Operational data - * lists without keys): - * "To support this without having completely separate - * APIs, we use a "pseudo" key in the ConfD APIs for - * this type of list. This key is not part of the data - * model, and completely hidden in the northbound agent - * interfaces, but is used with e.g. the get_next() and - * get_elem() callbacks as if it were a normal key. This - * "pseudo" key is always a single signed 64-bit - * integer, i.e. the confd_value_t type is C_INT64. The - * values can be chosen arbitrarily by the application, - * as long as a key value returned by get_next() can be - * used to get the data for the corresponding list entry - * with get_elem() or get_object() as usual. It could - * e.g. be an index into an array that holds the data, - * or even a memory address in integer form". - * - * Since we're using the CONFD_DAEMON_FLAG_STRINGSONLY - * option, we must convert our pseudo-key (a void - * pointer) to a string before sending it to confd. - */ - snprintf(pointer_str, sizeof(pointer_str), "%lu", - (unsigned long)nb_next); - CONFD_SET_STR(&v[0], pointer_str); - confd_data_reply_next_key(tctx, v, 1, (long)nb_next); - } - break; - case LYS_LEAFLIST: - data = nb_callback_get_elem(nb_node, xpath, nb_next); - if (data) { - if (data->value) { - CONFD_SET_STR(&v[0], data->value); - confd_data_reply_next_key(tctx, v, 1, - (long)nb_next); - } - yang_data_free(data); - } else - confd_data_reply_next_key(tctx, NULL, -1, -1); - break; - default: - break; - } - - return CONFD_OK; -} - -/* - * Optional callback - implemented for performance reasons. - */ -static int frr_confd_data_get_object(struct confd_trans_ctx *tctx, - confd_hkeypath_t *kp) -{ - struct nb_node *nb_node; - const struct lysc_node *child; - char xpath[XPATH_MAXLEN]; - char xpath_child[XPATH_MAXLEN * 2]; - struct list *elements; - struct yang_data *data; - const void *list_entry; - confd_value_t values[CONFD_MAX_CHILD_NODES]; - size_t nvalues = 0; - - frr_confd_get_xpath(kp, xpath, sizeof(xpath)); - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - confd_data_reply_not_found(tctx); - return CONFD_ERR; - } - - if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &list_entry) != 0) { - confd_data_reply_not_found(tctx); - return CONFD_OK; - } - - elements = yang_data_list_new(); - - /* Loop through list child nodes. */ - LY_LIST_FOR (lysc_node_child(nb_node->snode), child) { - struct nb_node *nb_node_child = child->priv; - confd_value_t *v; - - if (nvalues > CONFD_MAX_CHILD_NODES) - break; - - v = &values[nvalues++]; - - /* Non-presence containers, lists and leaf-lists. */ - if (!nb_node_child->cbs.get_elem) { - CONFD_SET_NOEXISTS(v); - continue; - } - - snprintf(xpath_child, sizeof(xpath_child), "%s/%s", xpath, - child->name); - data = nb_callback_get_elem(nb_node_child, xpath_child, - list_entry); - if (data) { - if (data->value) - CONFD_SET_STR(v, data->value); - else { - /* Presence containers and empty leafs. */ - CONFD_SET_XMLTAG( - v, nb_node_child->confd_hash, - confd_str2hash(nb_node_child->snode - ->module->ns)); - } - listnode_add(elements, data); - } else - CONFD_SET_NOEXISTS(v); - } - - confd_data_reply_value_array(tctx, values, nvalues); - - /* Release memory. */ - list_delete(&elements); - - return CONFD_OK; -} - -/* - * Optional callback - implemented for performance reasons. - */ -static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, - confd_hkeypath_t *kp, long next) -{ - char xpath[XPATH_MAXLEN]; - struct nb_node *nb_node; - struct list *elements; - const void *parent_list_entry; - const void *nb_next; -#define CONFD_OBJECTS_PER_TIME 100 - struct confd_next_object objects[CONFD_OBJECTS_PER_TIME + 1]; - char pseudo_keys[CONFD_OBJECTS_PER_TIME][32]; - int nobjects = 0; - - frr_confd_get_xpath(kp, xpath, sizeof(xpath)); - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - confd_data_reply_next_object_array(tctx, NULL, 0, 0); - return CONFD_OK; - } - - if (frr_confd_hkeypath_get_list_entry(kp, nb_node, &parent_list_entry) - != 0) { - confd_data_reply_next_object_array(tctx, NULL, 0, 0); - return CONFD_OK; - } - - elements = yang_data_list_new(); - nb_next = (next == -1) ? NULL : (void *)next; - - memset(objects, 0, sizeof(objects)); - for (int j = 0; j < CONFD_OBJECTS_PER_TIME; j++) { - struct confd_next_object *object; - const struct lysc_node *child; - struct yang_data *data; - size_t nvalues = 0; - - object = &objects[j]; - - nb_next = nb_callback_get_next(nb_node, parent_list_entry, - nb_next); - if (!nb_next) - /* End of the list. */ - break; - - object->next = (long)nb_next; - - /* Leaf-lists require special handling. */ - if (nb_node->snode->nodetype == LYS_LEAFLIST) { - object->v = XMALLOC(MTYPE_CONFD, sizeof(confd_value_t)); - data = nb_callback_get_elem(nb_node, xpath, nb_next); - assert(data && data->value); - CONFD_SET_STR(object->v, data->value); - nvalues++; - listnode_add(elements, data); - goto next; - } - - object->v = - XMALLOC(MTYPE_CONFD, - CONFD_MAX_CHILD_NODES * sizeof(confd_value_t)); - - /* - * ConfD 6.6 user guide, chapter 6.11 (Operational data lists - * without keys): - * "In the response to the get_next_object() callback, the data - * provider is expected to provide the key values along with the - * other leafs in an array that is populated according to the - * data model. This must be done also for this type of list, - * even though the key isn't actually in the data model. The - * "pseudo" key must always be the first element in the array". - */ - if (CHECK_FLAG(nb_node->flags, F_NB_NODE_KEYLESS_LIST)) { - confd_value_t *v; - - snprintf(pseudo_keys[j], sizeof(pseudo_keys[j]), "%lu", - (unsigned long)nb_next); - - v = &object->v[nvalues++]; - CONFD_SET_STR(v, pseudo_keys[j]); - } - - /* Loop through list child nodes. */ - LY_LIST_FOR (lysc_node_child(nb_node->snode), child) { - struct nb_node *nb_node_child = child->priv; - char xpath_child[XPATH_MAXLEN * 2]; - confd_value_t *v; - - if (nvalues > CONFD_MAX_CHILD_NODES) - break; - - v = &object->v[nvalues++]; - - /* Non-presence containers, lists and leaf-lists. */ - if (!nb_node_child->cbs.get_elem) { - CONFD_SET_NOEXISTS(v); - continue; - } - - snprintf(xpath_child, sizeof(xpath_child), "%s/%s", - xpath, child->name); - data = nb_callback_get_elem(nb_node_child, xpath_child, - nb_next); - if (data) { - if (data->value) - CONFD_SET_STR(v, data->value); - else { - /* - * Presence containers and empty leafs. - */ - CONFD_SET_XMLTAG( - v, nb_node_child->confd_hash, - confd_str2hash( - nb_node_child->snode - ->module->ns)); - } - listnode_add(elements, data); - } else - CONFD_SET_NOEXISTS(v); - } - next: - object->n = nvalues; - nobjects++; - } - - if (nobjects == 0) { - confd_data_reply_next_object_array(tctx, NULL, 0, 0); - list_delete(&elements); - return CONFD_OK; - } - - /* Detect end of the list. */ - if (!nb_next) { - nobjects++; - objects[nobjects].v = NULL; - } - - /* Reply to ConfD. */ - confd_data_reply_next_object_arrays(tctx, objects, nobjects, 0); - if (!nb_next) - nobjects--; - - /* Release memory. */ - list_delete(&elements); - for (int j = 0; j < nobjects; j++) { - struct confd_next_object *object; - - object = &objects[j]; - XFREE(MTYPE_CONFD, object->v); - } - - return CONFD_OK; -} - -static int frr_confd_notification_send(const char *xpath, - struct list *arguments) -{ - struct nb_node *nb_node; - struct yang_module *module; - struct confd_datetime now; - confd_tag_value_t *values; - int nvalues; - int i = 0; - struct yang_data *data; - struct listnode *node; - int ret; - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - return -1; - } - module = yang_module_find(nb_node->snode->module->name); - assert(module); - - nvalues = 2; - if (arguments) - nvalues += listcount(arguments); - - values = XMALLOC(MTYPE_CONFD, nvalues * sizeof(*values)); - - CONFD_SET_TAG_XMLBEGIN(&values[i++], nb_node->confd_hash, - module->confd_hash); - for (ALL_LIST_ELEMENTS_RO(arguments, node, data)) { - struct nb_node *nb_node_arg; - - nb_node_arg = nb_node_find(data->xpath); - if (!nb_node_arg) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, - data->xpath); - XFREE(MTYPE_CONFD, values); - return NB_ERR; - } - - CONFD_SET_TAG_STR(&values[i++], nb_node_arg->confd_hash, - data->value); - } - CONFD_SET_TAG_XMLEND(&values[i++], nb_node->confd_hash, - module->confd_hash); - - getdatetime(&now); - ret = confd_notification_send(live_ctx, &now, values, nvalues); - - /* Release memory. */ - XFREE(MTYPE_CONFD, values); - - /* Map ConfD return code to northbound return code. */ - switch (ret) { - case CONFD_OK: - return NB_OK; - default: - return NB_ERR; - } -} - -static int frr_confd_action_init(struct confd_user_info *uinfo) -{ - confd_action_set_fd(uinfo, dp_worker_sock); - - return CONFD_OK; -} - -static int frr_confd_action_execute(struct confd_user_info *uinfo, - struct xml_tag *name, confd_hkeypath_t *kp, - confd_tag_value_t *params, int nparams) -{ - char xpath[XPATH_MAXLEN]; - struct nb_node *nb_node; - struct list *input; - struct list *output; - struct yang_data *data; - confd_tag_value_t *reply; - int ret = CONFD_OK; - char errmsg[BUFSIZ] = {0}; - - /* Getting the XPath is tricky. */ - if (kp) { - /* This is a YANG RPC. */ - frr_confd_get_xpath(kp, xpath, sizeof(xpath)); - strlcat(xpath, "/", sizeof(xpath)); - strlcat(xpath, confd_hash2str(name->tag), sizeof(xpath)); - } else { - /* This is a YANG action. */ - snprintf(xpath, sizeof(xpath), "/%s:%s", - confd_ns2prefix(name->ns), confd_hash2str(name->tag)); - } - - nb_node = nb_node_find(xpath); - if (!nb_node) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, xpath); - return CONFD_ERR; - } - - input = yang_data_list_new(); - output = yang_data_list_new(); - - /* Process input nodes. */ - for (int i = 0; i < nparams; i++) { - char xpath_input[XPATH_MAXLEN * 2]; - char value_str[YANG_VALUE_MAXLEN]; - - snprintf(xpath_input, sizeof(xpath_input), "%s/%s", xpath, - confd_hash2str(params[i].tag.tag)); - - if (frr_confd_val2str(xpath_input, ¶ms[i].v, value_str, - sizeof(value_str)) - != 0) { - flog_err( - EC_LIB_CONFD_DATA_CONVERT, - "%s: failed to convert ConfD value to a string", - __func__); - ret = CONFD_ERR; - goto exit; - } - - data = yang_data_new(xpath_input, value_str); - listnode_add(input, data); - } - - /* Execute callback registered for this XPath. */ - if (nb_callback_rpc(nb_node, xpath, input, output, errmsg, - sizeof(errmsg)) - != NB_OK) { - flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s", - __func__, xpath); - ret = CONFD_ERR; - goto exit; - } - - /* Process output nodes. */ - if (listcount(output) > 0) { - struct listnode *node; - int i = 0; - - reply = XMALLOC(MTYPE_CONFD, - listcount(output) * sizeof(*reply)); - - for (ALL_LIST_ELEMENTS_RO(output, node, data)) { - struct nb_node *nb_node_output; - int hash; - - nb_node_output = nb_node_find(data->xpath); - if (!nb_node_output) { - flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, - "%s: unknown data path: %s", __func__, - data->xpath); - goto exit; - } - - hash = confd_str2hash(nb_node_output->snode->name); - CONFD_SET_TAG_STR(&reply[i++], hash, data->value); - } - confd_action_reply_values(uinfo, reply, listcount(output)); - XFREE(MTYPE_CONFD, reply); - } - -exit: - /* Release memory. */ - list_delete(&input); - list_delete(&output); - - return ret; -} - - -static int frr_confd_dp_read(struct confd_daemon_ctx *dctx, int fd) -{ - int ret; - - ret = confd_fd_ready(dctx, fd); - if (ret == CONFD_EOF) { - flog_err_confd("confd_fd_ready"); - frr_confd_finish(); - return -1; - } else if (ret == CONFD_ERR && confd_errno != CONFD_ERR_EXTERNAL) { - flog_err_confd("confd_fd_ready"); - frr_confd_finish(); - return -1; - } - - return 0; -} - -static void frr_confd_dp_ctl_read(struct event *thread) -{ - struct confd_daemon_ctx *dctx = EVENT_ARG(thread); - int fd = EVENT_FD(thread); - - event_add_read(master, frr_confd_dp_ctl_read, dctx, fd, &t_dp_ctl); - - frr_confd_dp_read(dctx, fd); -} - -static void frr_confd_dp_worker_read(struct event *thread) -{ - struct confd_daemon_ctx *dctx = EVENT_ARG(thread); - int fd = EVENT_FD(thread); - - event_add_read(master, frr_confd_dp_worker_read, dctx, fd, - &t_dp_worker); - - frr_confd_dp_read(dctx, fd); -} - -static int frr_confd_subscribe_state(const struct lysc_node *snode, void *arg) -{ - struct nb_node *nb_node = snode->priv; - struct confd_data_cbs *data_cbs = arg; - - if (!nb_node || !CHECK_FLAG(snode->flags, LYS_CONFIG_R)) - return YANG_ITER_CONTINUE; - /* We only need to subscribe to the root of the state subtrees. */ - if (snode->parent && CHECK_FLAG(snode->parent->flags, LYS_CONFIG_R)) - return YANG_ITER_CONTINUE; - - DEBUGD(&nb_dbg_client_confd, - "%s: providing data to '%s' (callpoint %s)", __func__, - nb_node->xpath, snode->name); - - strlcpy(data_cbs->callpoint, snode->name, sizeof(data_cbs->callpoint)); - if (confd_register_data_cb(dctx, data_cbs) != CONFD_OK) - flog_err_confd("confd_register_data_cb"); - - return YANG_ITER_CONTINUE; -} - -static int frr_confd_init_dp(const char *program_name) -{ - struct confd_trans_cbs trans_cbs; - struct confd_data_cbs data_cbs; - struct confd_notification_stream_cbs ncbs; - struct confd_action_cbs acbs; - - /* Initialize daemon context. */ - dctx = confd_init_daemon(program_name); - if (!dctx) { - flog_err_confd("confd_init_daemon"); - goto error; - } - - /* - * Inform we want to receive YANG values as raw strings, and that we - * want to provide only strings in the reply functions, regardless of - * the YANG type. - */ - confd_set_daemon_flags(dctx, CONFD_DAEMON_FLAG_STRINGSONLY); - - /* Establish a control socket. */ - dp_ctl_sock = socket(PF_INET, SOCK_STREAM, 0); - if (dp_ctl_sock < 0) { - flog_err(EC_LIB_SOCKET, "%s: failed to create socket: %s", - __func__, safe_strerror(errno)); - goto error; - } - - if (confd_connect(dctx, dp_ctl_sock, CONTROL_SOCKET, &confd_addr, - sizeof(struct sockaddr_in)) - != CONFD_OK) { - flog_err_confd("confd_connect"); - goto error; - } - - /* - * Establish a worker socket (only one since this plugin runs on a - * single thread). - */ - dp_worker_sock = socket(PF_INET, SOCK_STREAM, 0); - if (dp_worker_sock < 0) { - flog_err(EC_LIB_SOCKET, "%s: failed to create socket: %s", - __func__, safe_strerror(errno)); - goto error; - } - if (confd_connect(dctx, dp_worker_sock, WORKER_SOCKET, &confd_addr, - sizeof(struct sockaddr_in)) - != CONFD_OK) { - flog_err_confd("confd_connect"); - goto error; - } - - /* Register transaction callback functions. */ - memset(&trans_cbs, 0, sizeof(trans_cbs)); - trans_cbs.init = frr_confd_transaction_init; - confd_register_trans_cb(dctx, &trans_cbs); - - /* Register our read/write callbacks. */ - memset(&data_cbs, 0, sizeof(data_cbs)); - data_cbs.get_elem = frr_confd_data_get_elem; - data_cbs.exists_optional = frr_confd_data_get_elem; - data_cbs.get_next = frr_confd_data_get_next; - data_cbs.get_object = frr_confd_data_get_object; - data_cbs.get_next_object = frr_confd_data_get_next_object; - - /* - * Iterate over all loaded YANG modules and subscribe to the paths - * referent to state data. - */ - yang_snodes_iterate(NULL, frr_confd_subscribe_state, 0, &data_cbs); - - /* Register notification stream. */ - memset(&ncbs, 0, sizeof(ncbs)); - ncbs.fd = dp_worker_sock; - /* - * RFC 5277 - Section 3.2.3: - * A NETCONF server implementation supporting the notification - * capability MUST support the "NETCONF" notification event - * stream. This stream contains all NETCONF XML event notifications - * supported by the NETCONF server. - */ - strlcpy(ncbs.streamname, "NETCONF", sizeof(ncbs.streamname)); - if (confd_register_notification_stream(dctx, &ncbs, &live_ctx) - != CONFD_OK) { - flog_err_confd("confd_register_notification_stream"); - goto error; - } - - /* Register the action handler callback. */ - memset(&acbs, 0, sizeof(acbs)); - strlcpy(acbs.actionpoint, "actionpoint", sizeof(acbs.actionpoint)); - acbs.init = frr_confd_action_init; - acbs.action = frr_confd_action_execute; - if (confd_register_action_cbs(dctx, &acbs) != CONFD_OK) { - flog_err_confd("confd_register_action_cbs"); - goto error; - } - - /* Notify we registered all callbacks we wanted. */ - if (confd_register_done(dctx) != CONFD_OK) { - flog_err_confd("confd_register_done"); - goto error; - } - - event_add_read(master, frr_confd_dp_ctl_read, dctx, dp_ctl_sock, - &t_dp_ctl); - event_add_read(master, frr_confd_dp_worker_read, dctx, dp_worker_sock, - &t_dp_worker); - - return 0; - -error: - frr_confd_finish_dp(); - - return -1; -} - -static void frr_confd_finish_dp(void) -{ - if (dp_worker_sock > 0) { - EVENT_OFF(t_dp_worker); - close(dp_worker_sock); - } - if (dp_ctl_sock > 0) { - EVENT_OFF(t_dp_ctl); - close(dp_ctl_sock); - } - if (dctx != NULL) - confd_release_daemon(dctx); -} - -/* ------------ CLI ------------ */ - -DEFUN (debug_nb_confd, - debug_nb_confd_cmd, - "[no] debug northbound client confd", - NO_STR - DEBUG_STR - "Northbound debugging\n" - "Client\n" - "ConfD\n") -{ - uint32_t mode = DEBUG_NODE2MODE(vty->node); - bool no = strmatch(argv[0]->text, "no"); - - DEBUG_MODE_SET(&nb_dbg_client_confd, mode, !no); - - return CMD_SUCCESS; -} - -static int frr_confd_debug_config_write(struct vty *vty) -{ - if (DEBUG_MODE_CHECK(&nb_dbg_client_confd, DEBUG_MODE_CONF)) - vty_out(vty, "debug northbound client confd\n"); - - return 0; -} - -static int frr_confd_debug_set_all(uint32_t flags, bool set) -{ - DEBUG_FLAGS_SET(&nb_dbg_client_confd, flags, set); - - /* If all modes have been turned off, don't preserve options. */ - if (!DEBUG_MODE_CHECK(&nb_dbg_client_confd, DEBUG_MODE_ALL)) - DEBUG_CLEAR(&nb_dbg_client_confd); - - return 0; -} - -static void frr_confd_cli_init(void) -{ - hook_register(nb_client_debug_config_write, - frr_confd_debug_config_write); - hook_register(nb_client_debug_set_all, frr_confd_debug_set_all); - - install_element(ENABLE_NODE, &debug_nb_confd_cmd); - install_element(CONFIG_NODE, &debug_nb_confd_cmd); -} - -/* ------------ Main ------------ */ - -static int frr_confd_calculate_snode_hash(const struct lysc_node *snode, - void *arg) -{ - struct nb_node *nb_node = snode->priv; - - if (nb_node) - nb_node->confd_hash = confd_str2hash(snode->name); - - return YANG_ITER_CONTINUE; -} - -static int frr_confd_init(const char *program_name) -{ - struct sockaddr_in *confd_addr4 = (struct sockaddr_in *)&confd_addr; - int debuglevel = CONFD_SILENT; - int ret = -1; - - /* Initialize ConfD library. */ - confd_init(program_name, stderr, debuglevel); - - confd_addr4->sin_family = AF_INET; - confd_addr4->sin_addr.s_addr = inet_addr("127.0.0.1"); - confd_addr4->sin_port = htons(CONFD_PORT); - if (confd_load_schemas(&confd_addr, sizeof(struct sockaddr_in)) - != CONFD_OK) { - flog_err_confd("confd_load_schemas"); - return -1; - } - - ret = frr_confd_init_cdb(); - if (ret != 0) - goto error; - - ret = frr_confd_init_dp(program_name); - if (ret != 0) { - frr_confd_finish_cdb(); - goto error; - } - - yang_snodes_iterate(NULL, frr_confd_calculate_snode_hash, 0, NULL); - - hook_register(nb_notification_send, frr_confd_notification_send); - - confd_connected = true; - return 0; - -error: - confd_free_schemas(); - - return ret; -} - -static int frr_confd_finish(void) -{ - if (!confd_connected) - return 0; - - frr_confd_finish_cdb(); - frr_confd_finish_dp(); - - confd_free_schemas(); - - confd_connected = false; - - return 0; -} - -static int frr_confd_module_late_init(struct event_loop *tm) -{ - master = tm; - - if (frr_confd_init(frr_get_progname()) < 0) { - flog_err(EC_LIB_CONFD_INIT, - "failed to initialize the ConfD module"); - return -1; - } - - hook_register(frr_fini, frr_confd_finish); - frr_confd_cli_init(); - - return 0; -} - -static int frr_confd_module_init(void) -{ - hook_register(frr_late_init, frr_confd_module_late_init); - - return 0; -} - -FRR_MODULE_SETUP(.name = "frr_confd", .version = FRR_VERSION, - .description = "FRR ConfD integration module", - .init = frr_confd_module_init, -); diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index 6c33351cef04..612ec3981b82 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -427,25 +427,11 @@ static struct lyd_node *get_dnode_config(const std::string &path) return dnode; } -static int get_oper_data_cb(const struct lysc_node *snode, - struct yang_translator *translator, - struct yang_data *data, void *arg) -{ - struct lyd_node *dnode = static_cast(arg); - int ret = yang_dnode_edit(dnode, data->xpath, data->value); - yang_data_free(data); - - return (ret == 0) ? NB_OK : NB_ERR; -} - static struct lyd_node *get_dnode_state(const std::string &path) { - struct lyd_node *dnode = yang_dnode_new(ly_native_ctx, false); - if (nb_oper_data_iterate(path.c_str(), NULL, 0, get_oper_data_cb, dnode) - != NB_OK) { - yang_dnode_free(dnode); - return NULL; - } + struct lyd_node *dnode = NULL; + + (void)nb_oper_iterate_legacy(path.c_str(), NULL, 0, NULL, NULL, &dnode); return dnode; } @@ -1025,12 +1011,11 @@ grpc::Status HandleUnaryExecute( grpc_debug("%s: entered", __func__); struct nb_node *nb_node; - struct list *input_list; - struct list *output_list; - struct listnode *node; - struct yang_data *data; + struct lyd_node *input_tree, *output_tree, *child; const char *xpath; char errmsg[BUFSIZ] = {0}; + char path[XPATH_MAXLEN]; + LY_ERR err; // Request: string path = 1; xpath = tag->request.path().c_str(); @@ -1046,40 +1031,66 @@ grpc::Status HandleUnaryExecute( return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Unknown data path"); - input_list = yang_data_list_new(); - output_list = yang_data_list_new(); + // Create input data tree. + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, + (LYD_ANYDATA_VALUETYPE)0, 0, NULL, &input_tree); + if (err != LY_SUCCESS) { + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Invalid data path"); + } // Read input parameters. auto input = tag->request.input(); for (const frr::PathValue &pv : input) { // Request: repeated PathValue input = 2; - data = yang_data_new(pv.path().c_str(), pv.value().c_str()); - listnode_add(input_list, data); + err = lyd_new_path(input_tree, ly_native_ctx, pv.path().c_str(), + pv.value().c_str(), 0, NULL); + if (err != LY_SUCCESS) { + lyd_free_tree(input_tree); + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Invalid input data"); + } + } + + // Validate input data. + err = lyd_validate_op(input_tree, NULL, LYD_TYPE_RPC_YANG, NULL); + if (err != LY_SUCCESS) { + lyd_free_tree(input_tree); + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Invalid input data"); + } + + // Create output data tree. + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, + (LYD_ANYDATA_VALUETYPE)0, 0, NULL, &output_tree); + if (err != LY_SUCCESS) { + lyd_free_tree(input_tree); + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Invalid data path"); } // Execute callback registered for this XPath. - if (nb_callback_rpc(nb_node, xpath, input_list, output_list, errmsg, - sizeof(errmsg)) - != NB_OK) { + if (nb_callback_rpc(nb_node, xpath, input_tree, output_tree, errmsg, + sizeof(errmsg)) != NB_OK) { flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s", __func__, xpath); - list_delete(&input_list); - list_delete(&output_list); + lyd_free_tree(input_tree); + lyd_free_tree(output_tree); return grpc::Status(grpc::StatusCode::INTERNAL, "RPC failed"); } // Process output parameters. - for (ALL_LIST_ELEMENTS_RO(output_list, node, data)) { + LY_LIST_FOR (lyd_child(output_tree), child) { // Response: repeated PathValue output = 1; frr::PathValue *pv = tag->response.add_output(); - pv->set_path(data->xpath); - pv->set_value(data->value); + pv->set_path(lyd_path(child, LYD_PATH_STD, path, sizeof(path))); + pv->set_value(yang_dnode_get_string(child, NULL)); } // Release memory. - list_delete(&input_list); - list_delete(&output_list); + lyd_free_tree(input_tree); + lyd_free_tree(output_tree); return grpc::Status::OK; } diff --git a/lib/northbound_oper.c b/lib/northbound_oper.c new file mode 100644 index 000000000000..5f38c970c77e --- /dev/null +++ b/lib/northbound_oper.c @@ -0,0 +1,1826 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * October 14 2023, Christian Hopps + * + * Copyright (C) 2018 NetDEF, Inc. + * Renato Westphal + * Copyright (c) 2023, LabN Consulting, L.L.C. + * + */ + +#include +#include "darr.h" +#include "debug.h" +#include "frrevent.h" +#include "frrstr.h" +#include "lib_errors.h" +#include "monotime.h" +#include "northbound.h" + +/* + * YANG model yielding design restrictions: + * + * In order to be able to yield and guarantee we have a valid data tree at the + * point of yielding we must know that each parent has all it's siblings + * collected to represent a complete element. + * + * Basically, there should be a only single branch in the schema tree that + * supports yielding. In practice this means: + * + * list node schema with lookup next: + * - must not have any lookup-next list node sibling schema + * - must not have any list or container node siblings with lookup-next descendants. + * - any parent list nodes must also be lookup-next list nodes + * + * We must also process containers with lookup-next descendants last. + */ + +DEFINE_MTYPE_STATIC(LIB, NB_YIELD_STATE, "NB Yield State"); +DEFINE_MTYPE_STATIC(LIB, NB_NODE_INFOS, "NB Node Infos"); + +/* Amount of time allowed to spend constructing oper-state prior to yielding */ +#define NB_OP_WALK_INTERVAL_MS 50 +#define NB_OP_WALK_INTERVAL_US (NB_OP_WALK_INTERVAL_MS * 1000) + +/* ---------- */ +/* Data Types */ +/* ---------- */ +PREDECL_LIST(nb_op_walks); + +/* + * This is our information about a node on the branch we are looking at + */ +struct nb_op_node_info { + struct lyd_node *inner; + const struct lysc_node *schema; /* inner schema in case we rm inner */ + struct yang_list_keys keys; /* if list, keys to locate element */ + const void *list_entry; /* opaque entry from user or NULL */ + uint xpath_len; /* length of the xpath string for this node */ + uint niters; /* # list elems create this iteration */ + uint nents; /* # list elems create so far */ + bool query_specific_entry : 1; /* this info is specific specified */ + bool has_lookup_next : 1; /* if this node support lookup next */ + bool lookup_next_ok : 1; /* if this and all previous support */ +}; + +/** + * struct nb_op_yield_state - tracking required state for yielding. + * + * @xpath: current xpath representing the node_info stack. + * @xpath_orig: the original query string from the user + * @node_infos: the container stack for the walk from root to current + * @schema_path: the schema nodes along the path indicated by the query string. + * this will include the choice and case nodes which are not + * present in the query string. + * @query_tokstr: the query string tokenized with NUL bytes. + * @query_tokens: the string pointers to each query token (node). + * @non_specific_predicate: tracks if a query_token is non-specific predicate. + * @walk_root_level: The topmost specific node, +1 is where we start walking. + * @walk_start_level: @walk_root_level + 1. + * @query_base_level: the level the query string stops at and full walks + * commence below that. + */ +struct nb_op_yield_state { + /* Walking state */ + char *xpath; + char *xpath_orig; + struct nb_op_node_info *node_infos; + const struct lysc_node **schema_path; + char *query_tokstr; + char **query_tokens; + uint8_t *non_specific_predicate; + int walk_root_level; + int walk_start_level; + int query_base_level; + bool query_list_entry; /* XXX query was for a specific list entry */ + + /* Yielding state */ + bool query_did_entry; /* currently processing the entry */ + bool should_batch; + struct timeval start_time; + struct yang_translator *translator; + uint32_t flags; + nb_oper_data_cb cb; + void *cb_arg; + nb_oper_data_finish_cb finish; + void *finish_arg; + struct event *walk_ev; + struct nb_op_walks_item link; +}; + +DECLARE_LIST(nb_op_walks, struct nb_op_yield_state, link); + +/* ---------------- */ +/* Global Variables */ +/* ---------------- */ + +static struct event_loop *event_loop; +static struct nb_op_walks_head nb_op_walks; + +/* --------------------- */ +/* Function Declarations */ +/* --------------------- */ + +static enum nb_error nb_op_yield(struct nb_op_yield_state *ys); +static struct lyd_node *ys_root_node(struct nb_op_yield_state *ys); + +/* -------------------- */ +/* Function Definitions */ +/* -------------------- */ + +static inline struct nb_op_yield_state * +nb_op_create_yield_state(const char *xpath, struct yang_translator *translator, + uint32_t flags, bool should_batch, nb_oper_data_cb cb, + void *cb_arg, nb_oper_data_finish_cb finish, + void *finish_arg) +{ + struct nb_op_yield_state *ys; + + ys = XCALLOC(MTYPE_NB_YIELD_STATE, sizeof(*ys)); + ys->xpath = darr_strdup_cap(xpath, (size_t)XPATH_MAXLEN); + ys->xpath_orig = darr_strdup(xpath); + ys->translator = translator; + ys->flags = flags; + ys->should_batch = should_batch; + ys->cb = cb; + ys->cb_arg = cb_arg; + ys->finish = finish; + ys->finish_arg = finish_arg; + + nb_op_walks_add_tail(&nb_op_walks, ys); + + return ys; +} + +static inline void nb_op_free_yield_state(struct nb_op_yield_state *ys, + bool nofree_tree) +{ + if (ys) { + EVENT_OFF(ys->walk_ev); + nb_op_walks_del(&nb_op_walks, ys); + /* if we have a branch then free up it's libyang tree */ + if (!nofree_tree && ys_root_node(ys)) + lyd_free_all(ys_root_node(ys)); + darr_free(ys->query_tokens); + darr_free(ys->non_specific_predicate); + darr_free(ys->query_tokstr); + darr_free(ys->schema_path); + darr_free(ys->node_infos); + darr_free(ys->xpath_orig); + darr_free(ys->xpath); + XFREE(MTYPE_NB_YIELD_STATE, ys); + } +} + +static const struct lysc_node *ys_get_walk_stem_tip(struct nb_op_yield_state *ys) +{ + if (ys->walk_start_level <= 0) + return NULL; + return ys->node_infos[ys->walk_start_level - 1].schema; +} + +static struct lyd_node *ys_root_node(struct nb_op_yield_state *ys) +{ + if (!darr_len(ys->node_infos)) + return NULL; + return ys->node_infos[0].inner; +} + +static void ys_trim_xpath(struct nb_op_yield_state *ys) +{ + uint len = darr_len(ys->node_infos); + + if (len == 0) + darr_setlen(ys->xpath, 1); + else + darr_setlen(ys->xpath, darr_last(ys->node_infos)->xpath_len + 1); + ys->xpath[darr_len(ys->xpath) - 1] = 0; +} + +static void ys_pop_inner(struct nb_op_yield_state *ys) +{ + uint len = darr_len(ys->node_infos); + + assert(len); + darr_setlen(ys->node_infos, len - 1); + ys_trim_xpath(ys); +} + +static void ys_free_inner(struct nb_op_yield_state *ys, + struct nb_op_node_info *ni) +{ + if (!CHECK_FLAG(ni->schema->nodetype, LYS_CASE | LYS_CHOICE)) + lyd_free_tree(ni->inner); + ni->inner = NULL; +} + +static void nb_op_get_keys(struct lyd_node_inner *list_node, + struct yang_list_keys *keys) +{ + struct lyd_node *child; + uint n = 0; + + keys->num = 0; + LY_LIST_FOR (list_node->child, child) { + if (!lysc_is_key(child->schema)) + break; + strlcpy(keys->key[n], yang_dnode_get_string(child, NULL), + sizeof(keys->key[n])); + n++; + } + + keys->num = n; +} + +/** + * __move_back_to_next() - move back to the next lookup-next schema + */ +static bool __move_back_to_next(struct nb_op_yield_state *ys, int i) +{ + struct nb_op_node_info *ni; + int j; + + /* + * We will free the subtree we are trimming back to, or we will be done + * with the walk and will free the root on cleanup. + */ + + /* pop any node_info we dropped below on entry */ + for (j = darr_ilen(ys->node_infos) - 1; j > i; j--) + ys_pop_inner(ys); + + for (; i >= ys->walk_root_level; i--) { + if (ys->node_infos[i].has_lookup_next) + break; + ys_pop_inner(ys); + } + + if (i < ys->walk_root_level) + return false; + + ni = &ys->node_infos[i]; + + /* + * The i'th node has been lost after a yield so trim it from the tree + * now. + */ + ys_free_inner(ys, ni); + ni->list_entry = NULL; + + /* + * Leave the empty-of-data node_info on top, __walk will deal with + * this, by doing a lookup-next with the keys which we still have. + */ + + return true; +} + +static void nb_op_resume_data_tree(struct nb_op_yield_state *ys) +{ + struct nb_op_node_info *ni; + struct nb_node *nn; + const void *parent_entry; + const void *list_entry; + uint i; + + /* + * IMPORTANT: On yielding: we always yield during list iteration and + * after the initial list element has been created and handled, so the + * top of the yield stack will always point at a list node. + * + * Additionally, that list node has been processed and was in the + * process of being "get_next"d when we yielded. We process the + * lookup-next list node last so all the rest of the data (to the left) + * has been gotten. NOTE: To keep this simple we will require only a + * single lookup-next sibling in any parents list of children. + * + * Walk the rightmost branch (the node info stack) from base to tip + * verifying all list nodes are still present. If not we backup to the + * node which has a lookup next, and we prune the branch to this node. + * If the list node that went away is the topmost we will be using + * lookup_next, but if it's a parent then the list_entry will have been + * restored. + */ + darr_foreach_i (ys->node_infos, i) { + ni = &ys->node_infos[i]; + nn = ni->schema->priv; + + if (!CHECK_FLAG(ni->schema->nodetype, LYS_LIST)) + continue; + + assert(ni->list_entry != NULL || + ni == darr_last(ys->node_infos)); + + /* Verify the entry is still present */ + parent_entry = (i == 0 ? NULL : ni[-1].list_entry); + list_entry = nb_callback_lookup_entry(nn, parent_entry, + &ni->keys); + if (!list_entry || list_entry != ni->list_entry) { + /* May be NULL or a different pointer + * move back to first of + * container with last lookup_next list node + * (which may be this one) and get next. + */ + if (!__move_back_to_next(ys, i)) + DEBUGD(&nb_dbg_events, + "%s: Nothing to resume after delete during walk (yield)", + __func__); + return; + } + } +} + +/* + * Can only yield if all list nodes to root have lookup_next() callbacks + * + * In order to support lookup_next() the list_node get_next() callback + * needs to return ordered (i.e., sorted) results. + */ + +/* ======================= */ +/* Start of walk init code */ +/* ======================= */ + +/** + * nb_op_xpath_to_trunk() - generate a lyd_node tree (trunk) using an xpath. + * @xpath_in: xpath query string to build trunk from. + * @dnode: resulting tree (trunk) + * + * Use the longest prefix of @xpath_in as possible to resolve to a tree (trunk). + * This is logically as if we walked along the xpath string resolving each + * nodename reference (in particular list nodes) until we could not. + * + * Return: error if any, if no error then @dnode contains the tree (trunk). + */ +static enum nb_error nb_op_xpath_to_trunk(const char *xpath_in, + struct lyd_node **trunk) +{ + char *xpath = NULL; + enum nb_error ret = NB_OK; + LY_ERR err; + + darr_in_strdup(xpath, xpath_in); + for (;;) { + err = lyd_new_path2(NULL, ly_native_ctx, xpath, NULL, 0, 0, + LYD_NEW_PATH_UPDATE, NULL, trunk); + if (err == LY_SUCCESS) + break; + + ret = yang_xpath_pop_node(xpath); + if (ret != NB_OK) + break; + } + darr_free(xpath); + return ret; +} + +/* + * Finish initializing the node info based on the xpath string, and previous + * node_infos on the stack. If this node is a list node, obtain the specific + * list-entry object. + */ +static enum nb_error nb_op_ys_finalize_node_info(struct nb_op_yield_state *ys, + uint index) +{ + struct nb_op_node_info *ni = &ys->node_infos[index]; + struct lyd_node *inner = ni->inner; + struct nb_node *nn = ni->schema->priv; + bool yield_ok = ys->finish != NULL; + + ni->has_lookup_next = nn->cbs.lookup_next != NULL; + + /* track the last list_entry until updated by new list node */ + ni->list_entry = index == 0 ? NULL : ni[-1].list_entry; + + /* Assert that we are walking the rightmost branch */ + assert(!inner->parent || inner == inner->parent->child->prev); + + if (CHECK_FLAG(inner->schema->nodetype, + LYS_CASE | LYS_CHOICE | LYS_CONTAINER)) { + /* containers have only zero or one child on a branch of a tree */ + inner = ((struct lyd_node_inner *)inner)->child; + assert(!inner || inner->prev == inner); + ni->lookup_next_ok = yield_ok && + (index == 0 || ni[-1].lookup_next_ok); + return NB_OK; + } + + assert(CHECK_FLAG(inner->schema->nodetype, LYS_LIST)); + + ni->lookup_next_ok = yield_ok && ni->has_lookup_next && + (index == 0 || ni[-1].lookup_next_ok); + + nb_op_get_keys((struct lyd_node_inner *)inner, &ni->keys); + + /* A list entry cannot be present in a tree w/o it's keys */ + assert(ni->keys.num == yang_snode_num_keys(inner->schema)); + + /* + * Get this nodes opaque list_entry object + */ + + if (!nn->cbs.lookup_entry) { + flog_warn(EC_LIB_NB_OPERATIONAL_DATA, + "%s: data path doesn't support iteration over operational data: %s", + __func__, ys->xpath); + return NB_ERR_NOT_FOUND; + } + + /* ni->list_entry starts as the parent entry of this node */ + ni->list_entry = nb_callback_lookup_entry(nn, ni->list_entry, &ni->keys); + if (ni->list_entry == NULL) { + flog_warn(EC_LIB_NB_OPERATIONAL_DATA, + "%s: list entry lookup failed", __func__); + return NB_ERR_NOT_FOUND; + } + + /* + * By definition any list element we can get a specific list_entry for + * is specific. + */ + ni->query_specific_entry = true; + + return NB_OK; +} + +/** + * nb_op_ys_init_node_infos() - initialize the node info stack from the query. + * @ys: the yield state for this tree walk. + * + * On starting a walk we initialize the node_info stack as deeply as possible + * based on specific node references in the query string. We will stop at the + * point in the query string that is not specific (e.g., a list element without + * it's keys predicate) + * + * Return: northbound return value (enum nb_error) + */ +static enum nb_error nb_op_ys_init_node_infos(struct nb_op_yield_state *ys) +{ + struct nb_op_node_info *ni; + struct lyd_node *inner; + struct lyd_node *node = NULL; + enum nb_error ret; + uint i, len; + char *tmp; + + /* + * Obtain the trunk of the data node tree of the query. + * + * These are the nodes from the root that could be specifically + * identified with the query string. The trunk ends when a no specific + * node could be identified (e.g., a list-node name with no keys). + */ + + ret = nb_op_xpath_to_trunk(ys->xpath, &node); + if (ret || !node) { + flog_warn(EC_LIB_LIBYANG, + "%s: can't instantiate concrete path using xpath: %s", + __func__, ys->xpath); + if (!ret) + ret = NB_ERR_NOT_FOUND; + return ret; + } + + /* Move up to the container if on a leaf currently. */ + if (node && + !CHECK_FLAG(node->schema->nodetype, LYS_CONTAINER | LYS_LIST)) { + struct lyd_node *leaf = node; + + node = &node->parent->node; + + /* + * If the leaf is not a key, delete it, because it has a wrong + * empty value. + */ + if (!lysc_is_key(leaf->schema)) + lyd_free_tree(leaf); + } + assert(!node || + CHECK_FLAG(node->schema->nodetype, LYS_CONTAINER | LYS_LIST)); + if (!node) + return NB_ERR_NOT_FOUND; + + inner = node; + for (len = 1; inner->parent; len++) + inner = &inner->parent->node; + + darr_append_nz_mt(ys->node_infos, len, MTYPE_NB_NODE_INFOS); + + /* + * For each node find the prefix of the xpath query that identified it + * -- save the prefix length. + */ + inner = node; + for (i = len; i > 0; i--, inner = &inner->parent->node) { + ni = &ys->node_infos[i - 1]; + ni->inner = inner; + ni->schema = inner->schema; + /* + * NOTE: we could build this by hand with a litte more effort, + * but this simple implementation works and won't be expensive + * since the number of nodes is small and only done once per + * query. + */ + tmp = yang_dnode_get_path(inner, NULL, 0); + ni->xpath_len = strlen(tmp); + + /* Replace users supplied xpath with the libyang returned value */ + if (i == len) + darr_in_strdup(ys->xpath, tmp); + + /* The prefix must match the prefix of the stored xpath */ + assert(!strncmp(tmp, ys->xpath, ni->xpath_len)); + free(tmp); + } + + /* + * Obtain the specific list-entry objects for each list node on the + * trunk and finish initializing the node_info structs. + */ + + darr_foreach_i (ys->node_infos, i) { + ret = nb_op_ys_finalize_node_info(ys, i); + if (ret != NB_OK) { + if (ys->node_infos[0].inner) + lyd_free_all(ys->node_infos[0].inner); + darr_free(ys->node_infos); + return ret; + } + } + + ys->walk_start_level = darr_len(ys->node_infos); + + ys->walk_root_level = (int)ys->walk_start_level - 1; + + return NB_OK; +} + +/* ================ */ +/* End of init code */ +/* ================ */ + +/** + * nb_op_add_leaf() - Add leaf data to the get tree results + * @ys - the yield state for this tree walk. + * @nb_node - the northbound node representing this leaf. + * @xpath - the xpath (with key predicates) to this leaf value. + * + * Return: northbound return value (enum nb_error) + */ +static enum nb_error nb_op_iter_leaf(struct nb_op_yield_state *ys, + const struct nb_node *nb_node, + const char *xpath) +{ + const struct lysc_node *snode = nb_node->snode; + struct nb_op_node_info *ni = darr_last(ys->node_infos); + struct yang_data *data; + enum nb_error ret = NB_OK; + LY_ERR err; + + if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) + return NB_OK; + + /* Ignore list keys. */ + if (lysc_is_key(snode)) + return NB_OK; + + data = nb_callback_get_elem(nb_node, xpath, ni->list_entry); + if (data == NULL) + return NB_OK; + + /* Add a dnode to our tree */ + err = lyd_new_term(ni->inner, snode->module, snode->name, data->value, + false, NULL); + if (err) { + yang_data_free(data); + return NB_ERR_RESOURCE; + } + + if (ys->cb) + ret = (*ys->cb)(nb_node->snode, ys->translator, data, + ys->cb_arg); + yang_data_free(data); + + return ret; +} + +static enum nb_error nb_op_iter_leaflist(struct nb_op_yield_state *ys, + const struct nb_node *nb_node, + const char *xpath) +{ + const struct lysc_node *snode = nb_node->snode; + struct nb_op_node_info *ni = darr_last(ys->node_infos); + const void *list_entry = NULL; + enum nb_error ret = NB_OK; + LY_ERR err; + + if (CHECK_FLAG(snode->flags, LYS_CONFIG_W)) + return NB_OK; + + do { + struct yang_data *data; + + list_entry = nb_callback_get_next(nb_node, ni->list_entry, + list_entry); + if (!list_entry) + /* End of the list. */ + break; + + data = nb_callback_get_elem(nb_node, xpath, list_entry); + if (data == NULL) + continue; + + /* Add a dnode to our tree */ + err = lyd_new_term(ni->inner, snode->module, snode->name, + data->value, false, NULL); + if (err) { + yang_data_free(data); + return NB_ERR_RESOURCE; + } + + if (ys->cb) + ret = (*ys->cb)(nb_node->snode, ys->translator, data, + ys->cb_arg); + yang_data_free(data); + } while (ret == NB_OK && list_entry); + + return ret; +} + + +static bool nb_op_schema_path_has_predicate(struct nb_op_yield_state *ys, + int level) +{ + if (level > darr_lasti(ys->query_tokens)) + return false; + return strchr(ys->query_tokens[level], '[') != NULL; +} + +/** + * nb_op_empty_container_ok() - determine if should keep empty container node. + * + * Return: true if the empty container should be kept. + */ +static bool nb_op_empty_container_ok(const struct lysc_node *snode, + const char *xpath, const void *list_entry) +{ + struct nb_node *nn = snode->priv; + struct yang_data *data; + + if (!CHECK_FLAG(snode->flags, LYS_PRESENCE)) + return false; + + if (!nn->cbs.get_elem) + return false; + + data = nb_callback_get_elem(nn, xpath, list_entry); + if (data) { + yang_data_free(data); + return true; + } + return false; +} + +/** + * nb_op_get_child_path() - add child node name to the xpath. + * @xpath_parent - a darr string for the parent node. + * @schild - the child schema node. + * @xpath_child - a previous return value from this function to reuse. + */ +static char *nb_op_get_child_path(const char *xpath_parent, + const struct lysc_node *schild, + char *xpath_child) +{ + /* "/childname" */ + uint space, extra = strlen(schild->name) + 1; + bool new_mod = (!schild->parent || + schild->parent->module != schild->module); + int n; + + if (new_mod) + /* "modulename:" */ + extra += strlen(schild->module->name) + 1; + space = darr_len(xpath_parent) + extra; + + if (xpath_parent == xpath_child) + darr_ensure_cap(xpath_child, space); + else + darr_in_strdup_cap(xpath_child, xpath_parent, space); + if (new_mod) + n = snprintf(darr_strnul(xpath_child), extra + 1, "/%s:%s", + schild->module->name, schild->name); + else + n = snprintf(darr_strnul(xpath_child), extra + 1, "/%s", + schild->name); + assert(n == (int)extra); + _darr_len(xpath_child) += extra; + return xpath_child; +} + +static bool __is_yielding_node(const struct lysc_node *snode) +{ + struct nb_node *nn = snode->priv; + + return nn->cbs.lookup_next != NULL; +} + +static const struct lysc_node *__sib_next(bool yn, const struct lysc_node *sib) +{ + for (; sib; sib = sib->next) { + /* Always skip keys. */ + if (lysc_is_key(sib)) + continue; + if (yn == __is_yielding_node(sib)) + return sib; + } + return NULL; +} + +/** + * nb_op_sib_next() - Return the next sibling to walk to + * @ys: the yield state for this tree walk. + * @sib: the currently being visited sibling + * + * Return: the next sibling to walk to, walking non-yielding before yielding. + */ +static const struct lysc_node *nb_op_sib_next(struct nb_op_yield_state *ys, + const struct lysc_node *sib) +{ + struct lysc_node *parent = sib->parent; + bool yn = __is_yielding_node(sib); + + /* + * If the node info stack is shorter than the schema path then we are + * doign specific query still on the node from the schema path (should + * match) so just return NULL (i.e., don't process siblings) + */ + if (darr_len(ys->schema_path) > darr_len(ys->node_infos)) + return NULL; + /* + * If sib is on top of the node info stack then + * 1) it's a container node -or- + * 2) it's a list node that we were walking and we've reach the last entry + * 3) if sib is a list and the list was empty we never would have + * pushed sib on the stack so the top of the stack is the parent + * + * If the query string included this node then we do not process any + * siblings as we are not walking all the parent's children just this + * specified one give by the query string. + */ + if (sib == darr_last(ys->node_infos)->schema && + darr_len(ys->schema_path) >= darr_len(ys->node_infos)) + return NULL; + /* case (3) */ + else if (sib->nodetype == LYS_LIST && + parent == darr_last(ys->node_infos)->schema && + darr_len(ys->schema_path) > darr_len(ys->node_infos)) + return NULL; + + sib = __sib_next(yn, sib->next); + if (sib) + return sib; + if (yn) + return NULL; + return __sib_next(true, lysc_node_child(parent)); +} +/* + * sib_walk((struct lyd_node *)ni->inner->node.parent->parent->parent->parent->parent->parent->parent) + */ + +/** + * nb_op_sib_first() - obtain the first child to walk to + * @ys: the yield state for this tree walk. + * @parent: the parent whose child we seek + * @skip_keys: if should skip over keys + * + * Return: the first child to continue the walk to, starting with non-yielding + * siblings then yielding ones. There should be no more than 1 yielding sibling. + */ +static const struct lysc_node *nb_op_sib_first(struct nb_op_yield_state *ys, + const struct lysc_node *parent) +{ + const struct lysc_node *sib = lysc_node_child(parent); + const struct lysc_node *first_sib; + + /* + * NOTE: when we want to handle root level walks we will need to use + * lys_getnext() to walk root level of each module and + * ly_ctx_get_module_iter() to walk the modules. + */ + assert(darr_len(ys->node_infos) > 0); + + /* + * The top of the node stack points at @parent. + * + * If the schema path (original query) is longer than our current node + * info stack (current xpath location), we are building back up to the + * base of the user query, return the next schema node from the query + * string (schema_path). + */ + if (darr_last(ys->node_infos) != NULL && + !CHECK_FLAG(darr_last(ys->node_infos)->schema->nodetype, + LYS_CASE | LYS_CHOICE)) + assert(darr_last(ys->node_infos)->schema == parent); + if (darr_lasti(ys->node_infos) < ys->query_base_level) + return ys->schema_path[darr_lasti(ys->node_infos) + 1]; + + /* We always skip keys. */ + while (sib && lysc_is_key(sib)) + sib = sib->next; + if (!sib) + return NULL; + + /* Return non-yielding node's first */ + first_sib = sib; + if (__is_yielding_node(sib)) { + sib = __sib_next(false, sib); + if (sib) + return sib; + } + return first_sib; +} + +/* + * "3-dimensional" walk from base of the tree to the tip in-order. + * + * The actual tree is only 2-dimensional as list nodes are organized as adjacent + * siblings under a common parent perhaps with other siblings to each side; + * however, using 3d view here is easier to diagram. + * + * - A list node is yielding if it has a lookup_next callback. + * - All other node types are not yielding. + * - There's only one yielding node in a list of children (i.e., siblings). + * + * We visit all non-yielding children prior to the yielding child. + * That way we have the fullest tree possible even when something is deleted + * during a yield. + * --- child/parent descendant poinilnters + * ... next/prev sibling pointers + * o.o list entries pointers + * ~~~ diagram extension connector + * 1 + * / \ + * / \ o~~~~12 + * / \ . / \ + * 2.......5 o~~~9 13...14 + * / \ | . / \ + * 3...4 6 10...11 Cont Nodes: 1,2,5 + * / \ List Nodes: 6,9,12 + * 7...8 Leaf Nodes: 3,4,7,8,10,11,13,14 + * Schema Leaf A: 3 + * Schema Leaf B: 4 + * Schema Leaf C: 7,10,13 + * Schema Leaf D: 8,11,14 + */ +static enum nb_error __walk(struct nb_op_yield_state *ys, bool is_resume) +{ + const struct lysc_node *walk_stem_tip = ys_get_walk_stem_tip(ys); + const struct lysc_node *sib; + const void *parent_list_entry = NULL; + const void *list_entry = NULL; + struct nb_op_node_info *ni, *pni; + struct lyd_node *node; + struct nb_node *nn; + char *xpath_child = NULL; + // bool at_query_base; + bool at_root_level, list_start, is_specific_node; + enum nb_error ret = NB_OK; + LY_ERR err; + int at_clevel; + uint len; + + + monotime(&ys->start_time); + + /* Don't currently support walking all root nodes */ + if (!walk_stem_tip) + return NB_ERR_NOT_FOUND; + + if (ys->schema_path[0]->nodetype == LYS_CHOICE) { + flog_err(EC_LIB_NB_OPERATIONAL_DATA, + "%s: unable to walk root level choice node from module: %s", + __func__, ys->schema_path[0]->module->name); + return NB_ERR; + } + + /* + * If we are resuming then start with the list container on top. + * Otherwise get the first child of the container we are walking, + * starting with non-yielding children. + */ + if (is_resume) + sib = darr_last(ys->node_infos)->schema; + else { + /* + * Start with non-yielding children first. + * + * When adding root level walks, the sibling list are the root + * level nodes of all modules + */ + sib = nb_op_sib_first(ys, walk_stem_tip); + if (!sib) + return NB_ERR_NOT_FOUND; + } + + + while (true) { + /* Grab the top container/list node info on the stack */ + at_clevel = darr_lasti(ys->node_infos); + ni = &ys->node_infos[at_clevel]; + + /* + * This is the level of the last specific node at init + * time. +1 would be the first non-specific list or + * non-container if present in the container node. + */ + at_root_level = at_clevel == ys->walk_root_level; + + if (!sib) { + /* + * We've reached the end of the siblings inside a + * containing node; either a container, case, choice, or + * a specific list node entry. + * + * We handle case/choice/container node inline; however, + * for lists we are only done with a specific entry and + * need to move to the next element on the list so we + * drop down into the switch for that case. + */ + + /* Grab the containing node. */ + sib = ni->schema; + + if (CHECK_FLAG(sib->nodetype, + LYS_CASE | LYS_CHOICE | LYS_CONTAINER)) { + /* If we added an empty container node (no + * children) and it's not a presence container + * or it's not backed by the get_elem callback, + * remove the node from the tree. + */ + if (sib->nodetype == LYS_CONTAINER && + !lyd_child(ni->inner) && + !nb_op_empty_container_ok(sib, ys->xpath, + ni->list_entry)) + ys_free_inner(ys, ni); + + /* If we have returned to our original walk base, + * then we are done with the walk. + */ + if (at_root_level) { + ret = NB_OK; + goto done; + } + /* + * Grab the sibling of the container we are + * about to pop, so we will be mid-walk on the + * parent containers children. + */ + sib = nb_op_sib_next(ys, sib); + + /* Pop container node to the parent container */ + ys_pop_inner(ys); + + /* + * If are were working on a user narrowed path + * then we are done with these siblings. + */ + if (darr_len(ys->schema_path) > + darr_len(ys->node_infos)) + sib = NULL; + + /* Start over */ + continue; + } + /* + * If we are here we have reached the end of the + * children of a list entry node. sib points + * at the list node info. + */ + } + + if (CHECK_FLAG(sib->nodetype, + LYS_LEAF | LYS_LEAFLIST | LYS_CONTAINER)) + xpath_child = nb_op_get_child_path(ys->xpath, sib, + xpath_child); + else if (CHECK_FLAG(sib->nodetype, LYS_CASE | LYS_CHOICE)) + darr_in_strdup(xpath_child, ys->xpath); + + nn = sib->priv; + + switch (sib->nodetype) { + case LYS_LEAF: + /* + * If we have a non-specific walk to a specific leaf + * (e.g., "..../route-entry/metric") and the leaf value + * is not present, then we are left with the data nodes + * of the stem of the branch to the missing leaf data. + * For containers this will get cleaned up by the + * container code above that looks for no children; + * however, this doesn't work for lists. + * + * (FN:A) We need a similar check for empty list + * elements. Empty list elements below the + * query_base_level (i.e., the schema path length) + * should be cleaned up as they don't support anything + * the user is querying for, if they are above the + * query_base_level then they are part of the walk and + * should be kept. + */ + ret = nb_op_iter_leaf(ys, nn, xpath_child); + if (ret != NB_OK) + goto done; + sib = nb_op_sib_next(ys, sib); + continue; + case LYS_LEAFLIST: + ret = nb_op_iter_leaflist(ys, nn, xpath_child); + if (ret != NB_OK) + goto done; + sib = nb_op_sib_next(ys, sib); + continue; + case LYS_CASE: + case LYS_CHOICE: + case LYS_CONTAINER: + if (CHECK_FLAG(nn->flags, F_NB_NODE_CONFIG_ONLY)) { + sib = nb_op_sib_next(ys, sib); + continue; + } + + if (sib->nodetype != LYS_CONTAINER) { + /* Case/choice use parent inner. */ + /* TODO: thus we don't support root level choice */ + node = ni->inner; + } else { + err = lyd_new_inner(ni->inner, sib->module, + sib->name, false, &node); + if (err) { + ret = NB_ERR_RESOURCE; + goto done; + } + } + + /* push this choice/container node on top of the stack */ + ni = darr_appendz(ys->node_infos); + ni->inner = node; + ni->schema = sib; + ni->lookup_next_ok = ni[-1].lookup_next_ok; + ni->list_entry = ni[-1].list_entry; + + darr_in_strdup(ys->xpath, xpath_child); + ni->xpath_len = darr_strlen(ys->xpath); + + sib = nb_op_sib_first(ys, sib); + continue; + case LYS_LIST: + + /* + * Notes: + * + * NOTE: ni->inner may be NULL here if we resumed and it + * was gone. ni->schema and ni->keys will still be + * valid. + * + * NOTE: At this point sib is never NULL; however, if it + * was NULL at the top of the loop, then we were done + * working on a list element's children and will be + * attempting to get the next list element here so sib + * == ni->schema (i.e., !list_start). + * + * (FN:A): Before doing this let's remove empty list + * elements that are "inside" the query string as they + * represent a stem which didn't lead to actual data + * being requested by the user -- for example, + * ".../route-entry/metric" if metric is not present we + * don't want to return an empty route-entry to the + * user. + */ + + node = NULL; + list_start = ni->schema != sib; + if (list_start) { + /* + * List iteration: First Element + * ----------------------------- + * + * Our node info wasn't on top (wasn't an entry + * for sib) so this is a new list iteration, we + * will push our node info below. The top is our + * parent. + */ + if (CHECK_FLAG(nn->flags, + F_NB_NODE_CONFIG_ONLY)) { + sib = nb_op_sib_next(ys, sib); + continue; + } + /* we are now at one level higher */ + at_clevel += 1; + pni = ni; + ni = NULL; + } else { + /* + * List iteration: Next Element + * ---------------------------- + * + * This is the case where `sib == NULL` at the + * top of the loop, so, we just completed the + * walking the children of a list entry, i.e., + * we are done with that list entry. + * + * `sib` was reset to point at the our list node + * at the top of node_infos. + * + * Within this node_info, `ys->xpath`, `inner`, + * `list_entry`, and `xpath_len` are for the + * previous list entry, and need to be updated. + */ + pni = darr_len(ys->node_infos) > 1 ? &ni[-1] + : NULL; + } + + parent_list_entry = pni ? pni->list_entry : NULL; + list_entry = ni ? ni->list_entry : NULL; + + /* + * Before yielding we check to see if we are doing a + * specific list entry instead of a full list iteration. + * We do not want to yield during specific list entry + * processing. + */ + + /* + * If we are at a list start check to see if the node + * has a predicate. If so we will try and fetch the data + * node now that we've built part of the tree, if the + * predicates are keys or only depend on the tree already + * built, it should create the element for us. + */ + is_specific_node = false; + if (list_start && + at_clevel <= darr_lasti(ys->query_tokens) && + !ys->non_specific_predicate[at_clevel] && + nb_op_schema_path_has_predicate(ys, at_clevel)) { + err = lyd_new_path(pni->inner, NULL, + ys->query_tokens[at_clevel], + NULL, 0, &node); + if (!err) + is_specific_node = true; + else if (err == LY_EVALID) + ys->non_specific_predicate[at_clevel] = true; + else { + flog_err(EC_LIB_NB_OPERATIONAL_DATA, + "%s: unable to create node for specific query string: %s: %s", + __func__, + ys->query_tokens[at_clevel], + yang_ly_strerrcode(err)); + ret = NB_ERR; + goto done; + } + } + + if (list_entry && ni->query_specific_entry) { + /* + * Ending specific list entry processing. + */ + assert(!list_start); + is_specific_node = true; + list_entry = NULL; + } + + /* + * Should we yield? + * + * Don't yield if we have a specific entry. + */ + if (!is_specific_node && ni && ni->lookup_next_ok && + // make sure we advance, if the interval is + // fast and we are very slow. + ((monotime_since(&ys->start_time, NULL) > + NB_OP_WALK_INTERVAL_US && + ni->niters) || + (ni->niters + 1) % 10000 == 0)) { + /* This is a yield supporting list node and + * we've been running at least our yield + * interval, so yield. + * + * NOTE: we never yield on list_start, and we + * are always about to be doing a get_next. + */ + DEBUGD(&nb_dbg_events, + "%s: yielding after %u iterations", + __func__, ni->niters); + + ni->niters = 0; + ret = NB_YIELD; + goto done; + } + + /* + * Now get the backend list_entry opaque object for + * this list entry from the backend. + */ + + if (is_specific_node) { + /* + * Specific List Entry: + * -------------------- + */ + if (list_start) { + list_entry = + nb_callback_lookup_node_entry( + node, parent_list_entry); + /* + * If the node we created from a + * specific predicate entry is not + * actually there we need to delete the + * node from our data tree + */ + if (!list_entry) { + lyd_free_tree(node); + node = NULL; + } + } + } else if (!list_start && !list_entry && + ni->has_lookup_next) { + /* + * After Yield: + * ------------ + * After a yield the list_entry may have become + * invalid, so use lookup_next callback with + * parent and keys instead to find next element. + */ + list_entry = + nb_callback_lookup_next(nn, + parent_list_entry, + &ni->keys); + } else { + /* + * Normal List Iteration: + * ---------------------- + * Start (list_entry == NULL) or continue + * (list_entry != NULL) the list iteration. + */ + /* Obtain [next] list entry. */ + list_entry = + nb_callback_get_next(nn, + parent_list_entry, + list_entry); + } + + /* + * (FN:A) Reap empty list element? Check to see if we + * should reap an empty list element. We do this if the + * empty list element exists at or below the query base + * (i.e., it's not part of the walk, but a failed find + * on a more specific query e.g., for below the + * `route-entry` element for a query + * `.../route-entry/metric` where the list element had + * no metric value. + * + * However, if the user query is for a key of a list + * element, then when we reach that list element it will + * have no non-key children, check for this condition + * and do not reap if true. + */ + if (!list_start && ni->inner && + !lyd_child_no_keys(ni->inner) && + /* not the top element with a key match */ + !((darr_ilen(ys->node_infos) == + darr_ilen(ys->schema_path) - 1) && + lysc_is_key((*darr_last(ys->schema_path)))) && + /* is this at or below the base? */ + darr_ilen(ys->node_infos) <= ys->query_base_level) + ys_free_inner(ys, ni); + + + if (!list_entry) { + /* + * List Iteration Done + * ------------------- + */ + + /* + * Grab next sibling of the list node + */ + if (is_specific_node) + sib = NULL; + else + sib = nb_op_sib_next(ys, sib); + + /* + * If we are at the walk root (base) level then + * that specifies a list and we are done iterating + * the list, so we are done with the walk entirely. + */ + if (!sib && at_clevel == ys->walk_root_level) { + ret = NB_OK; + goto done; + } + + /* + * Pop the our list node info back to our + * parent. + * + * We only do this if we've already pushed a + * node for the current list schema. For + * `list_start` this hasn't happened yet, as + * would have happened below. So when list_start + * is true but list_entry if NULL we + * are processing an empty list. + */ + if (!list_start) + ys_pop_inner(ys); + + /* + * We should never be below the walk root + */ + assert(darr_lasti(ys->node_infos) >= + ys->walk_root_level); + + /* Move on to the sibling of the list node */ + continue; + } + + /* + * From here on, we have selected a new top node_info + * list entry (either newly pushed or replacing the + * previous entry in the walk), and we are filling in + * the details. + */ + + if (list_start) { + /* + * Starting iteration of a list type or + * processing a specific entry, push the list + * node_info on stack. + */ + ni = darr_appendz(ys->node_infos); + pni = &ni[-1]; /* memory may have moved */ + ni->has_lookup_next = nn->cbs.lookup_next != + NULL; + ni->lookup_next_ok = ((!pni && ys->finish) || + pni->lookup_next_ok) && + ni->has_lookup_next; + ni->query_specific_entry = is_specific_node; + ni->niters = 0; + ni->nents = 0; + + /* this will be our predicate-less xpath */ + ys->xpath = nb_op_get_child_path(ys->xpath, sib, + ys->xpath); + } else { + /* + * Reset our xpath to the list node (i.e., + * remove the entry predicates) + */ + if (ni->query_specific_entry) { + flog_warn(EC_LIB_NB_OPERATIONAL_DATA, + "%s: unexpected state", + __func__); + } + assert(!ni->query_specific_entry); + len = strlen(sib->name) + 1; /* "/sibname" */ + if (pni) + len += pni->xpath_len; + darr_setlen(ys->xpath, len + 1); + ys->xpath[len] = 0; + ni->xpath_len = len; + } + + /* Need to get keys. */ + + if (!CHECK_FLAG(nn->flags, F_NB_NODE_KEYLESS_LIST)) { + ret = nb_callback_get_keys(nn, list_entry, + &ni->keys); + if (ret) { + darr_pop(ys->node_infos); + ret = NB_ERR_RESOURCE; + goto done; + } + } + /* + * Append predicates to xpath. + */ + len = darr_strlen(ys->xpath); + if (ni->keys.num) { + yang_get_key_preds(ys->xpath + len, sib, + &ni->keys, + darr_cap(ys->xpath) - len); + } else { + /* add a position predicate (1s based?) */ + darr_ensure_avail(ys->xpath, 10); + snprintf(ys->xpath + len, + darr_cap(ys->xpath) - len + 1, "[%u]", + ni->nents + 1); + } + darr_setlen(ys->xpath, + strlen(ys->xpath + len) + len + 1); + ni->xpath_len = darr_strlen(ys->xpath); + + /* + * Create the new list entry node. + */ + + if (!node) { + err = yang_lyd_new_list((struct lyd_node_inner *) + ni[-1] + .inner, + sib, &ni->keys, &node); + if (err) { + darr_pop(ys->node_infos); + ret = NB_ERR_RESOURCE; + goto done; + } + } + + /* + * Save the new list entry with the list node info + */ + ni->inner = node; + ni->schema = node->schema; + ni->list_entry = list_entry; + ni->niters += 1; + ni->nents += 1; + + /* Skip over the key children, they've been created. */ + sib = nb_op_sib_first(ys, sib); + continue; + + default: + /*FALLTHROUGH*/ + case LYS_ANYXML: + case LYS_ANYDATA: + /* These schema types are not currently handled */ + flog_warn(EC_LIB_NB_OPERATIONAL_DATA, + "%s: unsupported schema node type: %s", + __func__, lys_nodetype2str(sib->nodetype)); + sib = nb_op_sib_next(ys, sib); + continue; + } + } + +done: + darr_free(xpath_child); + return ret; +} + +static void nb_op_walk_continue(struct event *thread) +{ + struct nb_op_yield_state *ys = EVENT_ARG(thread); + enum nb_error ret = NB_OK; + + DEBUGD(&nb_dbg_cbs_state, "northbound oper-state: resuming %s", + ys->xpath); + + nb_op_resume_data_tree(ys); + + /* if we've popped past the walk start level we're done */ + if (darr_lasti(ys->node_infos) < ys->walk_root_level) + goto finish; + + /* otherwise we are at a resumable node */ + assert(darr_last(ys->node_infos)->has_lookup_next); + + ret = __walk(ys, true); + if (ret == NB_YIELD) { + if (nb_op_yield(ys) != NB_OK) { + if (ys->should_batch) + goto stopped; + else + goto finish; + } + return; + } +finish: + (*ys->finish)(ys_root_node(ys), ys->finish_arg, ret); +stopped: + nb_op_free_yield_state(ys, false); +} + +static void __free_siblings(struct lyd_node *this) +{ + struct lyd_node *next, *sib; + uint count = 0; + + LY_LIST_FOR_SAFE(lyd_first_sibling(this), next, sib) + { + if (lysc_is_key(sib->schema)) + continue; + if (sib == this) + continue; + lyd_free_tree(sib); + count++; + } + DEBUGD(&nb_dbg_events, "NB oper-state: deleted %u siblings", count); +} + +/* + * Trim Algorithm: + * + * Delete final lookup-next list node and subtree, leave stack slot with keys. + * + * Then walking up the stack, delete all siblings except: + * 1. right-most container or list node (must be lookup-next by design) + * 2. keys supporting existing parent list node. + * + * NOTE the topmost node on the stack will be the final lookup-nexxt list node, + * as we only yield on lookup-next list nodes. + * + */ +static void nb_op_trim_yield_state(struct nb_op_yield_state *ys) +{ + struct nb_op_node_info *ni; + int i = darr_lasti(ys->node_infos); + + assert(i >= 0); + + DEBUGD(&nb_dbg_events, "NB oper-state: start trimming: top: %d", i); + + ni = &ys->node_infos[i]; + assert(ni->has_lookup_next); + + DEBUGD(&nb_dbg_events, "NB oper-state: deleting tree at level %d", i); + __free_siblings(ni->inner); + ys_free_inner(ys, ni); + + while (--i > 0) { + DEBUGD(&nb_dbg_events, + "NB oper-state: deleting siblings at level: %d", i); + __free_siblings(ys->node_infos[i].inner); + } + DEBUGD(&nb_dbg_events, "NB oper-state: stop trimming: new top: %d", + (int)darr_lasti(ys->node_infos)); +} + +static enum nb_error nb_op_yield(struct nb_op_yield_state *ys) +{ + enum nb_error ret; + unsigned long min_us = MAX(1, NB_OP_WALK_INTERVAL_US / 50000); + struct timeval tv = { .tv_sec = 0, .tv_usec = min_us }; + + DEBUGD(&nb_dbg_events, + "NB oper-state: yielding %s for %lldus (should_batch %d)", + ys->xpath, (long long)tv.tv_usec, ys->should_batch); + + if (ys->should_batch) { + /* + * TODO: add ability of finish to influence the timer. + * This will allow, for example, flow control based on how long + * it takes finish to process the batch. + */ + ret = (*ys->finish)(ys_root_node(ys), ys->finish_arg, NB_YIELD); + if (ret != NB_OK) + return ret; + /* now trim out that data we just "finished" */ + nb_op_trim_yield_state(ys); + + } + + event_add_timer_tv(event_loop, nb_op_walk_continue, ys, &tv, + &ys->walk_ev); + return NB_OK; +} + +static enum nb_error nb_op_ys_init_schema_path(struct nb_op_yield_state *ys, + struct nb_node **last) +{ + struct nb_node **nb_nodes = NULL; + const struct lysc_node *sn; + struct nb_node *nblast; + char *s, *s2; + int count; + uint i; + + /* + * Get the schema node stack for the entire query string + * + * The user might pass in something like "//metric" which may resolve to + * more than one schema node ("trunks"). nb_node_find() returns a single + * node though. We should expand the functionality to get the set of + * nodes that matches the xpath (not path) query and save that set in + * the yield state. Then we should do a walk using the users query + * string over each schema trunk in the set. + */ + nblast = nb_node_find(ys->xpath); + if (!nblast) { + nb_nodes = nb_nodes_find(ys->xpath); + nblast = darr_len(nb_nodes) ? nb_nodes[0] : NULL; + darr_free(nb_nodes); + } + if (!nblast) { + flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, + "%s: unknown data path: %s", __func__, ys->xpath); + return NB_ERR; + } + *last = nblast; + + /* + * Create a stack of schema nodes one element per node in the query + * path, only the top (last) element may be a non-container type. + * + * NOTE: appears to be a bug in nb_node linkage where parent can be NULL, + * or I'm misunderstanding the code, in any case we use the libyang + * linkage to walk which works fine. + * + * XXX: we don't actually support choice/case yet, they are container + * types in the libyang schema, but won't be in data so our length + * checking gets messed up. + */ + for (sn = nblast->snode, count = 0; sn; count++, sn = sn->parent) + if (sn != nblast->snode) + assert(CHECK_FLAG(sn->nodetype, + LYS_CONTAINER | LYS_LIST | + LYS_CHOICE | LYS_CASE)); + /* create our arrays */ + darr_append_n(ys->schema_path, count); + darr_append_n(ys->query_tokens, count); + darr_append_nz(ys->non_specific_predicate, count); + for (sn = nblast->snode; sn; sn = sn->parent) + ys->schema_path[--count] = sn; + + /* + * Now tokenize the query string and get pointers to each token + */ + + /* Get copy of query string start after initial '/'s */ + s = ys->xpath; + while (*s && *s == '/') + s++; + ys->query_tokstr = darr_strdup(s); + s = ys->query_tokstr; + + darr_foreach_i (ys->schema_path, i) { + const char *modname = ys->schema_path[i]->module->name; + const char *name = ys->schema_path[i]->name; + int nlen = strlen(name); + int mnlen = 0; + + /* + * Technically the query_token for choice/case should probably be pointing at + * the child (leaf) rather than the parent (container), however, + * we only use these for processing list nodes so KISS. + */ + if (CHECK_FLAG(ys->schema_path[i]->nodetype, + LYS_CASE | LYS_CHOICE)) { + ys->query_tokens[i] = ys->query_tokens[i - 1]; + continue; + } + + while (true) { + s2 = strstr(s, name); + if (!s2) + goto error; + + if (s2[-1] == ':') { + mnlen = strlen(modname) + 1; + if (ys->query_tokstr > s2 - mnlen || + strncmp(s2 - mnlen, modname, mnlen - 1)) + goto error; + s2 -= mnlen; + nlen += mnlen; + } + + s = s2; + if ((i == 0 || s[-1] == '/') && + (s[nlen] == 0 || s[nlen] == '[' || s[nlen] == '/')) + break; + /* + * Advance past the incorrect match, must have been + * part of previous predicate. + */ + s += nlen; + } + + /* NUL terminate previous token and save this one */ + if (i > 0) + s[-1] = 0; + ys->query_tokens[i] = s; + s += nlen; + } + + /* NOTE: need to subtract choice/case nodes when these are supported */ + ys->query_base_level = darr_lasti(ys->schema_path); + + return NB_OK; + +error: + darr_free(ys->query_tokstr); + darr_free(ys->schema_path); + darr_free(ys->query_tokens); + darr_free(ys->non_specific_predicate); + return NB_ERR; +} + + +/** + * nb_op_walk_start() - Start walking oper-state directed by query string. + * @ys: partially initialized yield state for this walk. + * + */ +static enum nb_error nb_op_walk_start(struct nb_op_yield_state *ys) +{ + struct nb_node *nblast; + enum nb_error ret; + + /* + * Get nb_node path (stack) corresponding to the xpath query + */ + ret = nb_op_ys_init_schema_path(ys, &nblast); + if (ret != NB_OK) + return ret; + + + /* + * Get the node_info path (stack) corresponding to the uniquely + * resolvable data nodes from the beginning of the xpath query. + */ + ret = nb_op_ys_init_node_infos(ys); + if (ret != NB_OK) + return ret; + + return __walk(ys, false); +} + + +void *nb_oper_walk(const char *xpath, struct yang_translator *translator, + uint32_t flags, bool should_batch, nb_oper_data_cb cb, + void *cb_arg, nb_oper_data_finish_cb finish, void *finish_arg) +{ + struct nb_op_yield_state *ys; + enum nb_error ret; + + ys = nb_op_create_yield_state(xpath, translator, flags, should_batch, + cb, cb_arg, finish, finish_arg); + + ret = nb_op_walk_start(ys); + if (ret == NB_YIELD) { + if (nb_op_yield(ys) != NB_OK) { + if (ys->should_batch) + goto stopped; + else + goto finish; + } + return ys; + } +finish: + (void)(*ys->finish)(ys_root_node(ys), ys->finish_arg, ret); +stopped: + nb_op_free_yield_state(ys, false); + return NULL; +} + + +void nb_oper_cancel_walk(void *walk) +{ + if (walk) + nb_op_free_yield_state(walk, false); +} + + +void nb_oper_cancel_all_walks(void) +{ + struct nb_op_yield_state *ys; + + frr_each_safe (nb_op_walks, &nb_op_walks, ys) + nb_oper_cancel_walk(ys); +} + + +/* + * The old API -- remove when we've update the users to yielding. + */ +enum nb_error nb_oper_iterate_legacy(const char *xpath, + struct yang_translator *translator, + uint32_t flags, nb_oper_data_cb cb, + void *cb_arg, struct lyd_node **tree) +{ + struct nb_op_yield_state *ys; + enum nb_error ret; + + ys = nb_op_create_yield_state(xpath, translator, flags, false, cb, + cb_arg, NULL, NULL); + + ret = nb_op_walk_start(ys); + assert(ret != NB_YIELD); + + if (tree && ret == NB_OK) + *tree = ys_root_node(ys); + else { + if (ys_root_node(ys)) + yang_dnode_free(ys_root_node(ys)); + if (tree) + *tree = NULL; + } + + nb_op_free_yield_state(ys, true); + return ret; +} + +void nb_oper_init(struct event_loop *loop) +{ + event_loop = loop; + nb_op_walks_init(&nb_op_walks); +} + +void nb_oper_terminate(void) +{ + nb_oper_cancel_all_walks(); +} diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 7fd4af83562f..0ec7610a9a7c 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -19,8 +19,6 @@ #include #include -DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module"); - static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"}; static struct event_loop *master; @@ -118,6 +116,9 @@ static int yang_data_frr2sr(struct yang_data *frr_data, sr_val_t *sr_data) sr_data->type = SR_INT64_T; sr_data->data.int64_val = yang_str2int64(frr_data->value); break; + case LY_TYPE_LEAFREF: + sr_val_set_str_data(sr_data, SR_STRING_T, frr_data->value); + break; case LY_TYPE_STRING: sr_val_set_str_data(sr_data, SR_STRING_T, frr_data->value); break; @@ -137,6 +138,11 @@ static int yang_data_frr2sr(struct yang_data *frr_data, sr_val_t *sr_data) sr_data->type = SR_UINT64_T; sr_data->data.uint64_val = yang_str2uint64(frr_data->value); break; + case LY_TYPE_UNION: + /* No way to deal with this using un-typed yang_data object */ + sr_val_set_str_data(sr_data, SR_STRING_T, frr_data->value); + break; + case LY_TYPE_UNKNOWN: default: return -1; } @@ -178,12 +184,12 @@ static int frr_sr_process_change(struct nb_config *candidate, /* Map operation values. */ switch (sr_op) { case SR_OP_CREATED: + nb_op = NB_OP_CREATE; + break; case SR_OP_MODIFIED: - if (nb_operation_is_valid(NB_OP_CREATE, nb_node->snode)) - nb_op = NB_OP_CREATE; - else if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode)) { + if (nb_is_operation_allowed(nb_node, NB_OP_MODIFY)) nb_op = NB_OP_MODIFY; - } else + else /* Ignore list keys modifications. */ return NB_OK; break; @@ -193,7 +199,7 @@ static int frr_sr_process_change(struct nb_config *candidate, * notified about the removal of all of its leafs, even the ones * that are non-optional. We need to ignore these notifications. */ - if (!nb_operation_is_valid(NB_OP_DESTROY, nb_node->snode)) + if (!nb_is_operation_allowed(nb_node, NB_OP_DESTROY)) return NB_OK; nb_op = NB_OP_DESTROY; @@ -213,7 +219,7 @@ static int frr_sr_process_change(struct nb_config *candidate, ret = nb_candidate_edit(candidate, nb_node, nb_op, xpath, NULL, data); yang_data_free(data); - if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) { + if (ret != NB_OK) { flog_warn( EC_LIB_NB_CANDIDATE_EDIT_ERROR, "%s: failed to edit candidate configuration: operation [%s] xpath [%s]", @@ -271,11 +277,12 @@ static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session, ret = nb_candidate_commit_prepare(context, candidate, NULL, &transaction, false, false, errmsg, sizeof(errmsg)); - if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) - flog_warn( - EC_LIB_LIBSYSREPO, - "%s: failed to prepare configuration transaction: %s (%s)", - __func__, nb_err_name(ret), errmsg); + if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { + flog_warn(EC_LIB_LIBSYSREPO, + "%s: failed to prepare configuration transaction: %s (%s)", + __func__, nb_err_name(ret), errmsg); + sr_session_set_error_message(session, errmsg); + } if (!transaction) nb_config_free(candidate); @@ -340,6 +347,8 @@ static int frr_sr_config_change_cb(sr_session_ctx_t *session, uint32_t sub_id, return frr_sr_config_change_cb_apply(session, module_name); case SR_EV_ABORT: return frr_sr_config_change_cb_abort(session, module_name); + case SR_EV_RPC: + case SR_EV_UPDATE: default: flog_err(EC_LIB_LIBSYSREPO, "%s: unexpected sysrepo event: %u", __func__, sr_ev); @@ -347,39 +356,16 @@ static int frr_sr_config_change_cb(sr_session_ctx_t *session, uint32_t sub_id, } } -static int frr_sr_state_data_iter_cb(const struct lysc_node *snode, - struct yang_translator *translator, - struct yang_data *data, void *arg) -{ - struct lyd_node *dnode = arg; - LY_ERR ly_errno; - - ly_errno = 0; - ly_errno = lyd_new_path(NULL, ly_native_ctx, data->xpath, data->value, - 0, &dnode); - if (ly_errno) { - flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed", - __func__); - yang_data_free(data); - return NB_ERR; - } - - yang_data_free(data); - return NB_OK; -} - /* Callback for state retrieval. */ static int frr_sr_state_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *module_name, const char *xpath, const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_ctx) { - struct lyd_node *dnode; + struct lyd_node *dnode = NULL; dnode = *parent; - if (nb_oper_data_iterate(request_xpath, NULL, 0, - frr_sr_state_data_iter_cb, dnode) - != NB_OK) { + if (nb_oper_iterate_legacy(request_xpath, NULL, 0, NULL, NULL, &dnode)) { flog_warn(EC_LIB_NB_OPERATIONAL_DATA, "%s: failed to obtain operational data [xpath %s]", __func__, xpath); @@ -391,16 +377,11 @@ static int frr_sr_state_cb(sr_session_ctx_t *session, uint32_t sub_id, return SR_ERR_OK; } static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, uint32_t sub_id, - const char *xpath, const sr_val_t *sr_input, - const size_t input_cnt, sr_event_t sr_ev, - uint32_t request_id, sr_val_t **sr_output, - size_t *sr_output_cnt, void *private_ctx) + const char *xpath, const struct lyd_node *input, + sr_event_t sr_ev, uint32_t request_id, + struct lyd_node *output, void *private_ctx) { struct nb_node *nb_node; - struct list *input; - struct list *output; - struct yang_data *data; - size_t cb_output_cnt; int ret = SR_ERR_OK; char errmsg[BUFSIZ] = {0}; @@ -411,19 +392,6 @@ static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, uint32_t sub_id, return SR_ERR_INTERNAL; } - input = yang_data_list_new(); - output = yang_data_list_new(); - - /* Process input. */ - for (size_t i = 0; i < input_cnt; i++) { - char value_str[YANG_VALUE_MAXLEN]; - - sr_val_to_buff(&sr_input[i], value_str, sizeof(value_str)); - - data = yang_data_new(xpath, value_str); - listnode_add(input, data); - } - /* Execute callback registered for this XPath. */ if (nb_callback_rpc(nb_node, xpath, input, output, errmsg, sizeof(errmsg)) @@ -431,44 +399,8 @@ static int frr_sr_config_rpc_cb(sr_session_ctx_t *session, uint32_t sub_id, flog_warn(EC_LIB_NB_CB_RPC, "%s: rpc callback failed: %s", __func__, xpath); ret = SR_ERR_OPERATION_FAILED; - goto exit; } - /* Process output. */ - if (listcount(output) > 0) { - sr_val_t *values = NULL; - struct listnode *node; - int i = 0; - - cb_output_cnt = listcount(output); - ret = sr_new_values(cb_output_cnt, &values); - if (ret != SR_ERR_OK) { - flog_err(EC_LIB_LIBSYSREPO, "%s: sr_new_values(): %s", - __func__, sr_strerror(ret)); - goto exit; - } - - for (ALL_LIST_ELEMENTS_RO(output, node, data)) { - if (yang_data_frr2sr(data, &values[i++]) != 0) { - flog_err( - EC_LIB_SYSREPO_DATA_CONVERT, - "%s: failed to convert data to Sysrepo format", - __func__); - ret = SR_ERR_INTERNAL; - sr_free_values(values, cb_output_cnt); - goto exit; - } - } - - *sr_output = values; - *sr_output_cnt = cb_output_cnt; - } - -exit: - /* Release memory. */ - list_delete(&input); - list_delete(&output); - return ret; } @@ -593,8 +525,9 @@ static int frr_sr_subscribe_rpc(const struct lysc_node *snode, void *arg) DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: providing RPC to '%s'", nb_node->xpath); - ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb, - NULL, 0, 0, &module->sr_subscription); + ret = sr_rpc_subscribe_tree(session, nb_node->xpath, + frr_sr_config_rpc_cb, NULL, 0, 0, + &module->sr_subscription); if (ret != SR_ERR_OK) flog_err(EC_LIB_LIBSYSREPO, "sr_rpc_subscribe(): %s", sr_strerror(ret)); diff --git a/lib/ntop.c b/lib/ntop.c index 49e1b152c931..89b4d5ecdcab 100644 --- a/lib/ntop.c +++ b/lib/ntop.c @@ -158,7 +158,7 @@ const char *frr_inet_ntop(int af, const void * restrict src, return dst; } -#if !defined(INET_NTOP_NO_OVERRIDE) && !defined(__APPLE__) +#if !defined(INET_NTOP_NO_OVERRIDE) /* we want to override libc inet_ntop, but make sure it shows up in backtraces * as frr_inet_ntop (to avoid confusion while debugging) */ diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h index df3bbd720fe1..a2df521f5828 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -16,6 +16,22 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new queue structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 4f3985bbca04..ecc3a68f157f 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -10,6 +10,21 @@ #ifdef __cplusplus extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new tree structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ /* * This file defines data structures for different types of trees: diff --git a/lib/pbr.h b/lib/pbr.h index d8c06e75bd2b..fe2d32a44a17 100644 --- a/lib/pbr.h +++ b/lib/pbr.h @@ -138,7 +138,7 @@ struct pbr_rule { struct pbr_filter filter; struct pbr_action action; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; }; /* TCP flags value shared diff --git a/lib/pid_output.c b/lib/pid_output.c index 064a7bb47fbb..ce1b7d1969a8 100644 --- a/lib/pid_output.c +++ b/lib/pid_output.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include "lib/version.h" diff --git a/lib/plist.c b/lib/plist.c index d8ce83d219ea..db502f877a75 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -28,6 +28,7 @@ DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table"); #define PLC_BITS 8 #define PLC_LEN (1 << PLC_BITS) #define PLC_MAXLEVELV4 2 /* /24 for IPv4 */ +#define PLC_MAXLEVELRTC 3 /* /96 for RTC */ #define PLC_MAXLEVELV6 4 /* /48 for IPv6 */ #define PLC_MAXLEVEL 4 /* max(v4,v6) */ @@ -58,6 +59,10 @@ struct prefix_master { /* number of bytes that have a trie level */ size_t trie_depth; + /* value to return if a prefix_list is empty and we are trying to get a + * match */ + enum prefix_list_type empty_action; + struct plist_head str; }; static int prefix_list_compare_func(const struct prefix_list *a, @@ -67,26 +72,36 @@ DECLARE_RBTREE_UNIQ(plist, struct prefix_list, plist_item, /* Static structure of IPv4 prefix_list's master. */ static struct prefix_master prefix_master_ipv4 = { - NULL, NULL, NULL, PLC_MAXLEVELV4, + NULL, NULL, NULL, PLC_MAXLEVELV4, PREFIX_PERMIT, }; /* Static structure of IPv6 prefix-list's master. */ static struct prefix_master prefix_master_ipv6 = { - NULL, NULL, NULL, PLC_MAXLEVELV6, + NULL, NULL, NULL, PLC_MAXLEVELV6, PREFIX_PERMIT, }; /* Static structure of BGP ORF prefix_list's master. */ static struct prefix_master prefix_master_orf_v4 = { - NULL, NULL, NULL, PLC_MAXLEVELV4, + NULL, NULL, NULL, PLC_MAXLEVELV4, PREFIX_PERMIT, }; /* Static structure of BGP ORF prefix_list's master. */ static struct prefix_master prefix_master_orf_v6 = { - NULL, NULL, NULL, PLC_MAXLEVELV6, + NULL, NULL, NULL, PLC_MAXLEVELV6, PREFIX_PERMIT, +}; + +/* Satic structure of BGP Route target constrain prefix_list's master. */ +static struct prefix_master prefix_master_rtc = { + NULL, NULL, NULL, PLC_MAXLEVELRTC, PREFIX_DENY, }; -static struct prefix_master *prefix_master_get(afi_t afi, int orf) +static struct prefix_master *prefix_master_get(afi_t afi, int orf, int rtc) { + if (orf && rtc) + return NULL; + + if (rtc) + return &prefix_master_rtc; if (afi == AFI_IP) return orf ? &prefix_master_orf_v4 : &prefix_master_ipv4; if (afi == AFI_IP6) @@ -114,7 +129,7 @@ static int prefix_list_compare_func(const struct prefix_list *a, } /* Lookup prefix_list from list of prefix_list by name. */ -static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, +static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, int rtc, const char *name) { struct prefix_list *plist, lookup; @@ -123,7 +138,7 @@ static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, if (name == NULL) return NULL; - master = prefix_master_get(afi, orf); + master = prefix_master_get(afi, orf, rtc); if (master == NULL) return NULL; @@ -135,12 +150,12 @@ static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, struct prefix_list *prefix_list_lookup(afi_t afi, const char *name) { - return prefix_list_lookup_do(afi, 0, name); + return prefix_list_lookup_do(afi, 0, 0, name); } struct prefix_list *prefix_bgp_orf_lookup(afi_t afi, const char *name) { - return prefix_list_lookup_do(afi, 1, name); + return prefix_list_lookup_do(afi, 1, 0, name); } static struct prefix_list *prefix_list_new(void) @@ -172,13 +187,13 @@ void prefix_list_entry_free(struct prefix_list_entry *pentry) /* Insert new prefix list to list of prefix_list. Each prefix_list is sorted by the name. */ -static struct prefix_list *prefix_list_insert(afi_t afi, int orf, +static struct prefix_list *prefix_list_insert(afi_t afi, int orf, int rtc, const char *name) { struct prefix_list *plist; struct prefix_master *master; - master = prefix_master_get(afi, orf); + master = prefix_master_get(afi, orf, rtc); if (master == NULL) return NULL; @@ -194,14 +209,15 @@ static struct prefix_list *prefix_list_insert(afi_t afi, int orf, return plist; } -struct prefix_list *prefix_list_get(afi_t afi, int orf, const char *name) +struct prefix_list *prefix_list_get(afi_t afi, int orf, int rtc, + const char *name) { struct prefix_list *plist; - plist = prefix_list_lookup_do(afi, orf, name); + plist = prefix_list_lookup_do(afi, orf, rtc, name); if (plist == NULL) - plist = prefix_list_insert(afi, orf, name); + plist = prefix_list_insert(afi, orf, rtc, name); return plist; } @@ -336,22 +352,6 @@ prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix, return NULL; } -static bool -prefix_list_entry_lookup_prefix(struct prefix_list *plist, - struct prefix_list_entry *plist_entry) -{ - struct prefix_list_entry *pentry = NULL; - - for (pentry = plist->head; pentry; pentry = pentry->next) { - if (pentry == plist_entry) - continue; - if (prefix_same(&pentry->prefix, &plist_entry->prefix)) - return true; - } - - return false; -} - static void trie_walk_affected(size_t validbits, struct pltrie_table *table, uint8_t byte, struct prefix_list_entry *object, void (*fn)(struct prefix_list_entry *object, @@ -418,17 +418,54 @@ static void prefix_list_trie_del(struct prefix_list *plist, } } +/** + * Find duplicated prefix entry (same prefix but different entry) in prefix + * list. + */ +static bool prefix_list_entry_is_duplicated(struct prefix_list *list, + struct prefix_list_entry *entry) +{ + size_t depth, maxdepth = list->master->trie_depth; + uint8_t byte, *bytes = entry->prefix.u.val; + size_t validbits = entry->prefix.prefixlen; + struct pltrie_table *table = list->trie; + struct prefix_list_entry *pentry; + + for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) { + byte = bytes[depth]; + if (!table->entries[byte].next_table) + return NULL; + + table = table->entries[byte].next_table; + validbits -= PLC_BITS; + } + + byte = bytes[depth]; + if (validbits > PLC_BITS) + pentry = table->entries[byte].final_chain; + else + pentry = table->entries[byte].up_chain; + + for (; pentry; pentry = pentry->next_best) { + if (pentry == entry) + continue; + if (prefix_same(&pentry->prefix, &entry->prefix)) + return true; + } + + return false; +} void prefix_list_entry_delete(struct prefix_list *plist, - struct prefix_list_entry *pentry, int update_list) + struct prefix_list_entry *pentry, + int update_list) { - bool duplicate = false; + bool duplicate; if (plist == NULL || pentry == NULL) return; - if (prefix_list_entry_lookup_prefix(plist, pentry)) - duplicate = true; + duplicate = prefix_list_entry_is_duplicated(plist, pentry); prefix_list_trie_del(plist, pentry); @@ -579,14 +616,13 @@ static void prefix_list_entry_add(struct prefix_list *plist, void prefix_list_entry_update_start(struct prefix_list_entry *ple) { struct prefix_list *pl = ple->pl; - bool duplicate = false; + bool duplicate; /* Not installed, nothing to do. */ if (!ple->installed) return; - if (prefix_list_entry_lookup_prefix(pl, ple)) - duplicate = true; + duplicate = prefix_list_entry_is_duplicated(pl, ple); prefix_list_trie_del(pl, ple); @@ -769,7 +805,7 @@ enum prefix_list_type prefix_list_apply_ext( if (plist->count == 0) { if (which) *which = NULL; - return PREFIX_PERMIT; + return plist->master->empty_action; } depth = plist->master->trie_depth; @@ -1053,17 +1089,13 @@ static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name, struct prefix_master *master; int64_t seqnum = 0; json_object *json = NULL; - json_object *json_proto = NULL; - master = prefix_master_get(afi, 0); + master = prefix_master_get(afi, 0, 0); if (master == NULL) return CMD_WARNING; - if (uj) { + if (uj) json = json_object_new_object(); - json_proto = json_object_new_object(); - json_object_object_add(json, frr_protoname, json_proto); - } if (seq) seqnum = (int64_t)atol(seq); @@ -1076,8 +1108,8 @@ static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name, "%% Can't find specified prefix-list\n"); return CMD_WARNING; } - vty_show_prefix_entry(vty, json_proto, afi, plist, master, - dtype, seqnum); + vty_show_prefix_entry(vty, json, afi, plist, master, dtype, + seqnum); } else { if (dtype == detail_display || dtype == summary_display) { if (master->recent && !uj) @@ -1087,8 +1119,8 @@ static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name, } frr_each (plist, &master->str, plist) - vty_show_prefix_entry(vty, json_proto, afi, plist, - master, dtype, seqnum); + vty_show_prefix_entry(vty, json, afi, plist, master, + dtype, seqnum); } return vty_json(vty, json); @@ -1169,7 +1201,7 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name, int ret; struct prefix p; - master = prefix_master_get(afi, 0); + master = prefix_master_get(afi, 0, 0); if (master == NULL) return CMD_WARNING; @@ -1207,9 +1239,9 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name, #include "lib/plist_clippy.c" -DEFPY (show_ip_prefix_list, +DEFPY_NOSH (show_ip_prefix_list, show_ip_prefix_list_cmd, - "show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]", + "show ip prefix-list [PREFIXLIST4_NAME$name [seq$dseq (1-4294967295)$arg]] [json$uj]", SHOW_STR IP_STR PREFIX_LIST_STR @@ -1219,16 +1251,17 @@ DEFPY (show_ip_prefix_list, JSON_STR) { enum display_type dtype = normal_display; + if (dseq) dtype = sequential_display; - return vty_show_prefix_list(vty, AFI_IP, prefix_list, arg_str, dtype, + return vty_show_prefix_list(vty, AFI_IP, name, arg_str, dtype, !!uj); } DEFPY (show_ip_prefix_list_prefix, show_ip_prefix_list_prefix_cmd, - "show ip prefix-list WORD A.B.C.D/M$prefix [longer$dl|first-match$dfm]", + "show ip prefix-list PREFIXLIST4_NAME$name A.B.C.D/M$prefix [longer$dl|first-match$dfm]", SHOW_STR IP_STR PREFIX_LIST_STR @@ -1238,18 +1271,19 @@ DEFPY (show_ip_prefix_list_prefix, "First matched prefix\n") { enum display_type dtype = normal_display; + if (dl) dtype = longer_display; else if (dfm) dtype = first_match_display; - return vty_show_prefix_list_prefix(vty, AFI_IP, prefix_list, prefix_str, + return vty_show_prefix_list_prefix(vty, AFI_IP, name, prefix_str, dtype); } -DEFPY (show_ip_prefix_list_summary, +DEFPY_NOSH (show_ip_prefix_list_summary, show_ip_prefix_list_summary_cmd, - "show ip prefix-list summary [WORD$prefix_list] [json$uj]", + "show ip prefix-list summary [PREFIXLIST4_NAME$name] [json$uj]", SHOW_STR IP_STR PREFIX_LIST_STR @@ -1257,13 +1291,13 @@ DEFPY (show_ip_prefix_list_summary, "Name of a prefix list\n" JSON_STR) { - return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL, + return vty_show_prefix_list(vty, AFI_IP, name, NULL, summary_display, !!uj); } -DEFPY (show_ip_prefix_list_detail, +DEFPY_NOSH (show_ip_prefix_list_detail, show_ip_prefix_list_detail_cmd, - "show ip prefix-list detail [WORD$prefix_list] [json$uj]", + "show ip prefix-list detail [PREFIXLIST4_NAME$name] [json$uj]", SHOW_STR IP_STR PREFIX_LIST_STR @@ -1271,25 +1305,25 @@ DEFPY (show_ip_prefix_list_detail, "Name of a prefix list\n" JSON_STR) { - return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL, + return vty_show_prefix_list(vty, AFI_IP, name, NULL, detail_display, !!uj); } DEFPY (clear_ip_prefix_list, clear_ip_prefix_list_cmd, - "clear ip prefix-list [WORD [A.B.C.D/M$prefix]]", + "clear ip prefix-list [PREFIXLIST4_NAME$name [A.B.C.D/M$prefix]]", CLEAR_STR IP_STR PREFIX_LIST_STR "Name of a prefix list\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - return vty_clear_prefix_list(vty, AFI_IP, prefix_list, prefix_str); + return vty_clear_prefix_list(vty, AFI_IP, name, prefix_str); } -DEFPY (show_ipv6_prefix_list, +DEFPY_NOSH(show_ipv6_prefix_list, show_ipv6_prefix_list_cmd, - "show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]", + "show ipv6 prefix-list [PREFIXLIST6_NAME$name [seq$dseq (1-4294967295)$arg]] [json$uj]", SHOW_STR IPV6_STR PREFIX_LIST_STR @@ -1299,16 +1333,17 @@ DEFPY (show_ipv6_prefix_list, JSON_STR) { enum display_type dtype = normal_display; + if (dseq) dtype = sequential_display; - return vty_show_prefix_list(vty, AFI_IP6, prefix_list, arg_str, dtype, + return vty_show_prefix_list(vty, AFI_IP6, name, arg_str, dtype, !!uj); } DEFPY (show_ipv6_prefix_list_prefix, show_ipv6_prefix_list_prefix_cmd, - "show ipv6 prefix-list WORD X:X::X:X/M$prefix [longer$dl|first-match$dfm]", + "show ipv6 prefix-list PREFIXLIST6_NAME$name X:X::X:X/M$prefix [longer$dl|first-match$dfm]", SHOW_STR IPV6_STR PREFIX_LIST_STR @@ -1318,18 +1353,19 @@ DEFPY (show_ipv6_prefix_list_prefix, "First matched prefix\n") { enum display_type dtype = normal_display; + if (dl) dtype = longer_display; else if (dfm) dtype = first_match_display; - return vty_show_prefix_list_prefix(vty, AFI_IP6, prefix_list, + return vty_show_prefix_list_prefix(vty, AFI_IP6, name, prefix_str, dtype); } -DEFPY (show_ipv6_prefix_list_summary, +DEFPY_NOSH (show_ipv6_prefix_list_summary, show_ipv6_prefix_list_summary_cmd, - "show ipv6 prefix-list summary [WORD$prefix-list] [json$uj]", + "show ipv6 prefix-list summary [PREFIXLIST6_NAME$name] [json$uj]", SHOW_STR IPV6_STR PREFIX_LIST_STR @@ -1337,13 +1373,13 @@ DEFPY (show_ipv6_prefix_list_summary, "Name of a prefix list\n" JSON_STR) { - return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL, + return vty_show_prefix_list(vty, AFI_IP6, name, NULL, summary_display, !!uj); } -DEFPY (show_ipv6_prefix_list_detail, +DEFPY_NOSH (show_ipv6_prefix_list_detail, show_ipv6_prefix_list_detail_cmd, - "show ipv6 prefix-list detail [WORD$prefix-list] [json$uj]", + "show ipv6 prefix-list detail [PREFIXLIST6_NAME$name] [json$uj]", SHOW_STR IPV6_STR PREFIX_LIST_STR @@ -1351,20 +1387,20 @@ DEFPY (show_ipv6_prefix_list_detail, "Name of a prefix list\n" JSON_STR) { - return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL, + return vty_show_prefix_list(vty, AFI_IP6, name, NULL, detail_display, !!uj); } DEFPY (clear_ipv6_prefix_list, clear_ipv6_prefix_list_cmd, - "clear ipv6 prefix-list [WORD [X:X::X:X/M$prefix]]", + "clear ipv6 prefix-list [PREFIXLIST6_NAME$name [X:X::X:X/M$prefix]]", CLEAR_STR IPV6_STR PREFIX_LIST_STR "Name of a prefix list\n" "IPv6 prefix /, e.g., 3ffe::/16\n") { - return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str); + return vty_clear_prefix_list(vty, AFI_IP6, name, prefix_str); } DEFPY (debug_prefix_list_match, @@ -1436,6 +1472,41 @@ struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist, return s; } +int prefix_bgp_rtc_set(char *name, struct prefix *p, int permit, int set) +{ + struct prefix_list *plist; + struct prefix_list_entry *pentry; + + + plist = prefix_list_get(AFI_IP, 0, 1, name); + if (!plist) { + return CMD_WARNING_CONFIG_FAILED; + } + + + if (set) { + pentry = prefix_list_entry_make( + p, (permit ? PREFIX_PERMIT : PREFIX_DENY), -1, 0, 0, + false); + + if (prefix_entry_dup_check(plist, pentry)) { + prefix_list_entry_free(pentry); + return CMD_WARNING_CONFIG_FAILED; + } + prefix_list_entry_add(plist, pentry); + } else { + pentry = prefix_list_entry_lookup( + plist, p, (permit ? PREFIX_PERMIT : PREFIX_DENY), -1, 0, + 0); + + if (!pentry) + return CMD_WARNING_CONFIG_FAILED; + + prefix_list_entry_delete(plist, pentry, 0); + } + + return CMD_SUCCESS; +} int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp, int permit, int set) @@ -1454,7 +1525,7 @@ int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp, if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128)) orfp->le = 0; - plist = prefix_list_get(afi, 1, name); + plist = prefix_list_get(afi, 1, 0, name); if (!plist) return CMD_WARNING_CONFIG_FAILED; @@ -1569,12 +1640,12 @@ int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, return plist->count; } -static void prefix_list_reset_afi(afi_t afi, int orf) +static void prefix_list_reset_afi(afi_t afi, int orf, int rtc) { struct prefix_list *plist; struct prefix_master *master; - master = prefix_master_get(afi, orf); + master = prefix_master_get(afi, orf, rtc); if (master == NULL) return; @@ -1598,7 +1669,7 @@ static void plist_autocomplete_afi(afi_t afi, vector comps, struct prefix_list *plist; struct prefix_master *master; - master = prefix_master_get(afi, 0); + master = prefix_master_get(afi, 0, 0); if (master == NULL) return; @@ -1612,12 +1683,26 @@ static void plist_autocomplete(vector comps, struct cmd_token *token) plist_autocomplete_afi(AFI_IP6, comps, token); } +static void plist4_autocomplete(vector comps, struct cmd_token *token) +{ + plist_autocomplete_afi(AFI_IP, comps, token); +} + +static void plist6_autocomplete(vector comps, struct cmd_token *token) +{ + plist_autocomplete_afi(AFI_IP6, comps, token); +} + static const struct cmd_variable_handler plist_var_handlers[] = { {/* "prefix-list WORD" */ .varname = "prefix_list", .completions = plist_autocomplete}, {.tokenname = "PREFIXLIST_NAME", .completions = plist_autocomplete}, + {.tokenname = "PREFIXLIST4_NAME", + .completions = plist4_autocomplete}, + {.tokenname = "PREFIXLIST6_NAME", + .completions = plist6_autocomplete}, {.completions = NULL}}; @@ -1659,6 +1744,7 @@ void prefix_list_init(void) plist_init(&prefix_master_orf_v4.str); plist_init(&prefix_master_ipv6.str); plist_init(&prefix_master_orf_v6.str); + plist_init(&prefix_master_rtc.str); cmd_variable_handler_register(plist_var_handlers); @@ -1668,8 +1754,9 @@ void prefix_list_init(void) void prefix_list_reset(void) { - prefix_list_reset_afi(AFI_IP, 0); - prefix_list_reset_afi(AFI_IP6, 0); - prefix_list_reset_afi(AFI_IP, 1); - prefix_list_reset_afi(AFI_IP6, 1); + prefix_list_reset_afi(AFI_IP, 0, 0); + prefix_list_reset_afi(AFI_IP6, 0, 0); + prefix_list_reset_afi(AFI_IP, 1, 0); + prefix_list_reset_afi(AFI_IP6, 1, 0); + prefix_list_reset_afi(AFI_IP, 0, 1); } diff --git a/lib/plist.h b/lib/plist.h index f31d8e879270..52f6a3774378 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -68,10 +68,12 @@ extern struct stream *prefix_bgp_orf_entry(struct stream *, uint8_t, uint8_t); extern int prefix_bgp_orf_set(char *, afi_t, struct orf_prefix *, int, int); extern void prefix_bgp_orf_remove_all(afi_t, char *); + +int prefix_bgp_rtc_set(char *name, struct prefix *p, int permit, int set); extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, bool use_json); -extern struct prefix_list *prefix_list_get(afi_t afi, int orf, +extern struct prefix_list *prefix_list_get(afi_t afi, int orf, int rtc, const char *name); extern void prefix_list_delete(struct prefix_list *plist); extern int64_t prefix_new_seq_get(struct prefix_list *plist); diff --git a/lib/prefix.c b/lib/prefix.c index f342c4c1dbea..254d317a79d5 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -174,6 +174,8 @@ const char *safi2str(safi_t safi) return "labeled-unicast"; case SAFI_FLOWSPEC: return "flowspec"; + case SAFI_RTC: + return "rtc"; case SAFI_UNSPEC: case SAFI_MAX: return "unknown"; @@ -347,6 +349,9 @@ void prefix_copy(union prefixptr udest, union prefixconstptr usrc) dest->u.prefix_flowspec.ptr = (uintptr_t)temp; memcpy((void *)dest->u.prefix_flowspec.ptr, (void *)src->u.prefix_flowspec.ptr, len); + } else if (src->family == AF_RTC) { + memcpy(&dest->u.prefix_rtc, &src->u.prefix_rtc, + sizeof(struct rtc_info)); } else { flog_err(EC_LIB_DEVELOPMENT, "prefix_copy(): Unknown address family %d", @@ -436,6 +441,10 @@ int prefix_same(union prefixconstptr up1, union prefixconstptr up2) p2->u.prefix_flowspec.prefixlen)) return 1; } + if (p1->family == AF_RTC) + if (!memcmp(&p1->u.prefix_rtc, &p2->u.prefix_rtc, + sizeof(struct rtc_info))) + return 1; } return 0; } @@ -567,6 +576,8 @@ const char *prefix_family_str(union prefixconstptr pu) return "ether"; if (p->family == AF_EVPN) return "evpn"; + if (p->family == AF_RTC) + return "rtc"; return "unspec"; } @@ -1116,6 +1127,10 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) strlcpy(str, "FS prefix", size); break; + case AF_RTC: + strlcpy(str, "RTC prefix", size); + break; + default: strlcpy(str, "UNK prefix", size); break; @@ -1124,6 +1139,15 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) return str; } +void prefix_mcast_ip_dump(const char *onfail, const struct ipaddr *addr, + char *buf, int buf_size) +{ + if (ipaddr_is_zero(addr)) + strlcpy(buf, "*", buf_size); + else + (void)snprintfrr(buf, buf_size, "%pIA", addr); +} + static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu) { const struct prefix *p = pu.p; @@ -1166,7 +1190,7 @@ const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str) char src_str[INET_ADDRSTRLEN]; char grp_str[INET_ADDRSTRLEN]; - prefix_mcast_inet4_dump("", sg->src, src_str, sizeof(src_str)); + prefix_mcast_ip_dump("", &sg->src, src_str, sizeof(src_str)); prefix_mcast_inet4_dump("", sg->grp, grp_str, sizeof(grp_str)); snprintf(sg_str, PREFIX_SG_STR_LEN, "(%s,%s)", src_str, grp_str); @@ -1637,10 +1661,10 @@ static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea, if (!sg) return bputs(buf, "(null)"); - if (sg->src.s_addr == INADDR_ANY) + if (ipaddr_is_zero(&sg->src)) ret += bputs(buf, "(*,"); else - ret += bprintfrr(buf, "(%pI4,", &sg->src); + ret += bprintfrr(buf, "(%pIA,", &sg->src); if (sg->grp.s_addr == INADDR_ANY) ret += bputs(buf, "*)"); diff --git a/lib/prefix.h b/lib/prefix.h index fc6e32dd54ac..957689a0aa7e 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -52,10 +52,10 @@ typedef enum { /* Maximum number of VTEPs per-ES - * XXX - temporary limit for allocating strings etc. */ -#define ES_VTEP_MAX_CNT 10 -#define ES_VTEP_LIST_STR_SZ (ES_VTEP_MAX_CNT * 16) +#define ES_VTEP_MAX_CNT 10 +#define ES_VTEP_LIST_STR_SZ (ES_VTEP_MAX_CNT * IPADDR_STRING_SIZE) -#define ETHER_ADDR_STRLEN (3*ETH_ALEN) +#define ETHER_ADDR_STRLEN (3 * ETH_ALEN) /* * there isn't a portable ethernet address type. We define our * own to simplify internal handling @@ -125,6 +125,11 @@ struct evpn_addr { #define prefix_addr u._prefix_addr }; +struct rtc_info { + uint32_t origin_as; + uint8_t route_target[8]; +}; + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -158,6 +163,10 @@ struct evpn_addr { #define AF_FLOWSPEC (AF_MAX + 2) #endif +#if !defined(AF_RTC) +#define AF_RTC (AF_MAX + 3) +#endif + struct flowspec_prefix { uint8_t family; uint16_t prefixlen; /* length in bytes */ @@ -181,6 +190,7 @@ struct prefix { uint32_t val32[4]; uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ + struct rtc_info prefix_rtc; /* AF_RTC */ struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */ } u __attribute__((aligned(8))); }; @@ -227,6 +237,13 @@ struct prefix_evpn { struct evpn_addr prefix __attribute__((aligned(8))); }; +struct prefix_rtc { + uint8_t family; + uint16_t prefixlen; + struct rtc_info prefix __attribute__((aligned(8))); +}; + + static inline int is_evpn_prefix_ipaddr_none(const struct prefix_evpn *evp) { if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) @@ -282,27 +299,31 @@ struct prefix_fs { struct prefix_sg { uint8_t family; uint16_t prefixlen; - struct in_addr src __attribute__((aligned(8))); + struct ipaddr src __attribute__((aligned(8))); struct in_addr grp; }; +/* clang-format off */ union prefixptr { - prefixtype(prefixptr, struct prefix, p) - prefixtype(prefixptr, struct prefix_ipv4, p4) - prefixtype(prefixptr, struct prefix_ipv6, p6) - prefixtype(prefixptr, struct prefix_evpn, evp) - prefixtype(prefixptr, struct prefix_fs, fs) - prefixtype(prefixptr, struct prefix_rd, rd) + uniontype(prefixptr, struct prefix, p) + uniontype(prefixptr, struct prefix_ipv4, p4) + uniontype(prefixptr, struct prefix_ipv6, p6) + uniontype(prefixptr, struct prefix_evpn, evp) + uniontype(prefixptr, struct prefix_fs, fs) + uniontype(prefixptr, struct prefix_rd, rd) + uniontype(prefixptr, struct prefix_rtc, rtc) } TRANSPARENT_UNION; union prefixconstptr { - prefixtype(prefixconstptr, const struct prefix, p) - prefixtype(prefixconstptr, const struct prefix_ipv4, p4) - prefixtype(prefixconstptr, const struct prefix_ipv6, p6) - prefixtype(prefixconstptr, const struct prefix_evpn, evp) - prefixtype(prefixconstptr, const struct prefix_fs, fs) - prefixtype(prefixconstptr, const struct prefix_rd, rd) + uniontype(prefixconstptr, const struct prefix, p) + uniontype(prefixconstptr, const struct prefix_ipv4, p4) + uniontype(prefixconstptr, const struct prefix_ipv6, p6) + uniontype(prefixconstptr, const struct prefix_evpn, evp) + uniontype(prefixconstptr, const struct prefix_fs, fs) + uniontype(prefixconstptr, const struct prefix_rd, rd) + uniontype(prefixconstptr, const struct prefix_rtc, rtc) } TRANSPARENT_UNION; +/* clang-format on */ #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 @@ -413,6 +434,8 @@ extern int str2prefix(const char *string, struct prefix *prefix); #define PREFIX2STR_BUFFER PREFIX_STRLEN +extern void prefix_mcast_ip_dump(const char *onfail, const struct ipaddr *addr, + char *buf, int buf_size); extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str); @@ -654,6 +677,7 @@ static inline bool ipv4_mcast_ssm(const struct in_addr *addr) #pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *) #pragma FRR printfrr_ext "%pFX" (struct prefix_fs *) #pragma FRR printfrr_ext "%pRDP" (struct prefix_rd *) +#pragma FRR printfrr_ext "%pRTC"(struct prefix_rtc *) /* RD with AS4B with dot and dot+ format */ #pragma FRR printfrr_ext "%pRDD" (struct prefix_rd *) #pragma FRR printfrr_ext "%pRDE" (struct prefix_rd *) diff --git a/lib/printf/README b/lib/printf/README index 46d51cec6a93..3c3ef74ca8bb 100644 --- a/lib/printf/README +++ b/lib/printf/README @@ -1,6 +1,7 @@ This is the printf implementation from FreeBSD. The history of this code is: - imported on 2019-05-12, from SVN revision 347514 - resynced on 2023-09-03, to pick up `%b` implementation +- resynced on 2024-03-10, to pick up `%w[f](8|16|32|64)d` implementation Please don't reindent or otherwise mangle the files to make importing fixes easy (not that there are significant changes likely to happen...) diff --git a/lib/printf/printf-pos.c b/lib/printf/printf-pos.c index ac775bea4e2b..b2ba1a714d69 100644 --- a/lib/printf/printf-pos.c +++ b/lib/printf/printf-pos.c @@ -355,7 +355,7 @@ reswitch: switch (ch) { goto rflag; case 'C': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'c': error = addtype(&types, (flags & LONGINT) ? T_WINT : T_INT); @@ -364,7 +364,7 @@ reswitch: switch (ch) { break; case 'D': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'd': case 'i': if ((error = addsarg(&types, flags))) @@ -408,7 +408,7 @@ reswitch: switch (ch) { #endif case 'O': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'o': if ((error = adduarg(&types, flags))) goto error; @@ -419,7 +419,7 @@ reswitch: switch (ch) { break; case 'S': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 's': error = addtype(&types, (flags & LONGINT) ? TP_WCHAR : TP_CHAR); @@ -428,7 +428,7 @@ reswitch: switch (ch) { break; case 'U': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'u': case 'X': case 'x': @@ -549,7 +549,7 @@ reswitch: switch (ch) { goto rflag; case 'C': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'c': error = addtype(&types, (flags & LONGINT) ? T_WINT : T_INT); @@ -558,7 +558,7 @@ reswitch: switch (ch) { break; case 'D': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'd': case 'i': if ((error = addsarg(&types, flags))) @@ -602,7 +602,7 @@ reswitch: switch (ch) { #endif case 'O': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'o': if ((error = adduarg(&types, flags))) goto error; @@ -613,7 +613,7 @@ reswitch: switch (ch) { break; case 'S': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 's': error = addtype(&types, (flags & LONGINT) ? TP_WCHAR : TP_CHAR); @@ -622,7 +622,7 @@ reswitch: switch (ch) { break; case 'U': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'u': case 'X': case 'x': diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h index 4b030912fe7e..93318c8fdb16 100644 --- a/lib/printf/printflocal.h +++ b/lib/printf/printflocal.h @@ -52,6 +52,7 @@ #define PTRDIFFT 0x800 /* ptrdiff_t */ #define INTMAXT 0x1000 /* intmax_t */ #define CHARINT 0x2000 /* print char using int format */ +#define FASTINT 0x4000 /* int_fastN_t */ /* * Macros for converting digits to letters and vice versa diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index 78f8be05cbf9..3f6700c8385d 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -340,7 +340,7 @@ reswitch: switch (ch) { if (width >= 0) goto rflag; width = -width; - /* FALLTHROUGH */ + fallthrough; case '-': flags |= LADJUST; goto rflag; @@ -416,6 +416,49 @@ reswitch: switch (ch) { case 't': flags |= PTRDIFFT; goto rflag; + case 'w': + /* + * Fixed-width integer types. On all platforms we + * support, int8_t is equivalent to char, int16_t + * is equivalent to short, int32_t is equivalent + * to int, int64_t is equivalent to long long int. + * Furthermore, int_fast8_t, int_fast16_t and + * int_fast32_t are equivalent to int, and + * int_fast64_t is equivalent to long long int. + */ + flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT); + if (fmt[0] == 'f') { + flags |= FASTINT; + fmt++; + } else { + flags &= ~FASTINT; + } + if (fmt[0] == '8') { + if (!(flags & FASTINT)) + flags |= CHARINT; + else + (void) 0; /* no flag set = 32 */ + fmt += 1; + } else if (fmt[0] == '1' && fmt[1] == '6') { + if (!(flags & FASTINT)) + flags |= SHORTINT; + else + (void) 0; /* no flag set = 32 */ + fmt += 2; + } else if (fmt[0] == '3' && fmt[1] == '2') { + /* no flag set = 32 */ + fmt += 2; + } else if (fmt[0] == '6' && fmt[1] == '4') { + flags |= LLONGINT; + fmt += 2; + } else { + if (flags & FASTINT) { + flags &= ~FASTINT; + fmt--; + } + goto invalid; + } + goto rflag; case 'z': flags |= SIZET; goto rflag; @@ -434,7 +477,7 @@ reswitch: switch (ch) { break; case 'C': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'c': #ifdef WCHAR_SUPPORT if (flags & LONGINT) { @@ -460,7 +503,7 @@ reswitch: switch (ch) { break; case 'D': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'd': case 'i': if (flags & INTMAX_SIZE) @@ -551,7 +594,7 @@ reswitch: switch (ch) { break; case 'O': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'o': if (flags & INTMAX_SIZE) ujval = UJARG(); @@ -595,7 +638,7 @@ reswitch: switch (ch) { goto nosign; case 'S': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 's': #ifdef WCHAR_SUPPORT if (flags & LONGINT) { @@ -621,7 +664,7 @@ reswitch: switch (ch) { break; case 'U': flags |= LONGINT; - /*FALLTHROUGH*/ + fallthrough; case 'u': if (flags & INTMAX_SIZE) ujval = UJARG(); @@ -684,6 +727,7 @@ number: if ((dprec = prec) >= 0) default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') goto done; +invalid: /* pretend it was %c with argument ch */ buf[0] = ch; cp = buf; diff --git a/lib/privs.c b/lib/privs.c index accd9895ffec..717a2e48d629 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -6,6 +6,15 @@ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. */ #include + +#include +#include + +#ifdef HAVE_LCAPS +#include +#include +#endif /* HAVE_LCAPS */ + #include "log.h" #include "privs.h" #include "memory.h" diff --git a/lib/pullwr.c b/lib/pullwr.c index 3967eb587541..919a663db536 100644 --- a/lib/pullwr.c +++ b/lib/pullwr.c @@ -6,6 +6,8 @@ #include "zebra.h" +#include + #include "pullwr.h" #include "memory.h" #include "monotime.h" diff --git a/lib/resolver.c b/lib/resolver.c index 99bf356eb3e6..901ccf8132e3 100644 --- a/lib/resolver.c +++ b/lib/resolver.c @@ -104,7 +104,7 @@ static void resolver_cb_timeout(struct event *t) { struct resolver_state *r = EVENT_ARG(t); - ares_process(r->channel, NULL, NULL); + ares_process_fd(r->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); resolver_update_timeouts(r); } @@ -179,7 +179,56 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable, resolver_fd_drop_maybe(resfd); } +#if (ARES_VERSION >= 0x011c00) +static void ares_address_cb(void *arg, int status, int timeouts, + struct ares_addrinfo *result) +{ + struct resolver_query *query = (struct resolver_query *)arg; + union sockunion addr[16]; + void (*callback)(struct resolver_query *q, const char *err, int ret, + union sockunion *s); + size_t i; + struct ares_addrinfo_node *node; + + callback = query->callback; + query->callback = NULL; + + if (status != ARES_SUCCESS) { + if (resolver_debug) + zlog_debug("[%p] Resolving failed (%s)", + query, ares_strerror(status)); + + callback(query, ares_strerror(status), -1, NULL); + if (result) + ares_freeaddrinfo(result); + return; + } + + + node = result->nodes; + for (i = 0; i < array_size(addr) && node; i++) { + memset(&addr[i], 0, sizeof(addr[i])); + addr[i].sa.sa_family = node->ai_family; + switch (node->ai_family) { + case AF_INET: + memcpy(&addr[i].sin.sin_addr, node->ai_addr, + node->ai_addrlen); + break; + case AF_INET6: + memcpy(&addr[i].sin6.sin6_addr, node->ai_addr, + node->ai_addrlen); + break; + } + node = node->ai_next; + } + if (resolver_debug) + zlog_debug("[%p] Resolved with %d results", query, (int)i); + + callback(query, NULL, i, &addr[0]); + ares_freeaddrinfo(result); +} +#else static void ares_address_cb(void *arg, int status, int timeouts, struct hostent *he) { @@ -222,6 +271,8 @@ static void ares_address_cb(void *arg, int status, int timeouts, callback(query, NULL, i, &addr[0]); } +#endif + static void resolver_cb_literal(struct event *t) { struct resolver_query *query = EVENT_ARG(t); @@ -240,6 +291,14 @@ void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id, int, union sockunion *)) { int ret; +#if (ARES_VERSION >= 0x011c00) + struct ares_addrinfo_hints hints = { + .ai_flags = 0, + .ai_family = af, + .ai_socktype = 0, /* any of SOCK_STREAM or SOCK_DGRAM */ + .ai_protocol = 0 /* any protocol */ + }; +#endif if (hostname == NULL) return; @@ -278,7 +337,13 @@ void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id, __func__, vrf_id, safe_strerror(errno)); return; } + +#if (ARES_VERSION >= 0x011c00) + ares_getaddrinfo(state.channel, hostname, NULL, &hints, ares_address_cb, + query); +#else ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query); +#endif ret = vrf_switchback_to_initial(); if (ret < 0) flog_err_sys(EC_LIB_SOCKET, @@ -335,3 +400,8 @@ void resolver_init(struct event_loop *tm) install_element(CONFIG_NODE, &debug_resolver_cmd); install_element(ENABLE_NODE, &debug_resolver_cmd); } + +void resolver_terminate(void) +{ + ares_destroy(state.channel); +} diff --git a/lib/resolver.h b/lib/resolver.h index 87e8ecdc4ae6..882f960a450c 100644 --- a/lib/resolver.h +++ b/lib/resolver.h @@ -23,6 +23,7 @@ struct resolver_query { }; void resolver_init(struct event_loop *tm); +void resolver_terminate(void); void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id, const char *hostname, void (*cb)(struct resolver_query *, const char *, int, diff --git a/lib/route_types.txt b/lib/route_types.txt index a82273a6dcb0..93cbc36e97bd 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -49,6 +49,7 @@ ZEBRA_ROUTE_SYSTEM, system, NULL, 'X', 0, 0, 0, "Reserved", none ZEBRA_ROUTE_KERNEL, kernel, zebra, 'K', 1, 1, 1, "kernel route", zebra ZEBRA_ROUTE_CONNECT, connected, zebra, 'C', 1, 1, 1, "connected", zebra +ZEBRA_ROUTE_LOCAL, local, zebra, 'L', 1, 1, 1, "local", zebra ZEBRA_ROUTE_STATIC, static, zebra, 'S', 1, 1, 1, "static", zebra ZEBRA_ROUTE_RIP, rip, ripd, 'R', 1, 0, 1, "RIP", ripd ZEBRA_ROUTE_RIPNG, ripng, ripngd, 'R', 0, 1, 1, "RIPng", ripngd @@ -86,6 +87,7 @@ ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric", fa ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP", vrrpd ZEBRA_ROUTE_NHG, zebra, none, '-', 0, 0, 0, "Nexthop Group", none ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE", none +ZEBRA_ROUTE_TABLE_DIRECT, table-direct, zebra, 't', 1, 1, 1, "Table-Direct", zebra ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-", none @@ -93,6 +95,7 @@ ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-", no ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" ZEBRA_ROUTE_KERNEL, "Kernel routes (not installed via the zebra RIB)" ZEBRA_ROUTE_CONNECT,"Connected routes (directly attached subnet or host)" +ZEBRA_ROUTE_LOCAL, "Local routes (directly attached host route)" ZEBRA_ROUTE_STATIC, "Statically configured routes" ZEBRA_ROUTE_RIP, "Routing Information Protocol (RIP)" ZEBRA_ROUTE_RIPNG, "Routing Information Protocol next-generation (IPv6) (RIPng)" @@ -116,3 +119,4 @@ ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)" ZEBRA_ROUTE_VRRP, "Virtual Router Redundancy Protocol (VRRP)" ZEBRA_ROUTE_OPENFABRIC, "OpenFabric Routing Protocol" ZEBRA_ROUTE_NHG, "Zebra Nexthop Groups (NHG)" +ZEBRA_ROUTE_TABLE_DIRECT, "Non-main Kernel Routing Table - Direct" diff --git a/lib/routemap.c b/lib/routemap.c index e0b0eb7a3cc5..ea917ebd8c73 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -1070,20 +1070,17 @@ static int vty_show_route_map(struct vty *vty, const char *name, bool use_json) { struct route_map *map; json_object *json = NULL; - json_object *json_proto = NULL; - if (use_json) { + if (use_json) json = json_object_new_object(); - json_proto = json_object_new_object(); - json_object_object_add(json, frr_protonameinst, json_proto); - } else + else vty_out(vty, "%s:\n", frr_protonameinst); if (name) { map = route_map_lookup_by_name(name); if (map) { - vty_show_route_map_entry(vty, map, json_proto); + vty_show_route_map_entry(vty, map, json); } else if (!use_json) { vty_out(vty, "%s: 'route-map %s' not found\n", frr_protonameinst, name); @@ -1099,7 +1096,7 @@ static int vty_show_route_map(struct vty *vty, const char *name, bool use_json) list_sort(maplist, sort_route_map); for (ALL_LIST_ELEMENTS_RO(maplist, ln, map)) - vty_show_route_map_entry(vty, map, json_proto); + vty_show_route_map_entry(vty, map, json); list_delete(&maplist); } @@ -2551,7 +2548,6 @@ route_map_result_t route_map_apply_ext(struct route_map *map, struct route_map_index *index = NULL; struct route_map_rule *set = NULL; bool skip_match_clause = false; - struct prefix conv; if (recursion > RMAP_RECURSION_LIMIT) { if (map) @@ -2574,31 +2570,14 @@ route_map_result_t route_map_apply_ext(struct route_map *map, map->applied++; - /* - * Handling for matching evpn_routes in the prefix table. - * - * We convert type2/5 prefix to ipv4/6 prefix to do longest - * prefix matching on. - */ if (prefix->family == AF_EVPN) { - if (evpn_prefix2prefix(prefix, &conv) != 0) { - if (unlikely(CHECK_FLAG(rmap_debug, - DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "Unable to convert EVPN prefix %pFX into IPv4/IPv6 prefix. Falling back to non-optimized route-map lookup", - prefix); - } else { - if (unlikely(CHECK_FLAG(rmap_debug, - DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "Converted EVPN prefix %pFX into %pFX for optimized route-map lookup", - prefix, &conv); - - prefix = &conv; - } + index = map->head; + } else { + skip_match_clause = true; + index = route_map_get_index(map, prefix, match_object, + &match_ret); } - index = route_map_get_index(map, prefix, match_object, &match_ret); if (index) { index->applied++; if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP))) @@ -2622,7 +2601,6 @@ route_map_result_t route_map_apply_ext(struct route_map *map, ret = RMAP_DENYMATCH; goto route_map_apply_end; } - skip_match_clause = true; for (; index; index = index->next) { if (!skip_match_clause) { @@ -3145,13 +3123,13 @@ DEFPY (rmap_clear_counters, } -DEFUN (rmap_show_name, - rmap_show_name_cmd, - "show route-map [WORD] [json]", - SHOW_STR - "route-map information\n" - "route-map name\n" - JSON_STR) +DEFUN_NOSH (rmap_show_name, + rmap_show_name_cmd, + "show route-map [WORD] [json]", + SHOW_STR + "route-map information\n" + "route-map name\n" + JSON_STR) { bool uj = use_json(argc, argv); int idx = 0; @@ -3412,7 +3390,7 @@ DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd, } /* Initialization of route map vector. */ -void route_map_init(void) +void route_map_init_new(bool in_backend) { int i; @@ -3427,7 +3405,10 @@ void route_map_init(void) UNSET_FLAG(rmap_debug, DEBUG_ROUTEMAP); - route_map_cli_init(); + if (!in_backend) { + /* we do not want to handle config commands in the backend */ + route_map_cli_init(); + } /* Install route map top node. */ install_node(&rmap_debug_node); @@ -3447,3 +3428,8 @@ void route_map_init(void) install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd); } + +void route_map_init(void) +{ + route_map_init_new(false); +} diff --git a/lib/routemap.h b/lib/routemap.h index 08e341221d8c..dfb84ced5bae 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -401,6 +401,7 @@ enum ecommunity_lb_type { /* Prototypes. */ extern void route_map_init(void); +extern void route_map_init_new(bool in_backend); /* * This should only be called on shutdown @@ -1024,6 +1025,7 @@ routemap_hook_context_insert(struct route_map_index *rmi); void routemap_hook_context_free(struct routemap_hook_context *rhc); extern const struct frr_yang_module_info frr_route_map_info; +extern const struct frr_yang_module_info frr_route_map_cli_info; /* routemap_cli.c */ extern int route_map_instance_cmp(const struct lyd_node *dnode1, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index a5e66880a75c..f22d5880807c 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -90,8 +90,8 @@ DEFPY_YANG( int route_map_instance_cmp(const struct lyd_node *dnode1, const struct lyd_node *dnode2) { - uint16_t seq1 = yang_dnode_get_uint16(dnode1, "./sequence"); - uint16_t seq2 = yang_dnode_get_uint16(dnode2, "./sequence"); + uint16_t seq1 = yang_dnode_get_uint16(dnode1, "sequence"); + uint16_t seq2 = yang_dnode_get_uint16(dnode2, "sequence"); return seq1 - seq2; } @@ -100,8 +100,8 @@ void route_map_instance_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *name = yang_dnode_get_string(dnode, "../name"); - const char *action = yang_dnode_get_string(dnode, "./action"); - const char *sequence = yang_dnode_get_string(dnode, "./sequence"); + const char *action = yang_dnode_get_string(dnode, "action"); + const char *sequence = yang_dnode_get_string(dnode, "sequence"); vty_out(vty, "route-map %s %s %s\n", name, action, sequence); @@ -188,7 +188,7 @@ DEFPY_YANG( DEFPY_YANG( match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, - "match ip address prefix-list PREFIXLIST_NAME$name", + "match ip address prefix-list PREFIXLIST4_NAME$name", MATCH_STR IP_STR "Match address of route\n" @@ -209,7 +209,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, - "no match ip address prefix-list [PREFIXLIST_NAME]", + "no match ip address prefix-list [PREFIXLIST4_NAME]", NO_STR MATCH_STR IP_STR @@ -265,7 +265,7 @@ DEFPY_YANG( DEFPY_YANG( match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, - "match ip next-hop prefix-list PREFIXLIST_NAME$name", + "match ip next-hop prefix-list PREFIXLIST4_NAME$name", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -287,7 +287,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, - "no match ip next-hop prefix-list [PREFIXLIST_NAME]", + "no match ip next-hop prefix-list [PREFIXLIST4_NAME]", NO_STR MATCH_STR IP_STR @@ -379,7 +379,7 @@ DEFPY_YANG( DEFPY_YANG( match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, - "match ipv6 address prefix-list PREFIXLIST_NAME$name", + "match ipv6 address prefix-list PREFIXLIST6_NAME$name", MATCH_STR IPV6_STR "Match address of route\n" @@ -401,7 +401,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_cmd, - "no match ipv6 address prefix-list [PREFIXLIST_NAME]", + "no match ipv6 address prefix-list [PREFIXLIST6_NAME]", NO_STR MATCH_STR IPV6_STR @@ -490,29 +490,33 @@ DEFPY_YANG( DEFPY_YANG( match_tag, match_tag_cmd, - "match tag (1-4294967295)$tag", + "match tag ", MATCH_STR "Match tag of route\n" + "Untagged route\n" "Tag value\n") { const char *xpath = "./match-condition[condition='frr-route-map:match-tag']"; char xpath_value[XPATH_MAXLEN]; + char value[64]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-match-condition/tag", xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); + snprintf(value, sizeof(value), "%lu", tagged ? tagged : 0); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); } DEFPY_YANG( no_match_tag, no_match_tag_cmd, - "no match tag [(1-4294967295)]", + "no match tag []", NO_STR MATCH_STR "Match tag of route\n" + "Untagged route\n" "Tag value\n") { const char *xpath = @@ -526,7 +530,7 @@ DEFPY_YANG( void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *condition = yang_dnode_get_string(dnode, "./condition"); + const char *condition = yang_dnode_get_string(dnode, "condition"); const struct lyd_node *ln; const char *acl; @@ -581,9 +585,15 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, yang_dnode_get_string(dnode, "./rmap-match-condition/metric")); } else if (IS_MATCH_TAG(condition)) { - vty_out(vty, " match tag %s\n", - yang_dnode_get_string(dnode, - "./rmap-match-condition/tag")); + uint32_t tag = + strtoul(yang_dnode_get_string(dnode, + "./rmap-match-condition/tag"), + NULL, 10); + + if (!tag) + vty_out(vty, " match tag untagged\n"); + else + vty_out(vty, " match tag %u\n", tag); } else if (IS_MATCH_IPv4_PREFIX_LEN(condition)) { vty_out(vty, " match ip address prefix-len %s\n", yang_dnode_get_string( @@ -729,6 +739,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, dnode, "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) vty_out(vty, " exact-match"); + if (yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any")) + vty_out(vty, " any"); vty_out(vty, "\n"); } else if (IS_MATCH_LCOMMUNITY(condition)) { vty_out(vty, " match large-community %s", @@ -739,6 +753,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, dnode, "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) vty_out(vty, " exact-match"); + if (yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any")) + vty_out(vty, " any"); vty_out(vty, "\n"); } else if (IS_MATCH_EXTCOMMUNITY(condition)) { vty_out(vty, " match extcommunity %s\n", @@ -919,7 +937,7 @@ DEFPY_YANG(no_set_min_metric, no_set_min_metric_cmd, "no set min-metric [(0-4294967295)]", NO_STR SET_STR "Minimum metric value for destination routing protocol\n" - "Minumum metric value\n") + "Minimum metric value\n") { const char *xpath = "./set-action[action='frr-route-map:set-min-metric']"; @@ -965,28 +983,32 @@ DEFPY_YANG(no_set_max_metric, no_set_max_metric_cmd, DEFPY_YANG( set_tag, set_tag_cmd, - "set tag (1-4294967295)$tag", + "set tag ", SET_STR "Tag value for routing protocol\n" + "Untagged route\n" "Tag value\n") { const char *xpath = "./set-action[action='frr-route-map:set-tag']"; char xpath_value[XPATH_MAXLEN]; + char value[64]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/tag", xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); + snprintf(value, sizeof(value), "%lu", tagged ? tagged : 0); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); } DEFPY_YANG( no_set_tag, no_set_tag_cmd, - "no set tag [(1-4294967295)]", + "no set tag []", NO_STR SET_STR "Tag value for routing protocol\n" + "Untagged route\n" "Tag value\n") { const char *xpath = "./set-action[action='frr-route-map:set-tag']"; @@ -1042,7 +1064,7 @@ DEFUN_YANG (no_set_srte_color, void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *action = yang_dnode_get_string(dnode, "./action"); + const char *action = yang_dnode_get_string(dnode, "action"); const struct lyd_node *ln; const char *acl; @@ -1093,8 +1115,15 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, yang_dnode_get_string(dnode, "./rmap-set-action/max-metric")); } else if (IS_SET_TAG(action)) { - vty_out(vty, " set tag %s\n", - yang_dnode_get_string(dnode, "./rmap-set-action/tag")); + uint32_t tag = + strtoul(yang_dnode_get_string(dnode, + "rmap-set-action/tag"), + NULL, 10); + + if (!tag) + vty_out(vty, " set tag untagged\n"); + else + vty_out(vty, " set tag %u\n", tag); } else if (IS_SET_SR_TE_COLOR(action)) { vty_out(vty, " set sr-te color %s\n", yang_dnode_get_string(dnode, @@ -1188,7 +1217,7 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " set large-comm-list %s delete\n", acl); } else if (IS_SET_EXTCOMM_LIST_DEL(action)) { acl = NULL; - ln = yang_dnode_get(dnode, "./rmap-set-action/frr-bgp-route-map:comm-list-name"); + ln = yang_dnode_get(dnode, "rmap-set-action/frr-bgp-route-map:comm-list-name"); if (ln) acl = yang_dnode_get_string(ln, NULL); @@ -1244,14 +1273,14 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, } else if (IS_SET_EXTCOMMUNITY_LB(action)) { enum ecommunity_lb_type lb_type; char str[VTY_BUFSIZ]; - uint16_t bandwidth; + uint32_t bandwidth; lb_type = yang_dnode_get_enum( dnode, "./rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type"); switch (lb_type) { case EXPLICIT_BANDWIDTH: - bandwidth = yang_dnode_get_uint16( + bandwidth = yang_dnode_get_uint32( dnode, "./rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth"); snprintf(str, sizeof(str), "%d", bandwidth); diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 5767e0aacf75..1bba4dad47a6 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -98,7 +98,7 @@ static int lib_route_map_create(struct nb_cb_create_args *args) /* NOTHING */ break; case NB_EV_APPLY: - rm_name = yang_dnode_get_string(args->dnode, "./name"); + rm_name = yang_dnode_get_string(args->dnode, "name"); rm = route_map_get(rm_name); nb_running_set_entry(args->dnode, rm); break; @@ -167,8 +167,8 @@ static int lib_route_map_entry_create(struct nb_cb_create_args *args) /* NOTHING */ break; case NB_EV_APPLY: - sequence = yang_dnode_get_uint16(args->dnode, "./sequence"); - action = yang_dnode_get_enum(args->dnode, "./action") == 0 + sequence = yang_dnode_get_uint16(args->dnode, "sequence"); + action = yang_dnode_get_enum(args->dnode, "action") == 0 ? RMAP_PERMIT : RMAP_DENY; rm = nb_running_get_entry(args->dnode, NULL, true); @@ -364,7 +364,6 @@ lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args *args) case 0: /* permit-or-deny */ break; case 1: /* next */ - /* FALLTHROUGH */ case 2: /* goto */ rm_action = yang_dnode_get_enum(args->dnode, "../action"); @@ -885,7 +884,7 @@ static int lib_route_map_entry_set_action_ipv4_address_modify( yang_dnode_get_ipv4(&ia, args->dnode, NULL); if (ia.s_addr == INADDR_ANY || !ipv4_unicast_valid(&ia)) return NB_ERR_VALIDATION; - /* FALLTHROUGH */ + return NB_OK; case NB_EV_PREPARE: case NB_EV_ABORT: return NB_OK; @@ -944,7 +943,7 @@ static int lib_route_map_entry_set_action_ipv6_address_modify( yang_dnode_get_ipv6(&i6a, args->dnode, NULL); if (!IN6_IS_ADDR_LINKLOCAL(&i6a)) return NB_ERR_VALIDATION; - /* FALLTHROUGH */ + return NB_OK; case NB_EV_PREPARE: case NB_EV_ABORT: return NB_OK; @@ -1551,3 +1550,45 @@ const struct frr_yang_module_info frr_route_map_info = { }, } }; + +const struct frr_yang_module_info frr_route_map_cli_info = { + .name = "frr-route-map", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map/optimization-disabled", + .cbs.cli_show = route_map_optimization_disabled_show, + }, + { + .xpath = "/frr-route-map:lib/route-map/entry", + .cbs = { + .cli_cmp = route_map_instance_cmp, + .cli_show = route_map_instance_show, + .cli_show_end = route_map_instance_show_end, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/description", + .cbs.cli_show = route_map_description_show, + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/call", + .cbs.cli_show = route_map_call_show, + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/exit-policy", + .cbs.cli_show = route_map_exit_policy_show, + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition", + .cbs.cli_show = route_map_condition_show, + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action", + .cbs.cli_show = route_map_action_show, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/routing_nb.c b/lib/routing_nb.c index 3d837bcc1149..33372d113a99 100644 --- a/lib/routing_nb.c +++ b/lib/routing_nb.c @@ -27,3 +27,13 @@ const struct frr_yang_module_info frr_routing_info = { }, } }; + +const struct frr_yang_module_info frr_routing_cli_info = { + .name = "frr-routing", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = NULL, + }, + } +}; diff --git a/lib/routing_nb.h b/lib/routing_nb.h index c185091a4bce..26b4cf08d821 100644 --- a/lib/routing_nb.h +++ b/lib/routing_nb.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #ifndef _FRR_ROUTING_NB_H_ #define _FRR_ROUTING_NB_H_ @@ -6,6 +8,7 @@ extern "C" { #endif extern const struct frr_yang_module_info frr_routing_info; +extern const struct frr_yang_module_info frr_routing_cli_info; /* Mandatory callbacks. */ int routing_control_plane_protocols_control_plane_protocol_create( @@ -29,6 +32,8 @@ int routing_control_plane_protocols_control_plane_protocol_destroy( * based on the control plane protocol */ DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)); +DECLARE_HOOK(routing_create, (struct nb_cb_create_args *args), (args)); +DECLARE_KOOH(routing_destroy, (struct nb_cb_destroy_args *args), (args)); void routing_control_plane_protocols_register_vrf_dependency(void); diff --git a/lib/routing_nb_config.c b/lib/routing_nb_config.c index f4fe48f5b371..d532279a22aa 100644 --- a/lib/routing_nb_config.c +++ b/lib/routing_nb_config.c @@ -14,6 +14,8 @@ DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)); +DEFINE_HOOK(routing_create, (struct nb_cb_create_args *args), (args)); +DEFINE_KOOH(routing_destroy, (struct nb_cb_destroy_args *args), (args)); /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol @@ -44,11 +46,12 @@ int routing_control_plane_protocols_control_plane_protocol_create( * find the vrf and store the pointer. */ if (nb_node_has_dependency(args->dnode->schema->priv)) { - vrfname = yang_dnode_get_string(args->dnode, "./vrf"); + vrfname = yang_dnode_get_string(args->dnode, "vrf"); vrf = vrf_lookup_by_name(vrfname); assert(vrf); nb_running_set_entry(args->dnode, vrf); } + hook_call(routing_create, args); break; }; @@ -61,6 +64,8 @@ int routing_control_plane_protocols_control_plane_protocol_destroy( if (args->event != NB_EV_APPLY) return NB_OK; + hook_call(routing_destroy, args); + /* * If dependency on VRF module is registered, then VRF * pointer was stored and must be cleared. @@ -76,7 +81,7 @@ static void vrf_to_control_plane_protocol(const struct lyd_node *dnode, { const char *vrf; - vrf = yang_dnode_get_string(dnode, "./name"); + vrf = yang_dnode_get_string(dnode, "name"); snprintf(xpath, XPATH_MAXLEN, FRR_ROUTING_KEY_XPATH_VRF, vrf); } @@ -86,7 +91,7 @@ static void control_plane_protocol_to_vrf(const struct lyd_node *dnode, { const char *vrf; - vrf = yang_dnode_get_string(dnode, "./vrf"); + vrf = yang_dnode_get_string(dnode, "vrf"); snprintf(xpath, XPATH_MAXLEN, FRR_VRF_KEY_XPATH, vrf); } diff --git a/lib/seqlock.c b/lib/seqlock.c index 62ce316920dd..e74e6718bfef 100644 --- a/lib/seqlock.c +++ b/lib/seqlock.c @@ -26,6 +26,39 @@ * OS specific synchronization wrappers * ****************************************/ +#ifndef __has_feature /* not available on old GCC */ +#define __has_feature(x) 0 +#endif + +#if (defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)) +/* TSAN really does not understand what is going on with the low-level + * futex/umtx calls. This leads to a whole bunch of warnings, a lot of which + * also have _extremely_ misleading text - since TSAN does not understand that + * there is in fact a synchronization primitive involved, it can end up pulling + * in completely unrelated things. + * + * What does work is the "unsupported platform" seqlock implementation based + * on a pthread mutex + condvar, since TSAN of course suppports these. + * + * It may be possible to also fix this with TSAN annotations (__tsan_acquire + * and __tsan_release), but using those (correctly) is not easy either, and + * for now just get things rolling. + */ + +#ifdef HAVE_SYNC_LINUX_FUTEX +#undef HAVE_SYNC_LINUX_FUTEX +#endif + +#ifdef HAVE_SYNC_OPENBSD_FUTEX +#undef HAVE_SYNC_OPENBSD_FUTEX +#endif + +#ifdef HAVE_SYNC_UMTX_OP +#undef HAVE_SYNC_UMTX_OP +#endif + +#endif /* TSAN */ + /* * Linux: sys_futex() */ diff --git a/lib/sigevent.c b/lib/sigevent.c index 3cd65eb80085..3e69f280da2e 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -4,6 +4,8 @@ */ #include + +#include #include #include #include @@ -238,7 +240,17 @@ core_handler(int signo, siginfo_t *siginfo, void *context) /* dump memory stats on core */ log_memstats(stderr, "core_handler"); - zlog_tls_buffer_fini(); + /* + * This is a buffer flush because FRR is going down + * hard. This is especially important if the crash + * was caused by a memory operation and if we call + * zlog_tls_buffer_fini() then it has memory + * operations as well. This will cause the + * core dump to not happen. BAD MOJO + * So this is intentional, let's try to flush + * what we can and let the crash happen. + */ + zlog_tls_buffer_flush(); /* give the kernel a chance to generate a coredump */ sigaddset(&sigset, signo); diff --git a/lib/smux.h b/lib/smux.h index cec4d2a1bf1e..0ed41410f57b 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -99,7 +99,9 @@ struct index_oid { */ extern bool smux_enabled(void); +extern void libagentx_init(void); extern void smux_init(struct event_loop *tm); +extern void smux_terminate(void); extern void smux_agentx_enable(void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid[], size_t); diff --git a/lib/sockopt.c b/lib/sockopt.c index 0c4adb0b7c22..74bc034ccd75 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -10,13 +10,12 @@ #include "sockunion.h" #include "lib_errors.h" -#if (defined(__FreeBSD__) \ - && ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) \ - || (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) \ - || (defined(__NetBSD__) && defined(__NetBSD_Version__) \ - && __NetBSD_Version__ >= 106010000) \ - || defined(__OpenBSD__) || defined(__APPLE__) \ - || defined(__DragonFly__) || defined(__sun) +#if (defined(__FreeBSD__) && \ + ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) || \ + (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) || \ + (defined(__NetBSD__) && defined(__NetBSD_Version__) && \ + __NetBSD_Version__ >= 106010000) || \ + defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) #define HAVE_BSD_STRUCT_IP_MREQ_HACK #endif @@ -24,9 +23,12 @@ void setsockopt_so_recvbuf(int sock, int size) { int orig_req = size; - while (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) - == -1) + while (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == + -1) { + if (size == 0) + break; size /= 2; + } if (size != orig_req) flog_err(EC_LIB_SOCKET, @@ -38,9 +40,12 @@ void setsockopt_so_sendbuf(const int sock, int size) { int orig_req = size; - while (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) - == -1) + while (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == + -1) { + if (size == 0) + break; size /= 2; + } if (size != orig_req) flog_err(EC_LIB_SOCKET, @@ -667,6 +672,9 @@ int sockopt_tcp_mss_get(int sock) int tcp_maxseg = 0; socklen_t tcp_maxseg_len = sizeof(tcp_maxseg); + if (sock < 0) + return 0; + ret = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len); if (ret != 0) { diff --git a/lib/sockopt.h b/lib/sockopt.h index ce7d665fab5f..e6fb78d5e4ef 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -60,6 +60,16 @@ extern int setsockopt_ipv6_tclass(int, int); (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) +/* + * If not defined then define the value for `TCP_MD5SIG_MAXKEYLEN`. This seems + * to be unavailable for NetBSD 8, FreeBSD 11 and FreeBSD 12. + * + * The value below was copied from `linux/tcp.h` from the Linux kernel headers. + */ +#ifndef TCP_MD5SIG_MAXKEYLEN +#define TCP_MD5SIG_MAXKEYLEN 80 +#endif + extern int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, diff --git a/lib/sockunion.h b/lib/sockunion.h index e5072559999d..146651225cdf 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -7,10 +7,13 @@ #ifndef _ZEBRA_SOCKUNION_H #define _ZEBRA_SOCKUNION_H +#include "compiler.h" + #include "privs.h" #include "if.h" #include #ifdef __OpenBSD__ +#include #include #endif @@ -27,8 +30,40 @@ union sockunion { struct sockaddr_mpls smpls; struct sockaddr_rtlabel rtlabel; #endif + + /* sockaddr_storage is guaranteed to be larger than the others */ + struct sockaddr_storage sa_storage; }; +/* clang-format off */ +/* for functions that want to accept any sockaddr pointer without casts */ +union sockaddrptr { + uniontype(sockaddrptr, union sockunion, su) + uniontype(sockaddrptr, struct sockaddr, sa) + uniontype(sockaddrptr, struct sockaddr_in, sin) + uniontype(sockaddrptr, struct sockaddr_in6, sin6) + uniontype(sockaddrptr, struct sockaddr_un, sun) +#ifdef __OpenBSD__ + uniontype(sockaddrptr, struct sockaddr_mpls, smpls) + uniontype(sockaddrptr, struct sockaddr_rtlabel, rtlabel) +#endif + uniontype(sockaddrptr, struct sockaddr_storage, sa_storage) +} TRANSPARENT_UNION; + +union sockaddrconstptr { + uniontype(sockaddrconstptr, const union sockunion, su) + uniontype(sockaddrconstptr, const struct sockaddr, sa) + uniontype(sockaddrconstptr, const struct sockaddr_in, sin) + uniontype(sockaddrconstptr, const struct sockaddr_in6, sin6) + uniontype(sockaddrconstptr, const struct sockaddr_un, sun) +#ifdef __OpenBSD__ + uniontype(sockaddrconstptr, const struct sockaddr_mpls, smpls) + uniontype(sockaddrconstptr, const struct sockaddr_rtlabel, rtlabel) +#endif + uniontype(sockaddrconstptr, const struct sockaddr_storage, sa_storage) +} TRANSPARENT_UNION; +/* clang-format on */ + enum connect_result { connect_error, connect_success, connect_in_progress }; /* Default address family. */ diff --git a/lib/srv6.c b/lib/srv6.c index 09835f3ea8b4..e6fc375fbb11 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -10,8 +10,11 @@ #include "log.h" DEFINE_QOBJ_TYPE(srv6_locator); +DEFINE_QOBJ_TYPE(srv6_sid_format); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_FORMAT, "SRv6 SID format"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_CTX, "SRv6 SID context"); const char *seg6local_action2str(uint32_t action) { @@ -68,6 +71,44 @@ int snprintf_seg6_segs(char *str, return strlen(str); } +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json) +{ + switch (action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + json_object_boolean_add(json, "USP", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + json_object_string_addf(json, "nh4", "%pI4", &ctx->nh4); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + json_object_int_add(json, "table", ctx->table); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + json_object_boolean_add(json, "none", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + default: + json_object_boolean_add(json, "unknown", true); + return; + } +} + const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action) @@ -94,9 +135,11 @@ const char *seg6local_context2str(char *str, size_t size, snprintf(str, size, "table %u", ctx->table); return str; - case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: case ZEBRA_SEG6_LOCAL_ACTION_END_B6: case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + snprintfrr(str, size, "nh6 %pI6", &ctx->nh6); + return str; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: case ZEBRA_SEG6_LOCAL_ACTION_END_BM: case ZEBRA_SEG6_LOCAL_ACTION_END_S: case ZEBRA_SEG6_LOCAL_ACTION_END_AS: @@ -108,7 +151,7 @@ const char *seg6local_context2str(char *str, size_t size, } } -static void srv6_locator_chunk_list_free(void *data) +void srv6_locator_chunk_list_free(void *data) { struct srv6_locator_chunk *chunk = data; @@ -137,6 +180,21 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) return chunk; } +void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator) +{ + strlcpy(copy->name, locator->name, sizeof(locator->name)); + copy->prefix = locator->prefix; + copy->block_bits_length = locator->block_bits_length; + copy->node_bits_length = locator->node_bits_length; + copy->function_bits_length = locator->function_bits_length; + copy->argument_bits_length = locator->argument_bits_length; + copy->algonum = locator->algonum; + copy->current = locator->current; + copy->status_up = locator->status_up; + copy->flags = locator->flags; +} + void srv6_locator_free(struct srv6_locator *locator) { if (locator) { @@ -152,6 +210,59 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); } +struct srv6_sid_format *srv6_sid_format_alloc(const char *name) +{ + struct srv6_sid_format *format = NULL; + + format = XCALLOC(MTYPE_SRV6_SID_FORMAT, sizeof(struct srv6_sid_format)); + strlcpy(format->name, name, sizeof(format->name)); + + QOBJ_REG(format, srv6_sid_format); + return format; +} + +void srv6_sid_format_free(struct srv6_sid_format *format) +{ + if (!format) + return; + + QOBJ_UNREG(format); + XFREE(MTYPE_SRV6_SID_FORMAT, format); +} + +/** + * Free an SRv6 SID format. + * + * @param val SRv6 SID format to be freed + */ +void delete_srv6_sid_format(void *val) +{ + srv6_sid_format_free((struct srv6_sid_format *)val); +} + +struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, vrf_id_t vrf_id) +{ + struct srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_SRV6_SID_CTX, sizeof(struct srv6_sid_ctx)); + ctx->behavior = behavior; + if (nh4) + ctx->nh4 = *nh4; + if (nh6) + ctx->nh6 = *nh6; + if (vrf_id) + ctx->vrf_id = vrf_id; + + return ctx; +} + +void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_SRV6_SID_CTX, ctx); +} + json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { json_object *jo_root = NULL; @@ -221,23 +332,47 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set status_up */ json_object_boolean_add(jo_root, "statusUp", @@ -270,23 +405,47 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set algonum */ json_object_int_add(jo_root, "algoNum", loc->algonum); diff --git a/lib/srv6.h b/lib/srv6.h index fb34f861c8c2..f25c5cfcaa5c 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -20,6 +20,8 @@ #define SRH_BASE_HEADER_LENGTH 8 #define SRH_SEGMENT_LENGTH 16 +#define SRV6_SID_FORMAT_NAME_SIZE 512 + #ifdef __cplusplus extern "C" { #endif @@ -127,6 +129,12 @@ struct srv6_locator { uint8_t flags; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ + /* Pointer to the SID format. */ + struct srv6_sid_format *sid_format; + + /* Pointer to the parent SID block of the locator. */ + void *sid_block; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(srv6_locator); @@ -183,6 +191,72 @@ struct nexthop_srv6 { struct seg6_seg_stack *seg6_segs; }; +/* SID format type */ +enum srv6_sid_format_type { + SRV6_SID_FORMAT_TYPE_UNSPEC = 0, + /* SRv6 SID uncompressed format */ + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED = 1, + /* SRv6 SID compressed uSID format */ + SRV6_SID_FORMAT_TYPE_USID = 2, +}; + +/* SRv6 SID format */ +struct srv6_sid_format { + /* Name of the format */ + char name[SRV6_SID_FORMAT_NAME_SIZE]; + + /* Format type: uncompressed vs compressed */ + enum srv6_sid_format_type type; + + /* + * Lengths of block/node/function/argument parts of the SIDs allocated + * using this format + */ + uint8_t block_len; + uint8_t node_len; + uint8_t function_len; + uint8_t argument_len; + + union { + /* Configuration settings for compressed uSID format type */ + struct { + /* Start of the Local ID Block (LIB) range */ + uint32_t lib_start; + + /* Start/End of the Explicit LIB range */ + uint32_t elib_start; + uint32_t elib_end; + + /* Start/End of the Wide LIB range */ + uint32_t wlib_start; + uint32_t wlib_end; + + /* Start/End of the Explicit Wide LIB range */ + uint32_t ewlib_start; + } usid; + + /* Configuration settings for uncompressed format type */ + struct { + /* Start of the Explicit range */ + uint32_t explicit_start; + } uncompressed; + } config; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(srv6_sid_format); + +/* Context for an SRv6 SID */ +struct srv6_sid_ctx { + /* Behavior associated with the SID */ + enum seg6local_action_t behavior; + + /* Behavior-specific attributes */ + struct in_addr nh4; + struct in6_addr nh6; + vrf_id_t vrf_id; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -245,6 +319,55 @@ seg6local_action2str(uint32_t action); const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action); +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json); + +static inline const char *srv6_sid_ctx2str(char *str, size_t size, + const struct srv6_sid_ctx *ctx) +{ + int len = 0; + + len += snprintf(str + len, size - len, "%s", + seg6local_action2str(ctx->behavior)); + + switch (ctx->behavior) { + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END: + snprintf(str + len, size - len, " USP"); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + snprintfrr(str + len, size - len, " nh4 %pI4", &ctx->nh4); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + snprintf(str + len, size - len, " vrf_id %u", ctx->vrf_id); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_END_BPF: + default: + snprintf(str + len, size - len, " unknown(%s)", __func__); + } + + return str; +} int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); @@ -252,13 +375,26 @@ int snprintf_seg6_segs(char *str, extern struct srv6_locator *srv6_locator_alloc(const char *name); extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); extern void srv6_locator_free(struct srv6_locator *locator); +extern void srv6_locator_chunk_list_free(void *data); extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk); +extern void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator); json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); json_object *srv6_locator_json(const struct srv6_locator *loc); json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); json_object * srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk); +extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name); +extern void srv6_sid_format_free(struct srv6_sid_format *format); +extern void delete_srv6_sid_format(void *format); + +extern struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, + vrf_id_t vrf_id); +extern void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx); + #ifdef __cplusplus } #endif diff --git a/lib/stream.c b/lib/stream.c index c6de3aefa17a..bb90f3b944e9 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -921,7 +921,7 @@ int stream_put_in_addr(struct stream *s, const struct in_addr *addr) return sizeof(uint32_t); } -bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip) +bool stream_put_ipaddr(struct stream *s, const struct ipaddr *ip) { stream_putw(s, ip->ipa_type); @@ -1241,9 +1241,7 @@ void stream_fifo_init(struct stream_fifo *fifo) /* Add new stream to fifo. */ void stream_fifo_push(struct stream_fifo *fifo, struct stream *s) { -#if defined DEV_BUILD size_t max, curmax; -#endif if (fifo->tail) fifo->tail->next = s; @@ -1252,15 +1250,11 @@ void stream_fifo_push(struct stream_fifo *fifo, struct stream *s) fifo->tail = s; fifo->tail->next = NULL; -#if !defined DEV_BUILD - atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release); -#else max = atomic_fetch_add_explicit(&fifo->count, 1, memory_order_release); curmax = atomic_load_explicit(&fifo->max_count, memory_order_relaxed); if (max > curmax) atomic_store_explicit(&fifo->max_count, max, memory_order_relaxed); -#endif } void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s) diff --git a/lib/stream.h b/lib/stream.h index 85eebb47bef2..e48cedc61345 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -105,9 +105,7 @@ struct stream_fifo { /* number of streams in this fifo */ atomic_size_t count; -#if defined DEV_BUILD atomic_size_t max_count; -#endif struct stream *head; struct stream *tail; @@ -177,7 +175,7 @@ extern int stream_putq(struct stream *, uint64_t); extern int stream_putq_at(struct stream *, size_t, uint64_t); extern int stream_put_ipv4(struct stream *, uint32_t); extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr); -extern bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip); +extern bool stream_put_ipaddr(struct stream *s, const struct ipaddr *ip); extern int stream_put_in_addr_at(struct stream *s, size_t putp, const struct in_addr *addr); extern int stream_put_in6_addr_at(struct stream *s, size_t putp, diff --git a/lib/subdir.am b/lib/subdir.am index d7b28ffbd59e..4bcce9a2b05a 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -53,9 +53,12 @@ lib_libfrr_la_SOURCES = \ lib/jhash.c \ lib/json.c \ lib/keychain.c \ + lib/keychain_cli.c \ + lib/keychain_nb.c \ lib/ldp_sync.c \ lib/lib_errors.c \ lib/lib_vty.c \ + lib/libagentx.c \ lib/libfrr.c \ lib/libfrr_trace.c \ lib/linklist.c \ @@ -68,6 +71,7 @@ lib_libfrr_la_SOURCES = \ lib/mgmt_be_client.c \ lib/mgmt_fe_client.c \ lib/mgmt_msg.c \ + lib/mgmt_msg_native.c \ lib/mlag.c \ lib/module.c \ lib/mpls.c \ @@ -80,6 +84,7 @@ lib_libfrr_la_SOURCES = \ lib/northbound.c \ lib/northbound_cli.c \ lib/northbound_db.c \ + lib/northbound_oper.c \ lib/ntop.c \ lib/openbsd-tree.c \ lib/pid_output.c \ @@ -127,6 +132,7 @@ lib_libfrr_la_SOURCES = \ lib/zlog_5424.c \ lib/zlog_5424_cli.c \ lib/zlog_live.c \ + lib/zlog_recirculate.c \ lib/zlog_targets.c \ lib/printf/printf-pos.c \ lib/printf/vfprintf.c \ @@ -146,7 +152,10 @@ nodist_lib_libfrr_la_SOURCES = \ yang/frr-vrf.yang.c \ yang/frr-routing.yang.c \ yang/frr-nexthop.yang.c \ + yang/ietf/frr-deviations-ietf-key-chain.yang.c \ yang/ietf/ietf-routing-types.yang.c \ + yang/ietf/ietf-netconf-acm.yang.c \ + yang/ietf/ietf-key-chain.yang.c \ yang/ietf/ietf-interfaces.yang.c \ yang/ietf/ietf-bgp-types.yang.c \ yang/frr-module-translator.yang.c \ @@ -179,6 +188,7 @@ clippy_scan += \ lib/if.c \ lib/filter_cli.c \ lib/if_rmap.c \ + lib/keychain_cli.c \ lib/log_vty.c \ lib/mgmt_be_client.c \ lib/mgmt_fe_client.c \ @@ -219,11 +229,13 @@ pkginclude_HEADERS += \ lib/filter.h \ lib/flex_algo.h \ lib/freebsd-queue.h \ + lib/frrdistance.h \ lib/frrlua.h \ lib/frrscript.h \ lib/frr_pthread.h \ lib/frratomic.h \ lib/frrcu.h \ + lib/frrsendmmsg.h \ lib/frrstr.h \ lib/graph.h \ lib/hash.h \ @@ -241,6 +253,7 @@ pkginclude_HEADERS += \ lib/ldp_sync.h \ lib/lib_errors.h \ lib/lib_vty.h \ + lib/libagentx.h \ lib/libfrr.h \ lib/libfrr_trace.h \ lib/libospf.h \ @@ -252,8 +265,10 @@ pkginclude_HEADERS += \ lib/memory.h \ lib/mgmt.pb-c.h \ lib/mgmt_be_client.h \ + lib/mgmt_defines.h \ lib/mgmt_fe_client.h \ lib/mgmt_msg.h \ + lib/mgmt_msg_native.h \ lib/mgmt_pb.h \ lib/module.h \ lib/monotime.h \ @@ -318,6 +333,7 @@ pkginclude_HEADERS += \ lib/zlog.h \ lib/zlog_5424.h \ lib/zlog_live.h \ + lib/zlog_recirculate.h \ lib/zlog_targets.h \ lib/pbr.h \ lib/tc.h \ @@ -396,18 +412,6 @@ lib_libfrrzmq_la_SOURCES = \ lib/frr_zmq.c \ #end -# -# Tail-f's ConfD support -# -if CONFD -module_LTLIBRARIES += lib/confd.la -endif - -lib_confd_la_CFLAGS = $(AM_CFLAGS) $(CONFD_CFLAGS) -lib_confd_la_LDFLAGS = $(MODULE_LDFLAGS) -lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS) -lib_confd_la_SOURCES = lib/northbound_confd.c - # # Sysrepo support # @@ -500,20 +504,41 @@ SUFFIXES += .xref %.xref: % $(CLIPPY) $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(WERROR) $(XRELFO_FLAGS) -o $@ $< +# these run up to a total of 350k lines at the time of writing. That's a lot +# for the compiler to chug down - enough to warrant splitting it up so it can +# benefit from parallel build. +vtysh_cmd_split = \ + vtysh/vtysh_cmd.1.c \ + vtysh/vtysh_cmd.2.c \ + vtysh/vtysh_cmd.3.c \ + vtysh/vtysh_cmd.4.c \ + vtysh/vtysh_cmd.5.c \ + vtysh/vtysh_cmd.6.c \ + vtysh/vtysh_cmd.7.c \ + vtysh/vtysh_cmd.8.c \ + # end + # dependencies added in python/makefile.py frr.xref: - $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ -c vtysh/vtysh_cmd.c $^ + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ \ + -c vtysh/vtysh_cmd.c $(vtysh_cmd_split) all-am: frr.xref clean-xref: -rm -rf $(xrefs) frr.xref clean-local: clean-xref -CLEANFILES += vtysh/vtysh_cmd.c vtysh/vtysh_cmd.c: frr.xref @test -f $@ || rm -f frr.xref || true @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) frr.xref +vtysh/vtysh_cmd.%.c: vtysh/vtysh_cmd.c + @test -f $@ || rm -f vtysh/vtysh_cmd.c || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) vtysh/vtysh_cmd.c + +nodist_vtysh_vtysh_SOURCES = vtysh/vtysh_cmd.c $(vtysh_cmd_split) +CLEANFILES += vtysh/vtysh_cmd.c $(vtysh_cmd_split) + ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< @@ -534,12 +559,22 @@ EXTRA_DIST += \ BUILT_SOURCES += \ lib/gitversion.h \ lib/route_types.h \ + lib/vtysh_daemons.h \ # end ## force route_types.h $(lib_clippy_OBJECTS): lib/route_types.h $(lib_libfrr_la_OBJECTS): lib/route_types.h +# force lib_daemons.h +$(lib_libfrr_la_OBJECTS): lib/vtysh_daemons.h + +CLEANFILES += lib/vtysh_daemons.h +lib/vtysh_daemons.h: + @$(MKDIR_P) lib + $(PERL) $(top_srcdir)/vtysh/daemons.pl $(vtysh_daemons) > lib/vtysh_daemons.h + + AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@ lib/command_lex.h: lib/command_lex.c diff --git a/lib/systemd.c b/lib/systemd.c index 56a53a6e781b..a82c376cfda5 100644 --- a/lib/systemd.c +++ b/lib/systemd.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "frrevent.h" diff --git a/lib/termtable.c b/lib/termtable.c index 9b36d5ebfa8b..88cc25bf68c5 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -496,7 +496,9 @@ char *ttable_dump(struct ttable *tt, const char *newline) * l int64 * s string (default) */ -json_object *ttable_json(struct ttable *tt, const char *const formats) +static json_object *ttable_json_internal(struct ttable *tt, + const char *const formats, + const char *row_text[]) { struct ttable_cell *row; /* iteration pointers */ json_object *json = NULL; @@ -522,9 +524,55 @@ json_object *ttable_json(struct ttable *tt, const char *const formats) default: val = json_object_new_string(row[j].text); } - json_object_object_add(jobj, tt->table[0][j].text, val); + if (row_text) + json_object_object_add(jobj, row_text[j], val); + else + json_object_object_add(jobj, + tt->table[0][j].text, + val); } } return json; } + +json_object *ttable_json(struct ttable *tt, const char *const formats) +{ + return ttable_json_internal(tt, formats, NULL); +} + +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text) +{ + char **row_name; /* iteration pointers */ + char *res, *section, *orig; + int col = 0; + int ncols = 0, j; + json_object *json = NULL; + + if (json_override_text) { + /* count how many columns we have */ + for (j = 0; json_override_text[j]; j++) + ncols += !!(json_override_text[j] == '|'); + ncols++; + } + if (json_override_text == NULL || ncols != tt->ncols) + return ttable_json_internal(tt, formats, NULL); + + /* CALLOC a block of cells */ + row_name = XCALLOC(MTYPE_TTABLE, ncols * sizeof(char *)); + orig = XSTRDUP(MTYPE_TTABLE, json_override_text); + res = orig; + while (res && col < ncols) { + section = strsep(&res, "|"); + row_name[col] = XSTRDUP(MTYPE_TTABLE, section); + col++; + } + json = ttable_json_internal(tt, formats, (const char **)row_name); + for (j = 0; j < col; j++) + XFREE(MTYPE_TTABLE, row_name[j]); + XFREE(MTYPE_TTABLE, row_name); + XFREE(MTYPE_TTABLE, orig); + return json; +} diff --git a/lib/termtable.h b/lib/termtable.h index 7258682bd80a..0782c82abdfd 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -289,6 +289,21 @@ char *ttable_dump(struct ttable *tt, const char *newline); */ json_object *ttable_json(struct ttable *tt, const char *const formats); +/** + * Convert a table to a JSON array of objects. + * + * Caller must free the returned json_object structure. + * + * @param tt the table to convert + * @param formats an array of characters indicating what JSON type should be + * used. + * @param formats an optinal string of row headers that overrids the first row of the table. + * This is useful to get naming convention that align with caml Format. + */ +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text); + #ifdef __cplusplus } #endif diff --git a/lib/typerb.h b/lib/typerb.h index b020a665f624..93370e1012c8 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -9,8 +9,10 @@ #ifndef _FRR_TYPERB_H #define _FRR_TYPERB_H +#ifndef _TYPESAFE_EXPAND_MACROS #include #include "typesafe.h" +#endif /* _TYPESAFE_EXPAND_MACROS */ #ifdef __cplusplus extern "C" { diff --git a/lib/typesafe.h b/lib/typesafe.h index 93258c595410..fc028049a458 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -6,10 +6,12 @@ #ifndef _FRR_TYPESAFE_H #define _FRR_TYPESAFE_H +#ifndef _TYPESAFE_EXPAND_MACROS #include #include #include #include "compiler.h" +#endif /* _TYPESAFE_EXPAND_MACROS */ #ifdef __cplusplus extern "C" { diff --git a/lib/vector.c b/lib/vector.c index bbea67c12f22..06361549607f 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -4,6 +4,7 @@ */ #include +#include #include "vector.h" #include "memory.h" @@ -23,45 +24,44 @@ vector vector_init(unsigned int size) v->alloced = size; v->active = 0; v->count = 0; + v->dynamic = true; v->index = XCALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * size); return v; } void vector_free(vector v) { - XFREE(MTYPE_VECTOR_INDEX, v->index); - XFREE(MTYPE_VECTOR, v); + if (v->alloced) + XFREE(MTYPE_VECTOR_INDEX, v->index); + if (v->dynamic) + XFREE(MTYPE_VECTOR, v); } -vector vector_copy(vector v) -{ - unsigned int size; - vector new = XCALLOC(MTYPE_VECTOR, sizeof(struct _vector)); - - new->active = v->active; - new->alloced = v->alloced; - new->count = v->count; - - size = sizeof(void *) * (v->alloced); - new->index = XCALLOC(MTYPE_VECTOR_INDEX, size); - memcpy(new->index, v->index, size); - - return new; -} - -/* Check assigned index, and if it runs short double index pointer */ +/* resize vector to a minimum of num + * may resize larger to avoid excessive realloc overhead + */ void vector_ensure(vector v, unsigned int num) { + unsigned int newsz; + if (v->alloced > num) return; - v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, - sizeof(void *) * (v->alloced * 2)); - memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); - v->alloced *= 2; + newsz = MAX(v->active * 2, num + 1); + + if (!v->alloced && v->index) { + /* currently using global variable, not malloc'd memory */ + void **orig_index = v->index; - if (v->alloced <= num) - vector_ensure(v, num); + v->index = XMALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * newsz); + memcpy(v->index, orig_index, v->active * sizeof(void *)); + v->alloced = v->active; + } else + v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, + sizeof(void *) * newsz); + + memset(&v->index[v->alloced], 0, sizeof(void *) * (newsz - v->alloced)); + v->alloced = newsz; } /* This function only returns next empty slot index. It dose not mean @@ -139,7 +139,7 @@ void *vector_lookup_ensure(vector v, unsigned int i) /* Unset value at specified index slot. */ void vector_unset(vector v, unsigned int i) { - if (i >= v->alloced) + if (i >= v->active) return; if (v->index[i]) diff --git a/lib/vector.h b/lib/vector.h index fcbc13257a17..ae05d4d3e049 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -15,9 +15,26 @@ extern "C" { /* struct for vector */ struct _vector { - unsigned int active; /* number of active slots */ - unsigned int alloced; /* number of allocated slot */ + /* active: index of last non-NULL item (+1) + * count: number of non-NULL items (+1) + * + * the two will be different if a slot is set to NULL (without pulling + * up later items in the array). Whether this happens depends on + * which vector functions are used. If no empty slots are used, the + * two fields will be identical. + * + * alloced: size of array pointed to by index. If this is 0, index + * points at a global variable rather than a malloc'd bit of memory. + * The vector code will convert to malloc'd memory if necessary to + * perform updates. + */ + unsigned int active; + unsigned int alloced; unsigned int count; + + /* whether struct _vector itself is dynamically allocated */ + bool dynamic; + void **index; /* index to data */ }; typedef struct _vector *vector; @@ -51,7 +68,6 @@ static inline unsigned int vector_count(vector v) } extern void vector_free(vector v); -extern vector vector_copy(vector v); extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); diff --git a/lib/vrf.c b/lib/vrf.c index b279e8b7bf48..31632a80d5e5 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -5,6 +5,7 @@ */ #include +#include #include "if.h" #include "vrf.h" @@ -325,6 +326,33 @@ void vrf_disable(struct vrf *vrf) (*vrf_master.vrf_disable_hook)(vrf); } +void vrf_iterate(vrf_iter_func fnc) +{ + struct vrf *vrf, *tmp; + + if (debug_vrf) + zlog_debug("%s: vrf subsystem iteration", __func__); + + RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) { + if (vrf->vrf_id == VRF_DEFAULT) + continue; + + fnc(vrf); + } + + RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) { + if (vrf->vrf_id == VRF_DEFAULT) + continue; + + fnc(vrf); + } + + /* Finally process default VRF */ + vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (vrf) + fnc(vrf); +} + const char *vrf_id_to_name(vrf_id_t vrf_id) { struct vrf *vrf; @@ -541,32 +569,12 @@ static void vrf_terminate_single(struct vrf *vrf) vrf_delete(vrf); } -/* Terminate VRF module. */ void vrf_terminate(void) { - struct vrf *vrf, *tmp; - if (debug_vrf) zlog_debug("%s: Shutting down vrf subsystem", __func__); - RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) { - if (vrf->vrf_id == VRF_DEFAULT) - continue; - - vrf_terminate_single(vrf); - } - - RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) { - if (vrf->vrf_id == VRF_DEFAULT) - continue; - - vrf_terminate_single(vrf); - } - - /* Finally terminate default VRF */ - vrf = vrf_lookup_by_id(VRF_DEFAULT); - if (vrf) - vrf_terminate_single(vrf); + vrf_iterate(vrf_terminate_single); } int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id, @@ -628,7 +636,7 @@ int vrf_configure_backend(enum vrf_backend_type backend) } /* vrf CLI commands */ -DEFUN_NOSH(vrf_exit, +DEFUN_YANG_NOSH (vrf_exit, vrf_exit_cmd, "exit-vrf", "Exit current mode and down to previous mode\n") @@ -680,18 +688,6 @@ DEFUN_YANG (no_vrf, const char *vrfname = argv[2]->arg; char xpath_list[XPATH_MAXLEN]; - struct vrf *vrfp; - - vrfp = vrf_lookup_by_name(vrfname); - - if (vrfp == NULL) - return CMD_SUCCESS; - - if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) { - vty_out(vty, "%% Only inactive VRFs can be deleted\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { /* * Remove the VRF interface config when removing the VRF. @@ -914,7 +910,7 @@ static int lib_vrf_create(struct nb_cb_create_args *args) const char *vrfname; struct vrf *vrfp; - vrfname = yang_dnode_get_string(args->dnode, "./name"); + vrfname = yang_dnode_get_string(args->dnode, "name"); if (args->event != NB_EV_APPLY) return NB_OK; @@ -955,6 +951,25 @@ static int lib_vrf_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +static void lib_vrf_cli_write(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + const char *name = yang_dnode_get_string(dnode, "name"); + + if (strcmp(name, VRF_DEFAULT_NAME)) { + vty_out(vty, "!\n"); + vty_out(vty, "vrf %s\n", name); + } +} + +static void lib_vrf_cli_write_end(struct vty *vty, const struct lyd_node *dnode) +{ + const char *name = yang_dnode_get_string(dnode, "name"); + + if (strcmp(name, VRF_DEFAULT_NAME)) + vty_out(vty, "exit-vrf\n"); +} + static const void *lib_vrf_get_next(struct nb_cb_get_next_args *args) { struct vrf *vrfp = (struct vrf *)args->list_entry; @@ -987,6 +1002,19 @@ static const void *lib_vrf_lookup_entry(struct nb_cb_lookup_entry_args *args) return vrf; } +static const void *lib_vrf_lookup_next(struct nb_cb_lookup_entry_args *args) +{ + const char *vrfname = args->keys->key[0]; + struct vrf vrfkey, *vrf; + + strlcpy(vrfkey.name, vrfname, sizeof(vrfkey.name)); + vrf = RB_FIND(vrf_name_head, &vrfs_by_name, &vrfkey); + if (!strcmp(vrf->name, vrfname)) + vrf = RB_NEXT(vrf_name_head, vrf); + + return vrf; +} + /* * XPath: /frr-vrf:lib/vrf/id */ @@ -1013,6 +1041,8 @@ lib_vrf_state_active_get_elem(struct nb_cb_get_elem_args *args) } /* clang-format off */ + +/* cli_show callbacks are kept here for daemons not yet converted to mgmtd */ const struct frr_yang_module_info frr_vrf_info = { .name = "frr-vrf", .nodes = { @@ -1021,9 +1051,12 @@ const struct frr_yang_module_info frr_vrf_info = { .cbs = { .create = lib_vrf_create, .destroy = lib_vrf_destroy, + .cli_show = lib_vrf_cli_write, + .cli_show_end = lib_vrf_cli_write_end, .get_next = lib_vrf_get_next, .get_keys = lib_vrf_get_keys, .lookup_entry = lib_vrf_lookup_entry, + .lookup_next = lib_vrf_lookup_next, }, .priority = NB_DFLT_PRIORITY - 2, }, @@ -1045,3 +1078,19 @@ const struct frr_yang_module_info frr_vrf_info = { } }; +const struct frr_yang_module_info frr_vrf_cli_info = { + .name = "frr-vrf", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-vrf:lib/vrf", + .cbs = { + .cli_show = lib_vrf_cli_write, + .cli_show_end = lib_vrf_cli_write_end, + }, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/vrf.h b/lib/vrf.h index f66a9e6b325e..3ebb6ddf5371 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -201,6 +201,12 @@ extern void vrf_init(int (*create)(struct vrf *vrf), int (*disable)(struct vrf *vrf), int (*destroy)(struct vrf *vrf)); +/* + * Iterate over custom VRFs and round up by processing the default VRF. + */ +typedef void (*vrf_iter_func)(struct vrf *vrf); +extern void vrf_iterate(vrf_iter_func fnc); + /* * Call vrf_terminate when the protocol is being shutdown */ @@ -294,6 +300,7 @@ extern int vrf_enable(struct vrf *vrf); extern void vrf_delete(struct vrf *vrf); extern const struct frr_yang_module_info frr_vrf_info; +extern const struct frr_yang_module_info frr_vrf_cli_info; #ifdef __cplusplus } diff --git a/lib/vty.c b/lib/vty.c index 15cc340eb0c5..0a4a3d2b86a3 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -6,6 +6,8 @@ #include +#include +#include #include #include #include @@ -37,6 +39,7 @@ #include "libfrr.h" #include "frrstr.h" #include "lib_errors.h" +#include #include "northbound_cli.h" #include "printfrr.h" #include "json.h" @@ -44,6 +47,8 @@ #include #include +#include "lib/config_paths.h" + #include "lib/vty_clippy.c" DEFINE_MTYPE_STATIC(LIB, VTY, "VTY"); @@ -122,6 +127,13 @@ bool vty_log_commands; static bool vty_log_commands_perm; char const *const mgmt_daemons[] = { + "zebra", +#ifdef HAVE_RIPD + "ripd", +#endif +#ifdef HAVE_RIPNGD + "ripngd", +#endif #ifdef HAVE_STATICD "staticd", #endif @@ -157,10 +169,9 @@ static int vty_mgmt_unlock_running_inline(struct vty *vty) return vty->mgmt_locked_running_ds ? -1 : 0; } -void vty_mgmt_resume_response(struct vty *vty, bool success) +void vty_mgmt_resume_response(struct vty *vty, int ret) { uint8_t header[4] = {0, 0, 0, 0}; - int ret = CMD_SUCCESS; if (!vty->mgmt_req_pending_cmd) { zlog_err( @@ -168,14 +179,10 @@ void vty_mgmt_resume_response(struct vty *vty, bool success) return; } - if (!success) - ret = CMD_WARNING_CONFIG_FAILED; - - MGMTD_FE_CLIENT_DBG( - "resuming CLI cmd after %s on vty session-id: %" PRIu64 - " with '%s'", - vty->mgmt_req_pending_cmd, vty->mgmt_session_id, - success ? "succeeded" : "failed"); + debug_fe_client("resuming CLI cmd after %s on vty session-id: %" PRIu64 + " with '%s'", + vty->mgmt_req_pending_cmd, vty->mgmt_session_id, + ret == CMD_SUCCESS ? "success" : "failed"); vty->mgmt_req_pending_cmd = NULL; @@ -383,11 +390,29 @@ int vty_json_no_pretty(struct vty *vty, struct json_object *json) return vty_json_helper(vty, json, JSON_C_TO_STRING_NOSLASHESCAPE); } -void vty_json_empty(struct vty *vty) + +void vty_json_key(struct vty *vty, const char *key, bool *first_key) { - json_object *json = json_object_new_object(); + vty_out(vty, "%s\"%s\":", *first_key ? "{" : ",", key); + *first_key = false; +} - vty_json(vty, json); +void vty_json_close(struct vty *vty, bool first_key) +{ + if (first_key) + /* JSON was not opened */ + vty_out(vty, "{"); + vty_out(vty, "}\n"); +} + +void vty_json_empty(struct vty *vty, struct json_object *json) +{ + json_object *jsonobj = json; + + if (!json) + jsonobj = json_object_new_object(); + + vty_json(vty, jsonobj); } /* Output current time to the vty. */ @@ -1565,7 +1590,7 @@ static void vty_read(struct event *thread) break; case '\r': vty->escape = VTY_CR; - /* fallthru */ + fallthrough; case '\n': vty_out(vty, "\n"); buffer_flush_available(vty->obuf, vty->wfd); @@ -2256,19 +2281,6 @@ bool mgmt_vty_read_configs(void) snprintf(path, sizeof(path), "%s/mgmtd.conf", frr_sysconfdir); confp = vty_open_config(path, config_default); - if (!confp) { - char *orig; - - snprintf(path, sizeof(path), "%s/zebra.conf", frr_sysconfdir); - orig = XSTRDUP(MTYPE_TMP, host_config_get()); - - zlog_info("mgmtd: trying backup config file: %s", path); - confp = vty_open_config(path, config_default); - - host_config_set(path); - XFREE(MTYPE_TMP, orig); - } - if (confp) { zlog_info("mgmtd: reading config file: %s", path); @@ -2406,10 +2418,9 @@ static void vtysh_read(struct event *thread) * we get response through callback. */ if (vty->mgmt_req_pending_cmd) { - MGMTD_FE_CLIENT_DBG( - "postpone CLI response pending mgmtd %s on vty session-id %" PRIu64, - vty->mgmt_req_pending_cmd, - vty->mgmt_session_id); + debug_fe_client("postpone CLI response pending mgmtd %s on vty session-id %" PRIu64, + vty->mgmt_req_pending_cmd, + vty->mgmt_session_id); return; } @@ -2490,14 +2501,14 @@ void vty_close(struct vty *vty) * so warn the user. */ if (vty->mgmt_num_pending_setcfg) - MGMTD_FE_CLIENT_ERR( + log_err_fe_client( "vty closed, uncommitted config will be lost."); /* Drop out of configure / transaction if needed. */ vty_config_exit(vty); if (mgmt_fe_client && vty->mgmt_session_id) { - MGMTD_FE_CLIENT_DBG("closing vty session"); + debug_fe_client("closing vty session"); mgmt_fe_destroy_client_session(mgmt_fe_client, vty->mgmt_client_id); vty->mgmt_session_id = 0; @@ -2890,6 +2901,12 @@ int vty_config_enter(struct vty *vty, bool private_config, bool exclusive, } assert(vty->mgmt_locked_candidate_ds); assert(vty->mgmt_locked_running_ds); + + /* + * As datastores are locked explicitly, we don't need implicit + * commits and should allow pending changes. + */ + vty->pending_allowed = true; } vty->node = CONFIG_NODE; @@ -2946,6 +2963,8 @@ int vty_config_node_exit(struct vty *vty) /* TODO: could we check for un-commited changes here? */ + vty->pending_allowed = false; + if (vty->mgmt_locked_running_ds) vty_mgmt_unlock_running_inline(vty); @@ -3469,9 +3488,8 @@ void vty_init_vtysh(void) static void vty_mgmt_server_connected(struct mgmt_fe_client *client, uintptr_t usr_data, bool connected) { - MGMTD_FE_CLIENT_DBG("Got %sconnected %s MGMTD Frontend Server", - !connected ? "dis: " : "", - !connected ? "from" : "to"); + debug_fe_client("Got %sconnected %s MGMTD Frontend Server", + !connected ? "dis: " : "", !connected ? "from" : "to"); /* * We should not have any sessions for connecting or disconnecting case. @@ -3484,7 +3502,7 @@ static void vty_mgmt_server_connected(struct mgmt_fe_client *client, /* Start or stop listening for vty connections */ if (connected) - frr_vty_serv_start(); + frr_vty_serv_start(true); else frr_vty_serv_stop(); } @@ -3507,8 +3525,8 @@ static void vty_mgmt_session_notify(struct mgmt_fe_client *client, return; } - MGMTD_FE_CLIENT_DBG("%s session for client %" PRIu64 " successfully", - create ? "Created" : "Destroyed", client_id); + debug_fe_client("%s session for client %" PRIu64 " successfully", + create ? "Created" : "Destroyed", client_id); if (create) { assert(session_id != 0); @@ -3539,8 +3557,8 @@ static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client, zlog_err("%socking for DS %u failed, Err: '%s' vty %p", lock_ds ? "L" : "Unl", ds_id, errmsg_if_any, vty); else { - MGMTD_FE_CLIENT_DBG("%socked DS %u successfully", - lock_ds ? "L" : "Unl", ds_id); + debug_fe_client("%socked DS %u successfully", + lock_ds ? "L" : "Unl", ds_id); if (ds_id == MGMTD_DS_CANDIDATE) vty->mgmt_locked_candidate_ds = lock_ds; else @@ -3549,7 +3567,8 @@ static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client, if (!is_short_circuit && vty->mgmt_req_pending_cmd) { assert(!strcmp(vty->mgmt_req_pending_cmd, "MESSAGE_LOCKDS_REQ")); - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, + success ? CMD_SUCCESS : CMD_WARNING); } } @@ -3567,12 +3586,14 @@ static void vty_mgmt_set_config_result_notified( zlog_err("SET_CONFIG request for client 0x%" PRIx64 " failed, Error: '%s'", client_id, errmsg_if_any ? errmsg_if_any : "Unknown"); - vty_out(vty, "ERROR: SET_CONFIG request failed, Error: %s\n", - errmsg_if_any ? errmsg_if_any : "Unknown"); + vty_out(vty, "%% Configuration failed.\n\n"); + if (errmsg_if_any) + vty_out(vty, "%s\n", errmsg_if_any); } else { - MGMTD_FE_CLIENT_DBG("SET_CONFIG request for client 0x%" PRIx64 - " req-id %" PRIu64 " was successfull", - client_id, req_id); + debug_fe_client("SET_CONFIG request for client 0x%" PRIx64 + " req-id %" PRIu64 " was successfull%s%s", + client_id, req_id, errmsg_if_any ? ": " : "", + errmsg_if_any ?: ""); } if (implicit_commit) { @@ -3581,7 +3602,8 @@ static void vty_mgmt_set_config_result_notified( vty_mgmt_unlock_running_inline(vty); } - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, success ? CMD_SUCCESS + : CMD_WARNING_CONFIG_FAILED); } static void vty_mgmt_commit_config_result_notified( @@ -3598,18 +3620,20 @@ static void vty_mgmt_commit_config_result_notified( zlog_err("COMMIT_CONFIG request for client 0x%" PRIx64 " failed, Error: '%s'", client_id, errmsg_if_any ? errmsg_if_any : "Unknown"); - vty_out(vty, "ERROR: COMMIT_CONFIG request failed, Error: %s\n", - errmsg_if_any ? errmsg_if_any : "Unknown"); + vty_out(vty, "%% Configuration failed.\n\n"); + if (errmsg_if_any) + vty_out(vty, "%s\n", errmsg_if_any); } else { - MGMTD_FE_CLIENT_DBG( - "COMMIT_CONFIG request for client 0x%" PRIx64 - " req-id %" PRIu64 " was successfull", - client_id, req_id); + debug_fe_client("COMMIT_CONFIG request for client 0x%" PRIx64 + " req-id %" PRIu64 " was successfull%s%s", + client_id, req_id, errmsg_if_any ? ": " : "", + errmsg_if_any ?: ""); if (errmsg_if_any) vty_out(vty, "MGMTD: %s\n", errmsg_if_any); } - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, success ? CMD_SUCCESS + : CMD_WARNING_CONFIG_FAILED); } static int vty_mgmt_get_data_result_notified( @@ -3629,13 +3653,14 @@ static int vty_mgmt_get_data_result_notified( client_id, errmsg_if_any ? errmsg_if_any : "Unknown"); vty_out(vty, "ERROR: GET_DATA request failed, Error: %s\n", errmsg_if_any ? errmsg_if_any : "Unknown"); - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, CMD_WARNING); return -1; } - MGMTD_FE_CLIENT_DBG("GET_DATA request succeeded, client 0x%" PRIx64 - " req-id %" PRIu64, - client_id, req_id); + debug_fe_client("GET_DATA request succeeded, client 0x%" PRIx64 + " req-id %" PRIu64 "%s%s", + client_id, req_id, errmsg_if_any ? ": " : "", + errmsg_if_any ?: ""); if (req_id != mgmt_last_req_id) { mgmt_last_req_id = req_id; @@ -3648,9 +3673,256 @@ static int vty_mgmt_get_data_result_notified( } if (next_key < 0) { vty_out(vty, "]\n"); - vty_mgmt_resume_response(vty, success); + vty_mgmt_resume_response(vty, CMD_SUCCESS); + } + + return 0; +} + +static ssize_t vty_mgmt_libyang_print(void *user_data, const void *buf, + size_t count) +{ + struct vty *vty = user_data; + + vty_out(vty, "%.*s", (int)count, (const char *)buf); + return count; +} + +static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format, + const struct ly_err_item *ei) +{ +#if (LY_VERSION_MAJOR < 3) +#define data_path path +#else +#define data_path data_path +#endif + bool have_apptag = ei->apptag && ei->apptag[0] != 0; + bool have_path = ei->data_path && ei->data_path[0] != 0; + bool have_msg = ei->msg && ei->msg[0] != 0; + const char *severity = NULL; + const char *evalid = NULL; + const char *ecode = NULL; +#if (LY_VERSION_MAJOR < 3) + LY_ERR err = ei->no; +#else + LY_ERR err = ei->err; +#endif + + if (ei->level == LY_LLERR) + severity = "error"; + else if (ei->level == LY_LLWRN) + severity = "warning"; + + ecode = yang_ly_strerrcode(err); + if (err == LY_EVALID && ei->vecode != LYVE_SUCCESS) + evalid = yang_ly_strvecode(ei->vecode); + + switch (format) { + case LYD_XML: + vty_out(vty, + ""); + vty_out(vty, "application"); + if (severity) + vty_out(vty, "%s", + severity); + if (ecode) + vty_out(vty, "%s", ecode); + if (evalid) + vty_out(vty, "%s\n", + evalid); + if (have_path) + vty_out(vty, "%s\n", + ei->data_path); + if (have_apptag) + vty_out(vty, "%s\n", + ei->apptag); + if (have_msg) + vty_out(vty, "%s\n", + ei->msg); + + vty_out(vty, ""); + break; + case LYD_JSON: + vty_out(vty, "{ \"error-type\": \"application\""); + if (severity) + vty_out(vty, ", \"error-severity\": \"%s\"", severity); + if (ecode) + vty_out(vty, ", \"error-code\": \"%s\"", ecode); + if (evalid) + vty_out(vty, ", \"error-validation\": \"%s\"", evalid); + if (have_path) + vty_out(vty, ", \"error-path\": \"%s\"", ei->data_path); + if (have_apptag) + vty_out(vty, ", \"error-app-tag\": \"%s\"", ei->apptag); + if (have_msg) + vty_out(vty, ", \"error-message\": \"%s\"", ei->msg); + + vty_out(vty, "}"); + break; + case LYD_UNKNOWN: + case LYD_LYB: + default: + vty_out(vty, "%% error"); + if (severity) + vty_out(vty, " severity: %s", severity); + if (evalid) + vty_out(vty, " invalid: %s", evalid); + if (have_path) + vty_out(vty, " path: %s", ei->data_path); + if (have_apptag) + vty_out(vty, " app-tag: %s", ei->apptag); + if (have_msg) + vty_out(vty, " msg: %s", ei->msg); + break; + } +#undef data_path +} + +static uint vty_out_yang_errors(struct vty *vty, LYD_FORMAT format) +{ + const struct ly_err_item *ei = ly_err_first(ly_native_ctx); + uint count; + + if (!ei) + return 0; + + if (format == LYD_JSON) + vty_out(vty, "\"ietf-restconf:errors\": [ "); + + for (count = 0; ei; count++, ei = ei->next) { + if (count) + vty_out(vty, ", "); + vty_out_yang_error(vty, format, ei); + } + + if (format == LYD_JSON) + vty_out(vty, " ]"); + + ly_err_clean(ly_native_ctx, NULL); + + return count; +} + + +static int vty_mgmt_get_tree_result_notified( + struct mgmt_fe_client *client, uintptr_t user_data, uint64_t client_id, + uint64_t session_id, uintptr_t session_ctx, uint64_t req_id, + Mgmtd__DatastoreId ds_id, LYD_FORMAT result_type, void *result, + size_t len, int partial_error) +{ + struct vty *vty; + struct lyd_node *dnode; + int ret = CMD_SUCCESS; + LY_ERR err; + + vty = (struct vty *)session_ctx; + + debug_fe_client("GET_TREE request %ssucceeded, client 0x%" PRIx64 + " req-id %" PRIu64, + partial_error ? "partially " : "", client_id, req_id); + + assert(result_type == LYD_LYB || + result_type == vty->mgmt_req_pending_data); + + if (vty->mgmt_req_pending_data == LYD_XML && partial_error) + vty_out(vty, + "\n"); + + if (result_type == LYD_LYB) { + /* + * parse binary into tree and print in the specified format + */ + result_type = vty->mgmt_req_pending_data; + + err = lyd_parse_data_mem(ly_native_ctx, result, LYD_LYB, 0, 0, + &dnode); + if (!err) + err = lyd_print_clb(vty_mgmt_libyang_print, vty, dnode, + result_type, LYD_PRINT_WITHSIBLINGS); + lyd_free_all(dnode); + + if (vty_out_yang_errors(vty, result_type) || err) + ret = CMD_WARNING; + } else { + /* + * Print the in-format result + */ + assert(result_type == LYD_XML || result_type == LYD_JSON); + vty_out(vty, "%.*s\n", (int)len - 1, (const char *)result); } + vty_mgmt_resume_response(vty, ret); + + return 0; +} + +static int vty_mgmt_edit_result_notified(struct mgmt_fe_client *client, + uintptr_t user_data, + uint64_t client_id, uint64_t session_id, + uintptr_t session_ctx, uint64_t req_id, + const char *xpath) +{ + struct vty *vty = (struct vty *)session_ctx; + + debug_fe_client("EDIT request for client 0x%" PRIx64 " req-id %" PRIu64 + " was successful, xpath: %s", + client_id, req_id, xpath); + + vty_mgmt_resume_response(vty, CMD_SUCCESS); + + return 0; +} + +static int vty_mgmt_rpc_result_notified(struct mgmt_fe_client *client, + uintptr_t user_data, uint64_t client_id, + uint64_t session_id, + uintptr_t session_ctx, uint64_t req_id, + const char *result) +{ + struct vty *vty = (struct vty *)session_ctx; + + debug_fe_client("RPC request for client 0x%" PRIx64 " req-id %" PRIu64 + " was successful", + client_id, req_id); + + if (result) + vty_out(vty, "%s\n", result); + + vty_mgmt_resume_response(vty, CMD_SUCCESS); + + return 0; +} + +static int vty_mgmt_error_notified(struct mgmt_fe_client *client, + uintptr_t user_data, uint64_t client_id, + uint64_t session_id, uintptr_t session_ctx, + uint64_t req_id, int error, + const char *errstr) +{ + struct vty *vty = (struct vty *)session_ctx; + const char *cname = mgmt_fe_client_name(client); + + if (!vty->mgmt_req_pending_cmd) { + debug_fe_client("Error with no pending command: %d returned for client %s 0x%" PRIx64 + " session-id %" PRIu64 " req-id %" PRIu64 + "error-str %s", + error, cname, client_id, session_id, req_id, + errstr); + vty_out(vty, + "%% Error %d from MGMTD for %s with no pending command: %s\n", + error, cname, errstr); + return CMD_WARNING; + } + + debug_fe_client("Error %d returned for client %s 0x%" PRIx64 + " session-id %" PRIu64 " req-id %" PRIu64 "error-str %s", + error, cname, client_id, session_id, req_id, errstr); + + vty_out(vty, "%% %s (for %s, client %s)\n", errstr, + vty->mgmt_req_pending_cmd, cname); + + vty_mgmt_resume_response(vty, error ? CMD_WARNING : CMD_SUCCESS); + return 0; } @@ -3661,6 +3933,11 @@ static struct mgmt_fe_client_cbs mgmt_cbs = { .set_config_notify = vty_mgmt_set_config_result_notified, .commit_config_notify = vty_mgmt_commit_config_result_notified, .get_data_notify = vty_mgmt_get_data_result_notified, + .get_tree_notify = vty_mgmt_get_tree_result_notified, + .edit_notify = vty_mgmt_edit_result_notified, + .rpc_notify = vty_mgmt_rpc_result_notified, + .error_notify = vty_mgmt_error_notified, + }; void vty_init_mgmt_fe(void) @@ -3707,12 +3984,15 @@ int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id, return 0; } -int vty_mgmt_send_config_data(struct vty *vty, bool implicit_commit) +int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base, + bool implicit_commit) { Mgmtd__YangDataValue value[VTY_MAXCFGCHANGES]; Mgmtd__YangData cfg_data[VTY_MAXCFGCHANGES]; Mgmtd__YangCfgDataReq cfg_req[VTY_MAXCFGCHANGES]; Mgmtd__YangCfgDataReq *cfgreq[VTY_MAXCFGCHANGES] = {0}; + char xpath[VTY_MAXCFGCHANGES][XPATH_MAXLEN]; + char *change_xpath; size_t indx; if (vty->type == VTY_FILE) { @@ -3748,6 +4028,9 @@ int vty_mgmt_send_config_data(struct vty *vty, bool implicit_commit) } } + if (xpath_base == NULL) + xpath_base = ""; + for (indx = 0; indx < vty->num_cfg_changes; indx++) { mgmt_yang_data_init(&cfg_data[indx]); @@ -3760,29 +4043,47 @@ int vty_mgmt_send_config_data(struct vty *vty, bool implicit_commit) cfg_data[indx].value = &value[indx]; } - cfg_data[indx].xpath = vty->cfg_changes[indx].xpath; + change_xpath = vty->cfg_changes[indx].xpath; + + memset(xpath[indx], 0, sizeof(xpath[indx])); + /* If change xpath is relative, prepend base xpath. */ + if (change_xpath[0] == '.') { + strlcpy(xpath[indx], xpath_base, sizeof(xpath[indx])); + change_xpath++; /* skip '.' */ + } + strlcat(xpath[indx], change_xpath, sizeof(xpath[indx])); + + cfg_data[indx].xpath = xpath[indx]; mgmt_yang_cfg_data_req_init(&cfg_req[indx]); cfg_req[indx].data = &cfg_data[indx]; switch (vty->cfg_changes[indx].operation) { - case NB_OP_DESTROY: + case NB_OP_DELETE: cfg_req[indx].req_type = MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA; break; + case NB_OP_DESTROY: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA; + break; + + case NB_OP_CREATE_EXCL: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA; + break; + + case NB_OP_REPLACE: + cfg_req[indx].req_type = + MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA; + break; + case NB_OP_CREATE: case NB_OP_MODIFY: case NB_OP_MOVE: - case NB_OP_PRE_VALIDATE: - case NB_OP_APPLY_FINISH: cfg_req[indx].req_type = MGMTD__CFG_DATA_REQ_TYPE__SET_DATA; break; - case NB_OP_GET_ELEM: - case NB_OP_GET_NEXT: - case NB_OP_GET_KEYS: - case NB_OP_LOOKUP_ENTRY: - case NB_OP_RPC: default: assertf(false, "Invalid operation type for send config: %d", @@ -3866,6 +4167,71 @@ int vty_mgmt_send_get_req(struct vty *vty, bool is_config, return 0; } +int vty_mgmt_send_get_data_req(struct vty *vty, uint8_t datastore, + LYD_FORMAT result_type, uint8_t flags, + uint8_t defaults, const char *xpath) +{ + LYD_FORMAT intern_format = result_type; + + vty->mgmt_req_id++; + + if (mgmt_fe_send_get_data_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, datastore, + intern_format, flags, defaults, xpath)) { + zlog_err("Failed to send GET-DATA to MGMTD session-id: %" PRIu64 + " req-id %" PRIu64 ".", + vty->mgmt_session_id, vty->mgmt_req_id); + vty_out(vty, "Failed to send GET-DATA to MGMTD!\n"); + return -1; + } + + vty->mgmt_req_pending_cmd = "MESSAGE_GET_DATA_REQ"; + vty->mgmt_req_pending_data = result_type; + + return 0; +} + +int vty_mgmt_send_edit_req(struct vty *vty, uint8_t datastore, + LYD_FORMAT request_type, uint8_t flags, + uint8_t operation, const char *xpath, + const char *data) +{ + vty->mgmt_req_id++; + + if (mgmt_fe_send_edit_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, datastore, request_type, + flags, operation, xpath, data)) { + zlog_err("Failed to send EDIT to MGMTD session-id: %" PRIu64 + " req-id %" PRIu64 ".", + vty->mgmt_session_id, vty->mgmt_req_id); + vty_out(vty, "Failed to send EDIT to MGMTD!\n"); + return -1; + } + + vty->mgmt_req_pending_cmd = "MESSAGE_EDIT_REQ"; + + return 0; +} + +int vty_mgmt_send_rpc_req(struct vty *vty, LYD_FORMAT request_type, + const char *xpath, const char *data) +{ + vty->mgmt_req_id++; + + if (mgmt_fe_send_rpc_req(mgmt_fe_client, vty->mgmt_session_id, + vty->mgmt_req_id, request_type, xpath, data)) { + zlog_err("Failed to send RPC to MGMTD session-id: %" PRIu64 + " req-id %" PRIu64 ".", + vty->mgmt_session_id, vty->mgmt_req_id); + vty_out(vty, "Failed to send RPC to MGMTD!\n"); + return -1; + } + + vty->mgmt_req_pending_cmd = "MESSAGE_RPC_REQ"; + + return 0; +} + /* Install vty's own commands like `who' command. */ void vty_init(struct event_loop *master_thread, bool do_command_logging) { diff --git a/lib/vty.h b/lib/vty.h index a8654f8b6999..c336a816cc1f 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -122,6 +122,10 @@ struct vty { size_t num_cfg_changes; struct nb_cfg_change cfg_changes[VTY_MAXCFGCHANGES]; + /* Input parameters */ + size_t num_rpc_params; + struct nb_cfg_change rpc_params[VTY_MAXCFGCHANGES]; + /* XPath of the current node */ int xpath_index; char xpath[VTY_MAXDEPTH][XPATH_MAXLEN]; @@ -229,12 +233,9 @@ struct vty { * CLI command and we are waiting on the reply so we can respond to the * vty user. */ const char *mgmt_req_pending_cmd; + uintptr_t mgmt_req_pending_data; bool mgmt_locked_candidate_ds; bool mgmt_locked_running_ds; - /* Need to track when we file-lock in vtysh to re-lock on end/conf t - * workaround - */ - bool vtysh_file_locked; }; static inline void vty_push_context(struct vty *vty, int node, uint64_t id) @@ -377,7 +378,9 @@ extern bool vty_set_include(struct vty *vty, const char *regexp); */ extern int vty_json(struct vty *vty, struct json_object *json); extern int vty_json_no_pretty(struct vty *vty, struct json_object *json); -extern void vty_json_empty(struct vty *vty); +void vty_json_key(struct vty *vty, const char *key, bool *first_key); +void vty_json_close(struct vty *vty, bool first_key); +extern void vty_json_empty(struct vty *vty, struct json_object *json); /* post fd to be passed to the vtysh client * fd is owned by the VTY code after this and will be closed when done */ @@ -412,15 +415,25 @@ extern bool vty_mgmt_fe_enabled(void); extern bool vty_mgmt_should_process_cli_apply_changes(struct vty *vty); extern bool mgmt_vty_read_configs(void); -extern int vty_mgmt_send_config_data(struct vty *vty, bool implicit_commit); +extern int vty_mgmt_send_config_data(struct vty *vty, const char *xpath_base, + bool implicit_commit); extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only, bool abort); extern int vty_mgmt_send_get_req(struct vty *vty, bool is_config, Mgmtd__DatastoreId datastore, const char **xpath_list, int num_req); +extern int vty_mgmt_send_get_data_req(struct vty *vty, uint8_t datastore, + LYD_FORMAT result_type, uint8_t flags, + uint8_t defaults, const char *xpath); +extern int vty_mgmt_send_edit_req(struct vty *vty, uint8_t datastore, + LYD_FORMAT request_type, uint8_t flags, + uint8_t operation, const char *xpath, + const char *data); +extern int vty_mgmt_send_rpc_req(struct vty *vty, LYD_FORMAT request_type, + const char *xpath, const char *data); extern int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id, bool lock, bool scok); -extern void vty_mgmt_resume_response(struct vty *vty, bool success); +extern void vty_mgmt_resume_response(struct vty *vty, int ret); static inline bool vty_needs_implicit_commit(struct vty *vty) { diff --git a/lib/workqueue.c b/lib/workqueue.c index fa5d585360cc..d630af1d1db0 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -42,6 +42,15 @@ static void work_queue_item_free(struct work_queue_item *item) return; } +static inline void work_queue_item_dequeue(struct work_queue *wq, + struct work_queue_item *item) +{ + assert(wq->item_count > 0); + + wq->item_count--; + STAILQ_REMOVE(&wq->items, item, work_queue_item, wq); +} + static void work_queue_item_remove(struct work_queue *wq, struct work_queue_item *item) { @@ -133,6 +142,13 @@ static int work_queue_schedule(struct work_queue *wq, unsigned int delay) return 0; } +static inline void work_queue_item_enqueue(struct work_queue *wq, + struct work_queue_item *item) +{ + STAILQ_INSERT_TAIL(&wq->items, item, wq); + wq->item_count++; +} + void work_queue_add(struct work_queue *wq, void *data) { struct work_queue_item *item; @@ -265,17 +281,14 @@ void work_queue_run(struct event *thread) do { ret = wq->spec.workfunc(wq, item->data); item->ran++; - } while ((ret == WQ_RETRY_NOW) - && (item->ran < wq->spec.max_retries)); + } while (item->ran < wq->spec.max_retries); switch (ret) { case WQ_QUEUE_BLOCKED: { /* decrement item->ran again, cause this isn't an item - * specific error, and fall through to WQ_RETRY_LATER + * specific error, and retry later */ item->ran--; - } - case WQ_RETRY_LATER: { goto stats; } case WQ_REQUEUE: { @@ -295,10 +308,6 @@ void work_queue_run(struct event *thread) titem = item; break; } - case WQ_RETRY_NOW: - /* a RETRY_NOW that gets here has exceeded max_tries, same as - * ERROR */ - /* fallthru */ case WQ_SUCCESS: default: { work_queue_item_remove(wq, item); @@ -350,8 +359,7 @@ void work_queue_run(struct event *thread) /* Is the queue done yet? If it is, call the completion callback. */ if (!work_queue_empty(wq)) { - if (ret == WQ_RETRY_LATER || - ret == WQ_QUEUE_BLOCKED) + if (ret == WQ_QUEUE_BLOCKED) work_queue_schedule(wq, wq->spec.retry); else work_queue_schedule(wq, 0); diff --git a/lib/workqueue.h b/lib/workqueue.h index 5d84739d5c6b..a495fe86156c 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -26,9 +26,7 @@ DECLARE_MTYPE(WORK_QUEUE); /* action value, for use by item processor and item error handlers */ typedef enum { WQ_SUCCESS = 0, - WQ_RETRY_NOW, /* retry immediately */ - WQ_RETRY_LATER, /* retry later, cease processing work queue */ - WQ_REQUEUE, /* requeue item, continue processing work queue */ + WQ_REQUEUE, /* requeue item, continue processing work queue */ WQ_QUEUE_BLOCKED, /* Queue cant be processed at this time. * Similar to WQ_RETRY_LATER, but doesn't penalise * the particular item.. */ @@ -117,22 +115,6 @@ work_queue_last_item(struct work_queue *wq) return STAILQ_LAST(&wq->items, work_queue_item, wq); } -static inline void work_queue_item_enqueue(struct work_queue *wq, - struct work_queue_item *item) -{ - STAILQ_INSERT_TAIL(&wq->items, item, wq); - wq->item_count++; -} - -static inline void work_queue_item_dequeue(struct work_queue *wq, - struct work_queue_item *item) -{ - assert(wq->item_count > 0); - - wq->item_count--; - STAILQ_REMOVE(&wq->items, item, work_queue_item, wq); -} - /* create a new work queue, of given name. * user must fill in the spec of the returned work queue before adding * anything to it @@ -160,6 +142,7 @@ bool work_queue_is_scheduled(struct work_queue *wq); /* Helpers, exported for thread.c and command.c */ extern void work_queue_run(struct event *thread); +/* Function to initialize the workqueue cli */ extern void workqueue_cmd_init(void); #ifdef __cplusplus diff --git a/lib/yang.c b/lib/yang.c index 4dd865421718..6c1aed00cc7b 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -6,15 +6,36 @@ #include +#include "darr.h" #include "log.h" #include "lib_errors.h" #include "yang.h" #include "yang_translator.h" +#include #include "northbound.h" +#include "frrstr.h" + +#include "lib/config_paths.h" DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module"); DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure"); +/* Safe to remove after libyang 2.2.8 */ +#if (LY_VERSION_MAJOR < 3) +#define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ + set) \ + lyd_find_xpath3(ctx_node, tree, xpath, vars, set) + +#ifndef LYD_NEW_VAL_OUTPUT +#define LYD_NEW_VAL_OUTPUT LYD_NEW_PATH_OUTPUT +#endif + +#else +#define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ + set) \ + lyd_find_xpath3(ctx_node, tree, xpath, LY_VALUE_JSON, NULL, vars, set) +#endif + /* libyang container. */ struct ly_ctx *ly_native_ctx; @@ -37,7 +58,8 @@ static LY_ERR yang_module_imp_clb(const char *mod_name, const char *mod_rev, struct yang_module_embed *e; if (!strcmp(mod_name, "ietf-inet-types") || - !strcmp(mod_name, "ietf-yang-types")) + !strcmp(mod_name, "ietf-yang-types") || + !strcmp(mod_name, "ietf-yang-metadata")) /* libyang has these built in, don't try finding them here */ return LY_ENOTFOUND; @@ -97,13 +119,14 @@ RB_GENERATE(yang_modules, yang_module, entry, yang_module_compare) struct yang_modules yang_modules = RB_INITIALIZER(&yang_modules); -struct yang_module *yang_module_load(const char *module_name) +struct yang_module *yang_module_load(const char *module_name, + const char **features) { struct yang_module *module; const struct lys_module *module_info; - module_info = - ly_ctx_load_module(ly_native_ctx, module_name, NULL, NULL); + module_info = ly_ctx_load_module(ly_native_ctx, module_name, NULL, + features); if (!module_info) { flog_err(EC_LIB_YANG_MODULE_LOAD, "%s: failed to load data model: %s", __func__, @@ -127,8 +150,10 @@ struct yang_module *yang_module_load(const char *module_name) void yang_module_load_all(void) { + static const char * const all_features[] = { "*", NULL }; + for (size_t i = 0; i < array_size(frr_native_modules); i++) - yang_module_load(frr_native_modules[i]); + yang_module_load(frr_native_modules[i], (const char **)all_features); } struct yang_module *yang_module_find(const char *module_name) @@ -192,6 +217,16 @@ int yang_snodes_iterate_subtree(const struct lysc_node *snode, if (ret == YANG_ITER_STOP) return ret; } + LY_LIST_FOR ((const struct lysc_node *)lysc_node_notifs(snode), child) { + ret = yang_snodes_iterate_subtree(child, module, cb, flags, arg); + if (ret == YANG_ITER_STOP) + return ret; + } + LY_LIST_FOR ((const struct lysc_node *)lysc_node_actions(snode), child) { + ret = yang_snodes_iterate_subtree(child, module, cb, flags, arg); + if (ret == YANG_ITER_STOP) + return ret; + } return ret; } @@ -250,19 +285,44 @@ void yang_snode_get_path(const struct lysc_node *snode, } } -struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath, - uint32_t options) +LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath, + struct lysc_node ***snodes, bool *simple) { struct lysc_node *snode; struct ly_set *set; LY_ERR err; - err = lys_find_xpath(ly_native_ctx, NULL, xpath, options, &set); - if (err || !set->count) - return NULL; + /* lys_find_path will not resolve complex xpaths */ + snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0); + if (snode) { + *darr_append(*snodes) = snode; + *simple = true; + return LY_SUCCESS; + } - snode = set->snodes[0]; + /* Try again to catch complex query cases */ + err = lys_find_xpath(ly_native_ctx, NULL, xpath, 0, &set); + if (err) + return err; + if (!set->count) { + ly_set_free(set, NULL); + return LY_ENOTFOUND; + } + + *simple = false; + darr_ensure_i(*snodes, set->count - 1); + memcpy(*snodes, set->snodes, set->count * sizeof(set->snodes[0])); ly_set_free(set, NULL); + return LY_SUCCESS; +} + + +struct lysc_node *yang_find_snode(struct ly_ctx *ly_ctx, const char *xpath, + uint32_t options) +{ + struct lysc_node *snode; + + snode = (struct lysc_node *)lys_find_path(ly_ctx, NULL, xpath, 0); return snode; } @@ -370,33 +430,10 @@ unsigned int yang_snode_num_keys(const struct lysc_node *snode) return count; } -void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath, - size_t xpath_len) -{ - lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len); -} - -const char *yang_dnode_get_schema_name(const struct lyd_node *dnode, - const char *xpath_fmt, ...) +char *yang_dnode_get_path(const struct lyd_node *dnode, char *xpath, + size_t xpath_len) { - if (xpath_fmt) { - va_list ap; - char xpath[XPATH_MAXLEN]; - - va_start(ap, xpath_fmt); - vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); - va_end(ap); - - dnode = yang_dnode_get(dnode, xpath); - if (!dnode) { - flog_err(EC_LIB_YANG_DNODE_NOT_FOUND, - "%s: couldn't find %s", __func__, xpath); - zlog_backtrace(LOG_ERR); - abort(); - } - } - - return dnode->schema->name; + return lyd_path(dnode, LYD_PATH_STD, xpath, xpath_len); } struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath) @@ -505,6 +542,30 @@ void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg, ly_set_free(set, NULL); } +uint32_t yang_dnode_count(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + va_list ap; + char xpath[XPATH_MAXLEN]; + struct ly_set *set; + uint32_t count; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + if (lyd_find_xpath(dnode, xpath, &set)) { + assert(0); + return 0; + } + + count = set->count; + + ly_set_free(set, NULL); + + return count; +} + bool yang_dnode_is_default(const struct lyd_node *dnode, const char *xpath) { const struct lysc_node *snode; @@ -596,7 +657,8 @@ struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode) { struct lyd_node *dup = NULL; LY_ERR err; - err = lyd_dup_siblings(dnode, NULL, LYD_DUP_RECURSIVE, &dup); + err = lyd_dup_siblings(dnode, NULL, + LYD_DUP_RECURSIVE | LYD_DUP_WITH_FLAGS, &dup); assert(!err); return dup; } @@ -608,6 +670,16 @@ void yang_dnode_free(struct lyd_node *dnode) lyd_free_all(dnode); } +void yang_dnode_rpc_output_add(struct lyd_node *output, const char *xpath, + const char *value) +{ + LY_ERR err; + + err = lyd_new_path(output, ly_native_ctx, xpath, value, + LYD_NEW_VAL_OUTPUT | LYD_NEW_PATH_UPDATE, NULL); + assert(err == LY_SUCCESS); +} + struct yang_data *yang_data_new(const char *xpath, const char *value) { struct yang_data *data; @@ -657,7 +729,12 @@ struct yang_data *yang_data_list_find(const struct list *list, } /* Make libyang log its errors using FRR logging infrastructure. */ -static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) +static void ly_zlog_cb(LY_LOG_LEVEL level, const char *msg, const char *data_path +#if !(LY_VERSION_MAJOR < 3) + , + const char *schema_path, uint64_t line +#endif +) { int priority = LOG_ERR; @@ -674,34 +751,214 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) break; } - if (path) - zlog(priority, "libyang: %s (%s)", msg, path); + if (data_path) + zlog(priority, "libyang: %s (%s)", msg, data_path); +#if !(LY_VERSION_MAJOR < 3) + else if (schema_path) + zlog(priority, "libyang %s (%s)\n", msg, schema_path); + else if (line) + zlog(priority, "libyang %s (line %" PRIu64 ")\n", msg, line); +#endif else zlog(priority, "libyang: %s", msg); } +LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format, + const char *data, struct lyd_node **notif) +{ + struct lyd_node *tree; + struct ly_set *set = NULL; + struct ly_in *in = NULL; + LY_ERR err; + + err = ly_in_new_memory(data, &in); + if (err) { + zlog_err("Failed to initialize ly_in: %s", ly_last_errmsg()); + return err; + } + + err = lyd_parse_op(ly_native_ctx, NULL, in, format, LYD_TYPE_NOTIF_YANG, + &tree, NULL); + ly_in_free(in, 0); + if (err) { + zlog_err("Failed to parse notification: %s", ly_last_errmsg()); + return err; + } + + err = yang_lyd_find_xpath3(NULL, tree, xpath, LY_VALUE_JSON, NULL, NULL, + &set); + if (err) { + zlog_err("Failed to parse notification: %s", ly_last_errmsg()); + lyd_free_all(tree); + return err; + } + if (set->count == 0) { + zlog_err("Notification not found in the parsed tree: %s", xpath); + ly_set_free(set, NULL); + lyd_free_all(tree); + return LY_ENOTFOUND; + } + *notif = set->dnodes[0]; + ly_set_free(set, NULL); + return LY_SUCCESS; +} + +LY_ERR yang_parse_rpc(const char *xpath, LYD_FORMAT format, const char *data, + bool reply, struct lyd_node **rpc) +{ + const struct lysc_node *snode; + struct lyd_node *parent = NULL; + struct ly_in *in = NULL; + LY_ERR err; + + snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); + if (!snode) { + zlog_err("Failed to find RPC/action schema node: %s", xpath); + return LY_ENOTFOUND; + } + + /* If it's an action, create its parent */ + if (snode->nodetype == LYS_ACTION) { + char *parent_xpath = XSTRDUP(MTYPE_TMP, xpath); + + if (yang_xpath_pop_node(parent_xpath) != NB_OK) { + XFREE(MTYPE_TMP, parent_xpath); + zlog_err("Invalid action xpath: %s", xpath); + return LY_EINVAL; + } + + err = lyd_new_path2(NULL, ly_native_ctx, parent_xpath, NULL, 0, + 0, 0, NULL, &parent); + XFREE(MTYPE_TMP, parent_xpath); + if (err) { + zlog_err("Failed to create parent node for action: %s", + ly_last_errmsg()); + return err; + } + } else if (snode->nodetype != LYS_RPC) { + zlog_err("Schema node is not an RPC/action: %s", xpath); + return LY_EINVAL; + } + + err = ly_in_new_memory(data, &in); + if (err) { + lyd_free_all(parent); + zlog_err("Failed to initialize ly_in: %s", ly_last_errmsg()); + return err; + } + + err = lyd_parse_op(ly_native_ctx, parent, in, format, + reply ? LYD_TYPE_REPLY_YANG : LYD_TYPE_RPC_YANG, + NULL, rpc); + ly_in_free(in, 0); + if (err) { + lyd_free_all(parent); + zlog_err("Failed to parse RPC/action: %s", ly_last_errmsg()); + return err; + } + + return LY_SUCCESS; +} + +static ssize_t yang_print_darr(void *arg, const void *buf, size_t count) +{ + uint8_t *dst = darr_append_n(*(uint8_t **)arg, count); + + memcpy(dst, buf, count); + return count; +} + +LY_ERR yang_print_tree_append(uint8_t **darr, const struct lyd_node *root, + LYD_FORMAT format, uint32_t options) +{ + LY_ERR err; + + err = lyd_print_clb(yang_print_darr, darr, root, format, options); + if (err) + zlog_err("Failed to save yang tree: %s", ly_last_errmsg()); + else if (format != LYD_LYB) + *darr_append(*darr) = 0; + return err; +} + +uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format, + uint32_t options) +{ + uint8_t *darr = NULL; + + if (yang_print_tree_append(&darr, root, format, options)) + return NULL; + return darr; +} + +char *yang_convert_lyd_format(const char *data, size_t data_len, + LYD_FORMAT in_format, LYD_FORMAT out_format, + bool shrink) +{ + struct lyd_node *tree = NULL; + uint32_t options = LYD_PRINT_WD_EXPLICIT | LYD_PRINT_WITHSIBLINGS; + uint8_t *result = NULL; + LY_ERR err; + + assert(out_format != LYD_LYB); + + if (in_format != LYD_LYB && (!data_len || data[data_len - 1] != 0)) { + zlog_err("Corrupt input data, no NUL terminating byte"); + return NULL; + } + + if (in_format == out_format) + return darr_strdup((const char *)data); + + err = lyd_parse_data_mem(ly_native_ctx, (const char *)data, in_format, + LYD_PARSE_ONLY, 0, &tree); + + if (err) { + flog_err_sys(EC_LIB_LIBYANG, + "cannot parse input data to convert: %s", + ly_last_errmsg()); + return NULL; + } + + if (shrink) + options |= LYD_PRINT_SHRINK; + + /* Take a guess at the initial capacity based on input data size */ + darr_ensure_cap(result, data_len); + err = yang_print_tree_append(&result, tree, out_format, options); + lyd_free_all(tree); + if (err) { + darr_free(result); + return NULL; + } + return (char *)result; +} + const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len) { - struct ly_err_item *ei; - const char *path; + const struct ly_err_item *ei; ei = ly_err_first(ly_ctx); if (!ei) return ""; strlcpy(buf, "YANG error(s):\n", buf_len); +#if (LY_VERSION_MAJOR < 3) +#define data_path path +#else +#define data_path data_path +#endif for (; ei; ei = ei->next) { - strlcat(buf, " ", buf_len); + if (ei->data_path) { + strlcat(buf, " Path: ", buf_len); + strlcat(buf, ei->data_path, buf_len); + strlcat(buf, "\n", buf_len); + } + strlcat(buf, " Error: ", buf_len); strlcat(buf, ei->msg, buf_len); strlcat(buf, "\n", buf_len); } - - path = ly_errpath(ly_ctx); - if (path) { - strlcat(buf, " YANG path: ", buf_len); - strlcat(buf, path, buf_len); - strlcat(buf, "\n", buf_len); - } +#undef data_path ly_err_clean(ly_ctx, NULL); @@ -723,6 +980,7 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) { struct ly_ctx *ctx = NULL; const char *yang_models_path = YANG_MODELS_PATH; + uint options; LY_ERR err; if (access(yang_models_path, R_OK | X_OK)) { @@ -736,7 +994,7 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) YANG_MODELS_PATH); } - uint options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD; + options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD; if (explicit_compile) options |= LY_CTX_EXPLICIT_COMPILE; err = ly_ctx_new(yang_models_path, options, &ctx); @@ -752,7 +1010,12 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) void yang_init(bool embedded_modules, bool defer_compile) { /* Initialize libyang global parameters that affect all containers. */ - ly_set_log_clb(ly_log_cb, 1); + ly_set_log_clb(ly_zlog_cb +#if (LY_VERSION_MAJOR < 3) + , + 1 +#endif + ); ly_log_options(LY_LOLOG | LY_LOSTORE); /* Initialize libyang container for native models. */ @@ -927,3 +1190,339 @@ uint32_t yang_get_list_elements_count(const struct lyd_node *node) } while (node); return count; } + +int yang_get_key_preds(char *s, const struct lysc_node *snode, + struct yang_list_keys *keys, ssize_t space) +{ + const struct lysc_node_leaf *skey; + ssize_t len2, len = 0; + ssize_t i = 0; + + LY_FOR_KEYS (snode, skey) { + assert(i < keys->num); + len2 = snprintf(s + len, space - len, "[%s='%s']", skey->name, + keys->key[i]); + if (len2 > space - len) + len = space; + else + len += len2; + i++; + } + + assert(i == keys->num); + return i; +} + +int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys) +{ + struct lyd_node *child = lyd_child(node); + + keys->num = 0; + for (; child && lysc_is_key(child->schema); child = child->next) { + const char *value = lyd_get_value(child); + + if (!value) + return NB_ERR; + strlcpy(keys->key[keys->num], value, + sizeof(keys->key[keys->num])); + keys->num++; + } + return NB_OK; +} + +int yang_xpath_pop_node(char *xpath) +{ + int len = strlen(xpath); + bool abs = xpath[0] == '/'; + char *slash; + + /* "//" or "/" => NULL */ + if (abs && (len == 1 || (len == 2 && xpath[1] == '/'))) + return NB_ERR_NOT_FOUND; + + slash = (char *)frrstr_back_to_char(xpath, '/'); + /* "/foo/bar/" or "/foo/bar//" => "/foo " */ + if (slash && slash == &xpath[len - 1]) { + xpath[--len] = 0; + slash = (char *)frrstr_back_to_char(xpath, '/'); + if (slash && slash == &xpath[len - 1]) { + xpath[--len] = 0; + slash = (char *)frrstr_back_to_char(xpath, '/'); + } + } + if (!slash) + return NB_ERR_NOT_FOUND; + *slash = 0; + return NB_OK; +} + +/* + * ------------------------ + * Libyang Future Functions + * ------------------------ + * + * All these functions are implemented in libyang versions (perhaps unreleased) + * beyond what we require currently so we must supply the functionality. + */ + +/* + * Safe to remove after libyang v2.1.xxx is required (.144 has a bug so + * something > .144) https://github.com/CESNET/libyang/issues/2149 + */ +LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent, + const struct lysc_node *snode, + const struct yang_list_keys *list_keys, + struct lyd_node **node) +{ +#if defined(HAVE_LYD_NEW_LIST3) && 0 + LY_ERR err; + const char *keys[LIST_MAXKEYS]; + + assert(list_keys->num <= LIST_MAXKEYS); + for (int i = 0; i < list_keys->num; i++) + keys[i] = list_keys->key[i]; + + err = lyd_new_list3(&parent->node, snode->module, snode->name, keys, + NULL, 0, node); + return err; +#else + struct lyd_node *pnode = &parent->node; + const char(*keys)[LIST_MAXKEYLEN] = list_keys->key; + + assert(list_keys->num <= 8); + switch (list_keys->num) { + case 0: + return lyd_new_list(pnode, snode->module, snode->name, false, + node); + case 1: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0]); + case 2: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1]); + case 3: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1], keys[2]); + case 4: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1], keys[2], keys[3]); + case 5: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1], keys[2], keys[3], + keys[4]); + case 6: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1], keys[2], keys[3], + keys[4], keys[5]); + case 7: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1], keys[2], keys[3], + keys[4], keys[5], keys[6]); + case 8: + return lyd_new_list(pnode, snode->module, snode->name, false, + node, keys[0], keys[1], keys[2], keys[3], + keys[4], keys[5], keys[6], keys[7]); + } + _Static_assert(LIST_MAXKEYS == 8, "max key mismatch in switch unroll"); + /*NOTREACHED*/ + return LY_EINVAL; +#endif +} + + +/* + * Safe to remove after libyang v2.1.144 is required + */ +LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath) +{ + LY_ERR err; +#ifdef HAVE_LYD_TRIM_XPATH + err = lyd_trim_xpath(root, xpath, NULL); + if (err) { + flog_err_sys(EC_LIB_LIBYANG, + "cannot obtain specific result for xpath \"%s\": %s", + xpath, yang_ly_strerrcode(err)); + return err; + } + return LY_SUCCESS; +#else + struct lyd_node *node, *sib; + struct lyd_node **remove = NULL; + struct ly_set *set = NULL; + uint32_t i; + + *root = lyd_first_sibling(*root); + + err = yang_lyd_find_xpath3(NULL, *root, xpath, LY_VALUE_JSON, NULL, + NULL, &set); + if (err) { + flog_err_sys(EC_LIB_LIBYANG, + "cannot obtain specific result for xpath \"%s\": %s", + xpath, yang_ly_strerrcode(err)); + return err; + } + /* + * Mark keepers and sweep deleting non-keepers. + * + * NOTE: We assume the data-nodes have NULL priv pointers and use that + * for our mark. + */ + + /* Mark */ + for (i = 0; i < set->count; i++) { + for (node = set->dnodes[i]; node; node = &node->parent->node) { + if (node->priv) + break; + if (node == set->dnodes[i]) + node->priv = (void *)2; + else + node->priv = (void *)1; + } + } + + darr_ensure_cap(remove, 128); + LY_LIST_FOR(*root, sib) { + LYD_TREE_DFS_BEGIN (sib, node) { + /* + * If this is a direct matching node then include its + * subtree which won't be marked and would otherwise + * be removed. + */ + if (node->priv == (void *)2) + LYD_TREE_DFS_continue = 1; + else if (!node->priv) { + *darr_append(remove) = node; + LYD_TREE_DFS_continue = 1; + } + LYD_TREE_DFS_END(sib, node); + } + } + darr_foreach_i (remove, i) { + if (remove[i] == *root) { + assert(*root); + *root = (*root)->next; + } + lyd_free_tree(remove[i]); + } + darr_free(remove); + + ly_set_free(set, NULL); + + return LY_SUCCESS; +#endif +} + +/* Can be replaced by `lyd_parse_data` with libyang >= 2.1.156 */ +LY_ERR yang_lyd_parse_data(const struct ly_ctx *ctx, struct lyd_node *parent, + struct ly_in *in, LYD_FORMAT format, + uint32_t parse_options, uint32_t validate_options, + struct lyd_node **tree) +{ + struct lyd_node *child; + LY_ERR err; + + err = lyd_parse_data(ctx, parent, in, format, parse_options, + validate_options, tree); + if (err) + return err; + + if (!parent || !(parse_options & LYD_PARSE_ONLY)) + return LY_SUCCESS; + + /* + * Versions prior to 2.1.156 don't return `tree` if `parent` is not NULL + * and validation is disabled (`LYD_PARSE_ONLY`). To work around this, + * go through the children and find the one with `LYD_NEW` flag set. + */ + *tree = NULL; + + LY_LIST_FOR (lyd_child_no_keys(parent), child) { + if (child->flags & LYD_NEW) { + *tree = child; + break; + } + } + + assert(tree); + + return LY_SUCCESS; +} + +/* + * Safe to remove after libyang v2.1.128 is required + */ +const char *yang_ly_strerrcode(LY_ERR err) +{ +#ifdef HAVE_LY_STRERRCODE + return ly_strerrcode(err); +#else + switch (err) { + case LY_SUCCESS: + return "ok"; + case LY_EMEM: + return "out of memory"; + case LY_ESYS: + return "system error"; + case LY_EINVAL: + return "invalid value given"; + case LY_EEXIST: + return "item exists"; + case LY_ENOTFOUND: + return "item not found"; + case LY_EINT: + return "operation interrupted"; + case LY_EVALID: + return "validation failed"; + case LY_EDENIED: + return "access denied"; + case LY_EINCOMPLETE: + return "incomplete"; + case LY_ERECOMPILE: + return "compile error"; + case LY_ENOT: + return "not"; + case LY_EPLUGIN: + case LY_EOTHER: + return "other"; + default: + return "unknown"; + } +#endif +} + +/* + * Safe to remove after libyang v2.1.128 is required + */ +const char *yang_ly_strvecode(LY_VECODE vecode) +{ +#ifdef HAVE_LY_STRVECODE + return ly_strvecode(vecode); +#else + switch (vecode) { + case LYVE_SUCCESS: + return ""; + case LYVE_SYNTAX: + return "syntax"; + case LYVE_SYNTAX_YANG: + return "yang-syntax"; + case LYVE_SYNTAX_YIN: + return "yin-syntax"; + case LYVE_REFERENCE: + return "reference"; + case LYVE_XPATH: + return "xpath"; + case LYVE_SEMANTICS: + return "semantics"; + case LYVE_SYNTAX_XML: + return "xml-syntax"; + case LYVE_SYNTAX_JSON: + return "json-syntax"; + case LYVE_DATA: + return "data"; + case LYVE_OTHER: + return "other"; + default: + return "unknown"; + } +#endif +} diff --git a/lib/yang.h b/lib/yang.h index 37369c09bf81..57131f478bac 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -45,9 +45,6 @@ struct yang_module { RB_ENTRY(yang_module) entry; const char *name; const struct lys_module *info; -#ifdef HAVE_CONFD - int confd_hash; -#endif #ifdef HAVE_SYSREPO sr_subscription_ctx_t *sr_subscription; struct event *sr_thread; @@ -112,10 +109,16 @@ extern struct yang_modules yang_modules; * module_name * Name of the YANG module. * + * features + * NULL-terminated array of feature names to enable. + * If NULL, all features are disabled. + * To enable all features, use ["*", NULL]. + * * Returns: * Pointer to newly created YANG module. */ -extern struct yang_module *yang_module_load(const char *module_name); +extern struct yang_module *yang_module_load(const char *module_name, + const char **features); /* * Load all FRR native YANG models. @@ -317,30 +320,16 @@ extern unsigned int yang_snode_num_keys(const struct lysc_node *snode); * libyang data node to be processed. * * xpath - * Pointer to previously allocated buffer. + * Pointer to previously allocated buffer or NULL. * * xpath_len - * Size of the xpath buffer. - */ -extern void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath, - size_t xpath_len); - -/* - * Return the schema name of the given libyang data node. - * - * dnode - * libyang data node. + * Size of the xpath buffer if xpath non-NULL. * - * xpath_fmt - * Optional XPath expression (absolute or relative) to specify a different - * data node to operate on in the same data tree. - * - * Returns: - * Schema name of the libyang data node. + * If xpath is NULL, the returned string (if non-NULL) needs to be free()d by + * the caller. */ -extern const char *yang_dnode_get_schema_name(const struct lyd_node *dnode, - const char *xpath_fmt, ...) - PRINTFRR(2, 3); +extern char *yang_dnode_get_path(const struct lyd_node *dnode, char *xpath, + size_t xpath_len); /* * Find a libyang data node by its YANG data path. @@ -434,6 +423,21 @@ void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg, const struct lyd_node *dnode, const char *xpath_fmt, ...) PRINTFRR(4, 5); +/* + * Count the number of data nodes that satisfy an XPath query. + * + * dnode + * Base libyang data node to operate on. + * + * xpath_fmt + * XPath expression (absolute or relative). + * + * ... + * any parameters for xpath_fmt. + */ +uint32_t yang_dnode_count(const struct lyd_node *dnode, const char *xpath_fmt, + ...) PRINTFRR(2, 3); + /* * Check if the libyang data node contains a default value. Non-presence * containers are assumed to always contain a default value. @@ -531,6 +535,21 @@ extern struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode); */ extern void yang_dnode_free(struct lyd_node *dnode); +/* + * Add a libyang data node to an RPC/action output container. + * + * output + * RPC/action output container. + * + * xpath + * XPath of the data node to add, relative to the output container. + * + * value + * String representing the value of the data node. + */ +extern void yang_dnode_rpc_output_add(struct lyd_node *output, + const char *xpath, const char *value); + /* * Create a new yang_data structure. * @@ -600,6 +619,88 @@ extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, */ extern void yang_debugging_set(bool enable); +/* + * Parse a YANG notification. + * + * Args: + * xpath: xpath of notification. + * format: LYD_FORMAT of input data. + * data: input data. + * notif: pointer to the libyang data tree to store the parsed notification. + * If the notification is not on the top level of the yang model, + * the pointer to the notification node is still returned, but it's + * part of the full data tree with all its parents. + */ +extern LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format, + const char *data, struct lyd_node **notif); + +/* + * Parse a YANG RPC. + * + * Args: + * xpath: xpath of an RPC/action. + * format: LYD_FORMAT of input data. + * data: input data. + * reply: true if the data represents a reply to an RPC/action. + * rpc: pointer to the libyang data tree to store the parsed RPC/action. + * If data represents an action, the pointer to the action node is + * still returned, but it's part of the full data tree with all its + * parents. + * + * Returns: + * LY_ERR from underlying calls. + */ +LY_ERR yang_parse_rpc(const char *xpath, LYD_FORMAT format, const char *data, + bool reply, struct lyd_node **rpc); + +/* + * "Print" the yang tree in `root` into dynamic sized array. + * + * Args: + * root: root of the subtree to "print" along with siblings. + * format: LYD_FORMAT of output (see lyd_print_mem) + * options: printing options (see lyd_print_mem) + * + * Return: + * A darr dynamic array with the "printed" output or NULL on failure. + */ +extern uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format, + uint32_t options); + + +/** + * yang_convert_lyd_format() - convert one libyang format to darr string. + * @data: data to convert. + * @data_len: length of the data. + * @in_format: format of the data. + * @out_format: format to return. + * @shrink: true to avoid pretty printing. + * + * Return: + * A darr based string or NULL for error. + */ +extern char *yang_convert_lyd_format(const char *data, size_t msg_len, + LYD_FORMAT in_format, + LYD_FORMAT out_format, bool shrink); + +/* + * "Print" the yang tree in `root` into an existing dynamic sized array. + * + * This function does not initialize or free the dynamic array, the array can + * already existing data, the tree will be appended to this data. + * + * Args: + * darr: existing `uint8_t *`, dynamic array. + * root: root of the subtree to "print" along with siblings. + * format: LYD_FORMAT of output (see lyd_print_mem) + * options: printing options (see lyd_print_mem) + * + * Return: + * LY_ERR from underlying calls. + */ +extern LY_ERR yang_print_tree_append(uint8_t **darr, const struct lyd_node *root, + LYD_FORMAT format, uint32_t options); + /* * Print libyang error messages into the provided buffer. * @@ -693,6 +794,57 @@ bool yang_is_last_list_dnode(const struct lyd_node *dnode); /* API to check if the given node is last node in the data tree level */ bool yang_is_last_level_dnode(const struct lyd_node *dnode); +/* Create a YANG predicate string based on the keys */ +extern int yang_get_key_preds(char *s, const struct lysc_node *snode, + struct yang_list_keys *keys, ssize_t space); + +/* Get YANG keys from an existing dnode */ +extern int yang_get_node_keys(struct lyd_node *node, struct yang_list_keys *keys); + +/** + * yang_xpath_pop_node() - remove the last node from xpath string + * @xpath: an xpath string + * + * Return: NB_OK or NB_ERR_NOT_FOUND if nothing left to pop. + */ +extern int yang_xpath_pop_node(char *xpath); + +/** + * yang_resolve_snodes() - Resolve an XPath to matching schema nodes. + * @ly_ctx: libyang context to operate on. + * @xpath: the path or XPath to resolve. + * @snodes: [OUT] pointer for resulting dynamic array (darr) of schema node + * pointers. + * @simple: [OUT] indicates if @xpath was resolvable simply or not. Non-simple + * means that the @xpath is not a simple path and utilizes XPath 1.0 + * functionality beyond simple key predicates. + * + * This function can be used to find the schema node (or nodes) that correspond + * to a given @xpath. If the @xpath includes non-key predicates (e.g., using + * functions) then @simple will be set to false, and @snodes may contain more + * than a single schema node. + * + * Return: a libyang error or LY_SUCCESS. + */ +extern LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath, + struct lysc_node ***snodes, bool *simple); + +/* + * Libyang future functions + */ +extern const char *yang_ly_strerrcode(LY_ERR err); +extern const char *yang_ly_strvecode(LY_VECODE vecode); +extern LY_ERR yang_lyd_new_list(struct lyd_node_inner *parent, + const struct lysc_node *snode, + const struct yang_list_keys *keys, + struct lyd_node **nodes); +extern LY_ERR yang_lyd_trim_xpath(struct lyd_node **rootp, const char *xpath); +extern LY_ERR yang_lyd_parse_data(const struct ly_ctx *ctx, + struct lyd_node *parent, struct ly_in *in, + LYD_FORMAT format, uint32_t parse_options, + uint32_t validate_options, + struct lyd_node **tree); + #ifdef __cplusplus } #endif diff --git a/lib/yang_translator.c b/lib/yang_translator.c index eae7577a0d1c..005f6422f3b3 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -146,7 +146,7 @@ struct yang_translator *yang_translator_load(const char *path) */ assert(dnode); - family = yang_dnode_get_string(dnode, "./family"); + family = yang_dnode_get_string(dnode, "family"); translator = yang_translator_find(family); if (translator != NULL) { flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, @@ -182,7 +182,7 @@ struct yang_translator *yang_translator_load(const char *path) tmodule = XCALLOC(MTYPE_YANG_TRANSLATOR_MODULE, sizeof(*tmodule)); - module_name = yang_dnode_get_string(set->dnodes[i], "./name"); + module_name = yang_dnode_get_string(set->dnodes[i], "name"); tmodule->module = ly_ctx_load_module(translator->ly_ctx, module_name, NULL, NULL); if (!tmodule->module) { @@ -233,7 +233,7 @@ struct yang_translator *yang_translator_load(const char *path) const struct lysc_node *snode_custom, *snode_native; xpath_custom = - yang_dnode_get_string(set->dnodes[i], "./custom"); + yang_dnode_get_string(set->dnodes[i], "custom"); snode_custom = yang_find_snode(translator->ly_ctx, xpath_custom, 0); @@ -246,7 +246,7 @@ struct yang_translator *yang_translator_load(const char *path) } xpath_native = - yang_dnode_get_string(set->dnodes[i], "./native"); + yang_dnode_get_string(set->dnodes[i], "native"); snode_native = yang_find_snode(ly_native_ctx, xpath_native, 0); if (!snode_native) { flog_warn(EC_LIB_YANG_TRANSLATOR_LOAD, diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index dc049a374a9e..4e49a129c24c 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -168,10 +168,9 @@ struct yang_data *yang_data_new_dec64(const char *xpath, double value) double yang_dnode_get_dec64(const struct lyd_node *dnode, const char *xpath_fmt, ...) { - const double denom[19] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, - 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, - 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, - 1e-15, 1e-16, 1e-17, 1e-18}; + const double denom[19] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, + 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, + 1e14, 1e15, 1e16, 1e17, 1e18 }; const struct lysc_type_dec *dectype; const struct lyd_value *dvalue; @@ -179,7 +178,7 @@ double yang_dnode_get_dec64(const struct lyd_node *dnode, const char *xpath_fmt, dectype = (const struct lysc_type_dec *)dvalue->realtype; assert(dectype->basetype == LY_TYPE_DEC64); assert(dectype->fraction_digits < sizeof(denom) / sizeof(*denom)); - return (double)dvalue->dec64 * denom[dectype->fraction_digits]; + return (double)dvalue->dec64 / denom[dectype->fraction_digits]; } double yang_get_default_dec64(const char *xpath_fmt, ...) @@ -1020,30 +1019,68 @@ void yang_str2mac(const char *value, struct ethaddr *mac) (void)prefix_str2mac(value, mac); } -struct yang_data *yang_data_new_date_and_time(const char *xpath, time_t time) +void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode, + const char *xpath_fmt, ...) { - struct tm tm; - char timebuf[MONOTIME_STRLEN]; - struct timeval _time, time_real; - char *ts_dot; - uint16_t buflen; + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + (void)prefix_str2mac(canon, mac); +} + +struct yang_data *yang_data_new_date_and_time(const char *xpath, time_t time, bool is_monotime) +{ + struct yang_data *yd; + char *times = NULL; + + if (is_monotime) { + struct timeval _time = { time, 0 }; + struct timeval time_real; + + monotime_to_realtime(&_time, &time_real); + time = time_real.tv_sec; + } + + (void)ly_time_time2str(time, NULL, ×); + yd = yang_data_new(xpath, times); + free(times); - _time.tv_sec = time; - _time.tv_usec = 0; - monotime_to_realtime(&_time, &time_real); + return yd; +} - gmtime_r(&time_real.tv_sec, &tm); +struct timespec yang_dnode_get_date_and_timespec(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + struct timespec ts; + LY_ERR err; - /* rfc-3339 format */ - strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm); - buflen = strlen(timebuf); - ts_dot = timebuf + buflen; + err = ly_time_str2ts(canon, &ts); + assert(!err); - /* microseconds and appends Z */ - snprintfrr(ts_dot, sizeof(timebuf) - buflen, ".%06luZ", - (unsigned long)time_real.tv_usec); + return ts; +} - return yang_data_new(xpath, timebuf); +time_t yang_dnode_get_date_and_time(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + time_t time; + LY_ERR err; + + err = ly_time_str2time(canon, &time, NULL); + assert(!err); + + return time; +} + +float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + const char *canon = YANG_DNODE_XPATH_GET_CANON(dnode, xpath_fmt); + float value; + + assert(sscanf(canon, "%a", &value) == 1); + + return value; } const char *yang_nexthop_type2str(uint32_t ntype) diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h index 06e05872e30d..d3d841995b20 100644 --- a/lib/yang_wrappers.h +++ b/lib/yang_wrappers.h @@ -7,6 +7,7 @@ #ifndef _FRR_NORTHBOUND_WRAPPERS_H_ #define _FRR_NORTHBOUND_WRAPPERS_H_ +#include #include "prefix.h" #ifdef __cplusplus @@ -195,10 +196,24 @@ extern void yang_get_default_ip(struct ipaddr *var, const char *xpath_fmt, ...) extern struct yang_data *yang_data_new_mac(const char *xpath, const struct ethaddr *mac); extern void yang_str2mac(const char *value, struct ethaddr *mac); +extern void yang_dnode_get_mac(struct ethaddr *mac, const struct lyd_node *dnode, + const char *xpath_fmt, ...) PRINTFRR(3, 4); /*data-and-time */ extern struct yang_data *yang_data_new_date_and_time(const char *xpath, - time_t time); + time_t time, + bool is_monotime); +struct timespec yang_dnode_get_date_and_timespec(const struct lyd_node *dnode, + const char *xpath_fmt, ...) + PRINTFRR(2, 3); +time_t yang_dnode_get_date_and_time(const struct lyd_node *dnode, + const char *xpath_fmt, ...) + PRINTFRR(2, 3); + +/* rt-types:bandwidth-ieee-float32 */ +extern float yang_dnode_get_bandwidth_ieee_float32(const struct lyd_node *dnode, + const char *xpath_fmt, ...) + PRINTFRR(2, 3); /* nexthop enum2str */ extern const char *yang_nexthop_type2str(uint32_t ntype); diff --git a/lib/zclient.c b/lib/zclient.c index f8f9cf7aba05..0e832f0d8fe5 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -41,8 +41,20 @@ static void zclient_event(enum zclient_event, struct zclient *); static void zebra_interface_if_set_value(struct stream *s, struct interface *ifp); -struct zclient_options zclient_options_default = {.receive_notify = false, - .synchronous = false}; +const struct zclient_options zclient_options_default = { + .synchronous = false, + .auxiliary = false, +}; + +const struct zclient_options zclient_options_sync = { + .synchronous = true, + .auxiliary = true, +}; + +const struct zclient_options zclient_options_auxiliary = { + .synchronous = false, + .auxiliary = true, +}; struct sockaddr_storage zclient_addr; socklen_t zclient_addr_len; @@ -52,7 +64,7 @@ static int zclient_debug; /* Allocate zclient structure. */ struct zclient *zclient_new(struct event_loop *master, - struct zclient_options *opt, + const struct zclient_options *opt, zclient_handler *const *handlers, size_t n_handlers) { struct zclient *zclient; @@ -69,8 +81,8 @@ struct zclient *zclient_new(struct event_loop *master, zclient->handlers = handlers; zclient->n_handlers = n_handlers; - zclient->receive_notify = opt->receive_notify; zclient->synchronous = opt->synchronous; + zclient->auxiliary = opt->auxiliary; return zclient; } @@ -270,6 +282,7 @@ static void zclient_flush_data(struct event *thread) zclient->sock, &zclient->t_write); break; case BUFFER_EMPTY: + /* Currently only Sharpd and Bgpd has callbacks defined */ if (zclient->zebra_buffer_write_ready) (*zclient->zebra_buffer_write_ready)(); break; @@ -392,10 +405,6 @@ enum zclient_send_status zclient_send_hello(struct zclient *zclient) stream_putc(s, zclient->redist_default); stream_putw(s, zclient->instance); stream_putl(s, zclient->session_id); - if (zclient->receive_notify) - stream_putc(s, 1); - else - stream_putc(s, 0); if (zclient->synchronous) stream_putc(s, 1); else @@ -891,7 +900,7 @@ static int zapi_nexthop_cmp_no_labels(const struct zapi_nexthop *next1, &next2->gate); if (ret != 0) return ret; - /* Intentional Fall-Through */ + fallthrough; case NEXTHOP_TYPE_IFINDEX: if (next1->ifindex < next2->ifindex) return -1; @@ -1031,7 +1040,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, } if (api_nh->weight) - stream_putl(s, api_nh->weight); + stream_putq(s, api_nh->weight); /* Router MAC for EVPN routes. */ if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_EVPN)) @@ -1116,6 +1125,11 @@ int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l) stream_put(s, l->name, strlen(l->name)); stream_putw(s, l->prefix.prefixlen); stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix)); + stream_putc(s, l->block_bits_length); + stream_putc(s, l->node_bits_length); + stream_putc(s, l->function_bits_length); + stream_putc(s, l->argument_bits_length); + stream_putc(s, l->flags); return 0; } @@ -1131,6 +1145,11 @@ int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l) STREAM_GETW(s, l->prefix.prefixlen); STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix)); l->prefix.family = AF_INET6; + STREAM_GETC(s, l->block_bits_length); + STREAM_GETC(s, l->node_bits_length); + STREAM_GETC(s, l->function_bits_length); + STREAM_GETC(s, l->argument_bits_length); + STREAM_GETC(s, l->flags); return 0; stream_failure: @@ -1403,7 +1422,7 @@ int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, } if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT)) - STREAM_GETL(s, api_nh->weight); + STREAM_GETQ(s, api_nh->weight); /* Router MAC for EVPN routes. */ if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) @@ -1851,7 +1870,7 @@ int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r) zapi_pbr_rule_filter_encode(s, &(r->filter)); zapi_pbr_rule_action_encode(s, &(r->action)); - stream_put(s, r->ifname, INTERFACE_NAMSIZ); + stream_put(s, r->ifname, IFNAMSIZ); /* Put length at the first point of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -1875,7 +1894,7 @@ bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r) if (!zapi_pbr_rule_action_decode(s, &(r->action))) goto stream_failure; - STREAM_GET(r->ifname, s, INTERFACE_NAMSIZ); + STREAM_GET(r->ifname, s, IFNAMSIZ); return true; stream_failure: @@ -2034,7 +2053,7 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, STREAM_GETL(s, seq); STREAM_GETL(s, prio); STREAM_GETL(s, uni); - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); + STREAM_GET(ifname, s, IFNAMSIZ); if (zclient_debug) zlog_debug("%s: %u %u %u %s", __func__, seq, prio, uni, ifname); @@ -2114,6 +2133,46 @@ bool zapi_iptable_notify_decode(struct stream *s, return false; } +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note, + char **p_locator_name) +{ + uint32_t f, wf; + uint16_t len; + static char locator_name[SRV6_LOCNAME_SIZE] = {}; + + STREAM_GET(note, s, sizeof(*note)); + STREAM_GET(ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GET(sid_value, s, sizeof(struct in6_addr)); + STREAM_GETL(s, f); + STREAM_GETL(s, wf); + + if (func) + *func = f; + if (wide_func) + *wide_func = wf; + + STREAM_GETW(s, len); + if (len > SRV6_LOCNAME_SIZE) { + *p_locator_name = NULL; + return false; + } + if (p_locator_name) { + if (len == 0) + *p_locator_name = NULL; + else { + STREAM_GET(locator_name, s, len); + *p_locator_name = locator_name; + } + } + return true; + +stream_failure: + return false; +} + struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); @@ -2123,6 +2182,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) n->ifindex = znh->ifindex; n->gate = znh->gate; n->srte_color = znh->srte_color; + n->weight = znh->weight; /* * This function currently handles labels @@ -2163,6 +2223,7 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, znh->weight = nh->weight; znh->ifindex = nh->ifindex; znh->gate = nh->gate; + znh->srte_color = nh->srte_color; if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK)) SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); @@ -2269,8 +2330,8 @@ const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf, /* * Decode the nexthop-tracking update message */ -bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, - struct zapi_route *nhr) +static bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, + struct zapi_route *nhr) { uint32_t i; @@ -2526,12 +2587,12 @@ static int zclient_vrf_delete(ZAPI_CALLBACK_ARGS) static int zclient_interface_add(ZAPI_CALLBACK_ARGS) { struct interface *ifp; - char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; + char ifname_tmp[IFNAMSIZ + 1] = {}; struct stream *s = zclient->ibuf; struct vrf *vrf; /* Read interface name. */ - STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); + STREAM_GET(ifname_tmp, s, IFNAMSIZ); /* Lookup/create interface by name. */ vrf = vrf_lookup_by_id(vrf_id); @@ -2562,10 +2623,10 @@ static int zclient_interface_add(ZAPI_CALLBACK_ARGS) struct interface *zebra_interface_state_read(struct stream *s, vrf_id_t vrf_id) { struct interface *ifp; - char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; + char ifname_tmp[IFNAMSIZ + 1] = {}; /* Read interface name. */ - STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); + STREAM_GET(ifname_tmp, s, IFNAMSIZ); /* Lookup this by interface index. */ ifp = if_lookup_by_name(ifname_tmp, vrf_id); @@ -3051,36 +3112,6 @@ zebra_interface_nbr_address_read(int type, struct stream *s, vrf_id_t vrf_id) return NULL; } -struct interface *zebra_interface_vrf_update_read(struct stream *s, - vrf_id_t vrf_id, - vrf_id_t *new_vrf_id) -{ - char ifname[INTERFACE_NAMSIZ + 1] = {}; - struct interface *ifp; - vrf_id_t new_id; - - /* Read interface name. */ - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); - - /* Lookup interface. */ - ifp = if_lookup_by_name(ifname, vrf_id); - if (ifp == NULL) { - flog_err(EC_LIB_ZAPI_ENCODE, - "INTERFACE_VRF_UPDATE: Cannot find IF %s in VRF %d", - ifname, vrf_id); - return NULL; - } - - /* Fetch new VRF Id. */ - STREAM_GETL(s, new_id); - - *new_vrf_id = new_id; - return ifp; - -stream_failure: - return NULL; -} - /* filter unwanted messages until the expected one arrives */ static int zclient_read_sync_response(struct zclient *zclient, uint16_t expected_cmd) @@ -3286,10 +3317,154 @@ int srv6_manager_release_locator_chunk(struct zclient *zclient, return zclient_send_message(zclient); } +/** + * Function to request a SRv6 locator in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 Manager (zebra) + * @param locator_name Name of SRv6 locator + * @return 0 on success, -1 otherwise + */ +int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name) +{ + struct stream *s; + size_t len; + + if (!locator_name) + return -1; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 Locator %s", locator_name); + + len = strlen(locator_name); + + /* Send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR, VRF_DEFAULT); + + /* Locator name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/** + * Function to request an SRv6 SID in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID + * @param sid_value SRv6 SID value for explicit SID allocation + * @param locator_name Name of the parent locator for dynamic SID allocation + * @param sid_func SID function assigned by the SRv6 Manager + * @result 0 on success, -1 otherwise + */ +int srv6_manager_get_sid(struct zclient *zclient, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name, + uint32_t *sid_func) +{ + struct stream *s; + uint8_t flags = 0; + size_t len; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return ZCLIENT_SEND_FAILURE; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Flags */ + if (!sid_zero_ipv6(sid_value)) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE); + if (locator_name) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR); + stream_putc(s, flags); + + /* SRv6 SID value */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) + stream_put(s, sid_value, sizeof(struct in6_addr)); + + /* SRv6 locator */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + len = strlen(locator_name); + stream_putw(s, len); + stream_put(s, locator_name, len); + } + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the request to SRv6 Manager */ + return zclient_send_message(zclient); +} + +/** + * Function to release an SRv6 SID + * + * @param zclient Zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID to be removed + * @result 0 on success, -1 otherwise + */ +int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx) +{ + struct stream *s; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Releasing SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, + VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the SID release message */ + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * - * @param zclient Zclient used to connect to label manager (zebra) + * @param zclient The zclient used to connect to label manager (zebra) * @param keep Avoid garbage collection * @param chunk_size Amount of labels requested * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care @@ -3946,7 +4121,7 @@ enum zclient_send_status zebra_send_pw(struct zclient *zclient, int command, stream_reset(s); zclient_create_header(s, command, VRF_DEFAULT); - stream_write(s, pw->ifname, INTERFACE_NAMSIZ); + stream_write(s, pw->ifname, IFNAMSIZ); stream_putl(s, pw->ifindex); /* Put type */ @@ -3993,7 +4168,7 @@ int zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS, struct zapi_pw_status *pw) s = zclient->ibuf; /* Get data. */ - stream_get(pw->ifname, s, INTERFACE_NAMSIZ); + stream_get(pw->ifname, s, IFNAMSIZ); STREAM_GETL(s, pw->ifindex); STREAM_GETL(s, pw->status); @@ -4298,6 +4473,28 @@ int zapi_client_close_notify_decode(struct stream *s, return -1; } +static int zclient_nexthop_update(ZAPI_CALLBACK_ARGS) +{ + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + struct prefix match; + struct zapi_route route; + + if (!vrf) { + zlog_warn("nexthop update for unknown VRF ID %u", vrf_id); + return 0; + } + + if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &route)) { + zlog_err("failed to decode nexthop update"); + return -1; + } + + if (zclient->nexthop_update) + zclient->nexthop_update(vrf, &match, &route); + + return 0; +} + static zclient_handler *const lib_handlers[] = { /* fundamentals */ [ZEBRA_CAPABILITIES] = zclient_capability_decode, @@ -4311,6 +4508,9 @@ static zclient_handler *const lib_handlers[] = { [ZEBRA_INTERFACE_UP] = zclient_interface_up, [ZEBRA_INTERFACE_DOWN] = zclient_interface_down, + /* NHT pre-decode */ + [ZEBRA_NEXTHOP_UPDATE] = zclient_nexthop_update, + /* BFD */ [ZEBRA_BFD_DEST_REPLAY] = zclient_bfd_session_replay, [ZEBRA_INTERFACE_BFD_DEST_UPDATE] = zclient_bfd_session_update, @@ -4419,7 +4619,8 @@ static void zclient_read(struct event *thread) zlog_debug("zclient %p command %s VRF %u", zclient, zserv_command_string(command), vrf_id); - if (command < array_size(lib_handlers) && lib_handlers[command]) + if (!zclient->auxiliary && command < array_size(lib_handlers) && + lib_handlers[command]) lib_handlers[command](command, zclient, length, vrf_id); if (command < zclient->n_handlers && zclient->handlers[command]) zclient->handlers[command](command, zclient, length, vrf_id); @@ -4516,6 +4717,24 @@ static void zclient_event(enum zclient_event event, struct zclient *zclient) } } +enum zclient_send_status zclient_interface_set_arp(struct zclient *client, + struct interface *ifp, + bool arp_enable) +{ + struct stream *s; + + s = client->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_INTERFACE_SET_ARP, ifp->vrf->vrf_id); + + stream_putl(s, ifp->ifindex); + stream_putc(s, arp_enable); + + stream_putw_at(s, 0, stream_get_endp(s)); + return zclient_send_message(client); +} + enum zclient_send_status zclient_interface_set_master(struct zclient *client, struct interface *master, struct interface *slave) @@ -4647,21 +4866,25 @@ char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len) return buf; } - snprintfrr( - buf, len, "%s%s%s%s%s%s%s%s%s%s", - CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION) ? "Recursion " - : "", - CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) ? "Self " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_IBGP) ? "iBGP " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_SELECTED) ? "Selected " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE) ? "Override " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE) ? "Evpn " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_RR_USE_DISTANCE) ? "RR Distance " - : "", - CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED) ? "Trapped " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED) ? "Offloaded " : "", - CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED) ? "Offload Failed " - : ""); + snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s", + CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION) ? "Recursion " + : "", + + CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) ? "Self " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_IBGP) ? "iBGP " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_SELECTED) ? "Selected " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE) ? "Override " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE) ? "Evpn " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_RR_USE_DISTANCE) ? "RR Distance " + : "", + + CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED) ? "Trapped " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED) ? "Offloaded " : "", + CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED) + ? "Offload Failed " + : "", + CHECK_FLAG(flags, ZEBRA_FLAG_OUTOFSYNC) ? "OutOfSync " : ""); + return buf; } @@ -4705,7 +4928,7 @@ static int zclient_neigh_ip_read_entry(struct stream *s, struct ipaddr *add) int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, union sockunion *out, struct interface *ifp, - int ndm_state) + int ndm_state, int ip_len) { int ret = 0; @@ -4718,6 +4941,7 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, sockunion_get_addrlen(out)); } else stream_putc(s, AF_UNSPEC); + stream_putl(s, ip_len); stream_putl(s, ifp->ifindex); if (out) stream_putl(s, ndm_state); @@ -4735,6 +4959,7 @@ int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api) return -1; zclient_neigh_ip_read_entry(s, &api->ip_out); + STREAM_GETL(s, api->ip_len); STREAM_GETL(s, api->index); STREAM_GETL(s, api->ndm_state); return 0; @@ -4881,3 +5106,23 @@ enum zclient_send_status zclient_opaque_drop_notify(struct zclient *zclient, return zclient_send_message(zclient); } + +void zclient_register_neigh(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi, + bool reg) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, + reg ? ZEBRA_NEIGH_REGISTER + : ZEBRA_NEIGH_UNREGISTER, + vrf_id); + stream_putw(s, afi); + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} diff --git a/lib/zclient.h b/lib/zclient.h index 2a3ce4e4880c..2877b347d8d0 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -98,6 +98,7 @@ typedef enum { ZEBRA_INTERFACE_UP, ZEBRA_INTERFACE_DOWN, ZEBRA_INTERFACE_SET_MASTER, + ZEBRA_INTERFACE_SET_ARP, ZEBRA_INTERFACE_SET_PROTODOWN, ZEBRA_ROUTE_ADD, ZEBRA_ROUTE_DELETE, @@ -127,7 +128,6 @@ typedef enum { ZEBRA_VRF_ADD, ZEBRA_VRF_DELETE, ZEBRA_VRF_LABEL, - ZEBRA_INTERFACE_VRF_UPDATE, ZEBRA_BFD_CLIENT_REGISTER, ZEBRA_BFD_CLIENT_DEREGISTER, ZEBRA_INTERFACE_ENABLE_RADV, @@ -209,6 +209,9 @@ typedef enum { ZEBRA_SRV6_LOCATOR_DELETE, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, + ZEBRA_SRV6_MANAGER_GET_LOCATOR, + ZEBRA_SRV6_MANAGER_GET_SRV6_SID, + ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -217,11 +220,11 @@ typedef enum { ZEBRA_NEIGH_DISCOVER, ZEBRA_ROUTE_NOTIFY_REQUEST, ZEBRA_CLIENT_CLOSE_NOTIFY, - ZEBRA_NHRP_NEIGH_ADDED, - ZEBRA_NHRP_NEIGH_REMOVED, - ZEBRA_NHRP_NEIGH_GET, - ZEBRA_NHRP_NEIGH_REGISTER, - ZEBRA_NHRP_NEIGH_UNREGISTER, + ZEBRA_NEIGH_ADDED, + ZEBRA_NEIGH_REMOVED, + ZEBRA_NEIGH_GET, + ZEBRA_NEIGH_REGISTER, + ZEBRA_NEIGH_UNREGISTER, ZEBRA_NEIGH_IP_ADD, ZEBRA_NEIGH_IP_DEL, ZEBRA_CONFIGURE_ARP, @@ -235,6 +238,7 @@ typedef enum { ZEBRA_TC_FILTER_ADD, ZEBRA_TC_FILTER_DELETE, ZEBRA_OPAQUE_NOTIFY, + ZEBRA_SRV6_SID_NOTIFY, } zebra_message_types_t; /* Zebra message types. Please update the corresponding * command_types array with any changes! @@ -294,6 +298,8 @@ struct zapi_cap { typedef int (zclient_handler)(ZAPI_CALLBACK_ARGS); /* clang-format on */ +struct zapi_route; + /* Structure for the zebra client. */ struct zclient { /* The thread master we schedule ourselves on */ @@ -302,12 +308,14 @@ struct zclient { /* Privileges to change socket values */ struct zebra_privs_t *privs; - /* Do we care about failure events for route install? */ - bool receive_notify; - /* Is this a synchronous client? */ bool synchronous; + /* Auxiliary clients don't execute standard library handlers + * (which otherwise would duplicate VRF/interface add/delete/etc. + */ + bool auxiliary; + /* BFD enabled with bfd_protocol_integration_init() */ bool bfd_integration; @@ -349,6 +357,19 @@ struct zclient { void (*zebra_connected)(struct zclient *); void (*zebra_capabilities)(struct zclient_capabilities *cap); + /* + * match -> is the prefix that the calling daemon asked to be matched + * against. + * nhr->prefix -> is the actual prefix that was matched against in the + * rib itself. + * + * This distinction is made because a LPM can be made if there is a + * covering route. This way the upper level protocol can make a + * decision point about whether or not it wants to use the match or not. + */ + void (*nexthop_update)(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr); + int (*handle_error)(enum zebra_error_types error); /* @@ -424,7 +445,7 @@ struct zapi_nexthop { struct ethaddr rmac; - uint32_t weight; + uint64_t weight; /* Backup nexthops, for IP-FRR, TI-LFA, etc */ uint8_t backup_num; @@ -630,7 +651,7 @@ struct zapi_sr_policy { }; struct zapi_pw { - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int type; int af; @@ -643,7 +664,7 @@ struct zapi_pw { }; struct zapi_pw_status { - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; uint32_t status; }; @@ -744,6 +765,13 @@ enum zapi_iptable_notify_owner { ZAPI_IPTABLE_FAIL_REMOVE, }; +enum zapi_srv6_sid_notify { + ZAPI_SRV6_SID_FAIL_ALLOC = 0, + ZAPI_SRV6_SID_ALLOCATED, + ZAPI_SRV6_SID_RELEASED, + ZAPI_SRV6_SID_FAIL_RELEASE, +}; + enum zclient_send_status { ZCLIENT_SEND_FAILURE = -1, ZCLIENT_SEND_SUCCESS = 0, @@ -796,6 +824,28 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) return ret; } +static inline const char *zapi_srv6_sid_notify2str(enum zapi_srv6_sid_notify note) +{ + const char *ret = "UNKNOWN"; + + switch (note) { + case ZAPI_SRV6_SID_FAIL_ALLOC: + ret = "ZAPI_SRV6_SID_FAIL_ALLOC"; + break; + case ZAPI_SRV6_SID_ALLOCATED: + ret = "ZAPI_SRV6_SID_ALLOCATED"; + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + ret = "ZAPI_SRV6_SID_FAIL_RELEASE"; + break; + case ZAPI_SRV6_SID_RELEASED: + ret = "ZAPI_SRV6_SID_RELEASED"; + break; + } + + return ret; +} + /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ @@ -820,11 +870,18 @@ extern char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; struct zclient_options { - bool receive_notify; bool synchronous; + + /* auxiliary = don't call common lib/ handlers that manage bits. + * Those should only run once, on the "main" zclient, which this is + * not. (This is also set for synchronous clients.) + */ + bool auxiliary; }; -extern struct zclient_options zclient_options_default; +extern const struct zclient_options zclient_options_default; +extern const struct zclient_options zclient_options_sync; +extern const struct zclient_options zclient_options_auxiliary; /* link layer representation for GRE like interfaces * ip_in is the underlay IP, ip_out is the tunnel dest @@ -844,6 +901,7 @@ extern struct zclient_options zclient_options_default; struct zapi_neigh_ip { int cmd; + int ip_len; struct ipaddr ip_in; struct ipaddr ip_out; ifindex_t index; @@ -852,7 +910,7 @@ struct zapi_neigh_ip { int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api); int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, union sockunion *out, struct interface *ifp, - int ndm_state); + int ndm_state, int ip_len); /* * We reserve the top 4 bits for l2-NHG, everything else @@ -866,12 +924,12 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, ((uint32_t)250000000) /* Bottom 28 bits then rounded down */ #define ZEBRA_NHG_PROTO_SPACING (ZEBRA_NHG_PROTO_UPPER / ZEBRA_ROUTE_MAX) #define ZEBRA_NHG_PROTO_LOWER \ - (ZEBRA_NHG_PROTO_SPACING * (ZEBRA_ROUTE_CONNECT + 1)) + (ZEBRA_NHG_PROTO_SPACING * (ZEBRA_ROUTE_LOCAL + 1)) extern uint32_t zclient_get_nhg_start(uint32_t proto); extern struct zclient *zclient_new(struct event_loop *m, - struct zclient_options *opt, + const struct zclient_options *opt, zclient_handler *const *handlers, size_t n_handlers); @@ -1012,6 +1070,9 @@ extern int zclient_read_header(struct stream *s, int sock, uint16_t *size, */ extern bool zapi_parse_header(struct stream *zmsg, struct zmsghdr *hdr); +extern enum zclient_send_status zclient_interface_set_arp(struct zclient *client, + struct interface *ifp, + bool arp_enable); extern enum zclient_send_status zclient_interface_set_master(struct zclient *client, struct interface *master, struct interface *slave); @@ -1020,9 +1081,6 @@ extern struct connected *zebra_interface_address_read(int, struct stream *, vrf_id_t); extern struct nbr_connected * zebra_interface_nbr_address_read(int, struct stream *, vrf_id_t); -extern struct interface *zebra_interface_vrf_update_read(struct stream *s, - vrf_id_t vrf_id, - vrf_id_t *new_vrf_id); extern int zebra_router_id_update_read(struct stream *s, struct prefix *rid); extern struct interface *zebra_interface_link_params_read(struct stream *s, @@ -1045,10 +1103,23 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); + +/* Zebra SRv6 Manager flags */ +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE 0x01 +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR 0x02 + extern int srv6_manager_get_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_release_locator_chunk(struct zclient *zclient, const char *locator_name); +extern int srv6_manager_get_locator(struct zclient *zclient, + const char *locator_name); +extern int srv6_manager_get_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name, uint32_t *sid_func); +extern int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, @@ -1103,6 +1174,11 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note); +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note, + char **locator_name); /* Nexthop-group message apis */ extern enum zclient_send_status @@ -1124,18 +1200,6 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, const struct nexthop *nh); int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, const struct nexthop *nh); -/* - * match -> is the prefix that the calling daemon asked to be matched - * against. - * nhr->prefix -> is the actual prefix that was matched against in the - * rib itself. - * - * This distinction is made because a LPM can be made if there is a - * covering route. This way the upper level protocol can make a decision - * point about whether or not it wants to use the match or not. - */ -extern bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, - struct zapi_route *nhr); const char *zapi_nexthop2str(const struct zapi_nexthop *znh, char *buf, int bufsize); @@ -1158,6 +1222,15 @@ static inline void zapi_route_set_blackhole(struct zapi_route *api, SET_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP); }; +static inline void zapi_route_set_nhg_id(struct zapi_route *api, + uint32_t *nhg_id) +{ + api->nexthop_num = 0; + api->nhgid = *nhg_id; + if (api->nhgid) + SET_FLAG(api->message, ZAPI_MESSAGE_NHG); +}; + extern enum zclient_send_status zclient_send_mlag_register(struct zclient *client, uint32_t bit_map); extern enum zclient_send_status @@ -1305,6 +1378,9 @@ enum zapi_opaque_registry { */ extern enum zclient_send_status zclient_send_hello(struct zclient *client); +extern void zclient_register_neigh(struct zclient *zclient, vrf_id_t vrf_id, + afi_t afi, bool reg); + extern enum zclient_send_status zclient_send_neigh_discovery_req(struct zclient *zclient, const struct interface *ifp, diff --git a/lib/zebra.h b/lib/zebra.h index ecc87f58f10f..e042396cbfb7 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -17,17 +17,9 @@ #include #include #include -#include -#include -#include -#include -#include -#include #ifdef HAVE_STROPTS_H #include #endif /* HAVE_STROPTS_H */ -#include -#include #include #include #ifdef HAVE_SYS_SYSCTL_H @@ -37,22 +29,15 @@ #include #endif #endif /* HAVE_SYS_SYSCTL_H */ -#include #ifdef HAVE_SYS_CONF_H #include #endif /* HAVE_SYS_CONF_H */ #ifdef HAVE_SYS_KSYM_H #include #endif /* HAVE_SYS_KSYM_H */ -#include #include #include -#include -#include -#include -#include #include -#include #ifdef HAVE_SYS_ENDIAN_H #include #endif @@ -63,11 +48,6 @@ /* misc include group */ #include -#ifdef HAVE_LCAPS -#include -#include -#endif /* HAVE_LCAPS */ - /* network include group */ #include @@ -76,10 +56,6 @@ #include #endif /* HAVE_SYS_SOCKIO_H */ -#ifdef __APPLE__ -#define __APPLE_USE_RFC_3542 -#endif - #ifndef HAVE_LIBCRYPT #ifdef HAVE_LIBCRYPTO #include @@ -87,15 +63,9 @@ #endif #endif -#ifdef CRYPTO_OPENSSL -#include -#include -#endif - #include "openbsd-tree.h" #include -#include #include #include @@ -113,14 +83,9 @@ #include #endif /* HAVE_NET_IF_VAR_H */ -#include - -#ifdef HAVE_NETLINK -#include -#include -#include -#else +#ifndef HAVE_NETLINK #define RT_TABLE_MAIN 0 +#define RT_TABLE_LOCAL RT_TABLE_MAIN #endif /* HAVE_NETLINK */ #include @@ -146,37 +111,14 @@ #include #endif /* HAVE_NETINET6_IN_H */ - #ifdef HAVE_NETINET6_IP6_H #include #endif /* HAVE_NETINET6_IP6_H */ -#include - #ifdef HAVE_NETINET6_ND6_H #include #endif /* HAVE_NETINET6_ND6_H */ -/* Some systems do not define UINT32_MAX, etc.. from inttypes.h - * e.g. this makes life easier for FBSD 4.11 users. - */ -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#ifdef HAVE_GLIBC_BACKTRACE -#include -#endif /* HAVE_GLIBC_BACKTRACE */ - /* Local includes: */ #if !defined(__GNUC__) #define __attribute__(x) @@ -210,26 +152,6 @@ size_t strlcpy(char *__restrict dest, void explicit_bzero(void *buf, size_t len); #endif -#if !defined(HAVE_STRUCT_MMSGHDR_MSG_HDR) || !defined(HAVE_SENDMMSG) -/* avoid conflicts in case we have partial support */ -#define mmsghdr frr_mmsghdr -#define sendmmsg frr_sendmmsg - -struct mmsghdr { - struct msghdr msg_hdr; - unsigned int msg_len; -}; - -/* just go 1 at a time here, the loop this is used in will handle the rest */ -static inline int sendmmsg(int fd, struct mmsghdr *mmh, unsigned int len, - int flags) -{ - int rv = sendmsg(fd, &mmh->msg_hdr, 0); - - return rv > 0 ? 1 : rv; -} -#endif - /* * RFC 3542 defines several macros for using struct cmsghdr. * Here, we define those that are not present @@ -283,10 +205,9 @@ struct in_pktinfo { * OpenBSD: network byte order, apart from older versions which are as per * *BSD */ -#if defined(__NetBSD__) \ - || (defined(__FreeBSD__) && (__FreeBSD_version < 1100030)) \ - || (defined(__OpenBSD__) && (OpenBSD < 200311)) \ - || (defined(__APPLE__)) +#if defined(__NetBSD__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version < 1100030)) || \ + (defined(__OpenBSD__) && (OpenBSD < 200311)) #define HAVE_IP_HDRINCL_BSD_ORDER #endif @@ -300,15 +221,6 @@ struct in_pktinfo { #define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL #endif /* IN6_ARE_ADDR_EQUAL */ -/* default zebra TCP port for zclient */ -#define ZEBRA_PORT 2600 - -/* - * The compiler.h header is used for anyone using the CPP_NOTICE - * since this is universally needed, let's add it to zebra.h - */ -#include "compiler.h" - /* Zebra route's types are defined in route_types.h */ #include "lib/route_types.h" @@ -347,7 +259,8 @@ typedef enum { SAFI_EVPN = 5, SAFI_LABELED_UNICAST = 6, SAFI_FLOWSPEC = 7, - SAFI_MAX = 8 + SAFI_RTC = 8, /* BGP-RTC RFC 4684 */ + SAFI_MAX = 9, } safi_t; #define FOREACH_AFI_SAFI(afi, safi) \ @@ -358,27 +271,6 @@ typedef enum { for (afi = AFI_IP; afi < AFI_MAX; afi++) \ for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) -/* Default Administrative Distance of each protocol. */ -#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 -#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 -#define ZEBRA_STATIC_DISTANCE_DEFAULT 1 -#define ZEBRA_RIP_DISTANCE_DEFAULT 120 -#define ZEBRA_RIPNG_DISTANCE_DEFAULT 120 -#define ZEBRA_OSPF_DISTANCE_DEFAULT 110 -#define ZEBRA_OSPF6_DISTANCE_DEFAULT 110 -#define ZEBRA_ISIS_DISTANCE_DEFAULT 115 -#define ZEBRA_IBGP_DISTANCE_DEFAULT 200 -#define ZEBRA_EBGP_DISTANCE_DEFAULT 20 -#define ZEBRA_TABLE_DISTANCE_DEFAULT 15 -#define ZEBRA_EIGRP_DISTANCE_DEFAULT 90 -#define ZEBRA_NHRP_DISTANCE_DEFAULT 10 -#define ZEBRA_LDP_DISTANCE_DEFAULT 150 -#define ZEBRA_BABEL_DISTANCE_DEFAULT 100 -#define ZEBRA_SHARP_DISTANCE_DEFAULT 150 -#define ZEBRA_PBR_DISTANCE_DEFAULT 200 -#define ZEBRA_OPENFABRIC_DISTANCE_DEFAULT 115 -#define ZEBRA_MAX_DISTANCE_DEFAULT 255 - /* Flag manipulation macros. */ #define CHECK_FLAG(V,F) ((V) & (F)) #define SET_FLAG(V,F) (V) |= (F) diff --git a/lib/zlog.c b/lib/zlog.c index 309a955fa90a..ffca5726095b 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -4,6 +4,12 @@ */ #include "zebra.h" +#include +#include + +#ifdef HAVE_GLIBC_BACKTRACE +#include +#endif /* HAVE_GLIBC_BACKTRACE */ #include #include @@ -32,9 +38,6 @@ #ifdef __DragonFly__ #include #endif -#ifdef __APPLE__ -#include -#endif #ifdef HAVE_LIBUNWIND #define UNW_LOCAL_ONLY @@ -47,6 +50,7 @@ #include "printfrr.h" #include "frrcu.h" #include "zlog.h" +#include "zlog_live.h" #include "libfrr_trace.h" #include "frrevent.h" @@ -81,7 +85,7 @@ static struct zlog_targets_head zlog_targets; /* Global setting for buffered vs immediate output. The default is * per-pthread buffering. */ -static bool default_immediate; +static bool zlog_default_immediate; /* cf. zlog.h for additional comments on this struct. * @@ -106,6 +110,9 @@ struct zlog_msg { size_t textlen; size_t hdrlen; + /* for relayed log messages ONLY (cf. zlog_recirculate_live_msg) */ + intmax_t pid, tid; + /* This is always ISO8601 with sub-second precision 9 here, it's * converted for callers as needed. ts_dot points to the "." * separating sub-seconds. ts_zonetail is "Z" or "+00:00" for the @@ -354,6 +361,16 @@ void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid) { #ifndef __OpenBSD__ static thread_local intmax_t cached_pid = -1; +#endif + + /* recirculated messages */ + if (msg->pid) { + *pid = msg->pid; + *tid = msg->tid; + return; + } + +#ifndef __OpenBSD__ if (cached_pid != -1) *pid = cached_pid; else @@ -442,7 +459,7 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref, struct zlog_msg *msg; char *buf; bool ignoremsg = true; - bool immediate = default_immediate; + bool immediate = zlog_default_immediate; /* avoid further processing cost if no target wants this message */ rcu_read_lock(); @@ -504,6 +521,89 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref, XFREE(MTYPE_LOG_MESSAGE, msg->text); } +/* reinject log message received by zlog_recirculate_recv(). As of writing, + * only used in the ldpd parent process to proxy messages from lde/ldpe + * subprocesses. + */ +void zlog_recirculate_live_msg(uint8_t *data, size_t len) +{ + struct zlog_target *zt; + struct zlog_msg stackmsg = {}, *msg = &stackmsg; + struct zlog_live_hdr *hdr; + struct xrefdata *xrefdata, ref = {}; + + if (len < sizeof(*hdr)) + return; + + hdr = (struct zlog_live_hdr *)data; + if (hdr->hdrlen < sizeof(*hdr)) + return; + data += hdr->hdrlen; + len -= sizeof(*hdr); + + msg->ts.tv_sec = hdr->ts_sec; + msg->ts.tv_nsec = hdr->ts_nsec; + msg->pid = hdr->pid; + msg->tid = hdr->tid; + msg->prio = hdr->prio; + + if (hdr->textlen > len) + return; + msg->textlen = hdr->textlen; + msg->hdrlen = hdr->texthdrlen; + msg->text = (char *)data; + + /* caller needs to make sure we have a trailing \n\0, it's not + * transmitted on zlog_live + */ + if (msg->text[msg->textlen] != '\n' || + msg->text[msg->textlen + 1] != '\0') + return; + + static_assert(sizeof(msg->argpos[0]) == sizeof(hdr->argpos[0]), + "in-memory struct doesn't match on-wire variant"); + msg->n_argpos = MIN(hdr->n_argpos, array_size(msg->argpos)); + memcpy(msg->argpos, hdr->argpos, msg->n_argpos * sizeof(msg->argpos[0])); + + /* This will only work if we're in the same daemon: we received a log + * message uid and are now doing a lookup in *our* known uids to find + * it. This works for ldpd because it's the same binary containing the + * same log messages, and ldpd is the only use case right now. + * + * When the uid is not found, the log message uid is lost but the + * message itself is still processed correctly. If this is needed, + * this can be made to work in two ways: + * (a) synthesize a temporary xref_logmsg from the received data. + * This is a bit annoying due to lifetimes with per-thread buffers. + * (b) extract and aggregate all log messages. This already happens + * with frr.xref but that would need to be fed back in. + */ + strlcpy(ref.uid, hdr->uid, sizeof(ref.uid)); + xrefdata = xrefdata_uid_find(&xrefdata_uid, &ref); + + if (xrefdata && xrefdata->xref->type == XREFT_LOGMSG) { + struct xref_logmsg *xref_logmsg; + + xref_logmsg = (struct xref_logmsg *)xrefdata->xref; + msg->xref = xref_logmsg; + msg->fmt = xref_logmsg->fmtstring; + } else { + /* fake out format string... */ + msg->fmt = msg->text + hdr->texthdrlen; + } + + rcu_read_lock(); + frr_each_safe (zlog_targets, &zlog_targets, zt) { + if (msg->prio > zt->prio_min) + continue; + if (!zt->logfn) + continue; + + zt->logfn(zt, &msg, 1); + } + rcu_read_unlock(); +} + static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio) { struct event *tc = pthread_getspecific(thread_current); @@ -963,7 +1063,12 @@ struct zlog_target *zlog_target_replace(struct zlog_target *oldzt, */ void zlog_set_immediate(bool set_p) { - default_immediate = set_p; + zlog_default_immediate = set_p; +} + +bool zlog_get_immediate_mode(void) +{ + return zlog_default_immediate; } /* common init */ diff --git a/lib/zlog.h b/lib/zlog.h index a207b29a3b6d..9d9397995778 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -125,6 +125,9 @@ static inline void zlog_ref(const struct xref_logmsg *xref, extern void zlog_sigsafe(const char *text, size_t len); +/* recirculate a log message from zlog_live */ +extern void zlog_recirculate_live_msg(uint8_t *data, size_t len); + /* extra priority value to disable a target without deleting it */ #define ZLOG_DISABLED (LOG_EMERG-1) @@ -276,6 +279,7 @@ extern void zlog_tls_buffer_fini(void); /* Enable or disable 'immediate' output - default is to buffer messages. */ extern void zlog_set_immediate(bool set_p); +bool zlog_get_immediate_mode(void); extern const char *zlog_priority_str(int priority); diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c index 9bc1c819a857..4c60d4b40564 100644 --- a/lib/zlog_5424.c +++ b/lib/zlog_5424.c @@ -13,6 +13,9 @@ */ #include "zebra.h" +#include + +#include "frrsendmmsg.h" #include "zlog_5424.h" @@ -913,7 +916,7 @@ static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type) } flags = O_NONBLOCK; - /* fallthru */ + fallthrough; case ZLOG_5424_DST_FILE: if (!zcf->filename) diff --git a/lib/zlog_live.c b/lib/zlog_live.c index 4d3c3508bffd..1b7696c893d0 100644 --- a/lib/zlog_live.c +++ b/lib/zlog_live.c @@ -5,6 +5,8 @@ #include "zebra.h" +#include "frrsendmmsg.h" + #include "zlog_live.h" #include "memory.h" diff --git a/lib/zlog_recirculate.c b/lib/zlog_recirculate.c new file mode 100644 index 000000000000..abc73eeed007 --- /dev/null +++ b/lib/zlog_recirculate.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2024 David Lamparter, for NetDEF, Inc. + */ + +#include "zebra.h" + +#include "log.h" +#include "frrevent.h" + +#include "zlog_recirculate.h" + +/* This is only the event loop part; it's split off from + * zlog_recirculate_live_msg since there's an integration boundary; this + * half deals with events, the other half with zlog interna. + * + * As of writing, this runs in ldpd in the *parent* process and receives log + * messages from the lde/ldpe subprocesses. It is not used anywhere else + * (yet?) + */ +static void zlog_recirculate_recv(struct event *ev) +{ + uint8_t rxbuf[4096]; + ssize_t n_rd; + int fd = EVENT_FD(ev); + + /* see below for -2, "\n\0" are added */ + n_rd = read(fd, rxbuf, sizeof(rxbuf) - 2); + if (n_rd == 0) { + /* EOF */ + close(fd); + /* event_add_read not called yet, nothing to cancel */ + return; + } + if (n_rd < 0 && (errno != EAGAIN) && (errno != EWOULDBLOCK)) { + /* error */ + zlog_warn("error on log relay socket %d: %m", fd); + close(fd); + /* event_add_read not called yet, nothing to cancel */ + return; + } + + event_add_read(ev->master, zlog_recirculate_recv, NULL, fd, NULL); + if (n_rd < 0) + return; + + /* log infrastructure has an implicit \n\0 at the end */ + rxbuf[n_rd] = '\n'; + rxbuf[n_rd + 1] = '\0'; + zlog_recirculate_live_msg(rxbuf, n_rd); +} + +void zlog_recirculate_subscribe(struct event_loop *el, int fd) +{ + event_add_read(el, zlog_recirculate_recv, NULL, fd, NULL); +} diff --git a/lib/zlog_recirculate.h b/lib/zlog_recirculate.h new file mode 100644 index 000000000000..a2ddb4e172d0 --- /dev/null +++ b/lib/zlog_recirculate.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2024 David Lamparter, for NetDEF, Inc. + */ + +#ifndef _FRR_ZLOG_RECIRCULATE_H +#define _FRR_ZLOG_RECIRCULATE_H + +/* fd should be one end of a socketpair() */ +extern void zlog_recirculate_subscribe(struct event_loop *tm, int fd); + +#endif diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c index b0f757149256..bbd228f28c7b 100644 --- a/lib/zlog_targets.c +++ b/lib/zlog_targets.c @@ -5,6 +5,7 @@ #include "zebra.h" +#include #include #include diff --git a/m4/.gitignore b/m4/.gitignore index 63f9fa78edd4..37888dd46c0c 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -7,6 +7,7 @@ !ax_prog_perl_modules.m4 !ax_pthread.m4 !ax_python.m4 +!ax_recursive_eval.m4 !ax_sys_weak_alias.m4 !ax_sys_weak_alias.m4 !pkg.m4 diff --git a/m4/ax_recursive_eval.m4 b/m4/ax_recursive_eval.m4 new file mode 100644 index 000000000000..02836025f770 --- /dev/null +++ b/m4/ax_recursive_eval.m4 @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later WITH Autoconf-exception-2.0 +# +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_recursive_eval.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_RECURSIVE_EVAL(VALUE, RESULT) +# +# DESCRIPTION +# +# Interpolate the VALUE in loop until it doesn't change, and set the +# result to $RESULT. This version has a recursion limit (10). +# +# LICENSE +# +# Copyright (c) 2008 Alexandre Duret-Lutz +# Copyright (c) 2024 David Lamparter + +AC_DEFUN([AX_RECURSIVE_EVAL], +[_lcl_receval="$1" +$2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" + _lcl_receval_old='' + for _rec_limit in 1 2 3 4 5 6 7 8 9 10; do + test "[$]_lcl_receval_old" = "[$]_lcl_receval" && break + _lcl_receval_old="[$]_lcl_receval" + eval _lcl_receval="\"[$]_lcl_receval\"" + done + echo "[$]_lcl_receval")`]) diff --git a/mgmtd/.gitignore b/mgmtd/.gitignore index 7ce107e93bb6..e12bcc08cd65 100644 --- a/mgmtd/.gitignore +++ b/mgmtd/.gitignore @@ -1 +1,2 @@ mgmtd +mgmtd_testc diff --git a/mgmtd/mgmt.c b/mgmtd/mgmt.c index 77c4473e49f1..fe0357e7e4ce 100644 --- a/mgmtd/mgmt.c +++ b/mgmtd/mgmt.c @@ -15,9 +15,9 @@ #include "mgmtd/mgmt_history.h" #include "mgmtd/mgmt_memory.h" -struct debug mgmt_debug_be = {.desc = "Management backend adapater"}; +struct debug mgmt_debug_be = { .desc = "Management backend adapter" }; struct debug mgmt_debug_ds = {.desc = "Management datastore"}; -struct debug mgmt_debug_fe = {.desc = "Management frontend adapater"}; +struct debug mgmt_debug_fe = { .desc = "Management frontend adapter" }; struct debug mgmt_debug_txn = {.desc = "Management transaction"}; /* MGMTD process wide configuration. */ @@ -52,17 +52,26 @@ void mgmt_init(void) /* Initialize the MGMTD Frontend Adapter Module */ mgmt_fe_adapter_init(mm->master); - /* Initialize the CLI frontend client */ + /* + * Initialize the CLI frontend client -- this queues an event for the + * client to short-circuit connect to the server (ourselves). + */ vty_init_mgmt_fe(); - /* MGMTD VTY commands installation. */ + /* + * MGMTD VTY commands installation -- the frr lib code will queue an + * event to read the config files which needs to happen after the + * connect from above is made. + */ mgmt_vty_init(); /* * Initialize the MGMTD Backend Adapter Module * - * We do this after the FE stuff so that we always read our config file - * prior to any BE connection. + * We do this after the FE stuff so that we have read our config file + * prior to any BE connection. Setting up the server will queue a + * "socket read" event to accept BE connections. So the code is counting + * on the above 2 events to run prior to any `accept` event from here. */ mgmt_be_adapter_init(mm->master); } diff --git a/mgmtd/mgmt.h b/mgmtd/mgmt.h index f52d478bc2c5..665e8d8fd853 100644 --- a/mgmtd/mgmt.h +++ b/mgmtd/mgmt.h @@ -13,14 +13,13 @@ #include "vrf.h" #include "defaults.h" #include "stream.h" +#include "mgmt_defines.h" #include "mgmtd/mgmt_memory.h" -#include "mgmtd/mgmt_defines.h" #include "mgmtd/mgmt_history.h" #include "mgmtd/mgmt_txn.h" #include "mgmtd/mgmt_ds.h" -#define MGMTD_VTY_PORT 2622 #define MGMTD_SOCKET_BUF_SIZE 65535 #define MGMTD_MAX_COMMIT_LIST 10 @@ -70,11 +69,6 @@ struct mgmt_master { extern struct mgmt_master *mm; /* Inline functions */ -static inline unsigned long timeval_elapsed(struct timeval a, struct timeval b) -{ - return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO) - + (a.tv_usec - b.tv_usec)); -} /* * Remove trailing separator from a string. diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index 399fdafded1a..f1c5424d0a1e 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -10,76 +10,160 @@ #include #include "darr.h" #include "frrevent.h" +#include "frrstr.h" #include "sockopt.h" #include "network.h" #include "libfrr.h" #include "mgmt_msg.h" +#include "mgmt_msg_native.h" #include "mgmt_pb.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_memory.h" #include "mgmt_be_client.h" #include "mgmtd/mgmt_be_adapter.h" -#define MGMTD_BE_ADAPTER_DBG(fmt, ...) \ +#define __dbg(fmt, ...) \ DEBUGD(&mgmt_debug_be, "BE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_BE_ADAPTER_ERR(fmt, ...) \ +#define __log_err(fmt, ...) \ zlog_err("BE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) #define FOREACH_ADAPTER_IN_LIST(adapter) \ frr_each_safe (mgmt_be_adapters, &mgmt_be_adapters, (adapter)) +/* ---------- */ +/* Client IDs */ +/* ---------- */ + +const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = { + [MGMTD_BE_CLIENT_ID_TESTC] = "mgmtd-testc", /* always first */ + [MGMTD_BE_CLIENT_ID_ZEBRA] = "zebra", +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = "ripd", +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = "ripngd", +#endif +#ifdef HAVE_STATICD + [MGMTD_BE_CLIENT_ID_STATICD] = "staticd", +#endif + [MGMTD_BE_CLIENT_ID_MAX] = "Unknown/Invalid", +}; + +/* ------------- */ +/* XPATH MAPPING */ +/* ------------- */ + /* - * Mapping of YANG XPath regular expressions to - * their corresponding backend clients. + * Mapping of YANG XPath prefixes to their corresponding backend clients. */ struct mgmt_be_xpath_map { - char *xpath_regexp; - uint subscr_info[MGMTD_BE_CLIENT_ID_MAX]; + char *xpath_prefix; + uint64_t clients; }; -struct mgmt_be_client_xpath { - const char *xpath; - uint subscribed; +/* + * Each client gets their own map, but also union all the strings into the + * above map as well. + */ + +static const char *const zebra_config_xpaths[] = { + "/frr-affinity-map:lib", + "/frr-filter:lib", + "/frr-route-map:lib", + "/frr-zebra:zebra", + "/frr-interface:lib", + "/frr-vrf:lib", + NULL, }; -struct mgmt_be_client_xpath_map { - struct mgmt_be_client_xpath *xpaths; - uint nxpaths; +static const char *const zebra_oper_xpaths[] = { + "/frr-interface:lib/interface", + "/frr-vrf:lib/vrf/frr-zebra:zebra", + "/frr-zebra:zebra", + NULL, }; -struct mgmt_be_get_adapter_config_params { - struct mgmt_be_client_adapter *adapter; - struct nb_config_cbs *cfg_chgs; - uint32_t seq; +#if HAVE_RIPD +static const char *const ripd_config_xpaths[] = { + "/frr-filter:lib", + "/frr-interface:lib/interface", + "/frr-ripd:ripd", + "/frr-route-map:lib", + "/frr-vrf:lib", + "/ietf-key-chain:key-chains", + NULL, +}; +static const char *const ripd_oper_xpaths[] = { + "/frr-ripd:ripd", + "/ietf-key-chain:key-chains", + NULL, }; +static const char *const ripd_rpc_xpaths[] = { + "/frr-ripd", + NULL, +}; +#endif + +#if HAVE_RIPNGD +static const char *const ripngd_config_xpaths[] = { + "/frr-filter:lib", + "/frr-interface:lib/interface", + "/frr-ripngd:ripngd", + "/frr-route-map:lib", + "/frr-vrf:lib", + NULL, +}; +static const char *const ripngd_oper_xpaths[] = { + "/frr-ripngd:ripngd", + NULL, +}; +static const char *const ripngd_rpc_xpaths[] = { + "/frr-ripngd", + NULL, +}; +#endif -/* - * Each client gets their own map, but also union all the strings into the - * above map as well. - */ #if HAVE_STATICD -static struct mgmt_be_client_xpath staticd_xpaths[] = { - { - .xpath = "/frr-vrf:lib/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, - { - .xpath = "/frr-interface:lib/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, - { - .xpath = - "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/*", - .subscribed = MGMT_SUBSCR_VALIDATE_CFG | MGMT_SUBSCR_NOTIFY_CFG, - }, +static const char *const staticd_config_xpaths[] = { + "/frr-vrf:lib", + "/frr-interface:lib", + "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd", + NULL, }; #endif -static struct mgmt_be_client_xpath_map - mgmt_client_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { +static const char *const *be_client_config_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { + [MGMTD_BE_CLIENT_ID_ZEBRA] = zebra_config_xpaths, +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = ripd_config_xpaths, +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = ripngd_config_xpaths, +#endif #ifdef HAVE_STATICD - [MGMTD_BE_CLIENT_ID_STATICD] = {staticd_xpaths, - array_size(staticd_xpaths)}, + [MGMTD_BE_CLIENT_ID_STATICD] = staticd_config_xpaths, +#endif +}; + +static const char *const *be_client_oper_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = ripd_oper_xpaths, +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = ripngd_oper_xpaths, +#endif + [MGMTD_BE_CLIENT_ID_ZEBRA] = zebra_oper_xpaths, +}; + +static const char *const *be_client_notif_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { +}; + +static const char *const *be_client_rpc_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { +#ifdef HAVE_RIPD + [MGMTD_BE_CLIENT_ID_RIPD] = ripd_rpc_xpaths, +#endif +#ifdef HAVE_RIPNGD + [MGMTD_BE_CLIENT_ID_RIPNGD] = ripngd_rpc_xpaths, #endif }; @@ -91,7 +175,11 @@ static struct mgmt_be_client_xpath_map * says this probably involves exact match/no-match on a stem in the map array * or something like that. */ -static struct mgmt_be_xpath_map *mgmt_xpath_map; + +static struct mgmt_be_xpath_map *be_cfg_xpath_map; +static struct mgmt_be_xpath_map *be_oper_xpath_map; +static struct mgmt_be_xpath_map *be_notif_xpath_map; +static struct mgmt_be_xpath_map *be_rpc_xpath_map; static struct event_loop *mgmt_loop; static struct msg_server mgmt_be_server = {.fd = -1}; @@ -101,12 +189,33 @@ static struct mgmt_be_adapters_head mgmt_be_adapters; static struct mgmt_be_client_adapter *mgmt_be_adapters_by_id[MGMTD_BE_CLIENT_ID_MAX]; + /* Forward declarations */ static void mgmt_be_adapter_sched_init_event(struct mgmt_be_client_adapter *adapter); -static uint mgmt_be_get_subscr_for_xpath_and_client( - const char *xpath, enum mgmt_be_client_id client_id, uint subscr_mask); +static bool be_is_client_interested(const char *xpath, enum mgmt_be_client_id id, + enum mgmt_be_xpath_subscr_type type); + +const char *mgmt_be_client_id2name(enum mgmt_be_client_id id) +{ + if (id > MGMTD_BE_CLIENT_ID_MAX) + return "invalid client id"; + return mgmt_be_client_names[id]; +} + +static enum mgmt_be_client_id mgmt_be_client_name2id(const char *name) +{ + enum mgmt_be_client_id id; + + FOREACH_MGMTD_BE_CLIENT_ID (id) { + if (!strncmp(mgmt_be_client_names[id], name, + MGMTD_CLIENT_NAME_MAX_LEN)) + return id; + } + + return MGMTD_BE_CLIENT_ID_MAX; +} static struct mgmt_be_client_adapter * mgmt_be_find_adapter_by_fd(int conn_fd) @@ -135,183 +244,134 @@ mgmt_be_find_adapter_by_name(const char *name) } static void mgmt_register_client_xpath(enum mgmt_be_client_id id, - const char *xpath, uint subscribed) + const char *xpath, + enum mgmt_be_xpath_subscr_type type) { - struct mgmt_be_xpath_map *map; + struct mgmt_be_xpath_map **maps, *map; - darr_foreach_p (mgmt_xpath_map, map) - if (!strcmp(xpath, map->xpath_regexp)) { - map->subscr_info[id] = subscribed; + switch (type) { + case MGMT_BE_XPATH_SUBSCR_TYPE_CFG: + maps = &be_cfg_xpath_map; + break; + case MGMT_BE_XPATH_SUBSCR_TYPE_OPER: + maps = &be_oper_xpath_map; + break; + case MGMT_BE_XPATH_SUBSCR_TYPE_NOTIF: + maps = &be_notif_xpath_map; + break; + case MGMT_BE_XPATH_SUBSCR_TYPE_RPC: + maps = &be_rpc_xpath_map; + break; + } + + darr_foreach_p (*maps, map) { + if (!strcmp(xpath, map->xpath_prefix)) { + map->clients |= (1u << id); return; } + } /* we didn't find a matching entry */ - map = darr_append(mgmt_xpath_map); - map->xpath_regexp = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); - map->subscr_info[id] = subscribed; + map = darr_append(*maps); + map->xpath_prefix = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); + map->clients = (1ul << id); } /* - * Load the initial mapping from static init map + * initial the combined maps from per client maps */ static void mgmt_be_xpath_map_init(void) { - struct mgmt_be_client_xpath *init, *end; enum mgmt_be_client_id id; + const char *const *init; - MGMTD_BE_ADAPTER_DBG("Init XPath Maps"); + __dbg("Init XPath Maps"); FOREACH_MGMTD_BE_CLIENT_ID (id) { - init = mgmt_client_xpaths[id].xpaths; - end = init + mgmt_client_xpaths[id].nxpaths; - for (; init < end; init++) { - MGMTD_BE_ADAPTER_DBG(" - XPATH: '%s'", init->xpath); - mgmt_register_client_xpath(id, init->xpath, - init->subscribed); + /* Initialize the common config init map */ + for (init = be_client_config_xpaths[id]; init && *init; init++) { + __dbg(" - CFG XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, + MGMT_BE_XPATH_SUBSCR_TYPE_CFG); + } + + /* Initialize the common oper init map */ + for (init = be_client_oper_xpaths[id]; init && *init; init++) { + __dbg(" - OPER XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, + MGMT_BE_XPATH_SUBSCR_TYPE_OPER); + } + + /* Initialize the common NOTIF init map */ + for (init = be_client_notif_xpaths[id]; init && *init; init++) { + __dbg(" - NOTIF XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, + MGMT_BE_XPATH_SUBSCR_TYPE_NOTIF); + } + + /* Initialize the common RPC init map */ + for (init = be_client_rpc_xpaths[id]; init && *init; init++) { + __dbg(" - RPC XPATH: '%s'", *init); + mgmt_register_client_xpath(id, *init, + MGMT_BE_XPATH_SUBSCR_TYPE_RPC); } } - MGMTD_BE_ADAPTER_DBG("Total XPath Maps: %u", darr_len(mgmt_xpath_map)); + __dbg("Total Cfg XPath Maps: %u", darr_len(be_cfg_xpath_map)); + __dbg("Total Oper XPath Maps: %u", darr_len(be_oper_xpath_map)); + __dbg("Total Noitf XPath Maps: %u", darr_len(be_notif_xpath_map)); + __dbg("Total RPC XPath Maps: %u", darr_len(be_rpc_xpath_map)); } static void mgmt_be_xpath_map_cleanup(void) { struct mgmt_be_xpath_map *map; - darr_foreach_p (mgmt_xpath_map, map) - XFREE(MTYPE_MGMTD_XPATH, map->xpath_regexp); - darr_free(mgmt_xpath_map); -} - -static int mgmt_be_eval_regexp_match(const char *xpath_regexp, - const char *xpath) -{ - int match_len = 0, re_indx = 0, xp_indx = 0; - int rexp_len, xpath_len; - bool match = true, re_wild = false, xp_wild = false; - bool delim = false, enter_wild_match = false; - char wild_delim = 0; - - rexp_len = strlen(xpath_regexp); - xpath_len = strlen(xpath); + darr_foreach_p (be_cfg_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_cfg_xpath_map); - /* - * Remove the trailing wildcard from the regexp and Xpath. - */ - if (rexp_len && xpath_regexp[rexp_len-1] == '*') - rexp_len--; - if (xpath_len && xpath[xpath_len-1] == '*') - xpath_len--; + darr_foreach_p (be_oper_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_oper_xpath_map); - if (!rexp_len || !xpath_len) - return 0; + darr_foreach_p (be_notif_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_notif_xpath_map); - for (re_indx = 0, xp_indx = 0; - match && re_indx < rexp_len && xp_indx < xpath_len;) { - match = (xpath_regexp[re_indx] == xpath[xp_indx]); - - /* - * Check if we need to enter wildcard matching. - */ - if (!enter_wild_match && !match && - (xpath_regexp[re_indx] == '*' - || xpath[xp_indx] == '*')) { - /* - * Found wildcard - */ - enter_wild_match = - (xpath_regexp[re_indx-1] == '/' - || xpath_regexp[re_indx-1] == '\'' - || xpath[xp_indx-1] == '/' - || xpath[xp_indx-1] == '\''); - if (enter_wild_match) { - if (xpath_regexp[re_indx] == '*') { - /* - * Begin RE wildcard match. - */ - re_wild = true; - wild_delim = xpath_regexp[re_indx-1]; - } else if (xpath[xp_indx] == '*') { - /* - * Begin XP wildcard match. - */ - xp_wild = true; - wild_delim = xpath[xp_indx-1]; - } - } - } + darr_foreach_p (be_rpc_xpath_map, map) + XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix); + darr_free(be_rpc_xpath_map); +} - /* - * Check if we need to exit wildcard matching. - */ - if (enter_wild_match) { - if (re_wild && xpath[xp_indx] == wild_delim) { - /* - * End RE wildcard matching. - */ - re_wild = false; - if (re_indx < rexp_len-1) - re_indx++; - enter_wild_match = false; - } else if (xp_wild - && xpath_regexp[re_indx] == wild_delim) { - /* - * End XP wildcard matching. - */ - xp_wild = false; - if (xp_indx < xpath_len-1) - xp_indx++; - enter_wild_match = false; - } - } - match = (xp_wild || re_wild - || xpath_regexp[re_indx] == xpath[xp_indx]); +/* + * Check if either path or xpath is a prefix of the other. Before checking the + * xpath is converted to a regular path string (e..g, removing key value + * specifiers). + */ +static bool mgmt_be_xpath_prefix(const char *path, const char *xpath) +{ + int xc, pc; - /* - * Check if we found a delimiter in both the Xpaths - */ - if ((xpath_regexp[re_indx] == '/' - && xpath[xp_indx] == '/') - || (xpath_regexp[re_indx] == ']' - && xpath[xp_indx] == ']') - || (xpath_regexp[re_indx] == '[' - && xpath[xp_indx] == '[')) { - /* - * Increment the match count if we have a - * new delimiter. - */ - if (match && re_indx && xp_indx && !delim) - match_len++; - delim = true; - } else { - delim = false; + while ((xc = *xpath++)) { + if (xc == '[') { + xpath = frrstr_skip_over_char(xpath, ']'); + if (!xpath) + return false; + continue; } - - /* - * Proceed to the next character in the RE/XP string as - * necessary. - */ - if (!re_wild) - re_indx++; - if (!xp_wild) - xp_indx++; + pc = *path++; + if (!pc) + return true; + if (pc != xc) + return false; } - - /* - * If we finished matching and the last token was a full match - * increment the match count appropriately. - */ - if (match && !delim && - (xpath_regexp[re_indx] == '/' - || xpath_regexp[re_indx] == ']')) - match_len++; - - return match_len; + return true; } static void mgmt_be_adapter_delete(struct mgmt_be_client_adapter *adapter) { - MGMTD_BE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name); + __dbg("deleting client adapter '%s'", adapter->name); /* * Notify about disconnect for appropriate cleanup @@ -330,8 +390,7 @@ static int mgmt_be_adapter_notify_disconnect(struct msg_conn *conn) { struct mgmt_be_client_adapter *adapter = conn->user; - MGMTD_BE_ADAPTER_DBG("notify disconnect for client adapter '%s'", - adapter->name); + __dbg("notify disconnect for client adapter '%s'", adapter->name); mgmt_be_adapter_delete(adapter); @@ -349,17 +408,14 @@ mgmt_be_adapter_cleanup_old_conn(struct mgmt_be_client_adapter *adapter) /* * We have a Zombie lingering around */ - MGMTD_BE_ADAPTER_DBG( - "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!", - adapter->name, adapter->conn->fd, - old->conn->fd); + __dbg("Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!", + adapter->name, adapter->conn->fd, old->conn->fd); /* this will/should delete old */ msg_conn_disconnect(old->conn, false); } } } - static int mgmt_be_adapter_send_msg(struct mgmt_be_client_adapter *adapter, Mgmtd__BeMessage *be_msg) { @@ -382,8 +438,8 @@ static int mgmt_be_send_subscr_reply(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY; be_msg.subscr_reply = &reply; - MGMTD_FE_CLIENT_DBG("Sending SUBSCR_REPLY client: %s sucess: %u", - adapter->name, success); + __dbg("Sending SUBSCR_REPLY client: %s success: %u", adapter->name, + success); return mgmt_be_adapter_send_msg(adapter, &be_msg); } @@ -392,32 +448,31 @@ static int mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, Mgmtd__BeMessage *be_msg) { + const char *xpath; + uint i, num; + /* * protobuf-c adds a max size enum with an internal, and changing by * version, name; cast to an int to avoid unhandled enum warnings */ switch ((int)be_msg->message_case) { case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ: - MGMTD_BE_ADAPTER_DBG( - "Got SUBSCR_REQ from '%s' to %sregister %zu xpaths", - be_msg->subscr_req->client_name, - !be_msg->subscr_req->subscribe_xpaths && - be_msg->subscr_req->n_xpath_reg - ? "de" - : "", - be_msg->subscr_req->n_xpath_reg); + __dbg("Got SUBSCR_REQ from '%s' to register xpaths config: %zu oper: %zu notif: %zu rpc: %zu", + be_msg->subscr_req->client_name, + be_msg->subscr_req->n_config_xpaths, + be_msg->subscr_req->n_oper_xpaths, + be_msg->subscr_req->n_notif_xpaths, + be_msg->subscr_req->n_rpc_xpaths); if (strlen(be_msg->subscr_req->client_name)) { strlcpy(adapter->name, be_msg->subscr_req->client_name, sizeof(adapter->name)); adapter->id = mgmt_be_client_name2id(adapter->name); if (adapter->id >= MGMTD_BE_CLIENT_ID_MAX) { - MGMTD_BE_ADAPTER_ERR( - "Unable to resolve adapter '%s' to a valid ID. Disconnecting!", - adapter->name); + __log_err("Unable to resolve adapter '%s' to a valid ID. Disconnecting!", + adapter->name); /* this will/should delete old */ msg_conn_disconnect(adapter->conn, false); - zlog_err("XXX different from original code"); break; } mgmt_be_adapters_by_id[adapter->id] = adapter; @@ -427,19 +482,41 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, mgmt_be_adapter_sched_init_event(adapter); } - if (be_msg->subscr_req->n_xpath_reg) - /* we aren't handling dynamic xpaths yet */ - mgmt_be_send_subscr_reply(adapter, false); - else - mgmt_be_send_subscr_reply(adapter, true); + num = be_msg->subscr_req->n_config_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->config_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_CFG); + } + + num = be_msg->subscr_req->n_oper_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->oper_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_OPER); + } + + num = be_msg->subscr_req->n_notif_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->notif_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_NOTIF); + } + + num = be_msg->subscr_req->n_rpc_xpaths; + for (i = 0; i < num; i++) { + xpath = be_msg->subscr_req->rpc_xpaths[i]; + mgmt_register_client_xpath(adapter->id, xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_RPC); + } + + mgmt_be_send_subscr_reply(adapter, true); break; case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY: - MGMTD_BE_ADAPTER_DBG( - "Got %s TXN_REPLY from '%s' txn-id %" PRIx64 - " with '%s'", - be_msg->txn_reply->create ? "Create" : "Delete", - adapter->name, be_msg->txn_reply->txn_id, - be_msg->txn_reply->success ? "success" : "failure"); + __dbg("Got %s TXN_REPLY from '%s' txn-id %" PRIx64 " with '%s'", + be_msg->txn_reply->create ? "Create" : "Delete", + adapter->name, be_msg->txn_reply->txn_id, + be_msg->txn_reply->success ? "success" : "failure"); /* * Forward the TXN_REPLY to txn module. */ @@ -449,58 +526,40 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter, be_msg->txn_reply->success, adapter); break; case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY: - MGMTD_BE_ADAPTER_DBG( - "Got CFGDATA_REPLY from '%s' txn-id %" PRIx64 - " batch-id %" PRIu64 " err:'%s'", - adapter->name, be_msg->cfg_data_reply->txn_id, - be_msg->cfg_data_reply->batch_id, - be_msg->cfg_data_reply->error_if_any - ? be_msg->cfg_data_reply->error_if_any - : "None"); + __dbg("Got CFGDATA_REPLY from '%s' txn-id %" PRIx64 " err:'%s'", + adapter->name, be_msg->cfg_data_reply->txn_id, + be_msg->cfg_data_reply->error_if_any + ? be_msg->cfg_data_reply->error_if_any + : "None"); /* * Forward the CGFData-create reply to txn module. */ mgmt_txn_notify_be_cfgdata_reply( be_msg->cfg_data_reply->txn_id, - be_msg->cfg_data_reply->batch_id, be_msg->cfg_data_reply->success, be_msg->cfg_data_reply->error_if_any, adapter); break; case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY: - MGMTD_BE_ADAPTER_DBG( - "Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64 - " for %zu batches id %" PRIu64 "-%" PRIu64 " err:'%s'", - be_msg->cfg_apply_reply->success ? "successful" - : "failed", - adapter->name, be_msg->cfg_apply_reply->txn_id, - be_msg->cfg_apply_reply->n_batch_ids, - be_msg->cfg_apply_reply->batch_ids[0], - be_msg->cfg_apply_reply->batch_ids - [be_msg->cfg_apply_reply->n_batch_ids - 1], - be_msg->cfg_apply_reply->error_if_any - ? be_msg->cfg_apply_reply->error_if_any - : "None"); + __dbg("Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64 + " err:'%s'", + be_msg->cfg_apply_reply->success ? "successful" : "failed", + adapter->name, be_msg->cfg_apply_reply->txn_id, + be_msg->cfg_apply_reply->error_if_any + ? be_msg->cfg_apply_reply->error_if_any + : "None"); /* * Forward the CGFData-apply reply to txn module. */ mgmt_txn_notify_be_cfg_apply_reply( be_msg->cfg_apply_reply->txn_id, be_msg->cfg_apply_reply->success, - (uint64_t *)be_msg->cfg_apply_reply->batch_ids, - be_msg->cfg_apply_reply->n_batch_ids, be_msg->cfg_apply_reply->error_if_any, adapter); break; - case MGMTD__BE_MESSAGE__MESSAGE_GET_REPLY: - /* - * TODO: Add handling code in future. - */ - break; /* * NOTE: The following messages are always sent from MGMTD to * Backend clients only and/or need not be handled on MGMTd. */ case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY: - case MGMTD__BE_MESSAGE__MESSAGE_GET_REQ: case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ: case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ: case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ: @@ -532,14 +591,13 @@ int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ; be_msg.txn_req = &txn_req; - MGMTD_BE_ADAPTER_DBG("Sending TXN_REQ to '%s' txn-id: %" PRIu64, - adapter->name, txn_id); + __dbg("Sending TXN_REQ to '%s' txn-id: %" PRIu64, adapter->name, txn_id); return mgmt_be_adapter_send_msg(adapter, &be_msg); } int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, - uint64_t txn_id, uint64_t batch_id, + uint64_t txn_id, Mgmtd__YangCfgDataReq **cfgdata_reqs, size_t num_reqs, bool end_of_data) { @@ -547,7 +605,6 @@ int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, Mgmtd__BeCfgDataCreateReq cfgdata_req; mgmtd__be_cfg_data_create_req__init(&cfgdata_req); - cfgdata_req.batch_id = batch_id; cfgdata_req.txn_id = txn_id; cfgdata_req.data_req = cfgdata_reqs; cfgdata_req.n_data_req = num_reqs; @@ -557,10 +614,8 @@ int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ; be_msg.cfg_data_req = &cfgdata_req; - MGMTD_BE_ADAPTER_DBG( - "Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64 - " batch-id: %" PRIu64, - adapter->name, txn_id, batch_id); + __dbg("Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64 " last: %s", + adapter->name, txn_id, end_of_data ? "yes" : "no"); return mgmt_be_adapter_send_msg(adapter, &be_msg); } @@ -578,42 +633,158 @@ int mgmt_be_send_cfgapply_req(struct mgmt_be_client_adapter *adapter, be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ; be_msg.cfg_apply_req = &apply_req; - MGMTD_BE_ADAPTER_DBG("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64, - adapter->name, txn_id); + __dbg("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64, adapter->name, + txn_id); return mgmt_be_adapter_send_msg(adapter, &be_msg); } +int mgmt_be_send_native(enum mgmt_be_client_id id, void *msg) +{ + struct mgmt_be_client_adapter *adapter = mgmt_be_get_adapter_by_id(id); + + if (!adapter) + return -1; + + return mgmt_msg_native_send_msg(adapter->conn, msg, false); +} + +static void mgmt_be_adapter_send_notify(struct mgmt_msg_notify_data *msg, + size_t msglen) +{ + struct mgmt_be_client_adapter *adapter; + struct mgmt_be_xpath_map *map; + struct nb_node *nb_node; + const char *notif; + uint id, len; + + if (!darr_len(be_notif_xpath_map)) + return; + + notif = mgmt_msg_native_xpath_decode(msg, msglen); + if (!notif) { + __log_err("Corrupt notify msg"); + return; + } + + nb_node = nb_node_find(notif); + if (!nb_node) { + __log_err("No schema found for notification: %s", notif); + return; + } + + darr_foreach_p (be_notif_xpath_map, map) { + len = strlen(map->xpath_prefix); + if (strncmp(map->xpath_prefix, nb_node->xpath, len) && + strncmp(map->xpath_prefix, notif, len)) + continue; + + FOREACH_BE_CLIENT_BITS (id, map->clients) { + adapter = mgmt_be_get_adapter_by_id(id); + if (!adapter) + continue; + msg_conn_send_msg(adapter->conn, MGMT_MSG_VERSION_NATIVE, + msg, msglen, NULL, false); + } + } +} + +/* + * Handle a native encoded message + */ +static void be_adapter_handle_native_msg(struct mgmt_be_client_adapter *adapter, + struct mgmt_msg_header *msg, + size_t msg_len) +{ + struct mgmt_msg_notify_data *notify_msg; + struct mgmt_msg_tree_data *tree_msg; + struct mgmt_msg_rpc_reply *rpc_msg; + struct mgmt_msg_error *error_msg; + + /* get the transaction */ + + switch (msg->code) { + case MGMT_MSG_CODE_ERROR: + error_msg = (typeof(error_msg))msg; + __dbg("Got ERROR from '%s' txn-id %" PRIx64, adapter->name, + msg->refer_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_error(adapter, msg->refer_id, msg->req_id, + error_msg->error, error_msg->errstr); + + break; + case MGMT_MSG_CODE_TREE_DATA: + /* tree data from a backend client */ + tree_msg = (typeof(tree_msg))msg; + __dbg("Got TREE_DATA from '%s' txn-id %" PRIx64, adapter->name, + msg->refer_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_tree_data_reply(adapter, tree_msg, msg_len); + break; + case MGMT_MSG_CODE_RPC_REPLY: + /* RPC reply from a backend client */ + rpc_msg = (typeof(rpc_msg))msg; + __dbg("Got RPC_REPLY from '%s' txn-id %" PRIx64, adapter->name, + msg->refer_id); + + /* Forward the reply to the txn module */ + mgmt_txn_notify_rpc_reply(adapter, rpc_msg, msg_len); + break; + case MGMT_MSG_CODE_NOTIFY: + notify_msg = (typeof(notify_msg))msg; + __dbg("Got NOTIFY from '%s'", adapter->name); + mgmt_be_adapter_send_notify(notify_msg, msg_len); + mgmt_fe_adapter_send_notify(notify_msg, msg_len); + break; + default: + __log_err("unknown native message txn-id %" PRIu64 + " req-id %" PRIu64 + " code %u from BE client for adapter %s", + msg->refer_id, msg->req_id, msg->code, adapter->name); + break; + } +} + + static void mgmt_be_adapter_process_msg(uint8_t version, uint8_t *data, size_t len, struct msg_conn *conn) { struct mgmt_be_client_adapter *adapter = conn->user; - Mgmtd__BeMessage *be_msg = mgmtd__be_message__unpack(NULL, len, data); + Mgmtd__BeMessage *be_msg; + + if (version == MGMT_MSG_VERSION_NATIVE) { + struct mgmt_msg_header *msg = (typeof(msg))data; + + if (len >= sizeof(*msg)) + be_adapter_handle_native_msg(adapter, msg, len); + else + __log_err("native message to adapter %s too short %zu", + adapter->name, len); + return; + } + be_msg = mgmtd__be_message__unpack(NULL, len, data); if (!be_msg) { - MGMTD_BE_ADAPTER_DBG( - "Failed to decode %zu bytes for adapter: %s", len, - adapter->name); + __dbg("Failed to decode %zu bytes for adapter: %s", len, + adapter->name); return; } - MGMTD_BE_ADAPTER_DBG("Decoded %zu bytes of message: %u for adapter: %s", - len, be_msg->message_case, adapter->name); + __dbg("Decoded %zu bytes of message: %u for adapter: %s", len, + be_msg->message_case, adapter->name); (void)mgmt_be_adapter_handle_msg(adapter, be_msg); mgmtd__be_message__free_unpacked(be_msg, NULL); } -static void mgmt_be_iter_and_get_cfg(const char *xpath, struct lyd_node *node, - struct nb_node *nb_node, void *ctx) -{ - struct mgmt_be_get_adapter_config_params *parms = ctx; - struct mgmt_be_client_adapter *adapter = parms->adapter; - uint subscr; - - subscr = mgmt_be_get_subscr_for_xpath_and_client( - xpath, adapter->id, MGMT_SUBSCR_NOTIFY_CFG); - if (subscr) - nb_config_diff_created(node, &parms->seq, parms->cfg_chgs); -} +/* + * Args for callback + */ +struct mgmt_be_get_adapter_config_params { + struct mgmt_be_client_adapter *adapter; + struct nb_config_cbs *cfg_chgs; + uint32_t seq; +}; /* * Initialize a BE client over a new connection @@ -625,28 +796,17 @@ static void mgmt_be_adapter_conn_init(struct event *thread) adapter = (struct mgmt_be_client_adapter *)EVENT_ARG(thread); assert(adapter && adapter->conn->fd >= 0); - /* - * Check first if the current session can run a CONFIG - * transaction or not. Reschedule if a CONFIG transaction - * from another session is already in progress. - */ - if (mgmt_config_txn_in_progress() != MGMTD_SESSION_ID_NONE) { - zlog_err("XXX txn in progress, retry init"); - mgmt_be_adapter_sched_init_event(adapter); - return; - } - /* * Notify TXN module to create a CONFIG transaction and * download the CONFIGs identified for this new client. * If the TXN module fails to initiate the CONFIG transaction - * disconnect from the client forcing a reconnect later. - * That should also take care of destroying the adapter. + * retry a bit later. It only fails if there's an existing config + * transaction in progress. */ if (mgmt_txn_notify_be_adapter_conn(adapter, true) != 0) { - zlog_err("XXX notify be adapter conn fail"); - msg_conn_disconnect(adapter->conn, false); - adapter = NULL; + zlog_err("XXX txn in progress, retry init"); + mgmt_be_adapter_sched_init_event(adapter); + return; } } @@ -686,15 +846,18 @@ extern void mgmt_be_adapter_unlock(struct mgmt_be_client_adapter **adapter) */ void mgmt_be_adapter_init(struct event_loop *tm) { + char server_path[MAXPATHLEN]; + assert(!mgmt_loop); mgmt_loop = tm; mgmt_be_adapters_init(&mgmt_be_adapters); mgmt_be_xpath_map_init(); - if (msg_server_init(&mgmt_be_server, MGMTD_BE_SERVER_PATH, tm, - mgmt_be_create_adapter, "backend", - &mgmt_debug_be)) { + snprintf(server_path, sizeof(server_path), MGMTD_BE_SOCK_NAME); + + if (msg_server_init(&mgmt_be_server, server_path, tm, + mgmt_be_create_adapter, "backend", &mgmt_debug_be)) { zlog_err("cannot initialize backend server"); exit(1); } @@ -733,14 +896,17 @@ struct msg_conn *mgmt_be_create_adapter(int conn_fd, union sockunion *from) mgmt_be_adapters_add_tail(&mgmt_be_adapters, adapter); RB_INIT(nb_config_cbs, &adapter->cfg_chgs); - adapter->conn = msg_server_conn_create( - mgmt_loop, conn_fd, mgmt_be_adapter_notify_disconnect, - mgmt_be_adapter_process_msg, MGMTD_BE_MAX_NUM_MSG_PROC, - MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MSG_MAX_LEN, adapter, - "BE-adapter"); + adapter->conn = msg_server_conn_create(mgmt_loop, conn_fd, + mgmt_be_adapter_notify_disconnect, + mgmt_be_adapter_process_msg, + MGMTD_BE_MAX_NUM_MSG_PROC, + MGMTD_BE_MAX_NUM_MSG_WRITE, + MGMTD_BE_MAX_MSG_LEN, adapter, + "BE-adapter"); - MGMTD_BE_ADAPTER_DBG("Added new MGMTD Backend adapter '%s'", - adapter->name); + adapter->conn->debug = DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL); + + __dbg("Added new MGMTD Backend adapter '%s'", adapter->name); return adapter->conn; } @@ -748,8 +914,7 @@ struct msg_conn *mgmt_be_create_adapter(int conn_fd, union sockunion *from) struct mgmt_be_client_adapter * mgmt_be_get_adapter_by_id(enum mgmt_be_client_id id) { - return (id < MGMTD_BE_CLIENT_ID_MAX ? mgmt_be_adapters_by_id[id] - : NULL); + return (id < MGMTD_BE_CLIENT_ID_MAX ? mgmt_be_adapters_by_id[id] : NULL); } struct mgmt_be_client_adapter * @@ -758,100 +923,114 @@ mgmt_be_get_adapter_by_name(const char *name) return mgmt_be_find_adapter_by_name(name); } -int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, - struct nb_config_cbs **cfg_chgs) +void mgmt_be_adapter_toggle_client_debug(bool set) { - struct mgmt_be_get_adapter_config_params parms; - struct nb_config *cfg_root = mgmt_ds_get_nb_config(mm->running_ds); - - assert(cfg_chgs); + struct mgmt_be_client_adapter *adapter; - /* - * TODO: we should consider making this an assertable condition and - * guaranteeing it be true when this function is called. B/c what is - * going to happen if there are some changes being sent, and we don't - * gather a new snapshot, what new changes that came after the previous - * snapshot will then be lost? - */ - if (RB_EMPTY(nb_config_cbs, &adapter->cfg_chgs)) { - parms.adapter = adapter; - parms.cfg_chgs = &adapter->cfg_chgs; - parms.seq = 0; + FOREACH_ADAPTER_IN_LIST (adapter) + adapter->conn->debug = set; +} - mgmt_ds_iter_data(MGMTD_DS_RUNNING, cfg_root, "", - mgmt_be_iter_and_get_cfg, (void *)&parms); +/* + * Get a full set of changes for all the config that an adapter is subscribed to + * receive. + */ +void mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, + struct nb_config_cbs **changes) +{ + const struct lyd_node *root, *dnode; + uint32_t seq = 0; + char *xpath; + + /* We can't be in the middle of sending other chgs when here. */ + assert(RB_EMPTY(nb_config_cbs, &adapter->cfg_chgs)); + + *changes = &adapter->cfg_chgs; + LY_LIST_FOR (running_config->dnode, root) { + LYD_TREE_DFS_BEGIN (root, dnode) { + if (lysc_is_key(dnode->schema)) + goto walk_cont; + + xpath = lyd_path(dnode, LYD_PATH_STD, NULL, 0); + if (be_is_client_interested(xpath, adapter->id, + MGMT_BE_XPATH_SUBSCR_TYPE_CFG)) + nb_config_diff_add_change(*changes, NB_CB_CREATE, &seq, dnode); + else + LYD_TREE_DFS_continue = 1; /* skip any subtree */ + free(xpath); + walk_cont: + LYD_TREE_DFS_END(root, dnode); + } } - - *cfg_chgs = &adapter->cfg_chgs; - return 0; } -void mgmt_be_get_subscr_info_for_xpath( - const char *xpath, struct mgmt_be_client_subscr_info *subscr_info) +uint64_t mgmt_be_interested_clients(const char *xpath, + enum mgmt_be_xpath_subscr_type type) { - struct mgmt_be_xpath_map *map; + struct mgmt_be_xpath_map *maps = NULL, *map; enum mgmt_be_client_id id; + uint64_t clients; - memset(subscr_info, 0, sizeof(*subscr_info)); - - MGMTD_BE_ADAPTER_DBG("XPATH: '%s'", xpath); - darr_foreach_p (mgmt_xpath_map, map) { - if (!mgmt_be_eval_regexp_match(map->xpath_regexp, xpath)) - continue; - FOREACH_MGMTD_BE_CLIENT_ID (id) { - subscr_info->xpath_subscr[id] |= map->subscr_info[id]; - } + switch (type) { + case MGMT_BE_XPATH_SUBSCR_TYPE_CFG: + maps = be_cfg_xpath_map; + break; + case MGMT_BE_XPATH_SUBSCR_TYPE_OPER: + maps = be_oper_xpath_map; + break; + case MGMT_BE_XPATH_SUBSCR_TYPE_NOTIF: + maps = be_notif_xpath_map; + break; + case MGMT_BE_XPATH_SUBSCR_TYPE_RPC: + maps = be_rpc_xpath_map; + break; } + clients = 0; + + __dbg("XPATH: '%s'", xpath); + darr_foreach_p (maps, map) + if (mgmt_be_xpath_prefix(map->xpath_prefix, xpath)) + clients |= map->clients; + if (DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL)) { - FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (!subscr_info->xpath_subscr[id]) - continue; - MGMTD_BE_ADAPTER_DBG("Cient: %s: subscribed: 0x%x", - mgmt_be_client_id2name(id), - subscr_info->xpath_subscr[id]); - } + FOREACH_BE_CLIENT_BITS (id, clients) + __dbg("Cient: %s: subscribed", + mgmt_be_client_id2name(id)); } + return clients; } /** - * Return the subscription info bits for a given `xpath` for a given - * `client_id`. + * Return true if `client_id` is interested in `xpath` for `config` + * or oper (!`config`). * * Args: - * xpath - the xpath to check for subscription information. + * xpath - the xpath to check for interest. * client_id - the BE client being checked for. - * subscr_mask - The subscr bits the caller is interested in seeing - * if set. + * bool - check for config (vs oper) subscription. * * Returns: - * The subscription info bits. + * Interested or not. */ -static uint mgmt_be_get_subscr_for_xpath_and_client( - const char *xpath, enum mgmt_be_client_id client_id, uint subscr_mask) +static bool be_is_client_interested(const char *xpath, enum mgmt_be_client_id id, + enum mgmt_be_xpath_subscr_type type) { - struct mgmt_be_client_xpath_map *map; - uint subscr = 0; - uint i; + uint64_t clients; - assert(client_id < MGMTD_BE_CLIENT_ID_MAX); + assert(id < MGMTD_BE_CLIENT_ID_MAX); - MGMTD_BE_ADAPTER_DBG("Checking client: %s for xpath: '%s'", - mgmt_be_client_id2name(client_id), xpath); + __dbg("Checking client: %s for xpath: '%s'", mgmt_be_client_id2name(id), + xpath); - map = &mgmt_client_xpaths[client_id]; - for (i = 0; i < map->nxpaths; i++) { - if (!mgmt_be_eval_regexp_match(map->xpaths[i].xpath, xpath)) - continue; - MGMTD_BE_ADAPTER_DBG("xpath: %s: matched: %s", - map->xpaths[i].xpath, xpath); - subscr |= map->xpaths[i].subscribed; - if ((subscr & subscr_mask) == subscr_mask) - break; + clients = mgmt_be_interested_clients(xpath, type); + if (IS_IDBIT_SET(clients, id)) { + __dbg("client: %s: interested", mgmt_be_client_id2name(id)); + return true; } - MGMTD_BE_ADAPTER_DBG("client: %s: subscribed: 0x%x", - mgmt_be_client_id2name(client_id), subscr); - return subscr; + + __dbg("client: %s: not interested", mgmt_be_client_id2name(id)); + return false; } void mgmt_be_adapter_status_write(struct vty *vty) @@ -878,56 +1057,67 @@ void mgmt_be_adapter_status_write(struct vty *vty) (int)mgmt_be_adapters_count(&mgmt_be_adapters)); } -void mgmt_be_xpath_register_write(struct vty *vty) +static void be_show_xpath_register(struct vty *vty, + struct mgmt_be_xpath_map *map) { - struct mgmt_be_xpath_map *map; enum mgmt_be_client_id id; - struct mgmt_be_client_adapter *adapter; - uint info; - - vty_out(vty, "MGMTD Backend XPath Registry\n"); + const char *astr; - darr_foreach_p (mgmt_xpath_map, map) { - vty_out(vty, " - XPATH: '%s'\n", map->xpath_regexp); - FOREACH_MGMTD_BE_CLIENT_ID (id) { - info = map->subscr_info[id]; - if (!info) - continue; - vty_out(vty, - " -- Client: '%s'\tValidate:%d, Notify:%d, Own:%d\n", - mgmt_be_client_id2name(id), - (info & MGMT_SUBSCR_VALIDATE_CFG) != 0, - (info & MGMT_SUBSCR_NOTIFY_CFG) != 0, - (info & MGMT_SUBSCR_OPER_OWN) != 0); - adapter = mgmt_be_get_adapter_by_id(id); - if (adapter) - vty_out(vty, " -- Adapter: %p\n", adapter); - } + vty_out(vty, " - xpath: '%s'\n", map->xpath_prefix); + FOREACH_BE_CLIENT_BITS (id, map->clients) { + astr = mgmt_be_get_adapter_by_id(id) ? "active" : "inactive"; + vty_out(vty, " -- %s-client: '%s'\n", astr, + mgmt_be_client_id2name(id)); } +} +void mgmt_be_xpath_register_write(struct vty *vty) +{ + struct mgmt_be_xpath_map *map; - vty_out(vty, "Total XPath Registries: %u\n", darr_len(mgmt_xpath_map)); + vty_out(vty, "MGMTD Backend CFG XPath Registry: Count: %u\n", + darr_len(be_oper_xpath_map)); + darr_foreach_p (be_cfg_xpath_map, map) + be_show_xpath_register(vty, map); + + vty_out(vty, "\nMGMTD Backend OPER XPath Registry: Count: %u\n", + darr_len(be_oper_xpath_map)); + darr_foreach_p (be_oper_xpath_map, map) + be_show_xpath_register(vty, map); + + vty_out(vty, "\nMGMTD Backend NOTIFY XPath Registry: Count: %u\n", + darr_len(be_notif_xpath_map)); + darr_foreach_p (be_notif_xpath_map, map) + be_show_xpath_register(vty, map); + + vty_out(vty, "\nMGMTD Backend RPC XPath Registry: Count: %u\n", + darr_len(be_rpc_xpath_map)); + darr_foreach_p (be_rpc_xpath_map, map) + be_show_xpath_register(vty, map); } -void mgmt_be_xpath_subscr_info_write(struct vty *vty, const char *xpath) +void mgmt_be_show_xpath_registries(struct vty *vty, const char *xpath) { - struct mgmt_be_client_subscr_info subscr; enum mgmt_be_client_id id; struct mgmt_be_client_adapter *adapter; - uint info; - - mgmt_be_get_subscr_info_for_xpath(xpath, &subscr); + uint64_t cclients, nclients, oclients, rclients, combined; + + cclients = mgmt_be_interested_clients(xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_CFG); + oclients = mgmt_be_interested_clients(xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_OPER); + nclients = mgmt_be_interested_clients(xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_NOTIF); + rclients = mgmt_be_interested_clients(xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_RPC); + combined = cclients | nclients | oclients | rclients; vty_out(vty, "XPath: '%s'\n", xpath); - FOREACH_MGMTD_BE_CLIENT_ID (id) { - info = subscr.xpath_subscr[id]; - if (!info) - continue; + FOREACH_BE_CLIENT_BITS (id, combined) { vty_out(vty, - " -- Client: '%s'\tValidate:%d, Notify:%d, Own:%d\n", - mgmt_be_client_id2name(id), - (info & MGMT_SUBSCR_VALIDATE_CFG) != 0, - (info & MGMT_SUBSCR_NOTIFY_CFG) != 0, - (info & MGMT_SUBSCR_OPER_OWN) != 0); + " -- Client: '%s'\tconfig:%d notify:%d oper:%d rpc:%d\n", + mgmt_be_client_id2name(id), IS_IDBIT_SET(cclients, id), + IS_IDBIT_SET(nclients, id), IS_IDBIT_SET(oclients, id), + IS_IDBIT_SET(rclients, id)); adapter = mgmt_be_get_adapter_by_id(id); if (adapter) vty_out(vty, " -- Adapter: %p\n", adapter); diff --git a/mgmtd/mgmt_be_adapter.h b/mgmtd/mgmt_be_adapter.h index ca8f55c457ff..c9f2ab1b7a88 100644 --- a/mgmtd/mgmt_be_adapter.h +++ b/mgmtd/mgmt_be_adapter.h @@ -12,14 +12,37 @@ #include "mgmt_be_client.h" #include "mgmt_msg.h" -#include "mgmtd/mgmt_defines.h" +#include "mgmt_defines.h" #include "mgmtd/mgmt_ds.h" #define MGMTD_BE_CONN_INIT_DELAY_MSEC 50 -#define MGMTD_FIND_ADAPTER_BY_INDEX(adapter_index) \ +#define MGMTD_FIND_ADAPTER_BY_INDEX(adapter_index) \ mgmt_adaptr_ref[adapter_index] +/** + * CLIENT-ID + * + * Add enum value for each supported component, wrap with + * #ifdef HAVE_COMPONENT + */ +enum mgmt_be_client_id { + MGMTD_BE_CLIENT_ID_TESTC, /* always first */ + MGMTD_BE_CLIENT_ID_ZEBRA, +#ifdef HAVE_RIPD + MGMTD_BE_CLIENT_ID_RIPD, +#endif +#ifdef HAVE_RIPNGD + MGMTD_BE_CLIENT_ID_RIPNGD, +#endif +#ifdef HAVE_STATICD + MGMTD_BE_CLIENT_ID_STATICD, +#endif + MGMTD_BE_CLIENT_ID_MAX +}; +#define MGMTD_BE_CLIENT_ID_MIN 0 + + enum mgmt_be_req_type { MGMTD_BE_REQ_NONE = 0, MGMTD_BE_REQ_CFG_VALIDATE, @@ -49,8 +72,6 @@ struct mgmt_be_client_adapter { enum mgmt_be_client_id id; uint32_t flags; char name[MGMTD_CLIENT_NAME_MAX_LEN]; - uint8_t num_xpath_reg; - char xpath_reg[MGMTD_MAX_NUM_XPATH_REG][MGMTD_MAX_XPATH_LEN]; int refcount; @@ -81,9 +102,36 @@ DECLARE_LIST(mgmt_be_adapters, struct mgmt_be_client_adapter, list_linkage); #define MGMT_SUBSCR_OPER_OWN 0x4 #define MGMT_SUBSCR_ALL 0x7 -struct mgmt_be_client_subscr_info { - uint xpath_subscr[MGMTD_BE_CLIENT_ID_MAX]; -}; +/* --------- */ +/* CLIENT-ID */ +/* --------- */ + +#define FOREACH_MGMTD_BE_CLIENT_ID(id) \ + for ((id) = MGMTD_BE_CLIENT_ID_MIN; (id) < MGMTD_BE_CLIENT_ID_MAX; \ + (id)++) + +#define IS_IDBIT_SET(v, id) (!IS_IDBIT_UNSET(v, id)) +#define IS_IDBIT_UNSET(v, id) (!((v) & (1ull << (id)))) + +#define __GET_NEXT_SET(id, bits) \ + ({ \ + enum mgmt_be_client_id __id = (id); \ + \ + for (; __id < MGMTD_BE_CLIENT_ID_MAX && \ + IS_IDBIT_UNSET(bits, __id); \ + __id++) \ + ; \ + __id; \ + }) + +#define FOREACH_BE_CLIENT_BITS(id, bits) \ + for ((id) = __GET_NEXT_SET(MGMTD_BE_CLIENT_ID_MIN, bits); \ + (id) < MGMTD_BE_CLIENT_ID_MAX; \ + (id) = __GET_NEXT_SET((id) + 1, bits)) + +/* ---------- */ +/* Prototypes */ +/* ---------- */ /* Initialise backend adapter module. */ extern void mgmt_be_adapter_init(struct event_loop *tm); @@ -109,9 +157,15 @@ mgmt_be_get_adapter_by_name(const char *name); extern struct mgmt_be_client_adapter * mgmt_be_get_adapter_by_id(enum mgmt_be_client_id id); +/* Get the client name given a client ID */ +extern const char *mgmt_be_client_id2name(enum mgmt_be_client_id id); + +/* Toggle debug on or off for connected clients. */ +extern void mgmt_be_adapter_toggle_client_debug(bool set); + /* Fetch backend adapter config. */ -extern int mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, - struct nb_config_cbs **cfg_chgs); +extern void mgmt_be_get_adapter_config(struct mgmt_be_client_adapter *adapter, + struct nb_config_cbs **changes); /* Create/destroy a transaction. */ extern int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter, @@ -126,9 +180,6 @@ extern int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter, * txn_id * Unique transaction identifier. * - * batch_id - * Request batch ID. - * * cfgdata_reqs * An array of pointer to Mgmtd__YangCfgDataReq. * @@ -142,7 +193,7 @@ extern int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter, * 0 on success, -1 on failure. */ extern int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter, - uint64_t txn_id, uint64_t batch_id, + uint64_t txn_id, Mgmtd__YangCfgDataReq **cfgdata_reqs, size_t num_reqs, bool end_of_data); @@ -171,23 +222,47 @@ extern void mgmt_be_adapter_status_write(struct vty *vty); */ extern void mgmt_be_xpath_register_write(struct vty *vty); + +/** + * Send a native message to a backend client + * + * Args: + * adapter: the client to send the message to. + * msg: a native message from mgmt_msg_native_alloc_msg() + * + * Return: + * Any return value from msg_conn_send_msg(). + */ +extern int mgmt_be_send_native(enum mgmt_be_client_id id, void *msg); + +enum mgmt_be_xpath_subscr_type { + MGMT_BE_XPATH_SUBSCR_TYPE_CFG, + MGMT_BE_XPATH_SUBSCR_TYPE_OPER, + MGMT_BE_XPATH_SUBSCR_TYPE_NOTIF, + MGMT_BE_XPATH_SUBSCR_TYPE_RPC, +}; + /** * Lookup the clients which are subscribed to a given `xpath` * and the way they are subscribed. * * Args: * xpath - the xpath to check for subscription information. - * subscr_info - An array of uint indexed by client id - * each eleemnt holds the subscription info - * for that client. + * type - type of subscription to check for. */ -extern void mgmt_be_get_subscr_info_for_xpath( - const char *xpath, struct mgmt_be_client_subscr_info *subscr_info); +extern uint64_t mgmt_be_interested_clients(const char *xpath, + enum mgmt_be_xpath_subscr_type type); +/** + * mgmt_fe_adapter_send_notify() - notify FE clients of a notification. + * @msg: the notify message from the backend client. + * @msglen: the length of the notify message. + */ +extern void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, + size_t msglen); /* * Dump backend client information for a given xpath to vty. */ -extern void mgmt_be_xpath_subscr_info_write(struct vty *vty, - const char *xpath); +extern void mgmt_be_show_xpath_registries(struct vty *vty, const char *xpath); #endif /* _FRR_MGMTD_BE_ADAPTER_H_ */ diff --git a/mgmtd/mgmt_be_nb.c b/mgmtd/mgmt_be_nb.c new file mode 100644 index 000000000000..613272d40728 --- /dev/null +++ b/mgmtd/mgmt_be_nb.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "config.h" +#include "xref.h" + +XREF_SETUP(); diff --git a/mgmtd/mgmt_ds.c b/mgmtd/mgmt_ds.c index a0e610c7c745..dabae4afd1b0 100644 --- a/mgmtd/mgmt_ds.c +++ b/mgmtd/mgmt_ds.c @@ -15,10 +15,9 @@ #include "mgmtd/mgmt_txn.h" #include "libyang/libyang.h" -#define MGMTD_DS_DBG(fmt, ...) \ +#define __dbg(fmt, ...) \ DEBUGD(&mgmt_debug_ds, "DS: %s: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_DS_ERR(fmt, ...) \ - zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__) +#define __log_err(fmt, ...) zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__) struct mgmt_ds_ctx { Mgmtd__DatastoreId ds_id; @@ -81,8 +80,8 @@ static int mgmt_ds_replace_dst_with_src_ds(struct mgmt_ds_ctx *src, if (!src || !dst) return -1; - MGMTD_DS_DBG("Replacing %s with %s", mgmt_ds_id2name(dst->ds_id), - mgmt_ds_id2name(src->ds_id)); + __dbg("Replacing %s with %s", mgmt_ds_id2name(dst->ds_id), + mgmt_ds_id2name(src->ds_id)); if (src->config_ds && dst->config_ds) nb_config_replace(dst->root.cfg_root, src->root.cfg_root, true); @@ -93,14 +92,6 @@ static int mgmt_ds_replace_dst_with_src_ds(struct mgmt_ds_ctx *src, dst->root.dnode_root = yang_dnode_dup(src->root.dnode_root); } - if (src->ds_id == MGMTD_DS_CANDIDATE) { - /* - * Drop the changes in scratch-buffer. - */ - MGMTD_DS_DBG("Emptying Candidate Scratch buffer!"); - nb_config_diff_del_changes(&src->root.cfg_root->cfg_chgs); - } - return 0; } @@ -112,7 +103,7 @@ static int mgmt_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src, if (!src || !dst) return -1; - MGMTD_DS_DBG("Merging DS %d with %d", dst->ds_id, src->ds_id); + __dbg("Merging DS %d with %d", dst->ds_id, src->ds_id); if (src->config_ds && dst->config_ds) ret = nb_config_merge(dst->root.cfg_root, src->root.cfg_root, true); @@ -122,18 +113,10 @@ static int mgmt_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src, src->root.dnode_root, 0); } if (ret != 0) { - MGMTD_DS_ERR("merge failed with err: %d", ret); + __log_err("merge failed with err: %d", ret); return ret; } - if (src->ds_id == MGMTD_DS_CANDIDATE) { - /* - * Drop the changes in scratch-buffer. - */ - MGMTD_DS_DBG("Emptying Candidate Scratch buffer!"); - nb_config_diff_del_changes(&src->root.cfg_root->cfg_chgs); - } - return 0; } @@ -144,7 +127,8 @@ static int mgmt_ds_load_cfg_from_file(const char *filepath, *dnode = NULL; ret = lyd_parse_data_path(ly_native_ctx, filepath, LYD_JSON, - LYD_PARSE_STRICT, 0, dnode); + LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, + LYD_VALIDATE_NO_STATE, dnode); if (ret != LY_SUCCESS) { if (*dnode) @@ -315,7 +299,7 @@ static int mgmt_walk_ds_nodes( assert(mgmt_ds_node_iter_fn); - MGMTD_DS_DBG(" -- START: base xpath: '%s'", base_xpath); + __dbg(" -- START: base xpath: '%s'", base_xpath); if (!base_dnode) /* @@ -326,9 +310,9 @@ static int mgmt_walk_ds_nodes( if (!base_dnode) return -1; - MGMTD_DS_DBG(" search base schema: '%s'", - lysc_path(base_dnode->schema, LYSC_PATH_LOG, xpath, - sizeof(xpath))); + __dbg(" search base schema: '%s'", + lysc_path(base_dnode->schema, LYSC_PATH_LOG, xpath, + sizeof(xpath))); nbnode = (struct nb_node *)base_dnode->schema->priv; (*mgmt_ds_node_iter_fn)(base_xpath, base_dnode, nbnode, ctx); @@ -351,7 +335,7 @@ static int mgmt_walk_ds_nodes( (void)lyd_path(dnode, LYD_PATH_STD, xpath, sizeof(xpath)); - MGMTD_DS_DBG(" -- Child xpath: %s", xpath); + __dbg(" -- Child xpath: %s", xpath); ret = mgmt_walk_ds_nodes(root, xpath, dnode, mgmt_ds_node_iter_fn, ctx); @@ -359,7 +343,7 @@ static int mgmt_walk_ds_nodes( break; } - MGMTD_DS_DBG(" -- END: base xpath: '%s'", base_xpath); + __dbg(" -- END: base xpath: '%s'", base_xpath); return ret; } @@ -423,8 +407,7 @@ int mgmt_ds_load_config_from_file(struct mgmt_ds_ctx *dst, return -1; if (mgmt_ds_load_cfg_from_file(file_path, &iter) != 0) { - MGMTD_DS_ERR("Failed to load config from the file %s", - file_path); + __log_err("Failed to load config from the file %s", file_path); return -1; } @@ -467,7 +450,7 @@ int mgmt_ds_iter_data(Mgmtd__DatastoreId ds_id, struct nb_config *root, * Oper-state should be kept in mind though for the prefix walk */ - MGMTD_DS_DBG(" -- START DS walk for DSid: %d", ds_id); + __dbg(" -- START DS walk for DSid: %d", ds_id); /* If the base_xpath is empty then crawl the sibblings */ if (xpath[0] == 0) { diff --git a/mgmtd/mgmt_ds.h b/mgmtd/mgmt_ds.h index 1cf4816027c3..b8e77e330afe 100644 --- a/mgmtd/mgmt_ds.h +++ b/mgmtd/mgmt_ds.h @@ -11,8 +11,8 @@ #include "mgmt_fe_client.h" #include "northbound.h" +#include "mgmt_defines.h" -#include "mgmtd/mgmt_defines.h" #include "mgmtd/mgmt_be_adapter.h" #include "mgmtd/mgmt_fe_adapter.h" @@ -29,8 +29,8 @@ #define MGMTD_MAX_COMMIT_LIST 10 -#define MGMTD_COMMIT_FILE_PATH DAEMON_DB_DIR "/commit-%s.json" -#define MGMTD_COMMIT_INDEX_FILE_NAME DAEMON_DB_DIR "/commit-index.dat" +#define MGMTD_COMMIT_FILE_PATH(id) "%s/commit-%s.json", frr_libstatedir, id +#define MGMTD_COMMIT_INDEX_FILE_PATH "%s/commit-index.dat", frr_libstatedir extern struct nb_config *running_config; diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index 2b2471c9014e..09d1910cee61 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -8,11 +8,13 @@ */ #include +#include "darr.h" #include "sockopt.h" #include "network.h" #include "libfrr.h" #include "mgmt_fe_client.h" #include "mgmt_msg.h" +#include "mgmt_msg_native.h" #include "mgmt_pb.h" #include "hash.h" #include "jhash.h" @@ -21,9 +23,9 @@ #include "mgmtd/mgmt_memory.h" #include "mgmtd/mgmt_fe_adapter.h" -#define MGMTD_FE_ADAPTER_DBG(fmt, ...) \ +#define __dbg(fmt, ...) \ DEBUGD(&mgmt_debug_fe, "FE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_FE_ADAPTER_ERR(fmt, ...) \ +#define __log_err(fmt, ...) \ zlog_err("FE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__) #define FOREACH_ADAPTER_IN_LIST(adapter) \ @@ -41,6 +43,7 @@ struct mgmt_fe_session_ctx { uint64_t txn_id; uint64_t cfg_txn_id; uint8_t ds_locked[MGMTD_DS_MAX_ID]; + const char **notify_xpaths; struct event *proc_cfg_txn_clnp; struct event *proc_show_txn_clnp; @@ -76,20 +79,18 @@ mgmt_fe_session_write_lock_ds(Mgmtd__DatastoreId ds_id, session->session_id, mgmt_ds_id2name(ds_id)); else { if (mgmt_ds_lock(ds_ctx, session->session_id)) { - MGMTD_FE_ADAPTER_DBG( - "Failed to lock the DS:%s for session-id: %" PRIu64 - " from %s!", - mgmt_ds_id2name(ds_id), session->session_id, - session->adapter->name); + __dbg("Failed to lock the DS:%s for session-id: %" PRIu64 + " from %s!", + mgmt_ds_id2name(ds_id), session->session_id, + session->adapter->name); return -1; } session->ds_locked[ds_id] = true; - MGMTD_FE_ADAPTER_DBG( - "Write-Locked the DS:%s for session-id: %" PRIu64 - " from %s", - mgmt_ds_id2name(ds_id), session->session_id, - session->adapter->name); + __dbg("Write-Locked the DS:%s for session-id: %" PRIu64 + " from %s", + mgmt_ds_id2name(ds_id), session->session_id, + session->adapter->name); } return 0; @@ -105,11 +106,10 @@ static void mgmt_fe_session_unlock_ds(Mgmtd__DatastoreId ds_id, session->ds_locked[ds_id] = false; mgmt_ds_unlock(ds_ctx); - MGMTD_FE_ADAPTER_DBG( - "Unlocked DS:%s write-locked earlier by session-id: %" PRIu64 - " from %s", - mgmt_ds_id2name(ds_id), session->session_id, - session->adapter->name); + __dbg("Unlocked DS:%s write-locked earlier by session-id: %" PRIu64 + " from %s", + mgmt_ds_id2name(ds_id), session->session_id, + session->adapter->name); } static void @@ -204,14 +204,13 @@ mgmt_fe_find_session_by_client_id(struct mgmt_fe_client_adapter *adapter, FOREACH_SESSION_IN_LIST (adapter, session) { if (session->client_id == client_id) { - MGMTD_FE_ADAPTER_DBG("Found session-id %" PRIu64 - " using client-id %" PRIu64, - session->session_id, client_id); + __dbg("Found session-id %" PRIu64 + " using client-id %" PRIu64, + session->session_id, client_id); return session; } } - MGMTD_FE_ADAPTER_DBG("Session not found using client-id %" PRIu64, - client_id); + __dbg("Session not found using client-id %" PRIu64, client_id); return NULL; } @@ -246,6 +245,23 @@ mgmt_session_id2ctx(uint64_t session_id) return session; } +void mgmt_fe_adapter_toggle_client_debug(bool set) +{ + struct mgmt_fe_client_adapter *adapter; + + FOREACH_ADAPTER_IN_LIST (adapter) + adapter->conn->debug = set; +} + +static struct mgmt_fe_session_ctx *fe_adapter_session_by_txn_id(uint64_t txn_id) +{ + uint64_t session_id = mgmt_txn_get_session_id(txn_id); + + if (session_id == MGMTD_SESSION_ID_NONE) + return NULL; + return mgmt_session_id2ctx(session_id); +} + static struct mgmt_fe_session_ctx * mgmt_fe_create_session(struct mgmt_fe_client_adapter *adapter, uint64_t client_id) @@ -273,6 +289,14 @@ mgmt_fe_create_session(struct mgmt_fe_client_adapter *adapter, return session; } +static int fe_adapter_send_native_msg(struct mgmt_fe_client_adapter *adapter, + void *msg, size_t len, + bool short_circuit_ok) +{ + return msg_conn_send_msg(adapter->conn, MGMT_MSG_VERSION_NATIVE, msg, + len, NULL, short_circuit_ok); +} + static int fe_adapter_send_msg(struct mgmt_fe_client_adapter *adapter, Mgmtd__FeMessage *fe_msg, bool short_circuit_ok) { @@ -303,9 +327,8 @@ static int fe_adapter_send_session_reply(struct mgmt_fe_client_adapter *adapter, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY; fe_msg.session_reply = &session_reply; - MGMTD_FE_ADAPTER_DBG( - "Sending SESSION_REPLY message to MGMTD Frontend client '%s'", - adapter->name); + __dbg("Sending SESSION_REPLY message to MGMTD Frontend client '%s'", + adapter->name); return fe_adapter_send_msg(adapter, &fe_msg, true); } @@ -334,9 +357,8 @@ static int fe_adapter_send_lockds_reply(struct mgmt_fe_session_ctx *session, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY; fe_msg.lockds_reply = &lockds_reply; - MGMTD_FE_ADAPTER_DBG( - "Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s' scok: %d", - session->adapter->name, scok); + __dbg("Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s' scok: %d", + session->adapter->name, scok); return fe_adapter_send_msg(session->adapter, &fe_msg, scok); } @@ -369,9 +391,8 @@ static int fe_adapter_send_set_cfg_reply(struct mgmt_fe_session_ctx *session, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY; fe_msg.setcfg_reply = &setcfg_reply; - MGMTD_FE_ADAPTER_DBG( - "Sending SETCFG_REPLY message to MGMTD Frontend client '%s'", - session->adapter->name); + __dbg("Sending SETCFG_REPLY message to MGMTD Frontend client '%s'", + session->adapter->name); if (implicit_commit) { if (mm->perf_stats_en) @@ -415,9 +436,8 @@ static int fe_adapter_send_commit_cfg_reply( fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY; fe_msg.commcfg_reply = &commcfg_reply; - MGMTD_FE_ADAPTER_DBG( - "Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'", - session->adapter->name); + __dbg("Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'", + session->adapter->name); /* * Cleanup the CONFIG transaction associated with this session. @@ -457,8 +477,8 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session, fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GET_REPLY; fe_msg.get_reply = &get_reply; - MGMTD_FE_ADAPTER_DBG("Sending GET_REPLY message to MGMTD Frontend client '%s'", - session->adapter->name); + __dbg("Sending GET_REPLY message to MGMTD Frontend client '%s'", + session->adapter->name); /* * Cleanup the SHOW transaction associated with this session. @@ -470,6 +490,48 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session, return fe_adapter_send_msg(session->adapter, &fe_msg, false); } +static int fe_adapter_conn_send_error(struct msg_conn *conn, + uint64_t session_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errfmt, ...) PRINTFRR(6, 7); +static int fe_adapter_conn_send_error(struct msg_conn *conn, uint64_t session_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, errfmt); + + ret = vmgmt_msg_native_send_error(conn, session_id, req_id, + short_circuit_ok, error, errfmt, ap); + va_end(ap); + + return ret; +} + +static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) + PRINTFRR(5, 6); + +static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, errfmt); + ret = vmgmt_msg_native_send_error(session->adapter->conn, + session->session_id, req_id, + short_circuit_ok, error, errfmt, ap); + va_end(ap); + + return ret; +} + + static void mgmt_fe_session_cfg_txn_clnup(struct event *thread) { struct mgmt_fe_session_ctx *session; @@ -523,7 +585,7 @@ mgmt_fe_find_adapter_by_fd(int conn_fd) static void mgmt_fe_adapter_delete(struct mgmt_fe_client_adapter *adapter) { struct mgmt_fe_session_ctx *session; - MGMTD_FE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name); + __dbg("deleting client adapter '%s'", adapter->name); /* TODO: notify about client disconnect for appropriate cleanup */ FOREACH_SESSION_IN_LIST (adapter, session) @@ -538,8 +600,7 @@ static int mgmt_fe_adapter_notify_disconnect(struct msg_conn *conn) { struct mgmt_fe_client_adapter *adapter = conn->user; - MGMTD_FE_ADAPTER_DBG("notify disconnect for client adapter '%s'", - adapter->name); + __dbg("notify disconnect for client adapter '%s'", adapter->name); mgmt_fe_adapter_delete(adapter); @@ -560,10 +621,8 @@ mgmt_fe_adapter_cleanup_old_conn(struct mgmt_fe_client_adapter *adapter) if (strncmp(adapter->name, old->name, sizeof(adapter->name))) continue; - MGMTD_FE_ADAPTER_DBG( - "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)", - adapter->name, adapter->conn->fd, - old->conn->fd); + __dbg("Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)", + adapter->name, adapter->conn->fd, old->conn->fd); msg_conn_disconnect(old->conn, false); } } @@ -616,11 +675,10 @@ mgmt_fe_session_handle_lockds_req_msg(struct mgmt_fe_session_ctx *session, if (fe_adapter_send_lockds_reply(session, lockds_req->ds_id, lockds_req->req_id, lockds_req->lock, true, NULL) != 0) { - MGMTD_FE_ADAPTER_DBG( - "Failed to send LOCK_DS_REPLY for DS %u session-id: %" PRIu64 - " from %s", - lockds_req->ds_id, session->session_id, - session->adapter->name); + __dbg("Failed to send LOCK_DS_REPLY for DS %u session-id: %" PRIu64 + " from %s", + lockds_req->ds_id, session->session_id, + session->adapter->name); } return 0; @@ -674,9 +732,6 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session, } if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) { - /* as we have the lock no-one else should have a config txn */ - assert(mgmt_config_txn_in_progress() == MGMTD_SESSION_ID_NONE); - /* Start a CONFIG Transaction (if not started already) */ session->cfg_txn_id = mgmt_create_txn(session->session_id, MGMTD_TXN_TYPE_CONFIG); @@ -690,14 +745,13 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session, } txn_created = true; - MGMTD_FE_ADAPTER_DBG("Created new Config txn-id: %" PRIu64 - " for session-id %" PRIu64, - session->cfg_txn_id, session->session_id); + __dbg("Created new Config txn-id: %" PRIu64 + " for session-id %" PRIu64, + session->cfg_txn_id, session->session_id); } else { - MGMTD_FE_ADAPTER_DBG("Config txn-id: %" PRIu64 - " for session-id: %" PRIu64 - " already created", - session->cfg_txn_id, session->session_id); + __dbg("Config txn-id: %" PRIu64 " for session-id: %" PRIu64 + " already created", + session->cfg_txn_id, session->session_id); if (setcfg_req->implicit_commit) { /* @@ -740,14 +794,8 @@ static int mgmt_fe_session_handle_get_req_msg(struct mgmt_fe_session_ctx *sessio struct nb_config *cfg_root = NULL; Mgmtd__DatastoreId ds_id = get_req->ds_id; uint64_t req_id = get_req->req_id; - bool is_cfg = get_req->config; - bool ds_ok = true; - - if (is_cfg && ds_id != MGMTD_DS_CANDIDATE && ds_id != MGMTD_DS_RUNNING) - ds_ok = false; - else if (!is_cfg && ds_id != MGMTD_DS_OPERATIONAL) - ds_ok = false; - if (!ds_ok) { + + if (ds_id != MGMTD_DS_CANDIDATE && ds_id != MGMTD_DS_RUNNING) { fe_adapter_send_get_reply(session, ds_id, req_id, false, NULL, "get-req on unsupported datastore"); return 0; @@ -768,23 +816,22 @@ static int mgmt_fe_session_handle_get_req_msg(struct mgmt_fe_session_ctx *sessio return -1; } - MGMTD_FE_ADAPTER_DBG("Created new show txn-id: %" PRIu64 - " for session-id: %" PRIu64, - session->txn_id, session->session_id); + __dbg("Created new show txn-id: %" PRIu64 + " for session-id: %" PRIu64, + session->txn_id, session->session_id); } else { fe_adapter_send_get_reply(session, ds_id, req_id, false, NULL, "Request processing for GET failed!"); - MGMTD_FE_ADAPTER_DBG("Transaction in progress txn-id: %" PRIu64 - " for session-id: %" PRIu64, - session->txn_id, session->session_id); + __dbg("Transaction in progress txn-id: %" PRIu64 + " for session-id: %" PRIu64, + session->txn_id, session->session_id); return -1; } /* * Get a copy of the datastore config root, avoids locking. */ - if (is_cfg) - cfg_root = nb_config_dup(mgmt_ds_get_nb_config(ds_ctx)); + cfg_root = nb_config_dup(mgmt_ds_get_nb_config(ds_ctx)); /* * Create a GET request under the transaction. @@ -848,6 +895,9 @@ static int mgmt_fe_session_handle_commit_config_req_msg( } if (session->cfg_txn_id == MGMTD_TXN_ID_NONE) { + /* as we have the lock no-one else should have a config txn */ + assert(!mgmt_config_txn_in_progress()); + /* * Start a CONFIG Transaction (if not started already) */ @@ -861,20 +911,21 @@ static int mgmt_fe_session_handle_commit_config_req_msg( "Failed to create a Configuration session!"); return 0; } - MGMTD_FE_ADAPTER_DBG("Created txn-id: %" PRIu64 - " for session-id %" PRIu64 - " for COMMIT-CFG-REQ", - session->cfg_txn_id, session->session_id); + __dbg("Created txn-id: %" PRIu64 " for session-id %" PRIu64 + " for COMMIT-CFG-REQ", + session->cfg_txn_id, session->session_id); } /* * Create COMMITConfig request under the transaction */ - if (mgmt_txn_send_commit_config_req( - session->cfg_txn_id, commcfg_req->req_id, - commcfg_req->src_ds_id, src_ds_ctx, commcfg_req->dst_ds_id, - dst_ds_ctx, commcfg_req->validate_only, commcfg_req->abort, - false) != 0) { + if (mgmt_txn_send_commit_config_req(session->cfg_txn_id, + commcfg_req->req_id, + commcfg_req->src_ds_id, src_ds_ctx, + commcfg_req->dst_ds_id, dst_ds_ctx, + commcfg_req->validate_only, + commcfg_req->abort, false, + NULL) != 0) { fe_adapter_send_commit_cfg_reply( session, commcfg_req->src_ds_id, commcfg_req->dst_ds_id, commcfg_req->req_id, MGMTD_INTERNAL_ERROR, @@ -898,8 +949,8 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, */ switch ((int)fe_msg->message_case) { case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ: - MGMTD_FE_ADAPTER_DBG("Got REGISTER_REQ from '%s'", - fe_msg->register_req->client_name); + __dbg("Got REGISTER_REQ from '%s'", + fe_msg->register_req->client_name); if (strlen(fe_msg->register_req->client_name)) { strlcpy(adapter->name, @@ -912,11 +963,10 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, if (fe_msg->session_req->create && fe_msg->session_req->id_case == MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID) { - MGMTD_FE_ADAPTER_DBG( - "Got SESSION_REQ (create) for client-id %" PRIu64 - " from '%s'", - fe_msg->session_req->client_conn_id, - adapter->name); + __dbg("Got SESSION_REQ (create) for client-id %" PRIu64 + " from '%s'", + fe_msg->session_req->client_conn_id, + adapter->name); session = mgmt_fe_create_session( adapter, fe_msg->session_req->client_conn_id); @@ -926,10 +976,9 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, !fe_msg->session_req->create && fe_msg->session_req->id_case == MGMTD__FE_SESSION_REQ__ID_SESSION_ID) { - MGMTD_FE_ADAPTER_DBG( - "Got SESSION_REQ (destroy) for session-id %" PRIu64 - "from '%s'", - fe_msg->session_req->session_id, adapter->name); + __dbg("Got SESSION_REQ (destroy) for session-id %" PRIu64 + "from '%s'", + fe_msg->session_req->session_id, adapter->name); session = mgmt_session_id2ctx( fe_msg->session_req->session_id); @@ -941,12 +990,11 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ: session = mgmt_session_id2ctx( fe_msg->lockds_req->session_id); - MGMTD_FE_ADAPTER_DBG( - "Got LOCKDS_REQ (%sLOCK) for DS:%s for session-id %" PRIu64 - " from '%s'", - fe_msg->lockds_req->lock ? "" : "UN", - mgmt_ds_id2name(fe_msg->lockds_req->ds_id), - fe_msg->lockds_req->session_id, adapter->name); + __dbg("Got LOCKDS_REQ (%sLOCK) for DS:%s for session-id %" PRIu64 + " from '%s'", + fe_msg->lockds_req->lock ? "" : "UN", + mgmt_ds_id2name(fe_msg->lockds_req->ds_id), + fe_msg->lockds_req->session_id, adapter->name); mgmt_fe_session_handle_lockds_req_msg( session, fe_msg->lockds_req); break; @@ -954,13 +1002,12 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, session = mgmt_session_id2ctx( fe_msg->setcfg_req->session_id); session->adapter->setcfg_stats.set_cfg_count++; - MGMTD_FE_ADAPTER_DBG( - "Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64 - " from '%s'", - (int)fe_msg->setcfg_req->n_data, - fe_msg->setcfg_req->implicit_commit ? 'T' : 'F', - mgmt_ds_id2name(fe_msg->setcfg_req->ds_id), - fe_msg->setcfg_req->session_id, adapter->name); + __dbg("Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64 + " from '%s'", + (int)fe_msg->setcfg_req->n_data, + fe_msg->setcfg_req->implicit_commit ? 'T' : 'F', + mgmt_ds_id2name(fe_msg->setcfg_req->ds_id), + fe_msg->setcfg_req->session_id, adapter->name); mgmt_fe_session_handle_setcfg_req_msg( session, fe_msg->setcfg_req); @@ -968,31 +1015,28 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ: session = mgmt_session_id2ctx( fe_msg->commcfg_req->session_id); - MGMTD_FE_ADAPTER_DBG( - "Got COMMCFG_REQ for src-DS:%s dst-DS:%s (Abort:%c) on session-id %" PRIu64 - " from '%s'", - mgmt_ds_id2name(fe_msg->commcfg_req->src_ds_id), - mgmt_ds_id2name(fe_msg->commcfg_req->dst_ds_id), - fe_msg->commcfg_req->abort ? 'T' : 'F', - fe_msg->commcfg_req->session_id, adapter->name); + __dbg("Got COMMCFG_REQ for src-DS:%s dst-DS:%s (Abort:%c) on session-id %" PRIu64 + " from '%s'", + mgmt_ds_id2name(fe_msg->commcfg_req->src_ds_id), + mgmt_ds_id2name(fe_msg->commcfg_req->dst_ds_id), + fe_msg->commcfg_req->abort ? 'T' : 'F', + fe_msg->commcfg_req->session_id, adapter->name); mgmt_fe_session_handle_commit_config_req_msg( session, fe_msg->commcfg_req); break; case MGMTD__FE_MESSAGE__MESSAGE_GET_REQ: session = mgmt_session_id2ctx(fe_msg->get_req->session_id); - MGMTD_FE_ADAPTER_DBG("Got GET_REQ (iscfg %d) for DS:%s (xpaths: %d) on session-id %" PRIu64 - " from '%s'", - (int)fe_msg->get_req->config, - mgmt_ds_id2name(fe_msg->get_req->ds_id), - (int)fe_msg->get_req->n_data, - fe_msg->get_req->session_id, adapter->name); + __dbg("Got GET_REQ for DS:%s (xpaths: %d) on session-id %" PRIu64 + " from '%s'", + mgmt_ds_id2name(fe_msg->get_req->ds_id), + (int)fe_msg->get_req->n_data, fe_msg->get_req->session_id, + adapter->name); mgmt_fe_session_handle_get_req_msg(session, fe_msg->get_req); break; case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ: case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ: - MGMTD_FE_ADAPTER_ERR( - "Got unhandled message of type %u from '%s'", - fe_msg->message_case, adapter->name); + __log_err("Got unhandled message of type %u from '%s'", + fe_msg->message_case, adapter->name); /* * TODO: Add handling code in future. */ @@ -1020,25 +1064,715 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter, return 0; } +/** + * Send result of get-tree request back to the FE client. + * + * Args: + * session: the session. + * req_id: the request ID. + * short_circuit_ok: if allowed to short circuit the message. + * result_format: LYD_FORMAT for the sent output. + * tree: the tree to send, can be NULL which will send an empty tree. + * partial_error: if an error occurred during gathering results. + * + * Return: + * Any error that occurs -- the message is likely not sent if non-zero. + */ +static int fe_adapter_send_tree_data(struct mgmt_fe_session_ctx *session, + uint64_t req_id, bool short_circuit_ok, + uint8_t result_type, uint32_t wd_options, + const struct lyd_node *tree, + int partial_error) + +{ + struct mgmt_msg_tree_data *msg; + uint8_t **darrp = NULL; + int ret = 0; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_tree_data, 0, + MTYPE_MSG_NATIVE_TREE_DATA); + msg->refer_id = session->session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_TREE_DATA; + msg->partial_error = partial_error; + msg->result_type = result_type; + + darrp = mgmt_msg_native_get_darrp(msg); + ret = yang_print_tree_append(darrp, tree, result_type, + (wd_options | LYD_PRINT_WITHSIBLINGS)); + if (ret != LY_SUCCESS) { + __log_err("Error building get-tree result for client %s session-id %" PRIu64 + " req-id %" PRIu64 " scok %d result type %u", + session->adapter->name, session->session_id, req_id, + short_circuit_ok, result_type); + goto done; + } + + __dbg("Sending get-tree result from adapter %s to session-id %" PRIu64 + " req-id %" PRIu64 " scok %d result type %u len %u", + session->adapter->name, session->session_id, req_id, + short_circuit_ok, result_type, mgmt_msg_native_get_msg_len(msg)); + + ret = fe_adapter_send_native_msg(session->adapter, msg, + mgmt_msg_native_get_msg_len(msg), + short_circuit_ok); +done: + mgmt_msg_native_free_msg(msg); + + return ret; +} + +static int fe_adapter_send_rpc_reply(struct mgmt_fe_session_ctx *session, + uint64_t req_id, uint8_t result_type, + const struct lyd_node *result) +{ + struct mgmt_msg_rpc_reply *msg; + uint8_t **darrp = NULL; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_rpc_reply, 0, + MTYPE_MSG_NATIVE_RPC_REPLY); + msg->refer_id = session->session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_RPC_REPLY; + msg->result_type = result_type; + + if (result) { + darrp = mgmt_msg_native_get_darrp(msg); + ret = yang_print_tree_append(darrp, result, result_type, 0); + if (ret != LY_SUCCESS) { + __log_err("Error building rpc-reply result for client %s session-id %" PRIu64 + " req-id %" PRIu64 " result type %u", + session->adapter->name, session->session_id, + req_id, result_type); + goto done; + } + } + + __dbg("Sending rpc-reply from adapter %s to session-id %" PRIu64 + " req-id %" PRIu64 " len %u", + session->adapter->name, session->session_id, req_id, + mgmt_msg_native_get_msg_len(msg)); + + ret = fe_adapter_send_native_msg(session->adapter, msg, + mgmt_msg_native_get_msg_len(msg), + false); +done: + mgmt_msg_native_free_msg(msg); + + return ret; +} + +static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session, + uint64_t req_id, const char *xpath) +{ + struct mgmt_msg_edit_reply *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_edit_reply, 0, + MTYPE_MSG_NATIVE_EDIT_REPLY); + msg->refer_id = session->session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_EDIT_REPLY; + + mgmt_msg_native_xpath_encode(msg, xpath); + + __dbg("Sending edit-reply from adapter %s to session-id %" PRIu64 + " req-id %" PRIu64 " len %u", + session->adapter->name, session->session_id, req_id, + mgmt_msg_native_get_msg_len(msg)); + + ret = fe_adapter_send_native_msg(session->adapter, msg, + mgmt_msg_native_get_msg_len(msg), + false); + mgmt_msg_native_free_msg(msg); + + return ret; +} + +static int +fe_adapter_native_send_session_reply(struct mgmt_fe_client_adapter *adapter, + uint64_t req_id, uint64_t session_id, + bool created) +{ + struct mgmt_msg_session_reply *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_session_reply, 0, + MTYPE_MSG_NATIVE_SESSION_REPLY); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_SESSION_REPLY; + msg->created = created; + + __dbg("Sending session-reply from adapter %s to session-id %" PRIu64 + " req-id %" PRIu64 " len %u", + adapter->name, session_id, req_id, + mgmt_msg_native_get_msg_len(msg)); + + ret = fe_adapter_send_native_msg(adapter, msg, + mgmt_msg_native_get_msg_len(msg), + false); + mgmt_msg_native_free_msg(msg); + + return ret; +} + +/** + * fe_adapter_handle_session_req() - Handle a session-req message from a FE client. + * @msg_raw: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_session_req(struct mgmt_fe_client_adapter *adapter, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_session_req *msg = __msg; + struct mgmt_fe_session_ctx *session; + uint64_t client_id; + + __dbg("Got session-req creating: %u for refer-id %" PRIu64 " from '%s'", + msg->refer_id == 0, msg->refer_id, adapter->name); + + if (msg->refer_id) { + uint64_t session_id = msg->refer_id; + + session = mgmt_session_id2ctx(session_id); + if (!session) { + fe_adapter_conn_send_error( + adapter->conn, session_id, msg->req_id, false, + -EINVAL, + "No session to delete for session-id: %" PRIu64, + session_id); + return; + } + fe_adapter_native_send_session_reply(adapter, msg->req_id, + session_id, false); + mgmt_fe_cleanup_session(&session); + return; + } + + client_id = msg->req_id; + + /* See if we have a client name to register */ + if (msg_len > sizeof(*msg)) { + if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) { + fe_adapter_conn_send_error( + adapter->conn, client_id, msg->req_id, false, + -EINVAL, + "Corrupt session-req message rcvd from client-id: %" PRIu64, + client_id); + return; + } + __dbg("Set client-name to '%s'", msg->client_name); + strlcpy(adapter->name, msg->client_name, sizeof(adapter->name)); + } + + session = mgmt_fe_create_session(adapter, client_id); + fe_adapter_native_send_session_reply(adapter, client_id, + session->session_id, true); +} + +/** + * fe_adapter_handle_get_data() - Handle a get-tree message from a FE client. + * @session: the client session. + * @msg_raw: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_get_data *msg = __msg; + struct lysc_node **snodes = NULL; + char *xpath_resolved = NULL; + uint64_t req_id = msg->req_id; + Mgmtd__DatastoreId ds_id; + uint64_t clients; + uint32_t wd_options; + bool simple_xpath; + LY_ERR err; + int ret; + + __dbg("Received get-data request from client %s for session-id %" PRIu64 + " req-id %" PRIu64, + session->adapter->name, session->session_id, msg->req_id); + + if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid message rcvd from session-id: %" PRIu64, + session->session_id); + goto done; + } + + if (session->txn_id != MGMTD_TXN_ID_NONE) { + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "Transaction in progress txn-id: %" PRIu64 + " for session-id: %" PRIu64, + session->txn_id, session->session_id); + goto done; + } + + switch (msg->defaults) { + case GET_DATA_DEFAULTS_EXPLICIT: + wd_options = LYD_PRINT_WD_EXPLICIT; + break; + case GET_DATA_DEFAULTS_TRIM: + wd_options = LYD_PRINT_WD_TRIM; + break; + case GET_DATA_DEFAULTS_ALL: + wd_options = LYD_PRINT_WD_ALL; + break; + case GET_DATA_DEFAULTS_ALL_ADD_TAG: + wd_options = LYD_PRINT_WD_IMPL_TAG; + break; + default: + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid defaults value %u for session-id: %" PRIu64, + msg->defaults, session->session_id); + goto done; + } + + switch (msg->datastore) { + case MGMT_MSG_DATASTORE_CANDIDATE: + ds_id = MGMTD_DS_CANDIDATE; + break; + case MGMT_MSG_DATASTORE_RUNNING: + ds_id = MGMTD_DS_RUNNING; + break; + case MGMT_MSG_DATASTORE_OPERATIONAL: + ds_id = MGMTD_DS_OPERATIONAL; + break; + default: + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Unsupported datastore %" PRIu8 + " requested from session-id: %" PRIu64, + msg->datastore, session->session_id); + goto done; + } + + err = yang_resolve_snode_xpath(ly_native_ctx, msg->xpath, &snodes, + &simple_xpath); + if (err) { + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "XPath doesn't resolve for session-id: %" PRIu64, + session->session_id); + goto done; + } + darr_free(snodes); + + clients = mgmt_be_interested_clients(msg->xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_OPER); + if (!clients && !CHECK_FLAG(msg->flags, GET_DATA_FLAG_CONFIG)) { + __dbg("No backends provide xpath: %s for txn-id: %" PRIu64 + " session-id: %" PRIu64, + msg->xpath, session->txn_id, session->session_id); + + fe_adapter_send_tree_data(session, req_id, false, + msg->result_type, wd_options, NULL, 0); + goto done; + } + + /* Start a SHOW Transaction */ + session->txn_id = mgmt_create_txn(session->session_id, + MGMTD_TXN_TYPE_SHOW); + if (session->txn_id == MGMTD_SESSION_ID_NONE) { + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "failed to create a 'show' txn"); + goto done; + } + + __dbg("Created new show txn-id: %" PRIu64 " for session-id: %" PRIu64, + session->txn_id, session->session_id); + + /* Create a GET-TREE request under the transaction */ + ret = mgmt_txn_send_get_tree_oper(session->txn_id, req_id, clients, + ds_id, msg->result_type, msg->flags, + wd_options, simple_xpath, msg->xpath); + if (ret) { + /* destroy the just created txn */ + mgmt_destroy_txn(&session->txn_id); + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "failed to create a 'show' txn"); + } +done: + darr_free(snodes); + darr_free(xpath_resolved); +} + +static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_edit *msg = __msg; + Mgmtd__DatastoreId ds_id, rds_id; + struct mgmt_ds_ctx *ds_ctx, *rds_ctx; + const char *xpath, *data; + bool lock, commit; + int ret; + + if (msg->datastore != MGMT_MSG_DATASTORE_CANDIDATE) { + fe_adapter_send_error(session, msg->req_id, false, -EINVAL, + "Unsupported datastore"); + return; + } + + xpath = mgmt_msg_native_xpath_data_decode(msg, msg_len, data); + if (!xpath) { + fe_adapter_send_error(session, msg->req_id, false, -EINVAL, + "Invalid message"); + return; + } + + ds_id = MGMTD_DS_CANDIDATE; + ds_ctx = mgmt_ds_get_ctx_by_id(mm, ds_id); + assert(ds_ctx); + + rds_id = MGMTD_DS_RUNNING; + rds_ctx = mgmt_ds_get_ctx_by_id(mm, rds_id); + assert(rds_ctx); + + lock = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_LOCK); + commit = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_COMMIT); + + if (lock) { + if (mgmt_fe_session_write_lock_ds(ds_id, ds_ctx, session)) { + fe_adapter_send_error(session, msg->req_id, false, + -EBUSY, + "Candidate DS is locked by another session"); + return; + } + + if (commit) { + if (mgmt_fe_session_write_lock_ds(rds_id, rds_ctx, + session)) { + mgmt_fe_session_unlock_ds(ds_id, ds_ctx, + session); + fe_adapter_send_error( + session, msg->req_id, false, -EBUSY, + "Running DS is locked by another session"); + return; + } + } + } else { + if (!session->ds_locked[ds_id]) { + fe_adapter_send_error(session, msg->req_id, false, + -EBUSY, + "Candidate DS is not locked"); + return; + } + + if (commit) { + if (!session->ds_locked[rds_id]) { + fe_adapter_send_error(session, msg->req_id, + false, -EBUSY, + "Running DS is not locked"); + return; + } + } + } + + session->cfg_txn_id = mgmt_create_txn(session->session_id, + MGMTD_TXN_TYPE_CONFIG); + if (session->cfg_txn_id == MGMTD_SESSION_ID_NONE) { + if (lock) { + mgmt_fe_session_unlock_ds(ds_id, ds_ctx, session); + if (commit) + mgmt_fe_session_unlock_ds(rds_id, rds_ctx, + session); + } + fe_adapter_send_error(session, msg->req_id, false, -EBUSY, + "Failed to create a configuration transaction"); + return; + } + + __dbg("Created new config txn-id: %" PRIu64 " for session-id: %" PRIu64, + session->cfg_txn_id, session->session_id); + + ret = mgmt_txn_send_edit(session->cfg_txn_id, msg->req_id, ds_id, + ds_ctx, rds_id, rds_ctx, lock, commit, + msg->request_type, msg->flags, msg->operation, + xpath, data); + if (ret) { + /* destroy the just created txn */ + mgmt_destroy_txn(&session->cfg_txn_id); + if (lock) { + mgmt_fe_session_unlock_ds(ds_id, ds_ctx, session); + if (commit) + mgmt_fe_session_unlock_ds(rds_id, rds_ctx, + session); + } + fe_adapter_send_error(session, msg->req_id, false, -EBUSY, + "Failed to create a configuration transaction"); + } +} + +/** + * fe_adapter_handle_notify_select() - Handle an Notify Select message. + * @session: the client session. + * @__msg: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_notify_select(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_notify_select *msg = __msg; + uint64_t req_id = msg->req_id; + const char **selectors = NULL; + const char **new; + + if (msg_len >= sizeof(*msg)) { + selectors = mgmt_msg_native_strings_decode(msg, msg_len, + msg->selectors); + if (!selectors) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid message"); + return; + } + } + if (msg->replace) { + darr_free_free(session->notify_xpaths); + session->notify_xpaths = selectors; + } else if (selectors) { + new = darr_append_nz(session->notify_xpaths, + darr_len(selectors)); + memcpy(new, selectors, darr_len(selectors) * sizeof(*selectors)); + darr_free(selectors); + } +} + +/** + * fe_adapter_handle_rpc() - Handle an RPC message from an FE client. + * @session: the client session. + * @__msg: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_rpc(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_rpc *msg = __msg; + const struct lysc_node *snode; + const char *xpath, *data; + uint64_t req_id = msg->req_id; + uint64_t clients; + int ret; + + __dbg("Received RPC request from client %s for session-id %" PRIu64 + " req-id %" PRIu64, + session->adapter->name, session->session_id, msg->req_id); + + xpath = mgmt_msg_native_xpath_data_decode(msg, msg_len, data); + if (!xpath) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid message"); + return; + } + + if (session->txn_id != MGMTD_TXN_ID_NONE) { + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "Transaction in progress txn-id: %" PRIu64 + " for session-id: %" PRIu64, + session->txn_id, session->session_id); + return; + } + + snode = lys_find_path(ly_native_ctx, NULL, xpath, 0); + if (!snode) { + fe_adapter_send_error(session, req_id, false, -ENOENT, + "No such path: %s", xpath); + return; + } + + if (snode->nodetype != LYS_RPC && snode->nodetype != LYS_ACTION) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Not an RPC or action path: %s", xpath); + return; + } + + clients = mgmt_be_interested_clients(xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_RPC); + if (!clients) { + __dbg("No backends implement xpath: %s for txn-id: %" PRIu64 + " session-id: %" PRIu64, + xpath, session->txn_id, session->session_id); + + fe_adapter_send_error(session, req_id, false, -ENOENT, + "No backends implement xpath: %s", xpath); + return; + } + + /* Start a RPC Transaction */ + session->txn_id = mgmt_create_txn(session->session_id, + MGMTD_TXN_TYPE_RPC); + if (session->txn_id == MGMTD_SESSION_ID_NONE) { + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "Failed to create an RPC transaction"); + return; + } + + __dbg("Created new rpc txn-id: %" PRIu64 " for session-id: %" PRIu64, + session->txn_id, session->session_id); + + /* Create an RPC request under the transaction */ + ret = mgmt_txn_send_rpc(session->txn_id, req_id, clients, + msg->request_type, xpath, data, + mgmt_msg_native_data_len_decode(msg, msg_len)); + if (ret) { + /* destroy the just created txn */ + mgmt_destroy_txn(&session->txn_id); + fe_adapter_send_error(session, req_id, false, -EINPROGRESS, + "Failed to create an RPC transaction"); + } +} + +/** + * Handle a native encoded message from the FE client. + */ +static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, + struct mgmt_msg_header *msg, + size_t msg_len) +{ + struct mgmt_fe_session_ctx *session; + size_t min_size = mgmt_msg_get_min_size(msg->code); + + if (msg_len < min_size) { + if (!min_size) + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " unknown message type %u", + adapter->name, msg->refer_id, msg->code); + else + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " short (%zu<%zu) msg for type %u", + adapter->name, msg->refer_id, msg_len, + min_size, msg->code); + return; + } + + if (msg->code == MGMT_MSG_CODE_SESSION_REQ) { + __dbg("adapter %s: session-id %" PRIu64 + " received SESSION_REQ message", + adapter->name, msg->refer_id); + fe_adapter_handle_session_req(adapter, msg, msg_len); + return; + } + + session = mgmt_session_id2ctx(msg->refer_id); + if (!session) { + __log_err("adapter %s: recv msg unknown session-id %" PRIu64, + adapter->name, msg->refer_id); + return; + } + assert(session->adapter == adapter); + + switch (msg->code) { + case MGMT_MSG_CODE_EDIT: + __dbg("adapter %s: session-id %" PRIu64 " received EDIT message", + adapter->name, msg->refer_id); + fe_adapter_handle_edit(session, msg, msg_len); + break; + case MGMT_MSG_CODE_NOTIFY_SELECT: + __dbg("adapter %s: session-id %" PRIu64 + " received NOTIFY_SELECT message", + adapter->name, msg->refer_id); + fe_adapter_handle_notify_select(session, msg, msg_len); + break; + case MGMT_MSG_CODE_GET_DATA: + __dbg("adapter %s: session-id %" PRIu64 + " received GET_DATA message", + adapter->name, msg->refer_id); + fe_adapter_handle_get_data(session, msg, msg_len); + break; + case MGMT_MSG_CODE_RPC: + __dbg("adapter %s: session-id %" PRIu64 " received RPC message", + adapter->name, msg->refer_id); + fe_adapter_handle_rpc(session, msg, msg_len); + break; + default: + __log_err("unknown native message session-id %" PRIu64 + " req-id %" PRIu64 " code %u to FE adapter %s", + msg->refer_id, msg->req_id, msg->code, adapter->name); + break; + } +} + + static void mgmt_fe_adapter_process_msg(uint8_t version, uint8_t *data, size_t len, struct msg_conn *conn) { struct mgmt_fe_client_adapter *adapter = conn->user; - Mgmtd__FeMessage *fe_msg = mgmtd__fe_message__unpack(NULL, len, data); + Mgmtd__FeMessage *fe_msg; + if (version == MGMT_MSG_VERSION_NATIVE) { + struct mgmt_msg_header *msg = (typeof(msg))data; + + if (len >= sizeof(*msg)) + fe_adapter_handle_native_msg(adapter, msg, len); + else + __log_err("native message to adapter %s too short %zu", + adapter->name, len); + return; + } + + fe_msg = mgmtd__fe_message__unpack(NULL, len, data); if (!fe_msg) { - MGMTD_FE_ADAPTER_DBG( - "Failed to decode %zu bytes for adapter: %s", len, - adapter->name); + __dbg("Failed to decode %zu bytes for adapter: %s", len, + adapter->name); return; } - MGMTD_FE_ADAPTER_DBG( - "Decoded %zu bytes of message: %u from adapter: %s", len, - fe_msg->message_case, adapter->name); + __dbg("Decoded %zu bytes of message: %u from adapter: %s", len, + fe_msg->message_case, adapter->name); (void)mgmt_fe_adapter_handle_msg(adapter, fe_msg); mgmtd__fe_message__free_unpacked(fe_msg, NULL); } +void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, size_t msglen) +{ + struct mgmt_fe_client_adapter *adapter; + struct mgmt_fe_session_ctx *session; + struct nb_node *nb_node; + const char **xpath_prefix; + const char *notif; + bool sendit; + uint len; + + assert(msg->refer_id == 0); + + notif = mgmt_msg_native_xpath_decode(msg, msglen); + if (!notif) { + __log_err("Corrupt notify msg"); + return; + } + + /* + * We need the nb_node to obtain a path which does not include any + * specific list entry selectors + */ + nb_node = nb_node_find(notif); + if (!nb_node) { + __log_err("No schema found for notification: %s", notif); + return; + } + + FOREACH_ADAPTER_IN_LIST (adapter) { + FOREACH_SESSION_IN_LIST (adapter, session) { + /* If no selectors then always send */ + sendit = !session->notify_xpaths; + darr_foreach_p (session->notify_xpaths, xpath_prefix) { + len = strlen(*xpath_prefix); + if (!strncmp(*xpath_prefix, notif, len) || + !strncmp(*xpath_prefix, nb_node->xpath, + len)) { + sendit = true; + break; + } + } + if (sendit) { + msg->refer_id = session->session_id; + (void)fe_adapter_send_native_msg(adapter, msg, + msglen, false); + } + } + } + msg->refer_id = 0; +} + void mgmt_fe_adapter_lock(struct mgmt_fe_client_adapter *adapter) { adapter->refcount++; @@ -1062,6 +1796,8 @@ extern void mgmt_fe_adapter_unlock(struct mgmt_fe_client_adapter **adapter) */ void mgmt_fe_adapter_init(struct event_loop *tm) { + char server_path[MAXPATHLEN]; + assert(!mgmt_loop); mgmt_loop = tm; @@ -1072,9 +1808,10 @@ void mgmt_fe_adapter_init(struct event_loop *tm) hash_create(mgmt_fe_session_hash_key, mgmt_fe_session_hash_cmp, "MGMT Frontend Sessions"); - if (msg_server_init(&mgmt_fe_server, MGMTD_FE_SERVER_PATH, tm, - mgmt_fe_create_adapter, "frontend", - &mgmt_debug_fe)) { + snprintf(server_path, sizeof(server_path), MGMTD_FE_SOCK_NAME); + + if (msg_server_init(&mgmt_fe_server, server_path, tm, + mgmt_fe_create_adapter, "frontend", &mgmt_debug_fe)) { zlog_err("cannot initialize frontend server"); exit(1); } @@ -1084,11 +1821,10 @@ static void mgmt_fe_abort_if_session(void *data) { struct mgmt_fe_session_ctx *session = data; - MGMTD_FE_ADAPTER_ERR("found orphaned session id %" PRIu64 - " client id %" PRIu64 " adapter %s", - session->session_id, session->client_id, - session->adapter ? session->adapter->name - : "NULL"); + __log_err("found orphaned session id %" PRIu64 " client id %" PRIu64 + " adapter %s", + session->session_id, session->client_id, + session->adapter ? session->adapter->name : "NULL"); abort(); } @@ -1129,13 +1865,15 @@ struct msg_conn *mgmt_fe_create_adapter(int conn_fd, union sockunion *from) adapter->conn = msg_server_conn_create( mgmt_loop, conn_fd, mgmt_fe_adapter_notify_disconnect, mgmt_fe_adapter_process_msg, MGMTD_FE_MAX_NUM_MSG_PROC, - MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MSG_MAX_LEN, + MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MAX_MSG_LEN, adapter, "FE-adapter"); + adapter->conn->debug = DEBUG_MODE_CHECK(&mgmt_debug_fe, + DEBUG_MODE_ALL); + adapter->setcfg_stats.min_tm = ULONG_MAX; adapter->cmt_stats.min_tm = ULONG_MAX; - MGMTD_FE_ADAPTER_DBG("Added new MGMTD Frontend adapter '%s'", - adapter->name); + __dbg("Added new MGMTD Frontend adapter '%s'", adapter->name); } return adapter->conn; } @@ -1151,10 +1889,9 @@ int mgmt_fe_send_set_cfg_reply(uint64_t session_id, uint64_t txn_id, session = mgmt_session_id2ctx(session_id); if (!session || session->cfg_txn_id != txn_id) { if (session) - MGMTD_FE_ADAPTER_ERR( - "txn-id doesn't match, session txn-id is %" PRIu64 - " current txnid: %" PRIu64, - session->cfg_txn_id, txn_id); + __log_err("txn-id doesn't match, session txn-id is %" PRIu64 + " current txnid: %" PRIu64, + session->cfg_txn_id, txn_id); return -1; } @@ -1198,8 +1935,120 @@ int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id, error_if_any); } -struct mgmt_setcfg_stats * -mgmt_fe_get_session_setcfg_stats(uint64_t session_id) +int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, LYD_FORMAT result_type, + uint32_t wd_options, + const struct lyd_node *tree, + int partial_error, bool short_circuit_ok) +{ + struct mgmt_fe_session_ctx *session; + int ret; + + session = mgmt_session_id2ctx(session_id); + if (!session || session->txn_id != txn_id) + return -1; + + ret = fe_adapter_send_tree_data(session, req_id, short_circuit_ok, + result_type, wd_options, tree, + partial_error); + + mgmt_destroy_txn(&session->txn_id); + + return ret; +} + +int mgmt_fe_adapter_send_rpc_reply(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, LYD_FORMAT result_type, + const struct lyd_node *result) +{ + struct mgmt_fe_session_ctx *session; + int ret; + + session = mgmt_session_id2ctx(session_id); + if (!session || session->txn_id != txn_id) + return -1; + + ret = fe_adapter_send_rpc_reply(session, req_id, result_type, result); + + mgmt_destroy_txn(&session->txn_id); + + return ret; +} + +int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, bool unlock, bool commit, + const char *xpath, int16_t error, + const char *errstr) +{ + struct mgmt_fe_session_ctx *session; + Mgmtd__DatastoreId ds_id, rds_id; + struct mgmt_ds_ctx *ds_ctx, *rds_ctx; + int ret; + + session = mgmt_session_id2ctx(session_id); + if (!session || session->cfg_txn_id != txn_id) + return -1; + + if (session->cfg_txn_id != MGMTD_TXN_ID_NONE && commit) + mgmt_fe_session_register_event(session, + MGMTD_FE_SESSION_CFG_TXN_CLNUP); + + if (unlock) { + ds_id = MGMTD_DS_CANDIDATE; + ds_ctx = mgmt_ds_get_ctx_by_id(mm, ds_id); + assert(ds_ctx); + + mgmt_fe_session_unlock_ds(ds_id, ds_ctx, session); + + if (commit) { + rds_id = MGMTD_DS_RUNNING; + rds_ctx = mgmt_ds_get_ctx_by_id(mm, rds_id); + assert(rds_ctx); + + mgmt_fe_session_unlock_ds(rds_id, rds_ctx, session); + } + } + + if (error) + ret = fe_adapter_send_error(session, req_id, false, error, "%s", + errstr); + else + ret = fe_adapter_send_edit_reply(session, req_id, xpath); + + if (session->cfg_txn_id != MGMTD_TXN_ID_NONE && !commit) + mgmt_destroy_txn(&session->cfg_txn_id); + + return ret; +} + +/** + * Send an error back to the FE client and cleanup any in-progress txn. + */ +int mgmt_fe_adapter_txn_error(uint64_t txn_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errstr) +{ + struct mgmt_fe_session_ctx *session; + int ret; + + session = fe_adapter_session_by_txn_id(txn_id); + if (!session) { + __log_err("failed sending error for txn-id %" PRIu64 + " session not found", + txn_id); + return -ENOENT; + } + + + ret = fe_adapter_send_error(session, req_id, false, error, "%s", errstr); + + mgmt_destroy_txn(&session->txn_id); + + return ret; +} + + +struct mgmt_setcfg_stats *mgmt_fe_get_session_setcfg_stats(uint64_t session_id) { struct mgmt_fe_session_ctx *session; @@ -1274,15 +2123,6 @@ mgmt_fe_adapter_cmt_stats_write(struct vty *vty, mgmt_realtime_to_string( &adapter->cmt_stats.txn_create_start, buf, sizeof(buf))); - vty_out(vty, -#ifdef MGMTD_LOCAL_VALIDATIONS_ENABLED - " Send-Config Start: \t\t%s\n", -#else - " Send-Config-Validate Start: \t%s\n", -#endif - mgmt_realtime_to_string( - &adapter->cmt_stats.send_cfg_start, buf, - sizeof(buf))); vty_out(vty, " Apply-Config Start: \t\t%s\n", mgmt_realtime_to_string( &adapter->cmt_stats.apply_cfg_start, diff --git a/mgmtd/mgmt_fe_adapter.h b/mgmtd/mgmt_fe_adapter.h index d2991ec1dbd0..61d6cfae13aa 100644 --- a/mgmtd/mgmt_fe_adapter.h +++ b/mgmtd/mgmt_fe_adapter.h @@ -12,7 +12,7 @@ #include "mgmt_fe_client.h" #include "mgmt_msg.h" -#include "mgmtd/mgmt_defines.h" +#include "mgmt_defines.h" struct mgmt_fe_client_adapter; struct mgmt_master; @@ -24,7 +24,6 @@ struct mgmt_commit_stats { #endif struct timeval prep_cfg_start; struct timeval txn_create_start; - struct timeval send_cfg_start; struct timeval apply_cfg_start; struct timeval apply_cfg_end; struct timeval txn_del_start; @@ -138,6 +137,92 @@ extern int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id, Mgmtd__YangDataReply *data_resp, const char *error_if_any); +/** + * Send get-tree data reply back to client. + * + * This also cleans up and frees the transaction. + * + * Args: + * session_id: the session. + * txn_id: the txn_id this data pertains to + * req_id: the req id for the get_tree message + * result_type: the format of the result data. + * wd_options: with-defaults options. + * tree: the results. + * partial_error: if there were errors while gather results. + * short_circuit_ok: True if OK to short-circuit the call. + * + * Return: + * the return value from the underlying send function. + * + */ +extern int +mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, LYD_FORMAT result_type, + uint32_t wd_options, const struct lyd_node *tree, + int partial_error, bool short_circuit_ok); + +/** + * Send RPC reply back to client. + * + * This also cleans up and frees the transaction. + * + * Args: + * session_id: the session. + * txn_id: the txn_id this data pertains to + * req_id: the req id for the rpc message + * result_type: the format of the result data. + * result: the results. + * + * Return: + * the return value from the underlying send function. + */ +extern int mgmt_fe_adapter_send_rpc_reply(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, + LYD_FORMAT result_type, + const struct lyd_node *result); + +/** + * Send edit reply back to client. If error is not 0, a native error is sent. + * + * This also cleans up and frees the transaction. + * + * Args: + * session_id: the session. + * txn_id: the txn_id this data pertains to + * req_id: the req id for the edit message + * unlock: implicit-lock flag was set in the request + * commit: implicit-commit flag was set in the request + * xpath: the xpath of the data node that was created + * error: the error code, zero for successful request + * errstr: the error string, if error is non-zero + */ +extern int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id, + uint64_t req_id, bool unlock, + bool commit, const char *xpath, + int16_t error, const char *errstr); + +/** + * Send an error back to the FE client using native messaging. + * + * This also cleans up and frees the transaction. + * + * Args: + * txn_id: the txn_id this error pertains to. + * short_circuit_ok: True if OK to short-circuit the call. + * error: An integer error value. + * errfmt: An error format string (i.e., printfrr) + * ...: args for use by the `errfmt` format string. + * + * Return: + * the return value from the underlying send function. + * + */ +extern int mgmt_fe_adapter_txn_error(uint64_t txn_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errstr); + + /* Fetch frontend client session set-config stats */ extern struct mgmt_setcfg_stats * mgmt_fe_get_session_setcfg_stats(uint64_t session_id); @@ -149,4 +234,8 @@ mgmt_fe_get_session_commit_stats(uint64_t session_id); extern void mgmt_fe_adapter_status_write(struct vty *vty, bool detail); extern void mgmt_fe_adapter_perf_measurement(struct vty *vty, bool config); extern void mgmt_fe_adapter_reset_perf_stats(struct vty *vty); + +/* Toggle debug on or off for connected clients. */ +extern void mgmt_fe_adapter_toggle_client_debug(bool set); + #endif /* _FRR_MGMTD_FE_ADAPTER_H_ */ diff --git a/mgmtd/mgmt_history.c b/mgmtd/mgmt_history.c index d4069325ca50..c97cb7f0fdf3 100644 --- a/mgmtd/mgmt_history.c +++ b/mgmtd/mgmt_history.c @@ -63,7 +63,7 @@ static struct mgmt_cmt_info_t *mgmt_history_new_cmt_info(void) mgmt_time_to_string(&tv, true, new->time_str, sizeof(new->time_str)); mgmt_time_to_string(&tv, false, new->cmtid_str, sizeof(new->cmtid_str)); snprintf(new->cmt_json_file, sizeof(new->cmt_json_file), - MGMTD_COMMIT_FILE_PATH, new->cmtid_str); + MGMTD_COMMIT_FILE_PATH(new->cmtid_str)); return new; } @@ -104,18 +104,21 @@ mgmt_history_find_cmt_record(const char *cmtid_str) static bool mgmt_history_read_cmt_record_index(void) { + char index_path[MAXPATHLEN]; FILE *fp; struct mgmt_cmt_info_t cmt_info; struct mgmt_cmt_info_t *new; int cnt = 0; - if (!file_exists(MGMTD_COMMIT_FILE_PATH)) - return false; + snprintf(index_path, sizeof(index_path), MGMTD_COMMIT_INDEX_FILE_PATH); - fp = fopen(MGMTD_COMMIT_INDEX_FILE_NAME, "rb"); + fp = fopen(index_path, "rb"); if (!fp) { - zlog_err("Failed to open commit history %s for reading: %s", - MGMTD_COMMIT_INDEX_FILE_NAME, safe_strerror(errno)); + if (errno == ENOENT || errno == ENOTDIR) + return false; + + zlog_err("Failed to open commit history %pSQq for reading: %m", + index_path); return false; } @@ -132,9 +135,8 @@ static bool mgmt_history_read_cmt_record_index(void) memcpy(new, &cmt_info, sizeof(struct mgmt_cmt_info_t)); mgmt_cmt_infos_add_tail(&mm->cmts, new); } else { - zlog_warn( - "More records found in commit history file %s than expected", - MGMTD_COMMIT_INDEX_FILE_NAME); + zlog_warn("More records found in commit history file %pSQq than expected", + index_path); fclose(fp); return false; } @@ -148,16 +150,19 @@ static bool mgmt_history_read_cmt_record_index(void) static bool mgmt_history_dump_cmt_record_index(void) { + char index_path[MAXPATHLEN]; FILE *fp; int ret = 0; struct mgmt_cmt_info_t *cmt_info; struct mgmt_cmt_info_t cmt_info_set[10]; int cnt = 0; - fp = fopen(MGMTD_COMMIT_INDEX_FILE_NAME, "wb"); + snprintf(index_path, sizeof(index_path), MGMTD_COMMIT_INDEX_FILE_PATH); + + fp = fopen(index_path, "wb"); if (!fp) { - zlog_err("Failed to open commit history %s for writing: %s", - MGMTD_COMMIT_INDEX_FILE_NAME, safe_strerror(errno)); + zlog_err("Failed to open commit history %pSQq for writing: %m", + index_path); return false; } @@ -176,7 +181,7 @@ static bool mgmt_history_dump_cmt_record_index(void) fclose(fp); if (ret != cnt) { zlog_err("Failed to write full commit history, removing file"); - remove_file(MGMTD_COMMIT_INDEX_FILE_NAME); + remove_file(index_path); return false; } return true; @@ -261,7 +266,9 @@ static int mgmt_history_rollback_to_cmt(struct vty *vty, void mgmt_history_rollback_complete(bool success) { - vty_mgmt_resume_response(rollback_vty, success); + vty_mgmt_resume_response(rollback_vty, + success ? CMD_SUCCESS + : CMD_WARNING_CONFIG_FAILED); rollback_vty = NULL; } diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c index 39362fa74a83..e181d0da5ef0 100644 --- a/mgmtd/mgmt_main.c +++ b/mgmtd/mgmt_main.c @@ -10,22 +10,26 @@ #include "lib/version.h" #include "routemap.h" #include "filter.h" +#include "keychain.h" #include "libfrr.h" #include "frr_pthread.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_ds.h" +#include "ripd/rip_nb.h" +#include "ripngd/ripng_nb.h" #include "routing_nb.h" - +#include "affinitymap.h" +#include "zebra/zebra_cli.h" /* mgmt options, we use GNU getopt library. */ static const struct option longopts[] = { {"skip_runas", no_argument, NULL, 'S'}, {"no_zebra", no_argument, NULL, 'Z'}, {"socket_size", required_argument, NULL, 's'}, + {"vrfwnetns", no_argument, NULL, 'n'}, {0}}; static void mgmt_exit(int); -static void mgmt_vrf_terminate(void); /* privileges */ static zebra_capabilities_t _caps_p[] = {ZCAP_BIND, ZCAP_NET_RAW, @@ -45,7 +49,6 @@ struct zebra_privs_t mgmt_privs = { }; static struct frr_daemon_info mgmtd_di; -char backup_config_file[256]; /* SIGHUP handler. */ static void sighup(void) @@ -114,8 +117,6 @@ static __attribute__((__noreturn__)) void mgmt_exit(int status) /* stop pthreads (if any) */ frr_pthread_stop_all(); - mgmt_vrf_terminate(); - frr_fini(); exit(status); } @@ -139,87 +140,83 @@ static struct frr_signal_t mgmt_signals[] = { }, }; -static int mgmt_vrf_new(struct vrf *vrf) -{ - zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id); - - return 0; -} - -static int mgmt_vrf_delete(struct vrf *vrf) -{ - zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id); - - return 0; -} - -static int mgmt_vrf_enable(struct vrf *vrf) -{ - zlog_debug("VRF Enable: %s(%u)", vrf->name, vrf->vrf_id); - - return 0; -} - -static int mgmt_vrf_disable(struct vrf *vrf) -{ - zlog_debug("VRF Disable: %s(%u)", vrf->name, vrf->vrf_id); - - /* Note: This is a callback, the VRF will be deleted by the caller. */ - return 0; -} - -static int mgmt_vrf_config_write(struct vty *vty) -{ - return 0; -} +#ifdef HAVE_STATICD +extern const struct frr_yang_module_info frr_staticd_cli_info; +#endif -static void mgmt_vrf_init(void) -{ - vrf_init(mgmt_vrf_new, mgmt_vrf_enable, mgmt_vrf_disable, - mgmt_vrf_delete); - vrf_cmd_init(mgmt_vrf_config_write); -} +/* + * These are modules that are only needed by mgmtd and hence not included into + * the lib and backend daemons. + */ +const struct frr_yang_module_info ietf_netconf_with_defaults_info = { + .name = "ietf-netconf-with-defaults", + .ignore_cfg_cbs = true, + .nodes = { { .xpath = NULL } }, +}; -static void mgmt_vrf_terminate(void) -{ - vrf_terminate(); -} +/* + * These are stub info structs that are used to load the modules used by backend + * clients into mgmtd. The modules are used by libyang in order to support + * parsing binary data returns from the backend. + */ +const struct frr_yang_module_info zebra_route_map_info = { + .name = "frr-zebra-route-map", + .ignore_cfg_cbs = true, + .nodes = { { .xpath = NULL } }, +}; /* * List of YANG modules to be loaded in the process context of * MGMTd. - * - * NOTE: In future this will also include the YANG modules of - * all individual Backend clients. */ static const struct frr_yang_module_info *const mgmt_yang_modules[] = { - &frr_filter_info, - &frr_interface_info, - &frr_route_map_info, - &frr_routing_info, - &frr_vrf_info, -/* - * YANG module info supported by backend clients get added here. - * NOTE: Always set .ignore_cbs true for to avoid validating - * backend northbound callbacks during loading. - */ + &frr_filter_cli_info, + &frr_interface_cli_info, + &frr_route_map_cli_info, + &frr_routing_cli_info, + &frr_vrf_cli_info, + &frr_affinity_map_cli_info, + + /* mgmtd-only modules */ + &ietf_netconf_with_defaults_info, + + /* + * YANG module info used by backend clients get added here. + */ + + &frr_zebra_cli_info, + &zebra_route_map_info, + &ietf_key_chain_cli_info, + &ietf_key_chain_deviation_info, + +#ifdef HAVE_RIPD + &frr_ripd_cli_info, +#endif +#ifdef HAVE_RIPNGD + &frr_ripngd_cli_info, +#endif #ifdef HAVE_STATICD - &(struct frr_yang_module_info){.name = "frr-staticd", - .ignore_cbs = true}, + &frr_staticd_cli_info, #endif }; -FRR_DAEMON_INFO(mgmtd, MGMTD, .vty_port = MGMTD_VTY_PORT, - +/* clang-format off */ +FRR_DAEMON_INFO(mgmtd, MGMTD, + .vty_port = MGMTD_VTY_PORT, .proghelp = "FRR Management Daemon.", - .signals = mgmt_signals, .n_signals = array_size(mgmt_signals), + .signals = mgmt_signals, + .n_signals = array_size(mgmt_signals), + + .privs = &mgmt_privs, - .privs = &mgmt_privs, .yang_modules = mgmt_yang_modules, + .yang_modules = mgmt_yang_modules, .n_yang_modules = array_size(mgmt_yang_modules), /* avoid libfrr trying to read our config file for us */ - .flags = FRR_MANUAL_VTY_START); + .flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG, + ); +/* clang-format on */ #define DEPRECATED_OPTIONS "" @@ -235,8 +232,9 @@ int main(int argc, char **argv) frr_preinit(&mgmtd_di, argc, argv); frr_opt_add( - "s:" DEPRECATED_OPTIONS, longopts, - " -s, --socket_size Set MGMTD peer socket send buffer size\n"); + "s:n" DEPRECATED_OPTIONS, longopts, + " -s, --socket_size Set MGMTD peer socket send buffer size\n" + " -n, --vrfwnetns Use NetNS as VRF backend\n"); /* Command line argument treatment. */ while (1) { @@ -258,6 +256,9 @@ int main(int argc, char **argv) case 's': buffer_size = atoi(optarg); break; + case 'n': + vrf_configure_backend(VRF_BACKEND_NETNS); + break; default: frr_help_exit(1); break; @@ -267,17 +268,15 @@ int main(int argc, char **argv) /* MGMTD master init. */ mgmt_master_init(frr_init(), buffer_size); - /* VRF Initializations. */ - mgmt_vrf_init(); + /* VRF commands initialization. */ + vrf_cmd_init(NULL); + + /* Interface commands initialization. */ + if_cmd_init(NULL); /* MGMTD related initialization. */ mgmt_init(); - snprintf(backup_config_file, sizeof(backup_config_file), - "%s/zebra.conf", frr_sysconfdir); - mgmtd_di.backup_config_file = backup_config_file; - - /* this will queue a read configs event */ frr_config_fork(); frr_run(mm->master); diff --git a/mgmtd/mgmt_memory.c b/mgmtd/mgmt_memory.c index b2a0f0e848c0..72ccca062670 100644 --- a/mgmtd/mgmt_memory.c +++ b/mgmtd/mgmt_memory.c @@ -20,6 +20,7 @@ DEFINE_MGROUP(MGMTD, "mgmt"); DEFINE_MTYPE(MGMTD, MGMTD, "instance"); DEFINE_MTYPE(MGMTD, MGMTD_XPATH, "xpath regex"); +DEFINE_MTYPE(MGMTD, MGMTD_ERR, "error"); DEFINE_MTYPE(MGMTD, MGMTD_BE_ADPATER, "backend adapter"); DEFINE_MTYPE(MGMTD, MGMTD_FE_ADPATER, "frontend adapter"); DEFINE_MTYPE(MGMTD, MGMTD_FE_SESSION, "frontend session"); @@ -29,5 +30,7 @@ DEFINE_MTYPE(MGMTD, MGMTD_TXN_SETCFG_REQ, "txn set-config requests"); DEFINE_MTYPE(MGMTD, MGMTD_TXN_COMMCFG_REQ, "txn commit-config requests"); DEFINE_MTYPE(MGMTD, MGMTD_TXN_GETDATA_REQ, "txn get-data requests"); DEFINE_MTYPE(MGMTD, MGMTD_TXN_GETDATA_REPLY, "txn get-data replies"); +DEFINE_MTYPE(MGMTD, MGMTD_TXN_GETTREE_REQ, "txn get-tree requests"); +DEFINE_MTYPE(MGMTD, MGMTD_TXN_RPC_REQ, "txn rpc requests"); DEFINE_MTYPE(MGMTD, MGMTD_TXN_CFG_BATCH, "txn config batches"); DEFINE_MTYPE(MGMTD, MGMTD_CMT_INFO, "commit info"); diff --git a/mgmtd/mgmt_memory.h b/mgmtd/mgmt_memory.h index 06518e38384f..e28586ed830d 100644 --- a/mgmtd/mgmt_memory.h +++ b/mgmtd/mgmt_memory.h @@ -14,6 +14,7 @@ DECLARE_MGROUP(MGMTD); DECLARE_MTYPE(MGMTD); DECLARE_MTYPE(MGMTD_XPATH); +DECLARE_MTYPE(MGMTD_ERR); DECLARE_MTYPE(MGMTD_BE_ADPATER); DECLARE_MTYPE(MGMTD_FE_ADPATER); DECLARE_MTYPE(MGMTD_FE_SESSION); @@ -23,6 +24,8 @@ DECLARE_MTYPE(MGMTD_TXN_SETCFG_REQ); DECLARE_MTYPE(MGMTD_TXN_COMMCFG_REQ); DECLARE_MTYPE(MGMTD_TXN_GETDATA_REQ); DECLARE_MTYPE(MGMTD_TXN_GETDATA_REPLY); +DECLARE_MTYPE(MGMTD_TXN_GETTREE_REQ); +DECLARE_MTYPE(MGMTD_TXN_RPC_REQ); DECLARE_MTYPE(MGMTD_TXN_CFG_BATCH); DECLARE_MTYPE(MGMTD_BE_ADAPTER_MSG_BUF); DECLARE_MTYPE(MGMTD_CMT_INFO); diff --git a/mgmtd/mgmt_testc.c b/mgmtd/mgmt_testc.c new file mode 100644 index 000000000000..8bb07ed06863 --- /dev/null +++ b/mgmtd/mgmt_testc.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * January 29 2024, Christian Hopps + * + * Copyright (c) 2024, LabN Consulting, L.L.C. + * + */ + +#include +#include +#include "darr.h" +#include "libfrr.h" +#include "mgmt_be_client.h" +#include "northbound.h" + +/* ---------------- */ +/* Local Prototypes */ +/* ---------------- */ + +static void async_notification(struct nb_cb_notify_args *args); +static int rpc_callback(struct nb_cb_rpc_args *args); + +static void sigusr1(void); +static void sigint(void); + +/* ----------- */ +/* Global Data */ +/* ----------- */ + +/* privileges */ +static zebra_capabilities_t _caps_p[] = {}; + +struct zebra_privs_t __privs = { +#if defined(FRR_USER) && defined(FRR_GROUP) + .user = FRR_USER, + .group = FRR_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0, +}; + +#define OPTION_LISTEN 2000 +#define OPTION_NOTIF_COUNT 2001 +#define OPTION_TIMEOUT 2002 +const struct option longopts[] = { + { "listen", no_argument, NULL, OPTION_LISTEN }, + { "notif-count", required_argument, NULL, OPTION_NOTIF_COUNT }, + { "timeout", required_argument, NULL, OPTION_TIMEOUT }, + { 0 } +}; + + +/* Master of threads. */ +struct event_loop *master; + +struct mgmt_be_client *mgmt_be_client; + +static struct frr_daemon_info mgmtd_testc_di; + +struct frr_signal_t __signals[] = { + { + .signal = SIGUSR1, + .handler = &sigusr1, + }, + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, +}; + +#define MGMTD_TESTC_VTY_PORT 2624 + +/* clang-format off */ +static const struct frr_yang_module_info frr_ripd_info = { + .name = "frr-ripd", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-ripd:authentication-failure", + .cbs.notify = async_notification, + }, + { + .xpath = "/frr-ripd:clear-rip-route", + .cbs.rpc = rpc_callback, + }, + { + .xpath = NULL, + } + } +}; + +static const struct frr_yang_module_info *const mgmt_yang_modules[] = { + &frr_ripd_info, +}; + +FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC, + .proghelp = "FRR Management Daemon Test Client.", + + .signals = __signals, + .n_signals = array_size(__signals), + + .privs = &__privs, + + .yang_modules = mgmt_yang_modules, + .n_yang_modules = array_size(mgmt_yang_modules), + + /* avoid libfrr trying to read our config file for us */ + .flags = FRR_MANUAL_VTY_START, + ); +/* clang-format on */ + +const char **__notif_xpaths; +const char **__rpc_xpaths; + +struct mgmt_be_client_cbs __client_cbs = {}; +struct event *event_timeout; + +int o_notif_count = 1; +int o_timeout; + +/* --------- */ +/* Functions */ +/* --------- */ + + +static void sigusr1(void) +{ + zlog_rotate(); +} + +static void quit(int exit_code) +{ + EVENT_OFF(event_timeout); + darr_free(__client_cbs.notif_xpaths); + darr_free(__client_cbs.rpc_xpaths); + + frr_fini(); + + exit(exit_code); +} + +static void sigint(void) +{ + zlog_notice("Terminating on signal"); + quit(0); +} + +static void timeout(struct event *event) +{ + zlog_notice("Timeout, exiting"); + quit(1); +} + +static void success(struct event *event) +{ + zlog_notice("Success, exiting"); + quit(0); +} + +static void async_notification(struct nb_cb_notify_args *args) +{ + zlog_notice("Received YANG notification"); + + printf("{\"frr-ripd:authentication-failure\": {\"interface-name\": \"%s\"}}\n", + yang_dnode_get_string(args->dnode, "interface-name")); + + if (o_notif_count && !--o_notif_count) + quit(0); +} + +static int rpc_callback(struct nb_cb_rpc_args *args) +{ + const char *vrf = NULL; + + zlog_notice("Received YANG RPC"); + + if (yang_dnode_exists(args->input, "vrf")) + vrf = yang_dnode_get_string(args->input, "vrf"); + + printf("{\"frr-ripd:clear-rip-route\": {\"vrf\": \"%s\"}}\n", vrf); + + event_cancel(&event_timeout); + event_add_timer(master, success, NULL, 1, NULL); + + return 0; +} + +int main(int argc, char **argv) +{ + int f_listen = 0; + int i; + + frr_preinit(&mgmtd_testc_di, argc, argv); + frr_opt_add("", longopts, ""); + + while (1) { + int opt; + + opt = frr_getopt(argc, argv, NULL); + + if (opt == EOF) + break; + + switch (opt) { + case OPTION_LISTEN: + f_listen = 1; + break; + case OPTION_NOTIF_COUNT: + o_notif_count = atoi(optarg); + break; + case OPTION_TIMEOUT: + o_timeout = atoi(optarg); + break; + case 0: + break; + default: + frr_help_exit(1); + } + } + + master = frr_init(); + + /* + * Setup notification listen + */ + argv += optind; + argc -= optind; + if (!argc && f_listen) { + fprintf(stderr, + "Must specify at least one notification xpath to listen to\n"); + exit(1); + } + if (argc && f_listen) { + for (i = 0; i < argc; i++) { + zlog_notice("Listen on xpath: %s", argv[i]); + darr_push(__notif_xpaths, argv[i]); + } + __client_cbs.notif_xpaths = __notif_xpaths; + __client_cbs.nnotif_xpaths = darr_len(__notif_xpaths); + } + + darr_push(__rpc_xpaths, "/frr-ripd:clear-rip-route"); + __client_cbs.rpc_xpaths = __rpc_xpaths; + __client_cbs.nrpc_xpaths = darr_len(__rpc_xpaths); + + mgmt_be_client = mgmt_be_client_create("mgmtd-testc", &__client_cbs, 0, + master); + + frr_config_fork(); + + if (o_timeout) + event_add_timer(master, timeout, NULL, o_timeout, &event_timeout); + + frr_run(master); + + /* Reached. */ + return 0; +} diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index 53b9b7df46c2..ed133243a1a3 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -7,17 +7,19 @@ */ #include +#include "darr.h" #include "hash.h" #include "jhash.h" #include "libfrr.h" +#include "mgmt_msg.h" +#include "mgmt_msg_native.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_memory.h" #include "mgmtd/mgmt_txn.h" -#define MGMTD_TXN_DBG(fmt, ...) \ +#define __dbg(fmt, ...) \ DEBUGD(&mgmt_debug_txn, "TXN: %s: " fmt, __func__, ##__VA_ARGS__) -#define MGMTD_TXN_ERR(fmt, ...) \ - zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__) +#define __log_err(fmt, ...) zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__) #define MGMTD_TXN_LOCK(txn) mgmt_txn_lock(txn, __FILE__, __LINE__) #define MGMTD_TXN_UNLOCK(txn) mgmt_txn_unlock(txn, __FILE__, __LINE__) @@ -26,9 +28,9 @@ enum mgmt_txn_event { MGMTD_TXN_PROC_SETCFG = 1, MGMTD_TXN_PROC_COMMITCFG, MGMTD_TXN_PROC_GETCFG, - MGMTD_TXN_PROC_GETDATA, + MGMTD_TXN_PROC_GETTREE, + MGMTD_TXN_PROC_RPC, MGMTD_TXN_COMMITCFG_TIMEOUT, - MGMTD_TXN_CLEANUP }; PREDECL_LIST(mgmt_txn_reqs); @@ -47,7 +49,6 @@ struct mgmt_set_cfg_req { enum mgmt_commit_phase { MGMTD_COMMIT_PHASE_PREPARE_CFG = 0, MGMTD_COMMIT_PHASE_TXN_CREATE, - MGMTD_COMMIT_PHASE_SEND_CFG, MGMTD_COMMIT_PHASE_APPLY_CFG, MGMTD_COMMIT_PHASE_TXN_DELETE, MGMTD_COMMIT_PHASE_MAX @@ -60,8 +61,6 @@ static inline const char *mgmt_commit_phase2str(enum mgmt_commit_phase cmt_phase return "PREP-CFG"; case MGMTD_COMMIT_PHASE_TXN_CREATE: return "CREATE-TXN"; - case MGMTD_COMMIT_PHASE_SEND_CFG: - return "SEND-CFG"; case MGMTD_COMMIT_PHASE_APPLY_CFG: return "APPLY-CFG"; case MGMTD_COMMIT_PHASE_TXN_DELETE: @@ -77,17 +76,14 @@ PREDECL_LIST(mgmt_txn_batches); struct mgmt_txn_be_cfg_batch { struct mgmt_txn_ctx *txn; - uint64_t batch_id; enum mgmt_be_client_id be_id; struct mgmt_be_client_adapter *be_adapter; - uint xp_subscr[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangCfgDataReq cfg_data[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangCfgDataReq *cfg_datap[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangData data[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; Mgmtd__YangDataValue value[MGMTD_MAX_CFG_CHANGES_IN_BATCH]; size_t num_cfg_data; int buf_space_left; - enum mgmt_commit_phase comm_phase; struct mgmt_txn_batches_item list_linkage; }; @@ -96,6 +92,11 @@ DECLARE_LIST(mgmt_txn_batches, struct mgmt_txn_be_cfg_batch, list_linkage); #define FOREACH_TXN_CFG_BATCH_IN_LIST(list, batch) \ frr_each_safe (mgmt_txn_batches, list, batch) +struct mgmt_edit_req { + char xpath_created[XPATH_MAXLEN]; + bool unlock; +}; + struct mgmt_commit_cfg_req { Mgmtd__DatastoreId src_ds_id; struct mgmt_ds_ctx *src_ds_ctx; @@ -106,10 +107,18 @@ struct mgmt_commit_cfg_req { uint8_t abort : 1; uint8_t implicit : 1; uint8_t rollback : 1; + uint8_t init : 1; /* Track commit phases */ - enum mgmt_commit_phase curr_phase; - enum mgmt_commit_phase next_phase; + enum mgmt_commit_phase phase; + + enum mgmt_commit_phase be_phase[MGMTD_BE_CLIENT_ID_MAX]; + + /* + * Additional information when the commit is triggered by native edit + * request. + */ + struct mgmt_edit_req *edit; /* * Set of config changes to commit. This is used only @@ -125,26 +134,17 @@ struct mgmt_commit_cfg_req { * Details on all the Backend Clients associated with * this commit. */ - struct mgmt_be_client_subscr_info subscr_info; + uint64_t clients; /* * List of backend batches for this commit to be validated * and applied at the backend. - * - * FIXME: Need to re-think this design for the case set of - * validators for a given YANG data item is different from - * the set of notifiers for the same. We may need to have - * separate list of batches for VALIDATE and APPLY. */ - struct mgmt_txn_batches_head curr_batches[MGMTD_BE_CLIENT_ID_MAX]; - struct mgmt_txn_batches_head next_batches[MGMTD_BE_CLIENT_ID_MAX]; + struct mgmt_txn_batches_head batches[MGMTD_BE_CLIENT_ID_MAX]; /* - * The last batch added for any backend client. This is always on - * 'curr_batches' + * The last batch added for any backend client. */ struct mgmt_txn_be_cfg_batch *last_be_cfg_batch[MGMTD_BE_CLIENT_ID_MAX]; - struct hash *batches; - uint64_t next_batch_id; struct mgmt_commit_stats *cmt_stats; }; @@ -176,6 +176,28 @@ struct mgmt_get_data_req { int total_reply; }; + +struct txn_req_get_tree { + char *xpath; /* xpath of tree to get */ + uint64_t sent_clients; /* Bitmask of clients sent req to */ + uint64_t recv_clients; /* Bitmask of clients recv reply from */ + int32_t partial_error; /* an error while gather results */ + uint8_t result_type; /* LYD_FORMAT for results */ + uint8_t wd_options; /* LYD_PRINT_WD_* flags for results */ + uint8_t exact; /* if exact node is requested */ + uint8_t simple_xpath; /* if xpath is simple */ + struct lyd_node *client_results; /* result tree from clients */ +}; + +struct txn_req_rpc { + char *xpath; /* xpath of rpc/action to invoke */ + uint64_t sent_clients; /* Bitmask of clients sent req to */ + uint64_t recv_clients; /* Bitmask of clients recv reply from */ + uint8_t result_type; /* LYD_FORMAT for results */ + char *errstr; /* error string */ + struct lyd_node *client_results; /* result tree from clients */ +}; + struct mgmt_txn_req { struct mgmt_txn_ctx *txn; enum mgmt_txn_event req_event; @@ -183,10 +205,11 @@ struct mgmt_txn_req { union { struct mgmt_set_cfg_req *set_cfg; struct mgmt_get_data_req *get_data; + struct txn_req_get_tree *get_tree; + struct txn_req_rpc *rpc; struct mgmt_commit_cfg_req commit_cfg; } req; - bool pending_be_proc; struct mgmt_txn_reqs_item list_linkage; }; @@ -206,7 +229,10 @@ struct mgmt_txn_ctx { struct event *proc_comm_cfg; struct event *proc_get_cfg; struct event *proc_get_data; + struct event *proc_get_tree; struct event *comm_cfg_timeout; + struct event *get_tree_timeout; + struct event *rpc_timeout; struct event *clnup; /* List of backend adapters involved in this transaction */ @@ -216,6 +242,10 @@ struct mgmt_txn_ctx { struct mgmt_txns_item list_linkage; + /* TODO: why do we need unique lists for each type of transaction since + * a transaction is of only 1 type? + */ + /* * List of pending set-config requests for a given * transaction/session. Just one list for requests @@ -231,13 +261,13 @@ struct mgmt_txn_ctx { */ struct mgmt_txn_reqs_head get_cfg_reqs; /* - * List of pending get-data requests for a given - * transaction/session Two lists, one for requests - * not processed at all, and one for requests that - * has been sent to backend for processing. + * List of pending get-tree requests. */ - struct mgmt_txn_reqs_head get_data_reqs; - struct mgmt_txn_reqs_head pending_get_datas; + struct mgmt_txn_reqs_head get_tree_reqs; + /* + * List of pending rpc requests. + */ + struct mgmt_txn_reqs_head rpc_reqs; /* * There will always be one commit-config allowed for a given * transaction/session. No need to maintain lists for it. @@ -254,15 +284,12 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, enum mgmt_result result, const char *error_if_any); -static inline const char *mgmt_txn_commit_phase_str(struct mgmt_txn_ctx *txn, - bool curr) +static inline const char *mgmt_txn_commit_phase_str(struct mgmt_txn_ctx *txn) { if (!txn->commit_cfg_req) return "None"; - return (mgmt_commit_phase2str( - curr ? txn->commit_cfg_req->req.commit_cfg.curr_phase - : txn->commit_cfg_req->req.commit_cfg.next_phase)); + return mgmt_commit_phase2str(txn->commit_cfg_req->req.commit_cfg.phase); } static void mgmt_txn_lock(struct mgmt_txn_ctx *txn, const char *file, int line); @@ -277,9 +304,7 @@ static struct mgmt_master *mgmt_txn_mm; static void mgmt_txn_register_event(struct mgmt_txn_ctx *txn, enum mgmt_txn_event event); -static int -mgmt_move_be_commit_to_next_phase(struct mgmt_txn_ctx *txn, - struct mgmt_be_client_adapter *adapter); +static void mgmt_txn_cleanup_txn(struct mgmt_txn_ctx **txn); static struct mgmt_txn_be_cfg_batch * mgmt_txn_cfg_batch_alloc(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id, @@ -296,7 +321,7 @@ mgmt_txn_cfg_batch_alloc(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id, MGMTD_TXN_LOCK(txn); assert(txn->commit_cfg_req); mgmt_txn_batches_add_tail(&txn->commit_cfg_req->req.commit_cfg - .curr_batches[id], + .batches[id], batch); batch->be_adapter = be_adapter; batch->buf_space_left = MGMTD_BE_CFGDATA_MAX_MSG_LEN; @@ -304,11 +329,6 @@ mgmt_txn_cfg_batch_alloc(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id, mgmt_be_adapter_lock(be_adapter); txn->commit_cfg_req->req.commit_cfg.last_be_cfg_batch[id] = batch; - if (!txn->commit_cfg_req->req.commit_cfg.next_batch_id) - txn->commit_cfg_req->req.commit_cfg.next_batch_id++; - batch->batch_id = txn->commit_cfg_req->req.commit_cfg.next_batch_id++; - hash_get(txn->commit_cfg_req->req.commit_cfg.batches, batch, - hash_alloc_intern); return batch; } @@ -318,15 +338,12 @@ static void mgmt_txn_cfg_batch_free(struct mgmt_txn_be_cfg_batch **batch) size_t indx; struct mgmt_commit_cfg_req *cmtcfg_req; - MGMTD_TXN_DBG(" freeing batch-id: %" PRIu64 " txn-id %" PRIu64, - (*batch)->batch_id, (*batch)->txn->txn_id); + __dbg(" freeing batch txn-id %" PRIu64, (*batch)->txn->txn_id); assert((*batch)->txn && (*batch)->txn->type == MGMTD_TXN_TYPE_CONFIG); cmtcfg_req = &(*batch)->txn->commit_cfg_req->req.commit_cfg; - hash_release(cmtcfg_req->batches, *batch); - mgmt_txn_batches_del(&cmtcfg_req->curr_batches[(*batch)->be_id], *batch); - mgmt_txn_batches_del(&cmtcfg_req->next_batches[(*batch)->be_id], *batch); + mgmt_txn_batches_del(&cmtcfg_req->batches[(*batch)->be_id], *batch); if ((*batch)->be_adapter) mgmt_be_adapter_unlock(&(*batch)->be_adapter); @@ -344,57 +361,13 @@ static void mgmt_txn_cfg_batch_free(struct mgmt_txn_be_cfg_batch **batch) *batch = NULL; } -static unsigned int mgmt_txn_cfgbatch_hash_key(const void *data) -{ - const struct mgmt_txn_be_cfg_batch *batch = data; - - return jhash2((uint32_t *)&batch->batch_id, - sizeof(batch->batch_id) / sizeof(uint32_t), 0); -} - -static bool mgmt_txn_cfgbatch_hash_cmp(const void *d1, const void *d2) -{ - const struct mgmt_txn_be_cfg_batch *batch1 = d1; - const struct mgmt_txn_be_cfg_batch *batch2 = d2; - - return (batch1->batch_id == batch2->batch_id); -} - -static void mgmt_txn_cfgbatch_hash_free(void *data) -{ - struct mgmt_txn_be_cfg_batch *batch = data; - - mgmt_txn_cfg_batch_free(&batch); -} - -static inline struct mgmt_txn_be_cfg_batch * -mgmt_txn_cfgbatch_id2ctx(struct mgmt_txn_ctx *txn, uint64_t batch_id) -{ - struct mgmt_txn_be_cfg_batch key = { 0 }; - struct mgmt_txn_be_cfg_batch *batch; - - if (!txn->commit_cfg_req) - return NULL; - - key.batch_id = batch_id; - batch = hash_lookup(txn->commit_cfg_req->req.commit_cfg.batches, &key); - - return batch; -} - static void mgmt_txn_cleanup_be_cfg_batches(struct mgmt_txn_ctx *txn, enum mgmt_be_client_id id) { struct mgmt_txn_be_cfg_batch *batch; struct mgmt_txn_batches_head *list; - list = &txn->commit_cfg_req->req.commit_cfg.curr_batches[id]; - FOREACH_TXN_CFG_BATCH_IN_LIST (list, batch) - mgmt_txn_cfg_batch_free(&batch); - - mgmt_txn_batches_fini(list); - - list = &txn->commit_cfg_req->req.commit_cfg.next_batches[id]; + list = &txn->commit_cfg_req->req.commit_cfg.batches[id]; FOREACH_TXN_CFG_BATCH_IN_LIST (list, batch) mgmt_txn_cfg_batch_free(&batch); @@ -415,7 +388,6 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn, txn_req->txn = txn; txn_req->req_id = req_id; txn_req->req_event = req_event; - txn_req->pending_be_proc = false; switch (txn_req->req_event) { case MGMTD_TXN_PROC_SETCFG: @@ -423,27 +395,24 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn, sizeof(struct mgmt_set_cfg_req)); assert(txn_req->req.set_cfg); mgmt_txn_reqs_add_tail(&txn->set_cfg_reqs, txn_req); - MGMTD_TXN_DBG("Added a new SETCFG req-id: %" PRIu64 - " txn-id: %" PRIu64 ", session-id: %" PRIu64, - txn_req->req_id, txn->txn_id, txn->session_id); + __dbg("Added a new SETCFG req-id: %" PRIu64 " txn-id: %" PRIu64 + ", session-id: %" PRIu64, + txn_req->req_id, txn->txn_id, txn->session_id); break; case MGMTD_TXN_PROC_COMMITCFG: txn->commit_cfg_req = txn_req; - MGMTD_TXN_DBG("Added a new COMMITCFG req-id: %" PRIu64 - " txn-id: %" PRIu64 " session-id: %" PRIu64, - txn_req->req_id, txn->txn_id, txn->session_id); + __dbg("Added a new COMMITCFG req-id: %" PRIu64 + " txn-id: %" PRIu64 " session-id: %" PRIu64, + txn_req->req_id, txn->txn_id, txn->session_id); FOREACH_MGMTD_BE_CLIENT_ID (id) { + txn_req->req.commit_cfg.be_phase[id] = + MGMTD_COMMIT_PHASE_PREPARE_CFG; mgmt_txn_batches_init( - &txn_req->req.commit_cfg.curr_batches[id]); - mgmt_txn_batches_init( - &txn_req->req.commit_cfg.next_batches[id]); + &txn_req->req.commit_cfg.batches[id]); } - txn_req->req.commit_cfg.batches = - hash_create(mgmt_txn_cfgbatch_hash_key, - mgmt_txn_cfgbatch_hash_cmp, - "MGMT Config Batches"); + txn_req->req.commit_cfg.phase = MGMTD_COMMIT_PHASE_PREPARE_CFG; break; case MGMTD_TXN_PROC_GETCFG: txn_req->req.get_data = @@ -451,22 +420,28 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn, sizeof(struct mgmt_get_data_req)); assert(txn_req->req.get_data); mgmt_txn_reqs_add_tail(&txn->get_cfg_reqs, txn_req); - MGMTD_TXN_DBG("Added a new GETCFG req-id: %" PRIu64 - " txn-id: %" PRIu64 " session-id: %" PRIu64, - txn_req->req_id, txn->txn_id, txn->session_id); + __dbg("Added a new GETCFG req-id: %" PRIu64 " txn-id: %" PRIu64 + " session-id: %" PRIu64, + txn_req->req_id, txn->txn_id, txn->session_id); break; - case MGMTD_TXN_PROC_GETDATA: - txn_req->req.get_data = - XCALLOC(MTYPE_MGMTD_TXN_GETDATA_REQ, - sizeof(struct mgmt_get_data_req)); - assert(txn_req->req.get_data); - mgmt_txn_reqs_add_tail(&txn->get_data_reqs, txn_req); - MGMTD_TXN_DBG("Added a new GETDATA req-id: %" PRIu64 - " txn-id: %" PRIu64 " session-id: %" PRIu64, - txn_req->req_id, txn->txn_id, txn->session_id); + case MGMTD_TXN_PROC_GETTREE: + txn_req->req.get_tree = XCALLOC(MTYPE_MGMTD_TXN_GETTREE_REQ, + sizeof(struct txn_req_get_tree)); + mgmt_txn_reqs_add_tail(&txn->get_tree_reqs, txn_req); + __dbg("Added a new GETTREE req-id: %" PRIu64 " txn-id: %" PRIu64 + " session-id: %" PRIu64, + txn_req->req_id, txn->txn_id, txn->session_id); + break; + case MGMTD_TXN_PROC_RPC: + txn_req->req.rpc = XCALLOC(MTYPE_MGMTD_TXN_RPC_REQ, + sizeof(struct txn_req_rpc)); + assert(txn_req->req.rpc); + mgmt_txn_reqs_add_tail(&txn->rpc_reqs, txn_req); + __dbg("Added a new RPC req-id: %" PRIu64 " txn-id: %" PRIu64 + " session-id: %" PRIu64, + txn_req->req_id, txn->txn_id, txn->session_id); break; case MGMTD_TXN_COMMITCFG_TIMEOUT: - case MGMTD_TXN_CLEANUP: break; } @@ -479,49 +454,33 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req) { int indx; struct mgmt_txn_reqs_head *req_list = NULL; - struct mgmt_txn_reqs_head *pending_list = NULL; enum mgmt_be_client_id id; struct mgmt_be_client_adapter *adapter; struct mgmt_commit_cfg_req *ccreq; + struct mgmt_set_cfg_req *set_cfg; bool cleanup; switch ((*txn_req)->req_event) { case MGMTD_TXN_PROC_SETCFG: - for (indx = 0; indx < (*txn_req)->req.set_cfg->num_cfg_changes; - indx++) { - if ((*txn_req)->req.set_cfg->cfg_changes[indx].value) { - MGMTD_TXN_DBG("Freeing value for %s at %p ==> '%s'", - (*txn_req) - ->req.set_cfg - ->cfg_changes[indx] - .xpath, - (*txn_req) - ->req.set_cfg - ->cfg_changes[indx] - .value, - (*txn_req) - ->req.set_cfg - ->cfg_changes[indx] - .value); - free((void *)(*txn_req) - ->req.set_cfg->cfg_changes[indx] - .value); - } + set_cfg = (*txn_req)->req.set_cfg; + for (indx = 0; indx < set_cfg->num_cfg_changes; indx++) { + if (set_cfg->cfg_changes[indx].value) + free((void *)set_cfg->cfg_changes[indx].value); } req_list = &(*txn_req)->txn->set_cfg_reqs; - MGMTD_TXN_DBG("Deleting SETCFG req-id: %" PRIu64 - " txn-id: %" PRIu64, - (*txn_req)->req_id, (*txn_req)->txn->txn_id); + __dbg("Deleting SETCFG req-id: %" PRIu64 " txn-id: %" PRIu64, + (*txn_req)->req_id, (*txn_req)->txn->txn_id); XFREE(MTYPE_MGMTD_TXN_SETCFG_REQ, (*txn_req)->req.set_cfg); break; case MGMTD_TXN_PROC_COMMITCFG: - MGMTD_TXN_DBG("Deleting COMMITCFG req-id: %" PRIu64 - " txn-id: %" PRIu64, - (*txn_req)->req_id, (*txn_req)->txn->txn_id); + __dbg("Deleting COMMITCFG req-id: %" PRIu64 " txn-id: %" PRIu64, + (*txn_req)->req_id, (*txn_req)->txn->txn_id); ccreq = &(*txn_req)->req.commit_cfg; - cleanup = (ccreq->curr_phase >= MGMTD_COMMIT_PHASE_TXN_CREATE && - ccreq->curr_phase < MGMTD_COMMIT_PHASE_TXN_DELETE); + cleanup = (ccreq->phase >= MGMTD_COMMIT_PHASE_TXN_CREATE && + ccreq->phase < MGMTD_COMMIT_PHASE_TXN_DELETE); + + XFREE(MTYPE_MGMTD_TXN_REQ, ccreq->edit); FOREACH_MGMTD_BE_CLIENT_ID (id) { /* @@ -534,20 +493,13 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req) * anything more with them */ mgmt_txn_cleanup_be_cfg_batches((*txn_req)->txn, id); - if (ccreq->batches) { - hash_clean(ccreq->batches, - mgmt_txn_cfgbatch_hash_free); - hash_free(ccreq->batches); - ccreq->batches = NULL; - } /* * If we were in the middle of the state machine then * send a txn delete message */ adapter = mgmt_be_get_adapter_by_id(id); - if (adapter && cleanup && - ccreq->subscr_info.xpath_subscr[id]) + if (adapter && cleanup && IS_IDBIT_SET(ccreq->clients, id)) mgmt_txn_send_be_txn_delete((*txn_req)->txn, adapter); } @@ -560,9 +512,8 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req) ->req.get_data->xpaths[indx]); } req_list = &(*txn_req)->txn->get_cfg_reqs; - MGMTD_TXN_DBG("Deleting GETCFG req-id: %" PRIu64 - " txn-id: %" PRIu64, - (*txn_req)->req_id, (*txn_req)->txn->txn_id); + __dbg("Deleting GETCFG req-id: %" PRIu64 " txn-id: %" PRIu64, + (*txn_req)->req_id, (*txn_req)->txn->txn_id); if ((*txn_req)->req.get_data->reply) XFREE(MTYPE_MGMTD_TXN_GETDATA_REPLY, (*txn_req)->req.get_data->reply); @@ -572,42 +523,33 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req) XFREE(MTYPE_MGMTD_TXN_GETDATA_REQ, (*txn_req)->req.get_data); break; - case MGMTD_TXN_PROC_GETDATA: - for (indx = 0; indx < (*txn_req)->req.get_data->num_xpaths; - indx++) { - if ((*txn_req)->req.get_data->xpaths[indx]) - free((void *)(*txn_req) - ->req.get_data->xpaths[indx]); - } - pending_list = &(*txn_req)->txn->pending_get_datas; - req_list = &(*txn_req)->txn->get_data_reqs; - MGMTD_TXN_DBG("Deleting GETDATA req-id: %" PRIu64 - " txn-id: %" PRIu64, - (*txn_req)->req_id, (*txn_req)->txn->txn_id); - if ((*txn_req)->req.get_data->reply) - XFREE(MTYPE_MGMTD_TXN_GETDATA_REPLY, - (*txn_req)->req.get_data->reply); - XFREE(MTYPE_MGMTD_TXN_GETDATA_REQ, (*txn_req)->req.get_data); + case MGMTD_TXN_PROC_GETTREE: + __dbg("Deleting GETTREE req-id: %" PRIu64 " of txn-id: %" PRIu64, + (*txn_req)->req_id, (*txn_req)->txn->txn_id); + req_list = &(*txn_req)->txn->get_tree_reqs; + lyd_free_all((*txn_req)->req.get_tree->client_results); + XFREE(MTYPE_MGMTD_XPATH, (*txn_req)->req.get_tree->xpath); + XFREE(MTYPE_MGMTD_TXN_GETTREE_REQ, (*txn_req)->req.get_tree); + break; + case MGMTD_TXN_PROC_RPC: + __dbg("Deleting RPC req-id: %" PRIu64 " txn-id: %" PRIu64, + (*txn_req)->req_id, (*txn_req)->txn->txn_id); + req_list = &(*txn_req)->txn->rpc_reqs; + lyd_free_all((*txn_req)->req.rpc->client_results); + XFREE(MTYPE_MGMTD_ERR, (*txn_req)->req.rpc->errstr); + XFREE(MTYPE_MGMTD_XPATH, (*txn_req)->req.rpc->xpath); + XFREE(MTYPE_MGMTD_TXN_RPC_REQ, (*txn_req)->req.rpc); break; case MGMTD_TXN_COMMITCFG_TIMEOUT: - case MGMTD_TXN_CLEANUP: break; } - if ((*txn_req)->pending_be_proc && pending_list) { - mgmt_txn_reqs_del(pending_list, *txn_req); - MGMTD_TXN_DBG("Removed req-id: %" PRIu64 - " from pending-list (left:%zu)", - (*txn_req)->req_id, - mgmt_txn_reqs_count(pending_list)); - } else if (req_list) { + if (req_list) { mgmt_txn_reqs_del(req_list, *txn_req); - MGMTD_TXN_DBG("Removed req-id: %" PRIu64 - " from request-list (left:%zu)", - (*txn_req)->req_id, mgmt_txn_reqs_count(req_list)); + __dbg("Removed req-id: %" PRIu64 " from request-list (left:%zu)", + (*txn_req)->req_id, mgmt_txn_reqs_count(req_list)); } - (*txn_req)->pending_be_proc = false; MGMTD_TXN_UNLOCK(&(*txn_req)->txn); XFREE(MTYPE_MGMTD_TXN_REQ, (*txn_req)); *txn_req = NULL; @@ -630,10 +572,10 @@ static void mgmt_txn_process_set_cfg(struct event *thread) assert(txn); cmt_stats = mgmt_fe_get_session_commit_stats(txn->session_id); - MGMTD_TXN_DBG("Processing %zu SET_CONFIG requests txn-id:%" PRIu64 - " session-id: %" PRIu64, - mgmt_txn_reqs_count(&txn->set_cfg_reqs), txn->txn_id, - txn->session_id); + __dbg("Processing %zu SET_CONFIG requests txn-id:%" PRIu64 + " session-id: %" PRIu64, + mgmt_txn_reqs_count(&txn->set_cfg_reqs), txn->txn_id, + txn->session_id); FOREACH_TXN_REQ_IN_LIST (&txn->set_cfg_reqs, txn_req) { assert(txn_req->req_event == MGMTD_TXN_PROC_SETCFG); @@ -666,7 +608,7 @@ static void mgmt_txn_process_set_cfg(struct event *thread) txn_req->req.set_cfg->cfg_changes, (size_t)txn_req->req.set_cfg ->num_cfg_changes, - NULL, NULL, 0, err_buf, + NULL, false, err_buf, sizeof(err_buf), &error); if (error) { mgmt_fe_send_set_cfg_reply(txn->session_id, txn->txn_id, @@ -685,14 +627,17 @@ static void mgmt_txn_process_set_cfg(struct event *thread) /* We expect the user to have locked the DST DS */ if (!mgmt_ds_is_locked(txn_req->req.set_cfg->dst_ds_ctx, txn->session_id)) { - MGMTD_TXN_ERR("DS %u not locked for implicit commit txn-id: %" PRIu64 - " session-id: %" PRIu64 " err: %s", - txn_req->req.set_cfg->dst_ds_id, - txn->txn_id, txn->session_id, - strerror(ret)); - mgmt_txn_send_commit_cfg_reply( - txn, MGMTD_DS_LOCK_FAILED, - "running DS not locked for implicit commit"); + __log_err("DS %u not locked for implicit commit txn-id: %" PRIu64 + " session-id: %" PRIu64 " err: %s", + txn_req->req.set_cfg->dst_ds_id, + txn->txn_id, txn->session_id, + strerror(ret)); + mgmt_fe_send_set_cfg_reply( + txn->session_id, txn->txn_id, + txn_req->req.set_cfg->ds_id, + txn_req->req_id, MGMTD_DS_LOCK_FAILED, + "running DS not locked for implicit commit", + txn_req->req.set_cfg->implicit_commit); goto mgmt_txn_process_set_cfg_done; } @@ -706,7 +651,8 @@ static void mgmt_txn_process_set_cfg(struct event *thread) ->dst_ds_id, txn_req->req.set_cfg ->dst_ds_ctx, - false, false, true); + false, false, true, + NULL); if (mm->perf_stats_en) gettimeofday(&cmt_stats->last_start, NULL); @@ -717,9 +663,9 @@ static void mgmt_txn_process_set_cfg(struct event *thread) txn_req->req_id, MGMTD_SUCCESS, NULL, false) != 0) { - MGMTD_TXN_ERR("Failed to send SET_CONFIG_REPLY txn-id %" PRIu64 - " session-id: %" PRIu64, - txn->txn_id, txn->session_id); + __log_err("Failed to send SET_CONFIG_REPLY txn-id %" PRIu64 + " session-id: %" PRIu64, + txn->txn_id, txn->session_id); } mgmt_txn_process_set_cfg_done: @@ -736,9 +682,8 @@ static void mgmt_txn_process_set_cfg(struct event *thread) left = mgmt_txn_reqs_count(&txn->set_cfg_reqs); if (left) { - MGMTD_TXN_DBG("Processed maximum number of Set-Config requests (%d/%d/%d). Rescheduling for rest.", - num_processed, MGMTD_TXN_MAX_NUM_SETCFG_PROC, - (int)left); + __dbg("Processed maximum number of Set-Config requests (%d/%d/%d). Rescheduling for rest.", + num_processed, MGMTD_TXN_MAX_NUM_SETCFG_PROC, (int)left); mgmt_txn_register_event(txn, MGMTD_TXN_PROC_SETCFG); } } @@ -758,7 +703,8 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, * b/c right now that is special cased.. that special casing should be * removed; however... */ - if (!txn->commit_cfg_req->req.commit_cfg.implicit && txn->session_id && + if (!txn->commit_cfg_req->req.commit_cfg.edit && + !txn->commit_cfg_req->req.commit_cfg.implicit && txn->session_id && !txn->commit_cfg_req->req.commit_cfg.rollback && mgmt_fe_send_commit_cfg_reply(txn->session_id, txn->txn_id, txn->commit_cfg_req->req.commit_cfg @@ -769,12 +715,13 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, txn->commit_cfg_req->req.commit_cfg .validate_only, result, error_if_any) != 0) { - MGMTD_TXN_ERR("Failed to send COMMIT-CONFIG-REPLY txn-id: %" PRIu64 - " session-id: %" PRIu64, - txn->txn_id, txn->session_id); + __log_err("Failed to send COMMIT-CONFIG-REPLY txn-id: %" PRIu64 + " session-id: %" PRIu64, + txn->txn_id, txn->session_id); } - if (txn->commit_cfg_req->req.commit_cfg.implicit && txn->session_id && + if (!txn->commit_cfg_req->req.commit_cfg.edit && + txn->commit_cfg_req->req.commit_cfg.implicit && txn->session_id && !txn->commit_cfg_req->req.commit_cfg.rollback && mgmt_fe_send_set_cfg_reply(txn->session_id, txn->txn_id, txn->commit_cfg_req->req.commit_cfg @@ -783,9 +730,24 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, success ? MGMTD_SUCCESS : MGMTD_INTERNAL_ERROR, error_if_any, true) != 0) { - MGMTD_TXN_ERR("Failed to send SET-CONFIG-REPLY txn-id: %" PRIu64 - " session-id: %" PRIu64, - txn->txn_id, txn->session_id); + __log_err("Failed to send SET-CONFIG-REPLY txn-id: %" PRIu64 + " session-id: %" PRIu64, + txn->txn_id, txn->session_id); + } + + if (txn->commit_cfg_req->req.commit_cfg.edit && + mgmt_fe_adapter_send_edit_reply(txn->session_id, txn->txn_id, + txn->commit_cfg_req->req_id, + txn->commit_cfg_req->req.commit_cfg + .edit->unlock, + true, + txn->commit_cfg_req->req.commit_cfg + .edit->xpath_created, + success ? 0 : -1, + error_if_any) != 0) { + __log_err("Failed to send EDIT-REPLY txn-id: %" PRIu64 + " session-id: %" PRIu64, + txn->txn_id, txn->session_id); } if (success) { @@ -848,6 +810,14 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, mgmt_history_rollback_complete(success); } + if (txn->commit_cfg_req->req.commit_cfg.init) { + /* + * This is the backend init request. + * We need to unlock the running datastore. + */ + mgmt_ds_unlock(txn->commit_cfg_req->req.commit_cfg.dst_ds_ctx); + } + txn->commit_cfg_req->req.commit_cfg.cmt_stats = NULL; mgmt_txn_req_free(&txn->commit_cfg_req); @@ -857,66 +827,26 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, * we need to cleanup by itself. */ if (!txn->session_id) - mgmt_txn_register_event(txn, MGMTD_TXN_CLEANUP); + mgmt_txn_cleanup_txn(&txn); return 0; } -static void -mgmt_move_txn_cfg_batch_to_next(struct mgmt_commit_cfg_req *cmtcfg_req, - struct mgmt_txn_be_cfg_batch *batch, - struct mgmt_txn_batches_head *src_list, - struct mgmt_txn_batches_head *dst_list, - bool update_commit_phase, - enum mgmt_commit_phase to_phase) -{ - mgmt_txn_batches_del(src_list, batch); - - if (update_commit_phase) { - MGMTD_TXN_DBG("Move txn-id %" PRIu64 " batch-id: %" PRIu64 - " from '%s' --> '%s'", - batch->txn->txn_id, batch->batch_id, - mgmt_commit_phase2str(batch->comm_phase), - mgmt_txn_commit_phase_str(batch->txn, false)); - batch->comm_phase = to_phase; - } - - mgmt_txn_batches_add_tail(dst_list, batch); -} - -static void mgmt_move_txn_cfg_batches(struct mgmt_txn_ctx *txn, - struct mgmt_commit_cfg_req *cmtcfg_req, - struct mgmt_txn_batches_head *src_list, - struct mgmt_txn_batches_head *dst_list, - bool update_commit_phase, - enum mgmt_commit_phase to_phase) -{ - struct mgmt_txn_be_cfg_batch *batch; - - FOREACH_TXN_CFG_BATCH_IN_LIST (src_list, batch) { - mgmt_move_txn_cfg_batch_to_next(cmtcfg_req, batch, src_list, - dst_list, update_commit_phase, - to_phase); - } -} - static int mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn, struct mgmt_commit_cfg_req *cmtcfg_req) { - struct mgmt_txn_batches_head *curr_list, *next_list; enum mgmt_be_client_id id; - MGMTD_TXN_DBG("txn-id: %" PRIu64 ", Phase(current:'%s' next:'%s')", - txn->txn_id, mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); + __dbg("txn-id: %" PRIu64 ", Phase '%s'", txn->txn_id, + mgmt_txn_commit_phase_str(txn)); /* * Check if all clients has moved to next phase or not. */ FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (cmtcfg_req->subscr_info.xpath_subscr[id] && - mgmt_txn_batches_count(&cmtcfg_req->curr_batches[id])) { + if (IS_IDBIT_SET(cmtcfg_req->clients, id) && + cmtcfg_req->be_phase[id] == cmtcfg_req->phase) { /* * There's atleast once client who hasn't moved to * next phase. @@ -929,83 +859,36 @@ mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn, } } - MGMTD_TXN_DBG("Move entire txn-id: %" PRIu64 " from '%s' to '%s'", - txn->txn_id, mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); - /* * If we are here, it means all the clients has moved to next phase. * So we can move the whole commit to next phase. */ - cmtcfg_req->curr_phase = cmtcfg_req->next_phase; - cmtcfg_req->next_phase++; - MGMTD_TXN_DBG("Move back all config batches for txn-id: %" PRIu64 - " from next to current branch", - txn->txn_id); - FOREACH_MGMTD_BE_CLIENT_ID (id) { - curr_list = &cmtcfg_req->curr_batches[id]; - next_list = &cmtcfg_req->next_batches[id]; - mgmt_move_txn_cfg_batches(txn, cmtcfg_req, next_list, curr_list, - false, 0); - } - - mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG); - - return 0; -} - -static int -mgmt_move_be_commit_to_next_phase(struct mgmt_txn_ctx *txn, - struct mgmt_be_client_adapter *adapter) -{ - struct mgmt_commit_cfg_req *cmtcfg_req; - struct mgmt_txn_batches_head *curr_list, *next_list; - - if (txn->type != MGMTD_TXN_TYPE_CONFIG || !txn->commit_cfg_req) - return -1; + cmtcfg_req->phase++; - cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; - - MGMTD_TXN_DBG("Move txn-id: %" PRIu64 - " for '%s' Phase(current: '%s' next:'%s')", - txn->txn_id, adapter->name, - mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); - - MGMTD_TXN_DBG("Move all config batches for '%s' from current to next list", - adapter->name); - curr_list = &cmtcfg_req->curr_batches[adapter->id]; - next_list = &cmtcfg_req->next_batches[adapter->id]; - mgmt_move_txn_cfg_batches(txn, cmtcfg_req, curr_list, next_list, true, - cmtcfg_req->next_phase); - - MGMTD_TXN_DBG("txn-id: %" PRIu64 ", Phase(current:'%s' next:'%s')", - txn->txn_id, mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); + __dbg("Move entire txn-id: %" PRIu64 " to phase '%s'", txn->txn_id, + mgmt_txn_commit_phase_str(txn)); - /* - * Check if all clients has moved to next phase or not. - */ - mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req); + mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG); return 0; } +/* + * This is the real workhorse + */ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, struct nb_config_cbs *changes) { struct nb_config_cb *cb, *nxt; struct nb_config_change *chg; struct mgmt_txn_be_cfg_batch *batch; - struct mgmt_be_client_subscr_info subscr_info; char *xpath = NULL, *value = NULL; - char err_buf[1024]; enum mgmt_be_client_id id; struct mgmt_be_client_adapter *adapter; struct mgmt_commit_cfg_req *cmtcfg_req; - bool found_validator; int num_chgs = 0; int xpath_len, value_len; + uint64_t clients, chg_clients; cmtcfg_req = &txn_req->req.commit_cfg; @@ -1029,24 +912,23 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, if (!value) value = (char *)MGMTD_BE_CONTAINER_NODE_VAL; - MGMTD_TXN_DBG("XPATH: %s, Value: '%s'", xpath, - value ? value : "NIL"); + __dbg("XPATH: %s, Value: '%s'", xpath, value ? value : "NIL"); - mgmt_be_get_subscr_info_for_xpath(xpath, &subscr_info); + clients = + mgmt_be_interested_clients(xpath, + MGMT_BE_XPATH_SUBSCR_TYPE_CFG); + + chg_clients = 0; xpath_len = strlen(xpath) + 1; value_len = strlen(value) + 1; - found_validator = false; - FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (!(subscr_info.xpath_subscr[id] & - (MGMT_SUBSCR_VALIDATE_CFG | - MGMT_SUBSCR_NOTIFY_CFG))) - continue; - + FOREACH_BE_CLIENT_BITS (id, clients) { adapter = mgmt_be_get_adapter_by_id(id); if (!adapter) continue; + chg_clients |= (1ull << id); + batch = cmtcfg_req->last_be_cfg_batch[id]; if (!batch || (batch->num_cfg_data == @@ -1058,18 +940,20 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, } batch->buf_space_left -= (xpath_len + value_len); - memcpy(&batch->xp_subscr[batch->num_cfg_data], - &subscr_info.xpath_subscr[id], - sizeof(batch->xp_subscr[0])); mgmt_yang_cfg_data_req_init( &batch->cfg_data[batch->num_cfg_data]); batch->cfg_datap[batch->num_cfg_data] = &batch->cfg_data[batch->num_cfg_data]; - if (chg->cb.operation == NB_OP_DESTROY) + /* + * On the backend, we don't really care if it's CREATE + * or MODIFY, because the existence was already checked + * on the frontend. Therefore we use SET for both. + */ + if (chg->cb.operation == NB_CB_DESTROY) batch->cfg_data[batch->num_cfg_data].req_type = - MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA; + MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA; else batch->cfg_data[batch->num_cfg_data].req_type = MGMTD__CFG_DATA_REQ_TYPE__SET_DATA; @@ -1087,28 +971,19 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, MGMTD__YANG_DATA_VALUE__VALUE_ENCODED_STR_VAL; batch->value[batch->num_cfg_data].encoded_str_val = value; - value = NULL; - if (subscr_info.xpath_subscr[id] & - MGMT_SUBSCR_VALIDATE_CFG) - found_validator = true; - - cmtcfg_req->subscr_info.xpath_subscr[id] |= - subscr_info.xpath_subscr[id]; - MGMTD_TXN_DBG(" -- %s, batch-id: %" PRIu64 " item:%d", - adapter->name, batch->batch_id, - (int)batch->num_cfg_data); + __dbg(" -- %s, batch item:%d", adapter->name, + (int)batch->num_cfg_data); batch->num_cfg_data++; num_chgs++; } - if (!found_validator) { - snprintf(err_buf, sizeof(err_buf), - "No validator module found for XPATH: '%s", - xpath); - MGMTD_TXN_ERR("***** %s", err_buf); - } + if (!chg_clients) + __dbg("Daemons interested in XPATH are not currently connected: %s", + xpath); + + cmtcfg_req->clients |= chg_clients; free(xpath); } @@ -1117,11 +992,17 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req, if (!num_chgs) { (void)mgmt_txn_send_commit_cfg_reply(txn_req->txn, MGMTD_NO_CFG_CHANGES, - "No changes found to commit!"); + "No connected daemons interested in changes"); return -1; } - cmtcfg_req->next_phase = MGMTD_COMMIT_PHASE_TXN_CREATE; + /* Move all BE clients to create phase */ + FOREACH_MGMTD_BE_CLIENT_ID(id) { + if (IS_IDBIT_SET(cmtcfg_req->clients, id)) + cmtcfg_req->be_phase[id] = + MGMTD_COMMIT_PHASE_TXN_CREATE; + } + return 0; } @@ -1194,25 +1075,28 @@ static int mgmt_txn_prepare_config(struct mgmt_txn_ctx *txn) } /* - * Check for diffs from scratch buffer. If found empty - * get the diff from Candidate DS itself. + * Validate YANG contents of the source DS and get the diff + * between source and destination DS contents. */ - cfg_chgs = &nb_config->cfg_chgs; - if (RB_EMPTY(nb_config_cbs, cfg_chgs)) { - /* - * This could be the case when the config is directly - * loaded onto the candidate DS from a file. Get the - * diff from a full comparison of the candidate and - * running DSs. - */ - nb_config_diff(mgmt_ds_get_nb_config( - txn->commit_cfg_req->req.commit_cfg - .dst_ds_ctx), - nb_config, &changes); - cfg_chgs = &changes; - del_cfg_chgs = true; + char err_buf[BUFSIZ] = { 0 }; + + ret = nb_candidate_validate_yang(nb_config, true, err_buf, + sizeof(err_buf) - 1); + if (ret != NB_OK) { + if (strncmp(err_buf, " ", strlen(err_buf)) == 0) + strlcpy(err_buf, "Validation failed", sizeof(err_buf)); + (void)mgmt_txn_send_commit_cfg_reply(txn, MGMTD_INVALID_PARAM, + err_buf); + ret = -1; + goto mgmt_txn_prepare_config_done; } + nb_config_diff(mgmt_ds_get_nb_config(txn->commit_cfg_req->req.commit_cfg + .dst_ds_ctx), + nb_config, &changes); + cfg_chgs = &changes; + del_cfg_chgs = true; + if (RB_EMPTY(nb_config_cbs, cfg_chgs)) { /* * This means there's no changes to commit whatsoever @@ -1229,29 +1113,13 @@ static int mgmt_txn_prepare_config(struct mgmt_txn_ctx *txn) gettimeofday(&txn->commit_cfg_req->req.commit_cfg.cmt_stats ->validate_start, NULL); - /* - * Validate YANG contents of the source DS and get the diff - * between source and destination DS contents. - */ - char err_buf[1024] = { 0 }; - nb_ctx.client = NB_CLIENT_MGMTD_SERVER; - nb_ctx.user = (void *)txn; - - ret = nb_candidate_validate_yang(nb_config, false, err_buf, - sizeof(err_buf) - 1); - if (ret != NB_OK) { - if (strncmp(err_buf, " ", strlen(err_buf)) == 0) - strlcpy(err_buf, "Validation failed", sizeof(err_buf)); - (void)mgmt_txn_send_commit_cfg_reply(txn, MGMTD_INVALID_PARAM, - err_buf); - ret = -1; - goto mgmt_txn_prepare_config_done; - } /* * Perform application level validations locally on the MGMTD * process by calling application specific validation routines * loaded onto MGMTD process using libraries. */ + nb_ctx.client = NB_CLIENT_MGMTD_SERVER; + nb_ctx.user = (void *)txn; ret = nb_candidate_validate_code(&nb_ctx, nb_config, &changes, err_buf, sizeof(err_buf) - 1); if (ret != NB_OK) { @@ -1290,7 +1158,7 @@ static int mgmt_txn_prepare_config(struct mgmt_txn_ctx *txn) } /* Move to the Transaction Create Phase */ - txn->commit_cfg_req->req.commit_cfg.curr_phase = + txn->commit_cfg_req->req.commit_cfg.phase = MGMTD_COMMIT_PHASE_TXN_CREATE; mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG); @@ -1312,13 +1180,12 @@ static int mgmt_txn_send_be_txn_create(struct mgmt_txn_ctx *txn) enum mgmt_be_client_id id; struct mgmt_be_client_adapter *adapter; struct mgmt_commit_cfg_req *cmtcfg_req; - struct mgmt_txn_be_cfg_batch *batch; assert(txn->type == MGMTD_TXN_TYPE_CONFIG && txn->commit_cfg_req); cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (cmtcfg_req->subscr_info.xpath_subscr[id]) { + if (IS_IDBIT_SET(cmtcfg_req->clients, id)) { adapter = mgmt_be_get_adapter_by_id(id); if (mgmt_be_send_txn_req(adapter, txn->txn_id, true)) { (void)mgmt_txn_send_commit_cfg_reply( @@ -1326,29 +1193,16 @@ static int mgmt_txn_send_be_txn_create(struct mgmt_txn_ctx *txn) "Could not send TXN_CREATE to backend adapter"); return -1; } - - FOREACH_TXN_CFG_BATCH_IN_LIST (&txn->commit_cfg_req->req - .commit_cfg - .curr_batches[id], - batch) - batch->comm_phase = - MGMTD_COMMIT_PHASE_TXN_CREATE; } } - txn->commit_cfg_req->req.commit_cfg.next_phase = - MGMTD_COMMIT_PHASE_SEND_CFG; - /* * Dont move the commit to next phase yet. Wait for the TXN_REPLY to * come back. */ - MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64 - " Phase(Current:'%s', Next: '%s')", - txn->txn_id, txn->session_id, - mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); + __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64 " Phase '%s'", + txn->txn_id, txn->session_id, mgmt_txn_commit_phase_str(txn)); return 0; } @@ -1364,46 +1218,36 @@ static int mgmt_txn_send_be_cfg_data(struct mgmt_txn_ctx *txn, assert(txn->type == MGMTD_TXN_TYPE_CONFIG && txn->commit_cfg_req); cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; - assert(cmtcfg_req->subscr_info.xpath_subscr[adapter->id]); + assert(IS_IDBIT_SET(cmtcfg_req->clients, adapter->id)); indx = 0; - num_batches = - mgmt_txn_batches_count(&cmtcfg_req->curr_batches[adapter->id]); - FOREACH_TXN_CFG_BATCH_IN_LIST (&cmtcfg_req->curr_batches[adapter->id], + num_batches = mgmt_txn_batches_count(&cmtcfg_req->batches[adapter->id]); + FOREACH_TXN_CFG_BATCH_IN_LIST (&cmtcfg_req->batches[adapter->id], batch) { - assert(cmtcfg_req->next_phase == MGMTD_COMMIT_PHASE_SEND_CFG); cfg_req.cfgdata_reqs = batch->cfg_datap; cfg_req.num_reqs = batch->num_cfg_data; indx++; if (mgmt_be_send_cfgdata_req(adapter, txn->txn_id, - batch->batch_id, cfg_req.cfgdata_reqs, cfg_req.num_reqs, indx == num_batches)) { (void)mgmt_txn_send_commit_cfg_reply( txn, MGMTD_INTERNAL_ERROR, "Internal Error! Could not send config data to backend!"); - MGMTD_TXN_ERR("Could not send CFGDATA_CREATE txn-id: %" PRIu64 - " batch-id: %" PRIu64 " to client '%s", - txn->txn_id, batch->batch_id, - adapter->name); + __log_err("Could not send CFGDATA_CREATE txn-id: %" PRIu64 + " to client '%s", + txn->txn_id, adapter->name); return -1; } cmtcfg_req->cmt_stats->last_num_cfgdata_reqs++; - mgmt_move_txn_cfg_batch_to_next( - cmtcfg_req, batch, - &cmtcfg_req->curr_batches[adapter->id], - &cmtcfg_req->next_batches[adapter->id], true, - MGMTD_COMMIT_PHASE_SEND_CFG); } /* - * This could be the last Backend Client to send CFGDATA_CREATE_REQ to. - * Try moving the commit to next phase. + * We don't advance the phase here, instead that is driven by the + * cfg_reply. */ - mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req); return 0; } @@ -1415,9 +1259,8 @@ static int mgmt_txn_send_be_txn_delete(struct mgmt_txn_ctx *txn, &txn->commit_cfg_req->req.commit_cfg; assert(txn->type == MGMTD_TXN_TYPE_CONFIG); - assert(!mgmt_txn_batches_count(&cmtcfg_req->curr_batches[adapter->id])); - if (!cmtcfg_req->subscr_info.xpath_subscr[adapter->id]) + if (IS_IDBIT_UNSET(cmtcfg_req->clients, adapter->id)) return 0; return mgmt_be_send_txn_req(adapter, txn->txn_id, false); @@ -1435,8 +1278,8 @@ static void mgmt_txn_cfg_commit_timedout(struct event *thread) if (!txn->commit_cfg_req) return; - MGMTD_TXN_ERR("Backend timeout txn-id: %" PRIu64 " aborting commit", - txn->txn_id); + __log_err("Backend timeout txn-id: %" PRIu64 " aborting commit", + txn->txn_id); /* * Send a COMMIT_CONFIG_REPLY with failure. @@ -1448,6 +1291,136 @@ static void mgmt_txn_cfg_commit_timedout(struct event *thread) "Operation on the backend timed-out. Aborting commit!"); } + +static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn, + struct mgmt_txn_req *txn_req) +{ + struct txn_req_get_tree *get_tree = txn_req->req.get_tree; + uint64_t req_id = txn_req->req_id; + struct lyd_node *result; + int ret = NB_OK; + + /* cancel timer and send reply onward */ + EVENT_OFF(txn->get_tree_timeout); + + if (!get_tree->simple_xpath && get_tree->client_results) { + /* + * We have a complex query so Filter results by the xpath query. + */ + if (yang_lyd_trim_xpath(&get_tree->client_results, + txn_req->req.get_tree->xpath)) + ret = NB_ERR; + } + + result = get_tree->client_results; + + if (ret == NB_OK && result && get_tree->exact) + result = yang_dnode_get(result, get_tree->xpath); + + if (ret == NB_OK) + ret = mgmt_fe_adapter_send_tree_data(txn->session_id, + txn->txn_id, + txn_req->req_id, + get_tree->result_type, + get_tree->wd_options, + result, + get_tree->partial_error, + false); + + /* we're done with the request */ + mgmt_txn_req_free(&txn_req); + + if (ret) { + __log_err("Error sending the results of GETTREE for txn-id %" PRIu64 + " req_id %" PRIu64 " to requested type %u", + txn->txn_id, req_id, get_tree->result_type); + + (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, ret, + "Error converting results of GETTREE"); + } + + return ret; +} + +static int txn_rpc_done(struct mgmt_txn_ctx *txn, struct mgmt_txn_req *txn_req) +{ + struct txn_req_rpc *rpc = txn_req->req.rpc; + uint64_t req_id = txn_req->req_id; + + /* cancel timer and send reply onward */ + EVENT_OFF(txn->rpc_timeout); + + if (rpc->errstr) + mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -1, + rpc->errstr); + else if (mgmt_fe_adapter_send_rpc_reply(txn->session_id, txn->txn_id, + req_id, rpc->result_type, + rpc->client_results)) { + __log_err("Error sending the results of RPC for txn-id %" PRIu64 + " req_id %" PRIu64 " to requested type %u", + txn->txn_id, req_id, rpc->result_type); + + (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -1, + "Error converting results of RPC"); + } + + /* we're done with the request */ + mgmt_txn_req_free(&txn_req); + + return 0; +} + +static void txn_get_tree_timeout(struct event *thread) +{ + struct mgmt_txn_ctx *txn; + struct mgmt_txn_req *txn_req; + + txn_req = (struct mgmt_txn_req *)EVENT_ARG(thread); + txn = txn_req->txn; + + assert(txn); + assert(txn->type == MGMTD_TXN_TYPE_SHOW); + + + __log_err("Backend timeout txn-id: %" PRIu64 " ending get-tree", + txn->txn_id); + + /* + * Send a get-tree data reply. + * + * NOTE: The transaction cleanup will be triggered from Front-end + * adapter. + */ + + txn_req->req.get_tree->partial_error = -ETIMEDOUT; + txn_get_tree_data_done(txn, txn_req); +} + +static void txn_rpc_timeout(struct event *thread) +{ + struct mgmt_txn_ctx *txn; + struct mgmt_txn_req *txn_req; + + txn_req = (struct mgmt_txn_req *)EVENT_ARG(thread); + txn = txn_req->txn; + + assert(txn); + assert(txn->type == MGMTD_TXN_TYPE_RPC); + + __log_err("Backend timeout txn-id: %" PRIu64 " ending rpc", txn->txn_id); + + /* + * Send a get-tree data reply. + * + * NOTE: The transaction cleanup will be triggered from Front-end + * adapter. + */ + + txn_req->req.rpc->errstr = + XSTRDUP(MTYPE_MGMTD_ERR, "Operation on the backend timed-out"); + txn_rpc_done(txn, txn_req); +} + /* * Send CFG_APPLY_REQs to all the backend client. * @@ -1461,8 +1434,6 @@ static int mgmt_txn_send_be_cfg_apply(struct mgmt_txn_ctx *txn) enum mgmt_be_client_id id; struct mgmt_be_client_adapter *adapter; struct mgmt_commit_cfg_req *cmtcfg_req; - struct mgmt_txn_batches_head *batch_list; - struct mgmt_txn_be_cfg_batch *batch; assert(txn->type == MGMTD_TXN_TYPE_CONFIG && txn->commit_cfg_req); @@ -1476,13 +1447,11 @@ static int mgmt_txn_send_be_cfg_apply(struct mgmt_txn_ctx *txn) } FOREACH_MGMTD_BE_CLIENT_ID (id) { - if (cmtcfg_req->subscr_info.xpath_subscr[id] & - MGMT_SUBSCR_NOTIFY_CFG) { + if (IS_IDBIT_SET(cmtcfg_req->clients, id)) { adapter = mgmt_be_get_adapter_by_id(id); if (!adapter) return -1; - batch_list = &cmtcfg_req->curr_batches[id]; if (mgmt_be_send_cfgapply_req(adapter, txn->txn_id)) { (void)mgmt_txn_send_commit_cfg_reply( txn, MGMTD_INTERNAL_ERROR, @@ -1493,15 +1462,9 @@ static int mgmt_txn_send_be_cfg_apply(struct mgmt_txn_ctx *txn) UNSET_FLAG(adapter->flags, MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED); - - FOREACH_TXN_CFG_BATCH_IN_LIST (batch_list, batch) - batch->comm_phase = MGMTD_COMMIT_PHASE_APPLY_CFG; } } - txn->commit_cfg_req->req.commit_cfg.next_phase = - MGMTD_COMMIT_PHASE_TXN_DELETE; - /* * Dont move the commit to next phase yet. Wait for all VALIDATE_REPLIES * to come back. @@ -1518,15 +1481,13 @@ static void mgmt_txn_process_commit_cfg(struct event *thread) txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread); assert(txn); - MGMTD_TXN_DBG("Processing COMMIT_CONFIG for txn-id: %" PRIu64 - " session-id: %" PRIu64 " Phase(Current:'%s', Next: '%s')", - txn->txn_id, txn->session_id, - mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); + __dbg("Processing COMMIT_CONFIG for txn-id: %" PRIu64 + " session-id: %" PRIu64 " Phase '%s'", + txn->txn_id, txn->session_id, mgmt_txn_commit_phase_str(txn)); assert(txn->commit_cfg_req); cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; - switch (cmtcfg_req->curr_phase) { + switch (cmtcfg_req->phase) { case MGMTD_COMMIT_PHASE_PREPARE_CFG: mgmt_txn_prepare_config(txn); break; @@ -1539,26 +1500,6 @@ static void mgmt_txn_process_commit_cfg(struct event *thread) */ mgmt_txn_send_be_txn_create(txn); break; - case MGMTD_COMMIT_PHASE_SEND_CFG: - if (mm->perf_stats_en) - gettimeofday(&cmtcfg_req->cmt_stats->send_cfg_start, - NULL); - /* - * All CFGDATA_CREATE_REQ should have been sent to - * Backend by now. - */ -#ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED - assert(cmtcfg_req->next_phase == MGMTD_COMMIT_PHASE_APPLY_CFG); - MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64 - " trigger sending CFG_VALIDATE_REQ to all backend clients", - txn->txn_id, txn->session_id); -#else /* ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED */ - assert(cmtcfg_req->next_phase == MGMTD_COMMIT_PHASE_APPLY_CFG); - MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64 - " trigger sending CFG_APPLY_REQ to all backend clients", - txn->txn_id, txn->session_id); -#endif /* ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED */ - break; case MGMTD_COMMIT_PHASE_APPLY_CFG: if (mm->perf_stats_en) gettimeofday(&cmtcfg_req->cmt_stats->apply_cfg_start, @@ -1587,12 +1528,6 @@ static void mgmt_txn_process_commit_cfg(struct event *thread) case MGMTD_COMMIT_PHASE_MAX: break; } - - MGMTD_TXN_DBG("txn-id:%" PRIu64 " session-id: %" PRIu64 - " phase updated to (current:'%s', next: '%s')", - txn->txn_id, txn->session_id, - mgmt_txn_commit_phase_str(txn, true), - mgmt_txn_commit_phase_str(txn, false)); } static void mgmt_init_get_data_reply(struct mgmt_get_data_reply *get_reply) @@ -1613,8 +1548,6 @@ static void mgmt_reset_get_data_reply(struct mgmt_get_data_reply *get_reply) get_reply->reply_xpathp[indx] = 0; } if (get_reply->reply_data[indx].xpath) { - zlog_debug("%s free xpath %p", __func__, - get_reply->reply_data[indx].xpath); free(get_reply->reply_data[indx].xpath); get_reply->reply_data[indx].xpath = 0; } @@ -1653,8 +1586,8 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req, data_reply->next_indx = (!get_reply->last_batch ? get_req->total_reply : -1); - MGMTD_TXN_DBG("Sending %zu Get-Config/Data replies next-index:%" PRId64, - data_reply->n_data, data_reply->next_indx); + __dbg("Sending %zu Get-Config/Data replies next-index:%" PRId64, + data_reply->n_data, data_reply->next_indx); switch (txn_req->req_event) { case MGMTD_TXN_PROC_GETCFG: @@ -1662,30 +1595,18 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req, txn_req->txn->txn_id, get_req->ds_id, txn_req->req_id, MGMTD_SUCCESS, data_reply, NULL) != 0) { - MGMTD_TXN_ERR("Failed to send GET-CONFIG-REPLY txn-id: %" PRIu64 - " session-id: %" PRIu64 - " req-id: %" PRIu64, - txn_req->txn->txn_id, - txn_req->txn->session_id, txn_req->req_id); - } - break; - case MGMTD_TXN_PROC_GETDATA: - if (mgmt_fe_send_get_reply(txn_req->txn->session_id, - txn_req->txn->txn_id, get_req->ds_id, - txn_req->req_id, MGMTD_SUCCESS, - data_reply, NULL) != 0) { - MGMTD_TXN_ERR("Failed to send GET-DATA-REPLY txn-id: %" PRIu64 - " session-id: %" PRIu64 - " req-id: %" PRIu64, - txn_req->txn->txn_id, - txn_req->txn->session_id, txn_req->req_id); + __log_err("Failed to send GET-CONFIG-REPLY txn-id: %" PRIu64 + " session-id: %" PRIu64 " req-id: %" PRIu64, + txn_req->txn->txn_id, + txn_req->txn->session_id, txn_req->req_id); } break; case MGMTD_TXN_PROC_SETCFG: case MGMTD_TXN_PROC_COMMITCFG: + case MGMTD_TXN_PROC_GETTREE: + case MGMTD_TXN_PROC_RPC: case MGMTD_TXN_COMMITCFG_TIMEOUT: - case MGMTD_TXN_CLEANUP: - MGMTD_TXN_ERR("Invalid Txn-Req-Event %u", txn_req->req_event); + __log_err("Invalid Txn-Req-Event %u", txn_req->req_event); break; } @@ -1695,10 +1616,8 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req, mgmt_reset_get_data_reply_buf(get_req); } -static void mgmt_txn_iter_and_send_get_cfg_reply(const char *xpath, - struct lyd_node *node, - struct nb_node *nb_node, - void *ctx) +static void txn_iter_get_config_data_cb(const char *xpath, struct lyd_node *node, + struct nb_node *nb_node, void *ctx) { struct mgmt_txn_req *txn_req; struct mgmt_get_data_req *get_req; @@ -1713,8 +1632,7 @@ static void mgmt_txn_iter_and_send_get_cfg_reply(const char *xpath, if (!(node->schema->nodetype & LYD_NODE_TERM)) return; - assert(txn_req->req_event == MGMTD_TXN_PROC_GETCFG || - txn_req->req_event == MGMTD_TXN_PROC_GETDATA); + assert(txn_req->req_event == MGMTD_TXN_PROC_GETCFG); get_req = txn_req->req.get_data; assert(get_req); @@ -1731,8 +1649,8 @@ static void mgmt_txn_iter_and_send_get_cfg_reply(const char *xpath, get_reply->num_reply++; get_req->total_reply++; - MGMTD_TXN_DBG(" [%d] XPATH: '%s', Value: '%s'", get_req->total_reply, - data->xpath, data_value->encoded_str_val); + __dbg(" [%d] XPATH: '%s', Value: '%s'", get_req->total_reply, + data->xpath, data_value->encoded_str_val); if (get_reply->num_reply == MGMTD_MAX_NUM_DATA_REPLY_IN_BATCH) mgmt_txn_send_getcfg_reply_data(txn_req, get_req); @@ -1766,8 +1684,8 @@ static int mgmt_txn_get_config(struct mgmt_txn_ctx *txn, */ get_reply = get_data->reply; for (indx = 0; indx < get_data->num_xpaths; indx++) { - MGMTD_TXN_DBG("Trying to get all data under '%s'", - get_data->xpaths[indx]); + __dbg("Trying to get all data under '%s'", + get_data->xpaths[indx]); mgmt_init_get_data_reply(get_reply); /* * mgmt_ds_iter_data works on path prefixes, but the user may @@ -1776,18 +1694,17 @@ static int mgmt_txn_get_config(struct mgmt_txn_ctx *txn, */ if (mgmt_ds_iter_data(get_data->ds_id, root, get_data->xpaths[indx], - mgmt_txn_iter_and_send_get_cfg_reply, + txn_iter_get_config_data_cb, (void *)txn_req) == -1) { - MGMTD_TXN_DBG("Invalid Xpath '%s", - get_data->xpaths[indx]); + __dbg("Invalid Xpath '%s", get_data->xpaths[indx]); mgmt_fe_send_get_reply(txn->session_id, txn->txn_id, get_data->ds_id, txn_req->req_id, MGMTD_INTERNAL_ERROR, NULL, "Invalid xpath"); goto mgmt_txn_get_config_failed; } - MGMTD_TXN_DBG("Got %d remaining data-replies for xpath '%s'", - get_reply->num_reply, get_data->xpaths[indx]); + __dbg("Got %d remaining data-replies for xpath '%s'", + get_reply->num_reply, get_data->xpaths[indx]); get_reply->last_batch = true; mgmt_txn_send_getcfg_reply_data(txn_req, get_data); } @@ -1814,10 +1731,10 @@ static void mgmt_txn_process_get_cfg(struct event *thread) txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread); assert(txn); - MGMTD_TXN_DBG("Processing %zu GET_CONFIG requests txn-id: %" PRIu64 - " session-id: %" PRIu64, - mgmt_txn_reqs_count(&txn->get_cfg_reqs), txn->txn_id, - txn->session_id); + __dbg("Processing %zu GET_CONFIG requests txn-id: %" PRIu64 + " session-id: %" PRIu64, + mgmt_txn_reqs_count(&txn->get_cfg_reqs), txn->txn_id, + txn->session_id); FOREACH_TXN_REQ_IN_LIST (&txn->get_cfg_reqs, txn_req) { error = false; @@ -1826,11 +1743,10 @@ static void mgmt_txn_process_get_cfg(struct event *thread) assert(cfg_root); if (mgmt_txn_get_config(txn, txn_req, cfg_root) != 0) { - MGMTD_TXN_ERR("Unable to retrieve config from DS %d txn-id: %" PRIu64 - " session-id: %" PRIu64 - " req-id: %" PRIu64, - txn_req->req.get_data->ds_id, txn->txn_id, - txn->session_id, txn_req->req_id); + __log_err("Unable to retrieve config from DS %d txn-id: %" PRIu64 + " session-id: %" PRIu64 " req-id: %" PRIu64, + txn_req->req.get_data->ds_id, txn->txn_id, + txn->session_id, txn_req->req_id); error = true; } @@ -1853,60 +1769,12 @@ static void mgmt_txn_process_get_cfg(struct event *thread) } if (mgmt_txn_reqs_count(&txn->get_cfg_reqs)) { - MGMTD_TXN_DBG("Processed maximum number of Get-Config requests (%d/%d). Rescheduling for rest.", - num_processed, MGMTD_TXN_MAX_NUM_GETCFG_PROC); + __dbg("Processed maximum number of Get-Config requests (%d/%d). Rescheduling for rest.", + num_processed, MGMTD_TXN_MAX_NUM_GETCFG_PROC); mgmt_txn_register_event(txn, MGMTD_TXN_PROC_GETCFG); } } -static void mgmt_txn_process_get_data(struct event *thread) -{ - struct mgmt_txn_ctx *txn; - struct mgmt_txn_req *txn_req; - int num_processed = 0; - - txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread); - assert(txn); - - MGMTD_TXN_DBG("Processing %zu GET_DATA requests txn-id: %" PRIu64 - " session-id: %" PRIu64, - mgmt_txn_reqs_count(&txn->get_data_reqs), txn->txn_id, - txn->session_id); - - FOREACH_TXN_REQ_IN_LIST (&txn->get_data_reqs, txn_req) { - assert(txn_req->req_event == MGMTD_TXN_PROC_GETDATA); - - /* - * TODO: Trigger GET procedures for Backend - * For now return back error. - */ - mgmt_fe_send_get_reply(txn->session_id, txn->txn_id, - txn_req->req.get_data->ds_id, - txn_req->req_id, MGMTD_INTERNAL_ERROR, - NULL, "GET-DATA is not supported yet!"); - /* - * Delete the txn request. - * Note: The following will remove it from the list - * as well. - */ - mgmt_txn_req_free(&txn_req); - - /* - * Else the transaction would have been already deleted or - * moved to corresponding pending list. No need to delete it. - */ - num_processed++; - if (num_processed == MGMTD_TXN_MAX_NUM_GETDATA_PROC) - break; - } - - if (mgmt_txn_reqs_count(&txn->get_data_reqs)) { - MGMTD_TXN_DBG("Processed maximum number of Get-Data requests (%d/%d). Rescheduling for rest.", - num_processed, MGMTD_TXN_MAX_NUM_GETDATA_PROC); - mgmt_txn_register_event(txn, MGMTD_TXN_PROC_GETDATA); - } -} - static struct mgmt_txn_ctx * mgmt_fe_find_txn_by_session_id(struct mgmt_master *cm, uint64_t session_id, enum mgmt_txn_type type) @@ -1926,15 +1794,9 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id, { struct mgmt_txn_ctx *txn = NULL; - /* - * For 'CONFIG' transaction check if one is already created - * or not. - */ - if (type == MGMTD_TXN_TYPE_CONFIG && mgmt_txn_mm->cfg_txn) { - if (mgmt_config_txn_in_progress() == session_id) - txn = mgmt_txn_mm->cfg_txn; - goto mgmt_create_txn_done; - } + /* Do not allow multiple config transactions */ + if (type == MGMTD_TXN_TYPE_CONFIG && mgmt_config_txn_in_progress()) + return NULL; txn = mgmt_fe_find_txn_by_session_id(mgmt_txn_mm, session_id, type); if (!txn) { @@ -1944,10 +1806,11 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id, txn->session_id = session_id; txn->type = type; mgmt_txns_add_tail(&mgmt_txn_mm->txn_list, txn); + /* TODO: why do we need N lists for one transaction */ mgmt_txn_reqs_init(&txn->set_cfg_reqs); mgmt_txn_reqs_init(&txn->get_cfg_reqs); - mgmt_txn_reqs_init(&txn->get_data_reqs); - mgmt_txn_reqs_init(&txn->pending_get_datas); + mgmt_txn_reqs_init(&txn->get_tree_reqs); + mgmt_txn_reqs_init(&txn->rpc_reqs); txn->commit_cfg_req = NULL; txn->refcount = 0; if (!mgmt_txn_mm->next_txn_id) @@ -1955,8 +1818,8 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id, txn->txn_id = mgmt_txn_mm->next_txn_id++; hash_get(mgmt_txn_mm->txn_hash, txn, hash_alloc_intern); - MGMTD_TXN_DBG("Added new '%s' txn-id: %" PRIu64, - mgmt_txn_type2str(type), txn->txn_id); + __dbg("Added new '%s' txn-id: %" PRIu64, + mgmt_txn_type2str(type), txn->txn_id); if (type == MGMTD_TXN_TYPE_CONFIG) mgmt_txn_mm->cfg_txn = txn; @@ -1964,7 +1827,6 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id, MGMTD_TXN_LOCK(txn); } -mgmt_create_txn_done: return txn; } @@ -2029,12 +1891,18 @@ static inline struct mgmt_txn_ctx *mgmt_txn_id2ctx(uint64_t txn_id) return txn; } +uint64_t mgmt_txn_get_session_id(uint64_t txn_id) +{ + struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id); + + return txn ? txn->session_id : MGMTD_SESSION_ID_NONE; +} + static void mgmt_txn_lock(struct mgmt_txn_ctx *txn, const char *file, int line) { txn->refcount++; - MGMTD_TXN_DBG("%s:%d --> Lock %s txn-id: %" PRIu64 " refcnt: %d", file, - line, mgmt_txn_type2str(txn->type), txn->txn_id, - txn->refcount); + __dbg("%s:%d --> Lock %s txn-id: %" PRIu64 " refcnt: %d", file, line, + mgmt_txn_type2str(txn->type), txn->txn_id, txn->refcount); } static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file, @@ -2043,9 +1911,8 @@ static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file, assert(*txn && (*txn)->refcount); (*txn)->refcount--; - MGMTD_TXN_DBG("%s:%d --> Unlock %s txn-id: %" PRIu64 " refcnt: %d", - file, line, mgmt_txn_type2str((*txn)->type), - (*txn)->txn_id, (*txn)->refcount); + __dbg("%s:%d --> Unlock %s txn-id: %" PRIu64 " refcnt: %d", file, line, + mgmt_txn_type2str((*txn)->type), (*txn)->txn_id, (*txn)->refcount); if (!(*txn)->refcount) { if ((*txn)->type == MGMTD_TXN_TYPE_CONFIG) if (mgmt_txn_mm->cfg_txn == *txn) @@ -2054,13 +1921,13 @@ static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file, EVENT_OFF((*txn)->proc_get_data); EVENT_OFF((*txn)->proc_comm_cfg); EVENT_OFF((*txn)->comm_cfg_timeout); + EVENT_OFF((*txn)->get_tree_timeout); hash_release(mgmt_txn_mm->txn_hash, *txn); mgmt_txns_del(&mgmt_txn_mm->txn_list, *txn); - MGMTD_TXN_DBG("Deleted %s txn-id: %" PRIu64 - " session-id: %" PRIu64, - mgmt_txn_type2str((*txn)->type), (*txn)->txn_id, - (*txn)->session_id); + __dbg("Deleted %s txn-id: %" PRIu64 " session-id: %" PRIu64, + mgmt_txn_type2str((*txn)->type), (*txn)->txn_id, + (*txn)->session_id); XFREE(MTYPE_MGMTD_TXN, *txn); } @@ -2086,16 +1953,6 @@ static void mgmt_txn_cleanup_all_txns(void) mgmt_txn_cleanup_txn(&txn); } -static void mgmt_txn_cleanup(struct event *thread) -{ - struct mgmt_txn_ctx *txn; - - txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread); - assert(txn); - - mgmt_txn_cleanup_txn(&txn); -} - static void mgmt_txn_register_event(struct mgmt_txn_ctx *txn, enum mgmt_txn_event event) { @@ -2117,19 +1974,15 @@ static void mgmt_txn_register_event(struct mgmt_txn_ctx *txn, event_add_timer_tv(mgmt_txn_tm, mgmt_txn_process_get_cfg, txn, &tv, &txn->proc_get_cfg); break; - case MGMTD_TXN_PROC_GETDATA: - event_add_timer_tv(mgmt_txn_tm, mgmt_txn_process_get_data, txn, - &tv, &txn->proc_get_data); - break; case MGMTD_TXN_COMMITCFG_TIMEOUT: - event_add_timer_msec(mgmt_txn_tm, mgmt_txn_cfg_commit_timedout, - txn, MGMTD_TXN_CFG_COMMIT_MAX_DELAY_MSEC, - &txn->comm_cfg_timeout); + event_add_timer(mgmt_txn_tm, mgmt_txn_cfg_commit_timedout, txn, + MGMTD_TXN_CFG_COMMIT_MAX_DELAY_SEC, + &txn->comm_cfg_timeout); + break; + case MGMTD_TXN_PROC_GETTREE: + case MGMTD_TXN_PROC_RPC: + assert(!"code bug do not register this event"); break; - case MGMTD_TXN_CLEANUP: - tv.tv_usec = MGMTD_TXN_CLEANUP_DELAY_USEC; - event_add_timer_tv(mgmt_txn_tm, mgmt_txn_cleanup, txn, &tv, - &txn->clnup); } } @@ -2154,12 +2007,12 @@ void mgmt_txn_destroy(void) mgmt_txn_hash_destroy(); } -uint64_t mgmt_config_txn_in_progress(void) +bool mgmt_config_txn_in_progress(void) { if (mgmt_txn_mm && mgmt_txn_mm->cfg_txn) - return mgmt_txn_mm->cfg_txn->session_id; + return true; - return MGMTD_SESSION_ID_NONE; + return false; } uint64_t mgmt_create_txn(uint64_t session_id, enum mgmt_txn_type type) @@ -2195,13 +2048,14 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id, size_t indx; uint16_t *num_chgs; struct nb_cfg_change *cfg_chg; + struct nb_node *node; txn = mgmt_txn_id2ctx(txn_id); if (!txn) return -1; if (implicit_commit && mgmt_txn_reqs_count(&txn->set_cfg_reqs)) { - MGMTD_TXN_ERR( + __log_err( "For implicit commit config only one SETCFG-REQ can be allowed!"); return -1; } @@ -2213,27 +2067,42 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id, for (indx = 0; indx < num_req; indx++) { cfg_chg = &txn_req->req.set_cfg->cfg_changes[*num_chgs]; - if (cfg_req[indx]->req_type == - MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA) + switch (cfg_req[indx]->req_type) { + case MGMTD__CFG_DATA_REQ_TYPE__DELETE_DATA: + cfg_chg->operation = NB_OP_DELETE; + break; + case MGMTD__CFG_DATA_REQ_TYPE__REMOVE_DATA: cfg_chg->operation = NB_OP_DESTROY; - else if (cfg_req[indx]->req_type == - MGMTD__CFG_DATA_REQ_TYPE__SET_DATA) - cfg_chg->operation = - mgmt_ds_find_data_node_by_xpath(ds_ctx, - cfg_req[indx] - ->data - ->xpath) - ? NB_OP_MODIFY - : NB_OP_CREATE; - else + break; + case MGMTD__CFG_DATA_REQ_TYPE__SET_DATA: + /* + * For backward compatibility, we need to allow creating + * *new* list keys with SET_DATA operation. NB_OP_MODIFY + * is not allowed for keys, so use NB_OP_CREATE_EXCL. + */ + node = nb_node_find(cfg_req[indx]->data->xpath); + if (node && lysc_is_key(node->snode)) + cfg_chg->operation = NB_OP_CREATE_EXCL; + else + cfg_chg->operation = NB_OP_MODIFY; + break; + case MGMTD__CFG_DATA_REQ_TYPE__CREATE_DATA: + cfg_chg->operation = NB_OP_CREATE_EXCL; + break; + case MGMTD__CFG_DATA_REQ_TYPE__REPLACE_DATA: + cfg_chg->operation = NB_OP_REPLACE; + break; + case MGMTD__CFG_DATA_REQ_TYPE__REQ_TYPE_NONE: + case _MGMTD__CFG_DATA_REQ_TYPE_IS_INT_SIZE: + default: continue; + } - MGMTD_TXN_DBG("XPath: '%s', Value: '%s'", - cfg_req[indx]->data->xpath, - (cfg_req[indx]->data->value && - cfg_req[indx]->data->value->encoded_str_val - ? cfg_req[indx]->data->value->encoded_str_val - : "NULL")); + __dbg("XPath: '%s', Value: '%s'", cfg_req[indx]->data->xpath, + (cfg_req[indx]->data->value && + cfg_req[indx]->data->value->encoded_str_val + ? cfg_req[indx]->data->value->encoded_str_val + : "NULL")); strlcpy(cfg_chg->xpath, cfg_req[indx]->data->xpath, sizeof(cfg_chg->xpath)); cfg_chg->value = @@ -2243,8 +2112,8 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id, ->data->value->encoded_str_val) : NULL); if (cfg_chg->value) - MGMTD_TXN_DBG("Allocated value at %p ==> '%s'", - cfg_chg->value, cfg_chg->value); + __dbg("Allocated value at %p ==> '%s'", cfg_chg->value, + cfg_chg->value); (*num_chgs)++; } @@ -2264,7 +2133,7 @@ int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id, Mgmtd__DatastoreId dst_ds_id, struct mgmt_ds_ctx *dst_ds_ctx, bool validate_only, bool abort, - bool implicit) + bool implicit, struct mgmt_edit_req *edit) { struct mgmt_txn_ctx *txn; struct mgmt_txn_req *txn_req; @@ -2274,9 +2143,9 @@ int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id, return -1; if (txn->commit_cfg_req) { - MGMTD_TXN_ERR("Commit already in-progress txn-id: %" PRIu64 - " session-id: %" PRIu64 ". Cannot start another", - txn->txn_id, txn->session_id); + __log_err("Commit already in-progress txn-id: %" PRIu64 + " session-id: %" PRIu64 ". Cannot start another", + txn->txn_id, txn->session_id); return -1; } @@ -2288,6 +2157,7 @@ int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id, txn_req->req.commit_cfg.validate_only = validate_only; txn_req->req.commit_cfg.abort = abort; txn_req->req.commit_cfg.implicit = implicit; + txn_req->req.commit_cfg.edit = edit; txn_req->req.commit_cfg.cmt_stats = mgmt_fe_get_session_commit_stats(txn->session_id); @@ -2306,15 +2176,26 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter, struct mgmt_commit_cfg_req *cmtcfg_req; static struct mgmt_commit_stats dummy_stats; struct nb_config_cbs *adapter_cfgs = NULL; + struct mgmt_ds_ctx *ds_ctx; memset(&dummy_stats, 0, sizeof(dummy_stats)); if (connect) { - /* Get config for this single backend client */ + ds_ctx = mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_RUNNING); + assert(ds_ctx); + + /* + * Lock the running datastore to prevent any changes while we + * are initializing the backend. + */ + if (mgmt_ds_lock(ds_ctx, 0) != 0) + return -1; + /* Get config for this single backend client */ mgmt_be_get_adapter_config(adapter, &adapter_cfgs); if (!adapter_cfgs || RB_EMPTY(nb_config_cbs, adapter_cfgs)) { SET_FLAG(adapter->flags, MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED); + mgmt_ds_unlock(ds_ctx); return 0; } @@ -2324,14 +2205,15 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter, */ txn = mgmt_txn_create_new(0, MGMTD_TXN_TYPE_CONFIG); if (!txn) { - MGMTD_TXN_ERR("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'", - adapter->name); + __log_err("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'", + adapter->name); + mgmt_ds_unlock(ds_ctx); + nb_config_diff_del_changes(adapter_cfgs); return -1; } - MGMTD_TXN_DBG("Created initial txn-id: %" PRIu64 - " for BE client '%s'", - txn->txn_id, adapter->name); + __dbg("Created initial txn-id: %" PRIu64 " for BE client '%s'", + txn->txn_id, adapter->name); /* * Set the changeset for transaction to commit and trigger the * commit request. @@ -2339,10 +2221,11 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter, txn_req = mgmt_txn_req_alloc(txn, 0, MGMTD_TXN_PROC_COMMITCFG); txn_req->req.commit_cfg.src_ds_id = MGMTD_DS_NONE; txn_req->req.commit_cfg.src_ds_ctx = 0; - txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_NONE; - txn_req->req.commit_cfg.dst_ds_ctx = 0; + txn_req->req.commit_cfg.dst_ds_id = MGMTD_DS_RUNNING; + txn_req->req.commit_cfg.dst_ds_ctx = ds_ctx; txn_req->req.commit_cfg.validate_only = false; txn_req->req.commit_cfg.abort = false; + txn_req->req.commit_cfg.init = true; txn_req->req.commit_cfg.cmt_stats = &dummy_stats; txn_req->req.commit_cfg.cfg_chgs = adapter_cfgs; @@ -2365,9 +2248,8 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter, ? &txn->commit_cfg_req->req .commit_cfg : NULL; - if (cmtcfg_req && - cmtcfg_req->subscr_info - .xpath_subscr[adapter->id]) { + if (cmtcfg_req && IS_IDBIT_SET(cmtcfg_req->clients, + adapter->id)) { mgmt_txn_send_commit_cfg_reply( txn, MGMTD_INTERNAL_ERROR, "Backend daemon disconnected while processing commit!"); @@ -2400,7 +2282,7 @@ int mgmt_txn_notify_be_txn_reply(uint64_t txn_id, bool create, bool success, * Done with TXN_CREATE. Move the backend client to * next phase. */ - assert(cmtcfg_req->curr_phase == + assert(cmtcfg_req->phase == MGMTD_COMMIT_PHASE_TXN_CREATE); /* @@ -2412,23 +2294,16 @@ int mgmt_txn_notify_be_txn_reply(uint64_t txn_id, bool create, bool success, txn, MGMTD_INTERNAL_ERROR, "Internal error! Failed to initiate transaction at backend!"); } - } else { - /* - * Done with TXN_DELETE. Move the backend client to next phase. - */ - if (false) - mgmt_move_be_commit_to_next_phase(txn, adapter); } return 0; } -int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id, - bool success, char *error_if_any, +int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, bool success, + char *error_if_any, struct mgmt_be_client_adapter *adapter) { struct mgmt_txn_ctx *txn; - struct mgmt_txn_be_cfg_batch *batch; struct mgmt_commit_cfg_req *cmtcfg_req; txn = mgmt_txn_id2ctx(txn_id); @@ -2439,15 +2314,11 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id, return -1; cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; - batch = mgmt_txn_cfgbatch_id2ctx(txn, batch_id); - if (!batch || batch->txn != txn) - return -1; - if (!success) { - MGMTD_TXN_ERR("CFGDATA_CREATE_REQ sent to '%s' failed txn-id: %" PRIu64 - " batch-id %" PRIu64 " err: %s", - adapter->name, txn->txn_id, batch->batch_id, - error_if_any ? error_if_any : "None"); + __log_err("CFGDATA_CREATE_REQ sent to '%s' failed txn-id: %" PRIu64 + " err: %s", + adapter->name, txn->txn_id, + error_if_any ? error_if_any : "None"); mgmt_txn_send_commit_cfg_reply( txn, MGMTD_INTERNAL_ERROR, error_if_any @@ -2456,14 +2327,11 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id, return 0; } - MGMTD_TXN_DBG("CFGDATA_CREATE_REQ sent to '%s' was successful txn-id: %" PRIu64 - " batch-id %" PRIu64 " err: %s", - adapter->name, txn->txn_id, batch->batch_id, - error_if_any ? error_if_any : "None"); - mgmt_move_txn_cfg_batch_to_next(cmtcfg_req, batch, - &cmtcfg_req->curr_batches[adapter->id], - &cmtcfg_req->next_batches[adapter->id], - true, MGMTD_COMMIT_PHASE_APPLY_CFG); + __dbg("CFGDATA_CREATE_REQ sent to '%s' was successful txn-id: %" PRIu64 + " err: %s", + adapter->name, txn->txn_id, error_if_any ? error_if_any : "None"); + + cmtcfg_req->be_phase[adapter->id] = MGMTD_COMMIT_PHASE_APPLY_CFG; mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req); @@ -2471,14 +2339,11 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id, } int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success, - uint64_t batch_ids[], - size_t num_batch_ids, char *error_if_any, + char *error_if_any, struct mgmt_be_client_adapter *adapter) { struct mgmt_txn_ctx *txn; - struct mgmt_txn_be_cfg_batch *batch; struct mgmt_commit_cfg_req *cmtcfg_req = NULL; - size_t indx; txn = mgmt_txn_id2ctx(txn_id); if (!txn || txn->type != MGMTD_TXN_TYPE_CONFIG || !txn->commit_cfg_req) @@ -2487,11 +2352,10 @@ int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success, cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg; if (!success) { - MGMTD_TXN_ERR("CFGDATA_APPLY_REQ sent to '%s' failed txn-id: %" PRIu64 - " batch ids %" PRIu64 " - %" PRIu64 " err: %s", - adapter->name, txn->txn_id, batch_ids[0], - batch_ids[num_batch_ids - 1], - error_if_any ? error_if_any : "None"); + __log_err("CFGDATA_APPLY_REQ sent to '%s' failed txn-id: %" PRIu64 + " err: %s", + adapter->name, txn->txn_id, + error_if_any ? error_if_any : "None"); mgmt_txn_send_commit_cfg_reply( txn, MGMTD_INTERNAL_ERROR, error_if_any @@ -2500,25 +2364,14 @@ int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success, return 0; } - for (indx = 0; indx < num_batch_ids; indx++) { - batch = mgmt_txn_cfgbatch_id2ctx(txn, batch_ids[indx]); - if (batch->txn != txn) - return -1; - mgmt_move_txn_cfg_batch_to_next( - cmtcfg_req, batch, - &cmtcfg_req->curr_batches[adapter->id], - &cmtcfg_req->next_batches[adapter->id], true, - MGMTD_COMMIT_PHASE_TXN_DELETE); - } + cmtcfg_req->be_phase[adapter->id] = MGMTD_COMMIT_PHASE_TXN_DELETE; - if (!mgmt_txn_batches_count(&cmtcfg_req->curr_batches[adapter->id])) { - /* - * All configuration for the specific backend has been applied. - * Send TXN-DELETE to wrap up the transaction for this backend. - */ - SET_FLAG(adapter->flags, MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED); - mgmt_txn_send_be_txn_delete(txn, adapter); - } + /* + * All configuration for the specific backend has been applied. + * Send TXN-DELETE to wrap up the transaction for this backend. + */ + SET_FLAG(adapter->flags, MGMTD_BE_ADAPTER_FLAGS_CFG_SYNCED); + mgmt_txn_send_be_txn_delete(txn, adapter); mgmt_try_move_commit_to_next_phase(txn, cmtcfg_req); if (mm->perf_stats_en) @@ -2540,15 +2393,14 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, if (!txn) return -1; - req_event = cfg_root ? MGMTD_TXN_PROC_GETCFG : MGMTD_TXN_PROC_GETDATA; - + req_event = MGMTD_TXN_PROC_GETCFG; txn_req = mgmt_txn_req_alloc(txn, req_id, req_event); txn_req->req.get_data->ds_id = ds_id; txn_req->req.get_data->cfg_root = cfg_root; for (indx = 0; indx < num_reqs && indx < MGMTD_MAX_NUM_DATA_REPLY_IN_BATCH; indx++) { - MGMTD_TXN_DBG("XPath: '%s'", data_req[indx]->data->xpath); + __dbg("XPath: '%s'", data_req[indx]->data->xpath); txn_req->req.get_data->xpaths[indx] = strdup(data_req[indx]->data->xpath); txn_req->req.get_data->num_xpaths++; @@ -2559,6 +2411,456 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, return 0; } + +/** + * Send get-tree requests to each client indicated in `clients` bitmask, which + * has registered operational state that matches the given `xpath` + */ +int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id, + uint64_t clients, Mgmtd__DatastoreId ds_id, + LYD_FORMAT result_type, uint8_t flags, + uint32_t wd_options, bool simple_xpath, + const char *xpath) +{ + struct mgmt_msg_get_tree *msg; + struct mgmt_txn_ctx *txn; + struct mgmt_txn_req *txn_req; + struct txn_req_get_tree *get_tree; + enum mgmt_be_client_id id; + ssize_t slen = strlen(xpath); + int ret; + + txn = mgmt_txn_id2ctx(txn_id); + if (!txn) + return -1; + + /* If error in this function below here, be sure to free the req */ + txn_req = mgmt_txn_req_alloc(txn, req_id, MGMTD_TXN_PROC_GETTREE); + get_tree = txn_req->req.get_tree; + get_tree->result_type = result_type; + get_tree->wd_options = wd_options; + get_tree->exact = CHECK_FLAG(flags, GET_DATA_FLAG_EXACT); + get_tree->simple_xpath = simple_xpath; + get_tree->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); + + if (CHECK_FLAG(flags, GET_DATA_FLAG_CONFIG)) { + /* + * If the requested datastore is operational, get the config + * from running. + */ + struct mgmt_ds_ctx *ds = + mgmt_ds_get_ctx_by_id(mm, ds_id == MGMTD_DS_OPERATIONAL + ? MGMTD_DS_RUNNING + : ds_id); + struct nb_config *config = mgmt_ds_get_nb_config(ds); + + if (config) { + struct ly_set *set = NULL; + LY_ERR err; + + err = lyd_find_xpath(config->dnode, xpath, &set); + if (err) { + get_tree->partial_error = err; + goto state; + } + + /* + * If there's a single result, duplicate the returned + * node. If there are multiple results, duplicate the + * whole config and mark simple_xpath as false so the + * result is trimmed later in txn_get_tree_data_done. + */ + if (set->count == 1) { + err = lyd_dup_single(set->dnodes[0], NULL, + LYD_DUP_WITH_PARENTS | + LYD_DUP_WITH_FLAGS | + LYD_DUP_RECURSIVE, + &get_tree->client_results); + if (!err) + while (get_tree->client_results->parent) + get_tree->client_results = lyd_parent( + get_tree->client_results); + } else if (set->count > 1) { + err = lyd_dup_siblings(config->dnode, NULL, + LYD_DUP_RECURSIVE | + LYD_DUP_WITH_FLAGS, + &get_tree->client_results); + if (!err) + get_tree->simple_xpath = false; + } + + if (err) + get_tree->partial_error = err; + + ly_set_free(set, NULL); + } + } +state: + /* If we are only getting config, we are done */ + if (!CHECK_FLAG(flags, GET_DATA_FLAG_STATE) || + ds_id != MGMTD_DS_OPERATIONAL || !clients) + return txn_get_tree_data_done(txn, txn_req); + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_get_tree, slen + 1, + MTYPE_MSG_NATIVE_GET_TREE); + msg->refer_id = txn_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_GET_TREE; + /* Always operate with the binary format in the backend */ + msg->result_type = LYD_LYB; + strlcpy(msg->xpath, xpath, slen + 1); + + assert(clients); + FOREACH_BE_CLIENT_BITS (id, clients) { + ret = mgmt_be_send_native(id, msg); + if (ret) { + __log_err("Could not send get-tree message to backend client %s", + mgmt_be_client_id2name(id)); + continue; + } + + __dbg("Sent get-tree req to backend client %s", + mgmt_be_client_id2name(id)); + + /* record that we sent the request to the client */ + get_tree->sent_clients |= (1u << id); + } + + mgmt_msg_native_free_msg(msg); + + /* Return if we didn't send any messages to backends */ + if (!get_tree->sent_clients) + return txn_get_tree_data_done(txn, txn_req); + + /* Start timeout timer - pulled out of register event code so we can + * pass a different arg + */ + event_add_timer(mgmt_txn_tm, txn_get_tree_timeout, txn_req, + MGMTD_TXN_GET_TREE_MAX_DELAY_SEC, + &txn->get_tree_timeout); + return 0; +} + +int mgmt_txn_send_edit(uint64_t txn_id, uint64_t req_id, + Mgmtd__DatastoreId ds_id, struct mgmt_ds_ctx *ds_ctx, + Mgmtd__DatastoreId commit_ds_id, + struct mgmt_ds_ctx *commit_ds_ctx, bool unlock, + bool commit, LYD_FORMAT request_type, uint8_t flags, + uint8_t operation, const char *xpath, const char *data) +{ + struct mgmt_txn_ctx *txn; + struct mgmt_edit_req *edit; + struct nb_config *nb_config; + char errstr[BUFSIZ]; + int ret; + + txn = mgmt_txn_id2ctx(txn_id); + if (!txn) + return -1; + + edit = XCALLOC(MTYPE_MGMTD_TXN_REQ, sizeof(struct mgmt_edit_req)); + + nb_config = mgmt_ds_get_nb_config(ds_ctx); + assert(nb_config); + + ret = nb_candidate_edit_tree(nb_config, operation, request_type, xpath, + data, edit->xpath_created, errstr, + sizeof(errstr)); + if (ret) + goto reply; + + if (commit) { + edit->unlock = unlock; + + mgmt_txn_send_commit_config_req(txn_id, req_id, ds_id, ds_ctx, + commit_ds_id, commit_ds_ctx, + false, false, true, edit); + return 0; + } +reply: + mgmt_fe_adapter_send_edit_reply(txn->session_id, txn->txn_id, req_id, + unlock, commit, edit->xpath_created, + ret ? -1 : 0, errstr); + + XFREE(MTYPE_MGMTD_TXN_REQ, edit); + + return 0; +} + +int mgmt_txn_send_rpc(uint64_t txn_id, uint64_t req_id, uint64_t clients, + LYD_FORMAT result_type, const char *xpath, + const char *data, size_t data_len) +{ + struct mgmt_txn_ctx *txn; + struct mgmt_txn_req *txn_req; + struct mgmt_msg_rpc *msg; + struct txn_req_rpc *rpc; + uint64_t id; + int ret; + + txn = mgmt_txn_id2ctx(txn_id); + if (!txn) + return -1; + + txn_req = mgmt_txn_req_alloc(txn, req_id, MGMTD_TXN_PROC_RPC); + rpc = txn_req->req.rpc; + rpc->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath); + rpc->result_type = result_type; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_rpc, 0, + MTYPE_MSG_NATIVE_RPC); + msg->refer_id = txn_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_RPC; + msg->request_type = result_type; + + mgmt_msg_native_xpath_encode(msg, xpath); + if (data) + mgmt_msg_native_append(msg, data, data_len); + + assert(clients); + FOREACH_BE_CLIENT_BITS (id, clients) { + ret = mgmt_be_send_native(id, msg); + if (ret) { + __log_err("Could not send rpc message to backend client %s", + mgmt_be_client_id2name(id)); + continue; + } + + __dbg("Sent rpc req to backend client %s", + mgmt_be_client_id2name(id)); + + /* record that we sent the request to the client */ + rpc->sent_clients |= (1u << id); + } + + mgmt_msg_native_free_msg(msg); + + if (!rpc->sent_clients) + return txn_rpc_done(txn, txn_req); + + event_add_timer(mgmt_txn_tm, txn_rpc_timeout, txn_req, + MGMTD_TXN_RPC_MAX_DELAY_SEC, &txn->rpc_timeout); + + return 0; +} + +/* + * Error reply from the backend client. + */ +int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter, + uint64_t txn_id, uint64_t req_id, int error, + const char *errstr) +{ + enum mgmt_be_client_id id = adapter->id; + struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id); + struct txn_req_get_tree *get_tree; + struct txn_req_rpc *rpc; + struct mgmt_txn_req *txn_req; + + if (!txn) { + __log_err("Error reply from %s cannot find txn-id %" PRIu64, + adapter->name, txn_id); + return -1; + } + + /* Find the request. */ + FOREACH_TXN_REQ_IN_LIST (&txn->get_tree_reqs, txn_req) + if (txn_req->req_id == req_id) + break; + if (!txn_req) + FOREACH_TXN_REQ_IN_LIST (&txn->rpc_reqs, txn_req) + if (txn_req->req_id == req_id) + break; + if (!txn_req) { + __log_err("Error reply from %s for txn-id %" PRIu64 + " cannot find req_id %" PRIu64, + adapter->name, txn_id, req_id); + return -1; + } + + __log_err("Error reply from %s for txn-id %" PRIu64 " req_id %" PRIu64, + adapter->name, txn_id, req_id); + + switch (txn_req->req_event) { + case MGMTD_TXN_PROC_GETTREE: + get_tree = txn_req->req.get_tree; + get_tree->recv_clients |= (1u << id); + get_tree->partial_error = error; + + /* check if done yet */ + if (get_tree->recv_clients != get_tree->sent_clients) + return 0; + return txn_get_tree_data_done(txn, txn_req); + case MGMTD_TXN_PROC_RPC: + rpc = txn_req->req.rpc; + rpc->recv_clients |= (1u << id); + if (errstr) { + XFREE(MTYPE_MGMTD_ERR, rpc->errstr); + rpc->errstr = XSTRDUP(MTYPE_MGMTD_ERR, errstr); + } + /* check if done yet */ + if (rpc->recv_clients != rpc->sent_clients) + return 0; + return txn_rpc_done(txn, txn_req); + + /* non-native message events */ + case MGMTD_TXN_PROC_SETCFG: + case MGMTD_TXN_PROC_COMMITCFG: + case MGMTD_TXN_PROC_GETCFG: + case MGMTD_TXN_COMMITCFG_TIMEOUT: + default: + assert(!"non-native req event in native error path"); + return -1; + } +} + +/* + * Get-tree data from the backend client. + */ +int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter, + struct mgmt_msg_tree_data *data_msg, + size_t msg_len) +{ + uint64_t txn_id = data_msg->refer_id; + uint64_t req_id = data_msg->req_id; + + enum mgmt_be_client_id id = adapter->id; + struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id); + struct mgmt_txn_req *txn_req; + struct txn_req_get_tree *get_tree; + struct lyd_node *tree = NULL; + LY_ERR err; + + if (!txn) { + __log_err("GETTREE reply from %s for a missing txn-id %" PRIu64, + adapter->name, txn_id); + return -1; + } + + /* Find the request. */ + FOREACH_TXN_REQ_IN_LIST (&txn->get_tree_reqs, txn_req) + if (txn_req->req_id == req_id) + break; + if (!txn_req) { + __log_err("GETTREE reply from %s for txn-id %" PRIu64 + " missing req_id %" PRIu64, + adapter->name, txn_id, req_id); + return -1; + } + + get_tree = txn_req->req.get_tree; + + /* store the result */ + err = lyd_parse_data_mem(ly_native_ctx, (const char *)data_msg->result, + data_msg->result_type, + LYD_PARSE_STRICT | LYD_PARSE_ONLY, + 0 /*LYD_VALIDATE_OPERATIONAL*/, &tree); + if (err) { + __log_err("GETTREE reply from %s for txn-id %" PRIu64 + " req_id %" PRIu64 " error parsing result of type %u", + adapter->name, txn_id, req_id, data_msg->result_type); + } + if (!err) { + /* TODO: we could merge ly_errs here if it's not binary */ + + if (!get_tree->client_results) + get_tree->client_results = tree; + else + err = lyd_merge_siblings(&get_tree->client_results, + tree, LYD_MERGE_DESTRUCT); + if (err) { + __log_err("GETTREE reply from %s for txn-id %" PRIu64 + " req_id %" PRIu64 " error merging result", + adapter->name, txn_id, req_id); + } + } + if (!get_tree->partial_error) + get_tree->partial_error = (data_msg->partial_error + ? data_msg->partial_error + : (int)err); + + if (!data_msg->more) + get_tree->recv_clients |= (1u << id); + + /* check if done yet */ + if (get_tree->recv_clients != get_tree->sent_clients) + return 0; + + return txn_get_tree_data_done(txn, txn_req); +} + +int mgmt_txn_notify_rpc_reply(struct mgmt_be_client_adapter *adapter, + struct mgmt_msg_rpc_reply *reply_msg, + size_t msg_len) +{ + uint64_t txn_id = reply_msg->refer_id; + uint64_t req_id = reply_msg->req_id; + enum mgmt_be_client_id id = adapter->id; + struct mgmt_txn_ctx *txn = mgmt_txn_id2ctx(txn_id); + struct mgmt_txn_req *txn_req; + struct txn_req_rpc *rpc; + struct lyd_node *tree; + size_t data_len = msg_len - sizeof(*reply_msg); + LY_ERR err = LY_SUCCESS; + + if (!txn) { + __log_err("RPC reply from %s for a missing txn-id %" PRIu64, + adapter->name, txn_id); + return -1; + } + + /* Find the request. */ + FOREACH_TXN_REQ_IN_LIST (&txn->rpc_reqs, txn_req) + if (txn_req->req_id == req_id) + break; + if (!txn_req) { + __log_err("RPC reply from %s for txn-id %" PRIu64 + " missing req_id %" PRIu64, + adapter->name, txn_id, req_id); + return -1; + } + + rpc = txn_req->req.rpc; + + tree = NULL; + if (data_len) + err = yang_parse_rpc(rpc->xpath, reply_msg->result_type, + reply_msg->data, true, &tree); + if (err) { + __log_err("RPC reply from %s for txn-id %" PRIu64 + " req_id %" PRIu64 " error parsing result of type %u: %s", + adapter->name, txn_id, req_id, reply_msg->result_type, + ly_strerrcode(err)); + } + if (!err && tree) { + if (!rpc->client_results) + rpc->client_results = tree; + else + err = lyd_merge_siblings(&rpc->client_results, tree, + LYD_MERGE_DESTRUCT); + if (err) { + __log_err("RPC reply from %s for txn-id %" PRIu64 + " req_id %" PRIu64 " error merging result: %s", + adapter->name, txn_id, req_id, + ly_strerrcode(err)); + } + } + if (err) { + XFREE(MTYPE_MGMTD_ERR, rpc->errstr); + rpc->errstr = XSTRDUP(MTYPE_MGMTD_ERR, + "Cannot parse result from the backend"); + } + + rpc->recv_clients |= (1u << id); + + /* check if done yet */ + if (rpc->recv_clients != rpc->sent_clients) + return 0; + + return txn_rpc_done(txn, txn_req); +} + void mgmt_txn_status_write(struct vty *vty) { struct mgmt_txn_ctx *txn; @@ -2614,12 +2916,12 @@ int mgmt_txn_rollback_trigger_cfg_apply(struct mgmt_ds_ctx *src_ds_ctx, */ txn = mgmt_txn_create_new(0, MGMTD_TXN_TYPE_CONFIG); if (!txn) { - MGMTD_TXN_ERR( + __log_err( "Failed to create CONFIG Transaction for downloading CONFIGs"); return -1; } - MGMTD_TXN_DBG("Created rollback txn-id: %" PRIu64, txn->txn_id); + __dbg("Created rollback txn-id: %" PRIu64, txn->txn_id); /* * Set the changeset for transaction to commit and trigger the commit diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h index 068f07a5ca8a..b6ca288675b7 100644 --- a/mgmtd/mgmt_txn.h +++ b/mgmtd/mgmt_txn.h @@ -9,23 +9,24 @@ #ifndef _FRR_MGMTD_TXN_H_ #define _FRR_MGMTD_TXN_H_ +#include "lib/mgmt_msg_native.h" #include "mgmtd/mgmt_be_adapter.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_ds.h" -#define MGMTD_TXN_PROC_DELAY_MSEC 5 #define MGMTD_TXN_PROC_DELAY_USEC 10 #define MGMTD_TXN_MAX_NUM_SETCFG_PROC 128 #define MGMTD_TXN_MAX_NUM_GETCFG_PROC 128 #define MGMTD_TXN_MAX_NUM_GETDATA_PROC 128 -#define MGMTD_TXN_SEND_CFGVALIDATE_DELAY_MSEC 100 -#define MGMTD_TXN_SEND_CFGAPPLY_DELAY_MSEC 100 -#define MGMTD_TXN_CFG_COMMIT_MAX_DELAY_MSEC 30000 /* 30 seconds */ +#define MGMTD_TXN_CFG_COMMIT_MAX_DELAY_SEC 600 +#define MGMTD_TXN_GET_TREE_MAX_DELAY_SEC 600 +#define MGMTD_TXN_RPC_MAX_DELAY_SEC 60 -#define MGMTD_TXN_CLEANUP_DELAY_MSEC 100 #define MGMTD_TXN_CLEANUP_DELAY_USEC 10 +#define MGMTD_TXN_ID_NONE 0 + /* * The following definition enables local validation of config * on the MGMTD process by loading client-defined NB callbacks @@ -43,11 +44,13 @@ PREDECL_LIST(mgmt_txns); struct mgmt_master; +struct mgmt_edit_req; enum mgmt_txn_type { MGMTD_TXN_TYPE_NONE = 0, MGMTD_TXN_TYPE_CONFIG, - MGMTD_TXN_TYPE_SHOW + MGMTD_TXN_TYPE_SHOW, + MGMTD_TXN_TYPE_RPC, }; static inline const char *mgmt_txn_type2str(enum mgmt_txn_type type) @@ -59,6 +62,8 @@ static inline const char *mgmt_txn_type2str(enum mgmt_txn_type type) return "CONFIG"; case MGMTD_TXN_TYPE_SHOW: return "SHOW"; + case MGMTD_TXN_TYPE_RPC: + return "RPC"; } return "Unknown"; @@ -71,12 +76,18 @@ extern int mgmt_txn_init(struct mgmt_master *cm, struct event_loop *tm); extern void mgmt_txn_destroy(void); /* - * Check if transaction is in progress. + * Check if configuration transaction is in progress. * * Returns: - * session ID if in-progress, MGMTD_SESSION_ID_NONE otherwise. + * true if in-progress, false otherwise. + */ +extern bool mgmt_config_txn_in_progress(void); + +/** + * Get the session ID associated with the given ``txn-id``. + * */ -extern uint64_t mgmt_config_txn_in_progress(void); +extern uint64_t mgmt_txn_get_session_id(uint64_t txn_id); /* * Create transaction. @@ -165,16 +176,17 @@ extern int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id, * implicit * TRUE if the commit is implicit, FALSE otherwise. * + * edit + * Additional info when triggered from native edit request. + * * Returns: * 0 on success, -1 on failures. */ -extern int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id, - Mgmtd__DatastoreId src_ds_id, - struct mgmt_ds_ctx *dst_ds_ctx, - Mgmtd__DatastoreId dst_ds_id, - struct mgmt_ds_ctx *src_ds_ctx, - bool validate_only, bool abort, - bool implicit); +extern int mgmt_txn_send_commit_config_req( + uint64_t txn_id, uint64_t req_id, Mgmtd__DatastoreId src_ds_id, + struct mgmt_ds_ctx *dst_ds_ctx, Mgmtd__DatastoreId dst_ds_id, + struct mgmt_ds_ctx *src_ds_ctx, bool validate_only, bool abort, + bool implicit, struct mgmt_edit_req *edit); /* * Send get-{cfg,data} request to be processed later in transaction. @@ -188,6 +200,75 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id, Mgmtd__YangGetDataReq **data_req, size_t num_reqs); + +/** + * Send get-tree to the backend `clients`. + * + * Args: + * txn_id: Transaction identifier. + * req_id: FE client request identifier. + * clients: Bitmask of clients to send get-tree to. + * ds_id: datastore ID. + * result_type: LYD_FORMAT result format. + * flags: option flags for the request. + * wd_options: LYD_PRINT_WD_* flags for the result. + * simple_xpath: true if xpath is simple (only key predicates). + * xpath: The xpath to get the tree from. + * + * Return: + * 0 on success. + */ +extern int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id, + uint64_t clients, + Mgmtd__DatastoreId ds_id, + LYD_FORMAT result_type, uint8_t flags, + uint32_t wd_options, bool simple_xpath, + const char *xpath); + +/** + * Send edit request. + * + * Args: + * txn_id: Transaction identifier. + * req_id: FE client request identifier. + * ds_id: Datastore ID. + * ds_ctx: Datastore context. + * commit_ds_id: Commit datastore ID. + * commit_ds_ctx: Commit datastore context. + * unlock: Unlock datastores after the edit. + * commit: Commit the candidate datastore after the edit. + * request_type: LYD_FORMAT request type. + * flags: option flags for the request. + * operation: The operation to perform. + * xpath: The xpath of data node to edit. + * data: The data tree. + */ +extern int +mgmt_txn_send_edit(uint64_t txn_id, uint64_t req_id, Mgmtd__DatastoreId ds_id, + struct mgmt_ds_ctx *ds_ctx, Mgmtd__DatastoreId commit_ds_id, + struct mgmt_ds_ctx *commit_ds_ctx, bool unlock, bool commit, + LYD_FORMAT request_type, uint8_t flags, uint8_t operation, + const char *xpath, const char *data); + +/** + * Send RPC request. + * + * Args: + * txn_id: Transaction identifier. + * req_id: FE client request identifier. + * clients: Bitmask of clients to send RPC to. + * result_type: LYD_FORMAT result format. + * xpath: The xpath of the RPC. + * data: The input parameters data tree. + * data_len: The length of the input parameters data. + * + * Return: + * 0 on success. + */ +extern int mgmt_txn_send_rpc(uint64_t txn_id, uint64_t req_id, uint64_t clients, + LYD_FORMAT result_type, const char *xpath, + const char *data, size_t data_len); + /* * Notifiy backend adapter on connection. */ @@ -206,8 +287,8 @@ mgmt_txn_notify_be_txn_reply(uint64_t txn_id, bool create, bool success, * Reply to backend adapater with config data create request. */ extern int -mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, uint64_t batch_id, - bool success, char *error_if_any, +mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, bool success, + char *error_if_any, struct mgmt_be_client_adapter *adapter); /* @@ -223,10 +304,49 @@ extern int mgmt_txn_notify_be_cfg_validate_reply( */ extern int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success, - uint64_t batch_ids[], - size_t num_batch_ids, char *error_if_any, + char *error_if_any, struct mgmt_be_client_adapter *adapter); + +/** + * Process a reply from a backend client to our get-tree request + * + * Args: + * adapter: The adapter that received the result. + * txn_id: The transaction for this get-tree request. + * req_id: The request ID for this transaction. + * error: the integer error value (negative) + * errstr: the string description of the error. + */ +int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter, + uint64_t txn_id, uint64_t req_id, int error, + const char *errstr); + +/** + * Process a reply from a backend client to our get-tree request + * + * Args: + * adapter: The adapter that received the result. + * data_msg: The message from the backend. + * msg_len: Total length of the message. + */ + +extern int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter, + struct mgmt_msg_tree_data *data_msg, + size_t msg_len); + +/** + * Process a reply from a backend client to our RPC request + * + * Args: + * adapter: The adapter that received the result. + * reply_msg: The message from the backend. + * msg_len: Total length of the message. + */ +extern int mgmt_txn_notify_rpc_reply(struct mgmt_be_client_adapter *adapter, + struct mgmt_msg_rpc_reply *reply_msg, + size_t msg_len); + /* * Dump transaction status to vty. */ diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c index 44c6c0097ad6..8ccb463577d4 100644 --- a/mgmtd/mgmt_vty.c +++ b/mgmtd/mgmt_vty.c @@ -8,10 +8,14 @@ #include +#include "affinitymap.h" #include "command.h" +#include "filter.h" #include "json.h" +#include "keychain.h" #include "network.h" #include "northbound_cli.h" +#include "routemap.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_be_adapter.h" @@ -20,6 +24,10 @@ #include "mgmtd/mgmt_history.h" #include "mgmtd/mgmt_vty_clippy.c" +#include "ripd/rip_nb.h" +#include "ripngd/ripng_nb.h" +#include "staticd/static_vty.h" +#include "zebra/zebra_cli.h" extern struct frr_daemon_info *mgmt_daemon_info; @@ -144,6 +152,23 @@ DEFPY(mgmt_commit, return CMD_SUCCESS; } +DEFPY(mgmt_create_config_data, mgmt_create_config_data_cmd, + "mgmt create-config WORD$path VALUE", + MGMTD_STR + "Create configuration data\n" + "XPath expression specifying the YANG data path\n" + "Value of the data to create\n") +{ + strlcpy(vty->cfg_changes[0].xpath, path, + sizeof(vty->cfg_changes[0].xpath)); + vty->cfg_changes[0].value = value; + vty->cfg_changes[0].operation = NB_OP_CREATE_EXCL; + vty->num_cfg_changes = 1; + + vty_mgmt_send_config_data(vty, NULL, false); + return CMD_SUCCESS; +} + DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd, "mgmt set-config WORD$path VALUE", MGMTD_STR @@ -154,10 +179,10 @@ DEFPY(mgmt_set_config_data, mgmt_set_config_data_cmd, strlcpy(vty->cfg_changes[0].xpath, path, sizeof(vty->cfg_changes[0].xpath)); vty->cfg_changes[0].value = value; - vty->cfg_changes[0].operation = NB_OP_CREATE; + vty->cfg_changes[0].operation = NB_OP_MODIFY; vty->num_cfg_changes = 1; - vty_mgmt_send_config_data(vty, false); + vty_mgmt_send_config_data(vty, NULL, false); return CMD_SUCCESS; } @@ -168,13 +193,121 @@ DEFPY(mgmt_delete_config_data, mgmt_delete_config_data_cmd, "XPath expression specifying the YANG data path\n") { + strlcpy(vty->cfg_changes[0].xpath, path, + sizeof(vty->cfg_changes[0].xpath)); + vty->cfg_changes[0].value = NULL; + vty->cfg_changes[0].operation = NB_OP_DELETE; + vty->num_cfg_changes = 1; + + vty_mgmt_send_config_data(vty, NULL, false); + return CMD_SUCCESS; +} + +DEFPY(mgmt_remove_config_data, mgmt_remove_config_data_cmd, + "mgmt remove-config WORD$path", + MGMTD_STR + "Remove configuration data\n" + "XPath expression specifying the YANG data path\n") +{ + strlcpy(vty->cfg_changes[0].xpath, path, sizeof(vty->cfg_changes[0].xpath)); vty->cfg_changes[0].value = NULL; vty->cfg_changes[0].operation = NB_OP_DESTROY; vty->num_cfg_changes = 1; - vty_mgmt_send_config_data(vty, false); + vty_mgmt_send_config_data(vty, NULL, false); + return CMD_SUCCESS; +} + +DEFPY(mgmt_replace_config_data, mgmt_replace_config_data_cmd, + "mgmt replace-config WORD$path VALUE", + MGMTD_STR + "Replace configuration data\n" + "XPath expression specifying the YANG data path\n" + "Value of the data to set\n") +{ + + strlcpy(vty->cfg_changes[0].xpath, path, + sizeof(vty->cfg_changes[0].xpath)); + vty->cfg_changes[0].value = value; + vty->cfg_changes[0].operation = NB_OP_REPLACE; + vty->num_cfg_changes = 1; + + vty_mgmt_send_config_data(vty, NULL, false); + return CMD_SUCCESS; +} + +DEFPY(mgmt_edit, mgmt_edit_cmd, + "mgmt edit {create|delete|merge|replace|remove}$op XPATH [json|xml]$fmt [lock$lock] [commit$commit] [DATA]", + MGMTD_STR + "Edit configuration data\n" + "Create data\n" + "Delete data\n" + "Merge data\n" + "Replace data\n" + "Remove data\n" + "XPath expression specifying the YANG data path\n" + "JSON input format (default)\n" + "XML input format\n" + "Lock the datastores automatically\n" + "Commit the changes automatically\n" + "Data tree\n") +{ + LYD_FORMAT format = (fmt && fmt[0] == 'x') ? LYD_XML : LYD_JSON; + uint8_t operation; + uint8_t flags = 0; + + switch (op[2]) { + case 'e': + operation = NB_OP_CREATE_EXCL; + break; + case 'l': + operation = NB_OP_DELETE; + break; + case 'r': + operation = NB_OP_MODIFY; + break; + case 'p': + operation = NB_OP_REPLACE; + break; + case 'm': + operation = NB_OP_DESTROY; + break; + default: + vty_out(vty, "Invalid operation!\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (!data && (operation == NB_OP_CREATE_EXCL || + operation == NB_OP_MODIFY || operation == NB_OP_REPLACE)) { + vty_out(vty, "Data tree is missing!\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (lock) + flags |= EDIT_FLAG_IMPLICIT_LOCK; + + if (commit) + flags |= EDIT_FLAG_IMPLICIT_COMMIT; + + vty_mgmt_send_edit_req(vty, MGMT_MSG_DATASTORE_CANDIDATE, format, flags, + operation, xpath, data); + return CMD_SUCCESS; +} + +DEFPY(mgmt_rpc, mgmt_rpc_cmd, + "mgmt rpc XPATH [json|xml]$fmt [DATA]", + MGMTD_STR + "Invoke RPC\n" + "XPath expression specifying the YANG data path\n" + "JSON input format (default)\n" + "XML input format\n" + "Input data tree\n") +{ + LYD_FORMAT format = (fmt && fmt[0] == 'x') ? LYD_XML : LYD_JSON; + + vty_mgmt_send_rpc_req(vty, format, xpath, data); return CMD_SUCCESS; } @@ -199,22 +332,69 @@ DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd, } DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd, - "show mgmt get-data [candidate|operational|running]$dsname WORD$path", - SHOW_STR MGMTD_STR - "Get data from a specific datastore\n" + "show mgmt get-data WORD$path [datastore $ds] [with-config|only-config]$content [exact]$exact [with-defaults $wd] [json|xml]$fmt", + SHOW_STR + MGMTD_STR + "Get a data from the operational datastore\n" + "XPath expression specifying the YANG data root\n" + "Specify datastore to get data from (operational by default)\n" "Candidate datastore\n" - "Operational datastore (default)\n" "Running datastore\n" - "XPath expression specifying the YANG data path\n") + "Operational datastore\n" + "Include \"config true\" data\n" + "Get only \"config true\" data\n" + "Get exact node instead of the whole data tree\n" + "Configure 'with-defaults' mode per RFC 6243 (\"explicit\" mode by default)\n" + "Use \"trim\" mode\n" + "Use \"report-all-tagged\" mode\n" + "Use \"report-all\" mode\n" + "JSON output format\n" + "XML output format\n") { - const char *xpath_list[VTY_MAXCFGCHANGES] = {0}; - Mgmtd__DatastoreId datastore = MGMTD_DS_OPERATIONAL; + LYD_FORMAT format = (fmt && fmt[0] == 'x') ? LYD_XML : LYD_JSON; + int plen = strlen(path); + char *xpath = NULL; + uint8_t flags = content ? GET_DATA_FLAG_CONFIG : GET_DATA_FLAG_STATE; + uint8_t defaults = GET_DATA_DEFAULTS_EXPLICIT; + uint8_t datastore = MGMT_MSG_DATASTORE_OPERATIONAL; + + if (content && content[0] == 'w') + flags |= GET_DATA_FLAG_STATE; + + if (exact) + flags |= GET_DATA_FLAG_EXACT; + + if (wd) { + if (wd[0] == 't') + defaults = GET_DATA_DEFAULTS_TRIM; + else if (wd[3] == '-') + defaults = GET_DATA_DEFAULTS_ALL_ADD_TAG; + else + defaults = GET_DATA_DEFAULTS_ALL; + } - if (dsname) - datastore = mgmt_ds_name2id(dsname); + if (ds) { + if (ds[0] == 'c') + datastore = MGMT_MSG_DATASTORE_CANDIDATE; + else if (ds[0] == 'r') + datastore = MGMT_MSG_DATASTORE_RUNNING; + } + + /* get rid of extraneous trailing slash-* or single '/' unless root */ + if (plen > 2 && ((path[plen - 2] == '/' && path[plen - 1] == '*') || + (path[plen - 2] != '/' && path[plen - 1] == '/'))) { + plen = path[plen - 1] == '/' ? plen - 1 : plen - 2; + xpath = XSTRDUP(MTYPE_TMP, path); + xpath[plen] = 0; + path = xpath; + } + + vty_mgmt_send_get_data_req(vty, datastore, format, flags, defaults, + path); + + if (xpath) + XFREE(MTYPE_TMP, xpath); - xpath_list[0] = path; - vty_mgmt_send_get_req(vty, false, datastore, xpath_list, 1); return CMD_SUCCESS; } @@ -239,7 +419,7 @@ DEFPY(show_mgmt_dump_data, LYD_FORMAT format = fmt[0] == 'j' ? LYD_JSON : LYD_XML; FILE *f = NULL; - if (datastore) + if (dsname) datastore = mgmt_ds_name2id(dsname); ds_ctx = mgmt_ds_get_ctx_by_id(mm, datastore); @@ -273,7 +453,7 @@ DEFPY(show_mgmt_map_xpath, "Get YANG Backend Subscription\n" "XPath expression specifying the YANG data path\n") { - mgmt_be_xpath_subscr_info_write(vty, path); + mgmt_be_show_xpath_registries(vty, path); return CMD_SUCCESS; } @@ -379,7 +559,7 @@ DEFPY(mgmt_rollback, int config_write_mgmt_debug(struct vty *vty); static struct cmd_node debug_node = { - .name = "debug", + .name = "mgmt debug", .node = DEBUG_NODE, .prompt = "", .config_write = config_write_mgmt_debug, @@ -438,12 +618,18 @@ DEFPY(debug_mgmt, debug_mgmt_cmd, { uint32_t mode = DEBUG_NODE2MODE(vty->node); - if (be) + if (be) { DEBUG_MODE_SET(&mgmt_debug_be, mode, !no); + mgmt_be_adapter_toggle_client_debug( + DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL)); + } if (ds) DEBUG_MODE_SET(&mgmt_debug_ds, mode, !no); - if (fe) + if (fe) { DEBUG_MODE_SET(&mgmt_debug_fe, mode, !no); + mgmt_fe_adapter_toggle_client_debug( + DEBUG_MODE_CHECK(&mgmt_debug_fe, DEBUG_MODE_ALL)); + } if (txn) DEBUG_MODE_SET(&mgmt_debug_txn, mode, !no); @@ -452,19 +638,58 @@ DEFPY(debug_mgmt, debug_mgmt_cmd, static void mgmt_config_read_in(struct event *event) { - mgmt_vty_read_configs(); + if (vty_mgmt_fe_enabled()) + mgmt_vty_read_configs(); + else { + zlog_warn("%s: no connection to front-end server, retry in 1s", + __func__); + event_add_timer(mm->master, mgmt_config_read_in, NULL, 1, + &mgmt_daemon_info->read_in); + } } +static int mgmtd_config_write(struct vty *vty) +{ + struct lyd_node *root; + + LY_LIST_FOR (running_config->dnode, root) { + nb_cli_show_dnode_cmds(vty, root, false); + } + + return 1; +} + +static struct cmd_node mgmtd_node = { + .name = "mgmtd", + .node = MGMTD_NODE, + .prompt = "", + .config_write = mgmtd_config_write, +}; + void mgmt_vty_init(void) { + /* + * Library based CLI handlers + */ + filter_cli_init(); + route_map_cli_init(); + affinity_map_init(); + keychain_cli_init(); + /* * Initialize command handling from VTYSH connection. * Call command initialization routines defined by * backend components that are moved to new MGMTD infra * here one by one. */ -#if HAVE_STATICD - extern void static_vty_init(void); + zebra_cli_init(); +#ifdef HAVE_RIPD + rip_cli_init(); +#endif +#ifdef HAVE_RIPNGD + ripng_cli_init(); +#endif +#ifdef HAVE_STATICD static_vty_init(); #endif @@ -472,6 +697,7 @@ void mgmt_vty_init(void) &mgmt_daemon_info->read_in); install_node(&debug_node); + install_node(&mgmtd_node); install_element(VIEW_NODE, &show_mgmt_be_adapter_cmd); install_element(VIEW_NODE, &show_mgmt_be_xpath_reg_cmd); @@ -485,8 +711,13 @@ void mgmt_vty_init(void) install_element(VIEW_NODE, &show_mgmt_cmt_hist_cmd); install_element(CONFIG_NODE, &mgmt_commit_cmd); + install_element(CONFIG_NODE, &mgmt_create_config_data_cmd); install_element(CONFIG_NODE, &mgmt_set_config_data_cmd); install_element(CONFIG_NODE, &mgmt_delete_config_data_cmd); + install_element(CONFIG_NODE, &mgmt_remove_config_data_cmd); + install_element(CONFIG_NODE, &mgmt_replace_config_data_cmd); + install_element(CONFIG_NODE, &mgmt_edit_cmd); + install_element(CONFIG_NODE, &mgmt_rpc_cmd); install_element(CONFIG_NODE, &mgmt_load_config_cmd); install_element(CONFIG_NODE, &mgmt_save_config_cmd); install_element(CONFIG_NODE, &mgmt_rollback_cmd); diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am index 67b45d5bd9bb..14544c4f0507 100644 --- a/mgmtd/subdir.am +++ b/mgmtd/subdir.am @@ -15,6 +15,10 @@ clippy_scan += \ # end lib_LTLIBRARIES += mgmtd/libmgmt_be_nb.la +mgmtd_libmgmt_be_nb_la_SOURCES = \ + mgmtd/mgmt_be_nb.c \ + zebra/zebra_cli.c \ + # end nodist_mgmtd_libmgmt_be_nb_la_SOURCES = \ # end mgmtd_libmgmt_be_nb_la_CFLAGS = $(AM_CFLAGS) -DINCLUDE_MGMTD_CMDDEFS_ONLY @@ -33,11 +37,6 @@ mgmtd_libmgmtd_a_SOURCES = \ mgmtd/mgmt_vty.c \ # end -mgmtdheaderdir = $(pkgincludedir)/mgmtd -mgmtdheader_HEADERS = \ - mgmtd/mgmt_defines.h \ - # end - noinst_HEADERS += \ mgmtd/mgmt.h \ mgmtd/mgmt_be_adapter.h \ @@ -46,23 +45,63 @@ noinst_HEADERS += \ mgmtd/mgmt_history.h \ mgmtd/mgmt_memory.h \ mgmtd/mgmt_txn.h \ + zebra/zebra_cli.h \ # end sbin_PROGRAMS += mgmtd/mgmtd +if MGMTD_TESTC +sbin_PROGRAMS += mgmtd/mgmtd_testc +mgmtd_mgmtd_testc_SOURCES = mgmtd/mgmt_testc.c +mgmtd_mgmtd_testc_LDADD = lib/libfrr.la +endif + mgmtd_mgmtd_SOURCES = \ mgmtd/mgmt_main.c \ # end nodist_mgmtd_mgmtd_SOURCES = \ + yang/frr-zebra.yang.c \ + yang/frr-zebra-route-map.yang.c \ + yang/ietf/ietf-netconf.yang.c \ + yang/ietf/ietf-netconf-with-defaults.yang.c \ # nothing mgmtd_mgmtd_CFLAGS = $(AM_CFLAGS) -I ./ mgmtd_mgmtd_LDADD = mgmtd/libmgmtd.a lib/libfrr.la $(LIBCAP) $(LIBM) $(LIBYANG_LIBS) $(UST_LIBS) mgmtd_mgmtd_LDADD += mgmtd/libmgmt_be_nb.la + +if STATICD +nodist_mgmtd_mgmtd_SOURCES += yang/frr-bfdd.yang.c +else +if RIPD +nodist_mgmtd_mgmtd_SOURCES += yang/frr-bfdd.yang.c +endif +endif + +if RIPD +nodist_mgmtd_mgmtd_SOURCES += \ + yang/frr-ripd.yang.c \ + # end +mgmtd_libmgmt_be_nb_la_SOURCES += \ + ripd/rip_cli.c \ + # end +endif + +if RIPNGD +nodist_mgmtd_mgmtd_SOURCES += \ + yang/frr-ripngd.yang.c \ + # end +mgmtd_libmgmt_be_nb_la_SOURCES += \ + ripngd/ripng_cli.c \ + # end +endif + if STATICD nodist_mgmtd_mgmtd_SOURCES += \ yang/frr-staticd.yang.c \ - yang/frr-bfdd.yang.c \ # end -nodist_mgmtd_libmgmt_be_nb_la_SOURCES += staticd/static_vty.c +nodist_mgmtd_libmgmt_be_nb_la_SOURCES += \ + staticd/static_vty.c \ + # end endif + diff --git a/mlag/mlag_pb.c b/mlag/mlag_pb.c new file mode 100644 index 000000000000..01c4f0b319ee --- /dev/null +++ b/mlag/mlag_pb.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: ISC +/* + * libmlag_pb library stub + */ + +#include "config.h" +#include "xref.h" + +XREF_SETUP(); diff --git a/mlag/subdir.am b/mlag/subdir.am index 376eea8bc9b5..aa30d33431e6 100644 --- a/mlag/subdir.am +++ b/mlag/subdir.am @@ -5,6 +5,7 @@ endif mlag_libmlag_pb_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 mlag_libmlag_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(PROTOBUF_C_CFLAGS) mlag_libmlag_pb_la_SOURCES = \ + mlag/mlag_pb.c \ # end nodist_mlag_libmlag_pb_la_SOURCES = \ diff --git a/nhrpd/debug.h b/nhrpd/debug.h index f2c7022ad409..d5c00ada8ee6 100644 --- a/nhrpd/debug.h +++ b/nhrpd/debug.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #include "log.h" #define NHRP_DEBUG_COMMON (1 << 0) diff --git a/nhrpd/linux.c b/nhrpd/linux.c index eb98166872c6..e4df0dd9640d 100644 --- a/nhrpd/linux.c +++ b/nhrpd/linux.c @@ -5,6 +5,7 @@ #include "zebra.h" +#include #include #include @@ -96,25 +97,6 @@ int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, return 0; } -static int linux_configure_arp(const char *iface, int on) -{ - struct ifreq ifr; - - strlcpy(ifr.ifr_name, iface, IFNAMSIZ); - if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr)) - return -1; - - if (on) - ifr.ifr_flags &= ~IFF_NOARP; - else - ifr.ifr_flags |= IFF_NOARP; - - if (ioctl(nhrp_socket_fd, SIOCSIFFLAGS, &ifr)) - return -1; - - return 0; -} - static int linux_icmp_redirect_off(const char *iface) { char fname[PATH_MAX]; @@ -142,7 +124,6 @@ int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af) ret |= linux_icmp_redirect_off(ifname); break; } - ret |= linux_configure_arp(ifname, 1); return ret; } diff --git a/nhrpd/netlink.h b/nhrpd/netlink.h index 7a3029b6c133..33af1a02c1f6 100644 --- a/nhrpd/netlink.h +++ b/nhrpd/netlink.h @@ -11,7 +11,6 @@ extern int netlink_nflog_group; extern int netlink_mcast_nflog_group; -int netlink_configure_arp(unsigned int ifindex, int pf); void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma); void netlink_set_nflog_group(int nlgroup); diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index 2e22f8e247a7..be909c862ae0 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -7,6 +7,10 @@ #include "config.h" #endif +#ifdef GNU_LINUX +#include +#endif + #include #include #include @@ -150,6 +154,10 @@ int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) struct zapi_neigh_ip api = {}; zclient_neigh_ip_decode(zclient->ibuf, &api); + + if (api.ip_len != IPV4_MAX_BYTELEN && api.ip_len != 0) + return 0; + if (api.ip_in.ipa_type == AF_UNSPEC) return 0; sockunion_family(&addr) = api.ip_in.ipa_type; @@ -172,26 +180,30 @@ int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) return 0; debugf(NHRP_DEBUG_KERNEL, "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u", - (cmd == ZEBRA_NHRP_NEIGH_GET) - ? "who-has" - : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh" - : "del-neigh", + (cmd == ZEBRA_NEIGH_GET) ? "who-has" + : (cmd == ZEBRA_NEIGH_ADDED) ? "new-neigh" + : "del-neigh", &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type); - if (cmd == ZEBRA_NHRP_NEIGH_GET) { + if (cmd == ZEBRA_NEIGH_GET) { if (c->cur.type >= NHRP_CACHE_CACHED) { nhrp_cache_set_used(c, 1); debugf(NHRP_DEBUG_KERNEL, "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU", &addr, ifp->name, &c->cur.remote_nbma_natoa, &c->cur.peer->vc->remote.nbma, &lladdr); + + if (lladdr.sa.sa_family == AF_UNSPEC) + /* nothing from zebra, so use nhrp peer */ + lladdr = c->cur.peer->vc->remote.nbma; + /* In case of shortcuts, nbma is given by lladdr, not * vc->remote.nbma. */ netlink_update_binding(ifp, &addr, &lladdr); } } else { - state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state - : ZEBRA_NEIGH_STATE_FAILED; + state = (cmd == ZEBRA_NEIGH_ADDED) ? ndm_state + : ZEBRA_NEIGH_STATE_FAILED; nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE); } return 0; diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index 1a11e0d98ba7..e0b8f7bf8888 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -70,6 +70,8 @@ static void nhrp_cache_free(struct nhrp_cache *c) notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE); assert(!notifier_active(&c->notifier_list)); hash_release(nifp->cache_hash, c); + if (c->cur.peer) + nhrp_peer_notify_del(c->cur.peer, &c->peer_notifier); nhrp_peer_unref(c->cur.peer); nhrp_peer_unref(c->new.peer); EVENT_OFF(c->t_timeout); diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 7c84fde3675b..e81a2efbb685 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -99,6 +99,8 @@ static int nhrp_if_delete_hook(struct interface *ifp) free(nifp->ipsec_fallback_profile); if (nifp->source) free(nifp->source); + if (nifp->auth_token) + zbuf_free(nifp->auth_token); XFREE(MTYPE_NHRP_IF, ifp->info); return 0; @@ -259,13 +261,12 @@ static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, struct nhrp_afi_data *if_ad = &nifp->afi[afi]; struct nhrp_cache *nc; struct connected *c, *best; - struct listnode *cnode; union sockunion addr; char buf[PREFIX_STRLEN]; /* Select new best match preferring primary address */ best = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (PREFIX_FAMILY(c->address) != family) continue; if (best == NULL) { @@ -352,6 +353,7 @@ void nhrp_interface_update(struct interface *ifp) if (!if_ad->configured) { os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi)); + nhrp_interface_update_arp(ifp, true); nhrp_send_zebra_configure_arp(ifp, afi2family(afi)); if_ad->configured = 1; nhrp_interface_update_address(ifp, afi, 1); diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 593498ca1347..adb8be36d303 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -88,10 +88,12 @@ static void nhrp_request_stop(void) nhrp_zebra_terminate(); vici_terminate(); evmgr_terminate(); - nhrp_vc_terminate(); vrf_terminate(); + nhrp_vc_terminate(); debugf(NHRP_DEBUG_COMMON, "Done."); + + resolver_terminate(); frr_fini(); exit(0); @@ -118,15 +120,20 @@ static const struct frr_yang_module_info *const nhrpd_yang_modules[] = { &frr_vrf_info, }; -FRR_DAEMON_INFO(nhrpd, NHRP, .vty_port = NHRP_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(nhrpd, NHRP, + .vty_port = NHRP_VTY_PORT, + .proghelp = "Implementation of the NHRP routing protocol.", - .proghelp = "Implementation of the NHRP routing protocol.", + .signals = sighandlers, + .n_signals = array_size(sighandlers), - .signals = sighandlers, .n_signals = array_size(sighandlers), + .privs = &nhrpd_privs, - .privs = &nhrpd_privs, .yang_modules = nhrpd_yang_modules, - .n_yang_modules = array_size(nhrpd_yang_modules), + .yang_modules = nhrpd_yang_modules, + .n_yang_modules = array_size(nhrpd_yang_modules), ); +/* clang-format on */ int main(int argc, char **argv) { @@ -155,8 +162,10 @@ int main(int argc, char **argv) nhrp_vc_init(); nhrp_packet_init(); vici_init(); - if_zapi_callbacks(nhrp_ifp_create, nhrp_ifp_up, - nhrp_ifp_down, nhrp_ifp_destroy); + hook_register_prio(if_real, 0, nhrp_ifp_create); + hook_register_prio(if_up, 0, nhrp_ifp_up); + hook_register_prio(if_down, 0, nhrp_ifp_down); + hook_register_prio(if_unreal, 0, nhrp_ifp_destroy); nhrp_zebra_init(); nhrp_shortcut_init(); diff --git a/nhrpd/nhrp_multicast.c b/nhrpd/nhrp_multicast.c index fdc1a31f2519..aead982842a1 100644 --- a/nhrpd/nhrp_multicast.c +++ b/nhrpd/nhrp_multicast.c @@ -7,6 +7,10 @@ #include "config.h" #endif +#ifdef GNU_LINUX +#include +#endif + #include #include #include diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index acd3b7df97f6..b8958ba22595 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -169,9 +169,15 @@ static void nhrp_reg_send_req(struct event *t) struct nhrp_cie_header *cie; if (!nhrp_peer_check(r->peer, 2)) { - debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %pSU", - &r->peer->vc->remote.nbma); - event_add_timer(master, nhrp_reg_send_req, r, 120, + int renewtime = if_ad->holdtime / 4; + /* RFC 2332 5.2.0.1 says "a retry is sent after an appropriate + * interval." Using holdtime/4, to be shorter than + * recommended renew time (holdtime/3), see RFC2332 Sec 5.2.3 + */ + debugf(NHRP_DEBUG_COMMON, + "NHS: Waiting link for %pSU, retrying in %d seconds", + &r->peer->vc->remote.nbma, renewtime); + event_add_timer(master, nhrp_reg_send_req, r, renewtime, &r->t_register); return; } @@ -210,7 +216,7 @@ static void nhrp_reg_send_req(struct event *t) cie->holding_time = htons(if_ad->holdtime); cie->mtu = htons(if_ad->mtu); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ if (sockunion_family(&r->proto_addr) != AF_UNSPEC) { @@ -234,7 +240,7 @@ static void nhrp_reg_send_req(struct event *t) cie->mtu = htons(if_ad->mtu); nhrp_ext_complete(zb, ext); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(r->peer, zb); zbuf_free(zb); } diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index 9d0b30cfeea2..71f5c2f00797 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -115,14 +115,32 @@ uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len) return (~csum) & 0xffff; } -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr) +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp) { + nhrp_packet_complete_auth(zb, hdr, ifp, true); +} + +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth) +{ + struct nhrp_interface *nifp = ifp->info; + struct zbuf *auth_token = nifp->auth_token; + struct nhrp_extension_header *dst; unsigned short size; + if (auth && auth_token) { + dst = nhrp_ext_push(zb, hdr, + NHRP_EXTENSION_AUTHENTICATION | + NHRP_EXTENSION_FLAG_COMPULSORY); + zbuf_copy_peek(zb, auth_token, zbuf_size(auth_token)); + nhrp_ext_complete(zb, dst); + } + if (hdr->extension_offset) nhrp_ext_push(zb, hdr, - NHRP_EXTENSION_END - | NHRP_EXTENSION_FLAG_COMPULSORY); + NHRP_EXTENSION_END | + NHRP_EXTENSION_FLAG_COMPULSORY); size = zb->tail - (uint8_t *)hdr; hdr->packet_size = htons(size); @@ -225,8 +243,7 @@ struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, return ext; } -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *ifp) +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr) { /* Place holders for standard extensions */ nhrp_ext_push(zb, hdr, @@ -270,7 +287,7 @@ int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, default: if (type & NHRP_EXTENSION_FLAG_COMPULSORY) goto err; - /* fallthru */ + fallthrough; case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: case NHRP_EXTENSION_REVERSE_TRANSIT_NHS: /* Supported compulsory extensions, and any diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index ffb6cf750643..3495317d4cb6 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -45,7 +45,8 @@ static void nhrp_peer_check_delete(struct nhrp_peer *p) EVENT_OFF(p->t_fallback); EVENT_OFF(p->t_timer); - hash_release(nifp->peer_hash, p); + if (nifp->peer_hash) + hash_release(nifp->peer_hash, p); nhrp_interface_notify_del(p->ifp, &p->ifp_notifier); nhrp_vc_notify_del(p->vc, &p->vc_notifier); XFREE(MTYPE_NHRP_PEER, p); @@ -139,7 +140,7 @@ static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd) nhrp_peer_vc_notify); __nhrp_peer_check(p); } - /* fallthru */ /* to post config update */ + fallthrough; /* to post config update */ case NOTIFY_INTERFACE_ADDRESS_CHANGED: notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED); break; @@ -602,7 +603,7 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) break; } } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); err: nhrp_peer_unref(peer); @@ -729,7 +730,8 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) } } - nhrp_packet_complete(zb, hdr); + /* auth ext was validated and copied from the request */ + nhrp_packet_complete_auth(zb, hdr, ifp, false); nhrp_peer_send(p->peer, zb); err: zbuf_free(zb); @@ -811,7 +813,7 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, /* Payload is the packet causing indication */ zbuf_copy(zb, pkt, zbuf_used(pkt)); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(p, zb); nhrp_peer_unref(p); zbuf_free(zb); @@ -957,9 +959,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, if (type == NHRP_EXTENSION_END) break; - dst = nhrp_ext_push(zb, hdr, htons(ext->type)); - if (!dst) - goto err; + dst = NULL; + if (type != NHRP_EXTENSION_AUTHENTICATION) { + dst = nhrp_ext_push(zb, hdr, htons(ext->type)); + if (!dst) + goto err; + } switch (type) { case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: @@ -1044,13 +1049,19 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_put(zb, extpl.head, len); } break; + case NHRP_EXTENSION_AUTHENTICATION: + /* Extensions can be copied from original packet except + * authentication extension which must be regenerated + * hop by hop. + */ + break; default: if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not * append our selves to the transit NHS list */ goto err; - /* fallthru */ + fallthrough; case NHRP_EXTENSION_RESPONDER_ADDRESS: /* Supported compulsory extensions, and any * non-compulsory that is not explicitly handled, @@ -1059,10 +1070,11 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_copy(zb, &extpl, len); break; } - nhrp_ext_complete(zb, dst); + if (dst) + nhrp_ext_complete(zb, dst); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, true); nhrp_peer_send(p, zb); zbuf_free(zb); zbuf_free(zb_copy); @@ -1088,8 +1100,7 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir) reply = packet_types[hdr->type].type == PACKET_REPLY; debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %pSU -> %pSU", dir, - (packet_types[hdr->type].name ? packet_types[hdr->type].name - : "Unknown"), + (packet_types[hdr->type].name ? : "Unknown"), hdr->type, reply ? &dst_proto : &src_proto, reply ? &src_proto : &dst_proto); } @@ -1105,11 +1116,78 @@ static int proto2afi(uint16_t proto) return AF_UNSPEC; } -struct nhrp_route_info { - int local; - struct interface *ifp; - struct nhrp_vc *vc; -}; +static int nhrp_packet_send_error(struct nhrp_packet_parser *pp, + uint16_t indication_code, uint16_t offset) +{ + union sockunion src_proto, dst_proto; + struct nhrp_packet_header *hdr; + struct zbuf *zb; + + src_proto = pp->src_proto; + dst_proto = pp->dst_proto; + if (packet_types[pp->hdr->type].type != PACKET_REPLY) { + src_proto = pp->dst_proto; + dst_proto = pp->src_proto; + } + /* Create reply */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_ERROR_INDICATION, &pp->src_nbma, + &src_proto, &dst_proto); + + hdr->u.error.code = htons(indication_code); + hdr->u.error.offset = htons(offset); + hdr->flags = pp->hdr->flags; + hdr->hop_count = 0; /* XXX: cisco returns 255 */ + + /* Payload is the packet causing error */ + /* Don`t add extension according to RFC */ + zbuf_put(zb, pp->hdr, sizeof(*pp->hdr)); + zbuf_put(zb, sockunion_get_addr(&pp->src_nbma), + hdr->src_nbma_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->src_proto), + hdr->src_protocol_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->dst_proto), + hdr->dst_protocol_address_len); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); + + nhrp_peer_send(pp->peer, zb); + zbuf_free(zb); + return 0; +} + +static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp) +{ + struct nhrp_cisco_authentication_extension *auth_ext; + struct nhrp_interface *nifp = pp->ifp->info; + struct zbuf *auth = nifp->auth_token; + struct nhrp_extension_header *ext; + struct zbuf *extensions, pl; + int cmp = 1; + + extensions = zbuf_alloc(zbuf_used(&pp->extensions)); + zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions)); + while ((ext = nhrp_ext_pull(extensions, &pl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_AUTHENTICATION: + cmp = memcmp(auth->buf, pl.buf, zbuf_size(auth)); + auth_ext = (struct nhrp_cisco_authentication_extension *) + auth->buf; + debugf(NHRP_DEBUG_COMMON, + "Processing Authentication Extension for (%s:%s|%d)", + auth_ext->secret, + ((struct nhrp_cisco_authentication_extension *) + pl.buf) + ->secret, + cmp); + break; + default: + /* Ignoring all received extensions except Authentication*/ + break; + } + } + zbuf_free(extensions); + return cmp == 0; +} void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) { @@ -1190,10 +1268,20 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) goto drop; } + /* RFC2332 5.3.4 - Authentication is always done pairwise on an NHRP + * hop-by-hop basis; i.e. regenerated at each hop. */ nhrp_packet_debug(zb, "Recv"); - - /* FIXME: Check authentication here. This extension needs to be - * pre-handled. */ + if (nifp->auth_token && + (hdr->type != NHRP_PACKET_ERROR_INDICATION || + hdr->u.error.code != NHRP_ERROR_AUTHENTICATION_FAILURE)) { + if (!nhrp_connection_authorized(&pp)) { + nhrp_packet_send_error(&pp, + NHRP_ERROR_AUTHENTICATION_FAILURE, + 0); + info = "authentication failure"; + goto drop; + } + } /* Figure out if this is local */ target_addr = (packet_types[hdr->type].type == PACKET_REPLY) @@ -1220,7 +1308,7 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) /* FIXME: send error-indication */ } } - /* fallthru */ /* FIXME: double check, is this correct? */ + fallthrough; /* FIXME: double check, is this correct? */ case NHRP_ROUTE_OFF_NBMA: if (packet_types[hdr->type].handler) { packet_types[hdr->type].handler(&pp); diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 060e60314d73..fd9090bd6e74 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -75,24 +75,6 @@ static void nhrp_route_update_zebra(const struct prefix *p, } } -static void nhrp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg) -{ - struct stream *s; - - if (!zclient || zclient->sock < 0) - return; - - s = zclient->obuf; - stream_reset(s); - - zclient_create_header(s, reg ? ZEBRA_NHRP_NEIGH_REGISTER : - ZEBRA_NHRP_NEIGH_UNREGISTER, - vrf_id); - stream_putw(s, afi); - stream_putw_at(s, 0, stream_get_endp(s)); - zclient_send_message(zclient); -} - void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) { struct route_node *rn; @@ -368,8 +350,8 @@ static void nhrp_zebra_connected(struct zclient *zclient) ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT); - nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true); - nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true); + zclient_register_neigh(zclient, VRF_DEFAULT, AFI_IP, true); + zclient_register_neigh(zclient, VRF_DEFAULT, AFI_IP6, true); } static zclient_handler *const nhrp_handlers[] = { @@ -377,9 +359,9 @@ static zclient_handler *const nhrp_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_DELETE] = nhrp_interface_address_delete, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = nhrp_route_read, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = nhrp_route_read, - [ZEBRA_NHRP_NEIGH_ADDED] = nhrp_neighbor_operation, - [ZEBRA_NHRP_NEIGH_REMOVED] = nhrp_neighbor_operation, - [ZEBRA_NHRP_NEIGH_GET] = nhrp_neighbor_operation, + [ZEBRA_NEIGH_ADDED] = nhrp_neighbor_operation, + [ZEBRA_NEIGH_REMOVED] = nhrp_neighbor_operation, + [ZEBRA_NEIGH_GET] = nhrp_neighbor_operation, [ZEBRA_GRE_UPDATE] = nhrp_gre_update, }; @@ -456,10 +438,11 @@ void nhrp_send_zebra_nbr(union sockunion *in, return; s = zclient->obuf; stream_reset(s); - zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD : - ZEBRA_NEIGH_IP_DEL, in, out, - ifp, out ? ZEBRA_NEIGH_STATE_REACHABLE - : ZEBRA_NEIGH_STATE_FAILED); + zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD : ZEBRA_NEIGH_IP_DEL, + in, out, ifp, + out ? ZEBRA_NEIGH_STATE_REACHABLE + : ZEBRA_NEIGH_STATE_FAILED, + 0); stream_putw_at(s, 0, stream_get_endp(s)); zclient_send_message(zclient); } @@ -469,10 +452,16 @@ int nhrp_send_zebra_gre_request(struct interface *ifp) return zclient_send_zebra_gre_request(zclient, ifp); } +void nhrp_interface_update_arp(struct interface *ifp, bool arp_enable) +{ + zclient_interface_set_arp(zclient, ifp, arp_enable); +} + + void nhrp_zebra_terminate(void) { - nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false); - nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false); + zclient_register_neigh(zclient, VRF_DEFAULT, AFI_IP, false); + zclient_register_neigh(zclient, VRF_DEFAULT, AFI_IP6, false); zclient_stop(zclient); zclient_free(zclient); diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index 04dad2aea627..9b47d974c340 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -19,7 +19,8 @@ DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut"); static struct route_table *shortcut_rib[AFI_MAX]; static void nhrp_shortcut_do_purge(struct event *t); -static void nhrp_shortcut_delete(struct nhrp_shortcut *s); +static void nhrp_shortcut_delete(struct nhrp_shortcut *s, + void *arg __attribute__((__unused__))); static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s); static void nhrp_shortcut_check_use(struct nhrp_shortcut *s) @@ -72,7 +73,7 @@ static void nhrp_shortcut_cache_notify(struct notifier_block *n, s->route_installed = 0; } if (cmd == NOTIFY_CACHE_DELETE) - nhrp_shortcut_delete(s); + nhrp_shortcut_delete(s, NULL); break; } } @@ -132,7 +133,8 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, } } -static void nhrp_shortcut_delete(struct nhrp_shortcut *s) +static void nhrp_shortcut_delete(struct nhrp_shortcut *s, + void *arg __attribute__((__unused__))) { struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(s->p)); @@ -158,7 +160,7 @@ static void nhrp_shortcut_do_purge(struct event *t) { struct nhrp_shortcut *s = EVENT_ARG(t); s->t_timer = NULL; - nhrp_shortcut_delete(s); + nhrp_shortcut_delete(s, NULL); } static struct nhrp_shortcut *nhrp_shortcut_get(struct prefix *p) @@ -423,7 +425,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) "Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u", ntohs(cie->holding_time), ntohs(cie->mtu), s->holding_time); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); @@ -436,7 +438,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) nhrp_ext_complete(zb, ext); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); nhrp_peer_unref(peer); @@ -469,6 +471,8 @@ void nhrp_shortcut_init(void) void nhrp_shortcut_terminate(void) { + nhrp_shortcut_foreach(AFI_IP, nhrp_shortcut_delete, NULL); + nhrp_shortcut_foreach(AFI_IP6, nhrp_shortcut_delete, NULL); route_table_finish(shortcut_rib[AFI_IP]); route_table_finish(shortcut_rib[AFI_IP6]); } diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c index 2c3201438b83..6f3346c95c74 100644 --- a/nhrpd/nhrp_vc.c +++ b/nhrpd/nhrp_vc.c @@ -214,4 +214,5 @@ void nhrp_vc_terminate(void) { nhrp_vc_reset(); hash_clean(nhrp_vc_hash, nhrp_vc_free); + hash_free(nhrp_vc_hash); } diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 40d38c44d272..22b6bdcec739 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -12,6 +12,9 @@ #include "nhrpd.h" #include "netlink.h" +#include "nhrp_protocol.h" + +#include "nhrpd/nhrp_vty_clippy.c" static int nhrp_config_write(struct vty *vty); static struct cmd_node zebra_node = { @@ -459,6 +462,59 @@ DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd, return CMD_SUCCESS; } +#define NHRP_CISCO_PASS_LEN 8 +DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, + AFI_CMD "nhrp authentication PASSWORD$password", + AFI_STR + NHRP_STR + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_cisco_authentication_extension *auth; + struct nhrp_interface *nifp = ifp->info; + int pass_len = strlen(password); + + if (pass_len > NHRP_CISCO_PASS_LEN) { + vty_out(vty, "Password size limit exceeded (%d>%d)\n", + pass_len, NHRP_CISCO_PASS_LEN); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nifp->auth_token) { + zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } + + nifp->auth_token = zbuf_alloc(pass_len + sizeof(uint32_t)); + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + auth->type = htonl(NHRP_AUTHENTICATION_PLAINTEXT); + memcpy(auth->secret, password, pass_len); + + return CMD_SUCCESS; +} + + +DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd, + "no " AFI_CMD "nhrp authentication PASSWORD$password", + NO_STR + AFI_STR + NHRP_STR + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_interface *nifp = ifp->info; + + if (nifp->auth_token) { + zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } + return CMD_SUCCESS; +} + + DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd, "ip nhrp mtu <(576-1500)|opennhrp>", IP_STR @@ -1053,6 +1109,7 @@ DEFUN(show_dmvpn, show_dmvpn_cmd, static void clear_nhrp_cache(struct nhrp_cache *c, void *data) { struct info_ctx *ctx = data; + if (c->cur.type <= NHRP_CACHE_DYNAMIC) { nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, NULL); @@ -1129,6 +1186,7 @@ static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, static int interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct nhrp_cisco_authentication_extension *auth; struct write_map_ctx mapctx; struct interface *ifp; struct nhrp_interface *nifp; @@ -1155,6 +1213,12 @@ static int interface_config_write(struct vty *vty) if (nifp->source) vty_out(vty, " tunnel source %s\n", nifp->source); + if (nifp->auth_token) { + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + vty_out(vty, " ip nhrp authentication %s\n", auth->secret); + } + for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; @@ -1256,6 +1320,8 @@ void nhrp_config_init(void) install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd); install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd); + install_element(INTERFACE_NODE, &if_nhrp_authentication_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_authentication_cmd); install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_nhrp_flags_cmd); diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 1421f0fc387a..344e1d51780f 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -16,7 +16,6 @@ DECLARE_MGROUP(NHRPD); #define NHRPD_DEFAULT_HOLDTIME 7200 -#define NHRP_VTY_PORT 2610 #define NHRP_DEFAULT_CONFIG "nhrpd.conf" extern struct event_loop *master; @@ -312,6 +311,7 @@ DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry); struct nhrp_interface { struct interface *ifp; + struct zbuf *auth_token; unsigned enabled : 1; char *ipsec_profile, *ipsec_fallback_profile, *source; @@ -362,6 +362,7 @@ int sock_open_unix(const char *path); void nhrp_interface_init(void); void nhrp_interface_update(struct interface *ifp); +void nhrp_interface_update_arp(struct interface *ifp, bool arp_enable); void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi); void nhrp_interface_update_nbma(struct interface *ifp, struct nhrp_gre_info *gre_info); @@ -480,9 +481,13 @@ struct nhrp_packet_header *nhrp_packet_push(struct zbuf *zb, uint8_t type, const union sockunion *src_nbma, const union sockunion *src_proto, const union sockunion *dst_proto); -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr); uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len); +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp); +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth); + struct nhrp_packet_header *nhrp_packet_pull(struct zbuf *zb, union sockunion *src_nbma, union sockunion *src_proto, @@ -501,8 +506,7 @@ nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type); void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext); struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload); -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *); +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr); int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload); diff --git a/nhrpd/os.h b/nhrpd/os.h index 2b9e07fa6ef5..3f3b0de91230 100644 --- a/nhrpd/os.h +++ b/nhrpd/os.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later int os_socket(void); int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, diff --git a/nhrpd/reqid.c b/nhrpd/reqid.c index 738e935ec24c..c2f5d24b69b8 100644 --- a/nhrpd/reqid.c +++ b/nhrpd/reqid.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #include "zebra.h" #include "hash.h" #include "nhrpd.h" diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 227ff6c6787d..94fb3bb5bebe 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -42,3 +42,7 @@ noinst_HEADERS += \ nhrpd/zbuf.h \ nhrpd/znl.h \ # end + +clippy_scan += \ + nhrpd/nhrp_vty.c \ + # end diff --git a/nhrpd/vici.c b/nhrpd/vici.c index 2f76362603ce..8162ac06a6e4 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "frrevent.h" #include "zbuf.h" diff --git a/nhrpd/vici.h b/nhrpd/vici.h index f2ad3a9fe37d..8a8011f51044 100644 --- a/nhrpd/vici.h +++ b/nhrpd/vici.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later enum vici_type_t { VICI_START = 0, diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index f4202a4a29e7..0c5be29ff82c 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -553,9 +553,8 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, lsa_header = (struct ospf6_lsa_header *)buffer; if (route->type == OSPF6_DEST_TYPE_ROUTER) { - router_lsa = (struct ospf6_inter_router_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + router_lsa = (struct ospf6_inter_router_lsa *) + ospf6_lsa_header_end(lsa_header); p = (caddr_t)router_lsa + sizeof(struct ospf6_inter_router_lsa); /* Fill Inter-Area-Router-LSA */ @@ -566,9 +565,8 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, router_lsa->router_id = ADV_ROUTER_IN_PREFIX(&route->prefix); type = htons(OSPF6_LSTYPE_INTER_ROUTER); } else { - prefix_lsa = (struct ospf6_inter_prefix_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + ospf6_lsa_header_end(lsa_header); p = (caddr_t)prefix_lsa + sizeof(struct ospf6_inter_prefix_lsa); /* Fill Inter-Area-Prefix-LSA */ @@ -1018,9 +1016,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) oa->name); } - prefix_lsa = - (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + ospf6_lsa_header_end(lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa, @@ -1039,11 +1036,9 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) oa->name); } - router_lsa = - (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); - ospf6_linkstate_prefix(router_lsa->router_id, htonl(0), - &prefix); + router_lsa = (struct ospf6_inter_router_lsa *) + ospf6_lsa_header_end(lsa->header); + ospf6_linkstate_prefix(router_lsa->router_id, htonl(0), &prefix); if (is_debug) inet_ntop(AF_INET, &router_lsa->router_id, buf, sizeof(buf)); @@ -1275,8 +1270,6 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) continue; } - list_delete_all_node(old_route->nh_list); - ospf6_route_copy_nexthops(old_route, route); old_entry_updated = true; for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, @@ -1330,6 +1323,15 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) } } + /* We added a path or updated a path's nexthops above, + * recompute (old) route nexthops by merging all path nexthops + */ + list_delete_all_node(old_route->nh_list); + for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode, o_path)) { + ospf6_merge_nexthops(old_route->nh_list, + o_path->nh_list); + } + if (is_debug) zlog_debug( "%s: Update route: %s %p old cost %u new cost %u nh %u", @@ -1350,9 +1352,10 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) * does not match with the new entry then add the new route */ if (old_entry_updated == false) { - if ((old == NULL) || (old->type != route->type) - || (old->path.type != route->path.type) - || (old->path.cost != route->path.cost)) + if ((old == NULL) || (old->type != route->type) || + (old->path.type != route->path.type) || + (old->path.cost != route->path.cost) || + (old->path.router_bits != route->path.router_bits)) add_route = true; } @@ -1426,9 +1429,8 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, char tbuf[16]; if (lsa != NULL) { - prefix_lsa = - (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + ospf6_lsa_header_end(lsa->header); ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix); if (buf) { @@ -1450,7 +1452,7 @@ static int ospf6_inter_area_prefix_lsa_show(struct vty *vty, struct ospf6_inter_prefix_lsa *prefix_lsa; char buf[INET6_ADDRSTRLEN]; - prefix_lsa = (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END( + prefix_lsa = (struct ospf6_inter_prefix_lsa *)ospf6_lsa_header_end( lsa->header); if (use_json) { @@ -1487,9 +1489,8 @@ static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa *lsa, struct ospf6_inter_router_lsa *router_lsa; if (lsa != NULL) { - router_lsa = - (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); + router_lsa = (struct ospf6_inter_router_lsa *) + ospf6_lsa_header_end(lsa->header); if (buf) @@ -1507,7 +1508,7 @@ static int ospf6_inter_area_router_lsa_show(struct vty *vty, struct ospf6_inter_router_lsa *router_lsa; char buf[64]; - router_lsa = (struct ospf6_inter_router_lsa *)OSPF6_LSA_HEADER_END( + router_lsa = (struct ospf6_inter_router_lsa *)ospf6_lsa_header_end( lsa->header); ospf6_options_printbuf(router_lsa->options, buf, sizeof(buf)); diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h index 7bb1619133c2..52686ed49fd1 100644 --- a/ospf6d/ospf6_abr.h +++ b/ospf6d/ospf6_abr.h @@ -33,11 +33,12 @@ struct ospf6_inter_router_lsa { uint32_t router_id; }; -#define OSPF6_ABR_SUMMARY_METRIC(E) (ntohl ((E)->metric & htonl (0x00ffffff))) +#define OSPF6_ABR_SUMMARY_METRIC(E) \ + (ntohl((E)->metric & htonl(OSPF6_EXT_PATH_METRIC_MAX))) #define OSPF6_ABR_SUMMARY_METRIC_SET(E, C) \ { \ (E)->metric &= htonl(0x00000000); \ - (E)->metric |= htonl(0x00ffffff) & htonl(C); \ + (E)->metric |= htonl(OSPF6_EXT_PATH_METRIC_MAX) & htonl(C); \ } #define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC) diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 69c711bf06e0..cf5479e18c87 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -731,7 +731,7 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6) DEFUN (area_filter_list, area_filter_list_cmd, - "area filter-list prefix PREFIXLIST_NAME ", + "area filter-list prefix PREFIXLIST6_NAME ", "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" "OSPF6 area ID as a decimal value\n" @@ -774,7 +774,7 @@ DEFUN (area_filter_list, DEFUN (no_area_filter_list, no_area_filter_list_cmd, - "no area filter-list prefix PREFIXLIST_NAME ", + "no area filter-list prefix PREFIXLIST6_NAME ", NO_STR "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 713dd820751c..2065527c9377 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -14,6 +14,7 @@ #include "table.h" #include "plist.h" #include "frrevent.h" +#include "frrstr.h" #include "linklist.h" #include "lib/northbound_cli.h" @@ -101,9 +102,8 @@ struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - as_external_lsa = (struct ospf6_as_external_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + as_external_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( + lsa_header); p = (caddr_t)((caddr_t)as_external_lsa + sizeof(struct ospf6_as_external_lsa)); @@ -216,7 +216,7 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa) if (!lsa) return 0; - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) @@ -481,7 +481,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, static int ospf6_ase_forward_address_check(struct ospf6 *ospf6, struct in6_addr *fwd_addr) { - struct listnode *anode, *node, *cnode; + struct listnode *anode, *node; struct ospf6_interface *oi; struct ospf6_area *oa; struct interface *ifp; @@ -494,7 +494,7 @@ static int ospf6_ase_forward_address_check(struct ospf6 *ospf6, continue; ifp = oi->interface; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (IPV6_ADDR_SAME(&c->address->u.prefix6, fwd_addr)) return 0; @@ -520,7 +520,7 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) type = ntohs(lsa->header->type); oa = lsa->lsdb->data; - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) @@ -725,7 +725,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, int type; bool debug = false; - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA)) @@ -1376,11 +1376,59 @@ ospf6_external_aggr_match(struct ospf6 *ospf6, struct prefix *p) return node->info; } +static void ospf6_external_lsa_fwd_addr_set(struct ospf6 *ospf6, + const struct in6_addr *nexthop, + struct in6_addr *fwd_addr) +{ + struct vrf *vrf; + struct interface *ifp; + struct prefix nh; + + /* Initialize forwarding address to zero. */ + memset(fwd_addr, 0, sizeof(*fwd_addr)); + + vrf = vrf_lookup_by_id(ospf6->vrf_id); + if (!vrf) + return; + + nh.family = AF_INET6; + nh.u.prefix6 = *nexthop; + nh.prefixlen = IPV6_MAX_BITLEN; + + /* + * Use the route's nexthop as the forwarding address if it meets the + * following conditions: + * - It's a global address. + * - The associated nexthop interface is OSPF-enabled. + */ + if (IN6_IS_ADDR_UNSPECIFIED(nexthop) || IN6_IS_ADDR_LINKLOCAL(nexthop)) + return; + + FOR_ALL_INTERFACES (vrf, ifp) { + struct ospf6_interface *oi = ifp->info; + struct connected *connected; + + if (!oi || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) + continue; + + frr_each (if_connected, ifp->connected, connected) { + if (connected->address->family != AF_INET6) + continue; + if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6)) + continue; + if (!prefix_match(connected->address, &nh)) + continue; + + *fwd_addr = *nexthop; + return; + } + } +} + void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, - struct prefix *prefix, - unsigned int nexthop_num, - const struct in6_addr *nexthop, - route_tag_t tag, struct ospf6 *ospf6) + struct prefix *prefix, unsigned int nexthop_num, + const struct in6_addr *nexthop, route_tag_t tag, + struct ospf6 *ospf6, uint32_t metric) { route_map_result_t ret; struct ospf6_route troute; @@ -1423,6 +1471,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, if (ROUTEMAP(red)) { troute.route_option = &tinfo; troute.ospf6 = ospf6; + troute.path.redistribute_cost = metric; tinfo.ifindex = ifindex; tinfo.tag = tag; @@ -1470,10 +1519,8 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, if (nexthop_num && nexthop) { ospf6_route_add_nexthop(match, ifindex, nexthop); - if (!IN6_IS_ADDR_UNSPECIFIED(nexthop) - && !IN6_IS_ADDR_LINKLOCAL(nexthop)) - memcpy(&info->forwarding, nexthop, - sizeof(struct in6_addr)); + ospf6_external_lsa_fwd_addr_set(ospf6, nexthop, + &info->forwarding); } else ospf6_route_add_nexthop(match, ifindex, NULL); @@ -1520,10 +1567,8 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, info->type = type; if (nexthop_num && nexthop) { ospf6_route_add_nexthop(route, ifindex, nexthop); - if (!IN6_IS_ADDR_UNSPECIFIED(nexthop) - && !IN6_IS_ADDR_LINKLOCAL(nexthop)) - memcpy(&info->forwarding, nexthop, - sizeof(struct in6_addr)); + ospf6_external_lsa_fwd_addr_set(ospf6, nexthop, + &info->forwarding); } else ospf6_route_add_nexthop(route, ifindex, NULL); @@ -1879,7 +1924,7 @@ static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate) case DEFAULT_ORIGINATE_ALWAYS: ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0, (struct prefix *)&p, 0, &nexthop, 0, - ospf6); + ospf6, 0); break; } } @@ -2108,25 +2153,81 @@ static const struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_free, }; +struct ospf6_metric { + enum { metric_increment, metric_decrement, metric_absolute } type; + bool used; + uint32_t metric; +}; + static enum route_map_cmd_result_t ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix, void *object) { - char *metric = rule; - struct ospf6_route *route = object; + struct ospf6_metric *metric; + struct ospf6_route *route; + + /* Fetch routemap's rule information. */ + metric = rule; + route = object; + + /* Set metric out value. */ + if (!metric->used) + return RMAP_OKAY; + + if (route->path.redistribute_cost > OSPF6_EXT_PATH_METRIC_MAX) + route->path.redistribute_cost = OSPF6_EXT_PATH_METRIC_MAX; + + if (metric->type == metric_increment) { + route->path.cost = route->path.redistribute_cost + + metric->metric; + + /* Check overflow */ + if (route->path.cost > OSPF6_EXT_PATH_METRIC_MAX || + route->path.cost < metric->metric) + route->path.cost = OSPF6_EXT_PATH_METRIC_MAX; + } else if (metric->type == metric_decrement) { + route->path.cost = route->path.redistribute_cost - + metric->metric; + + /* Check overflow */ + if (route->path.cost == 0 || + route->path.cost > route->path.redistribute_cost) + route->path.cost = 1; + } else if (metric->type == metric_absolute) + route->path.cost = metric->metric; - route->path.cost = atoi(metric); return RMAP_OKAY; } static void *ospf6_routemap_rule_set_metric_compile(const char *arg) { - uint32_t metric; - char *endp; - metric = strtoul(arg, &endp, 0); - if (metric > OSPF_LS_INFINITY || *endp != '\0') - return NULL; - return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); + struct ospf6_metric *metric; + + metric = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*metric)); + metric->used = false; + + if (all_digit(arg)) + metric->type = metric_absolute; + + if ((arg[0] == '+') && all_digit(arg + 1)) { + metric->type = metric_increment; + arg++; + } + + if ((arg[0] == '-') && all_digit(arg + 1)) { + metric->type = metric_decrement; + arg++; + } + + metric->metric = strtoul(arg, NULL, 10); + + if (metric->metric > OSPF6_EXT_PATH_METRIC_MAX) + metric->metric = OSPF6_EXT_PATH_METRIC_MAX; + + if (metric->metric) + metric->used = true; + + return metric; } static void ospf6_routemap_rule_set_metric_free(void *rule) @@ -2323,7 +2424,7 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa, char tbuf[16]; if (lsa) { - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); if (pos == 0) { @@ -2358,7 +2459,7 @@ static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, char buf[64]; assert(lsa->header); - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); /* bits */ @@ -2926,8 +3027,8 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6, return; } - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END - (aggr_lsa->header); + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( + aggr_lsa->header); metric = (unsigned long)OSPF6_ASBR_METRIC(external); tag = ospf6_as_external_lsa_get_tag(aggr_lsa); mtype = CHECK_FLAG(external->bits_metric, @@ -3075,8 +3176,7 @@ ospf6_handle_external_aggr_modify(struct ospf6 *ospf6, return OSPF6_FAILURE; } - asel = (struct ospf6_as_external_lsa *) - OSPF6_LSA_HEADER_END(lsa->header); + asel = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(lsa->header); metric = (unsigned long)OSPF6_ASBR_METRIC(asel); tag = ospf6_as_external_lsa_get_tag(lsa); mtype = CHECK_FLAG(asel->bits_metric, @@ -3265,9 +3365,8 @@ static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6, lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), htonl(info->id), ospf6->router_id, ospf6->lsdb); if (lsa) { - ext_lsa = (struct ospf6_as_external_lsa - *)((char *)(lsa->header) - + sizeof(struct ospf6_lsa_header)); + ext_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( + lsa->header); if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length) return; diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index d63e46727890..21e6d898e828 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -94,11 +94,13 @@ struct ospf6_as_external_lsa { #define OSPF6_ASBR_BIT_F ntohl (0x02000000) #define OSPF6_ASBR_BIT_E ntohl (0x04000000) -#define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff))) +#define OSPF6_ASBR_METRIC(E) \ + (ntohl((E)->bits_metric & htonl(OSPF6_EXT_PATH_METRIC_MAX))) #define OSPF6_ASBR_METRIC_SET(E, C) \ { \ - (E)->bits_metric &= htonl(0xff000000); \ - (E)->bits_metric |= htonl(0x00ffffff) & htonl(C); \ + (E)->bits_metric &= htonl(~OSPF6_EXT_PATH_METRIC_MAX); \ + (E)->bits_metric |= htonl(OSPF6_EXT_PATH_METRIC_MAX) & \ + htonl(C); \ } extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa); @@ -115,7 +117,8 @@ extern void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, const struct in6_addr *nexthop, - route_tag_t tag, struct ospf6 *ospf6); + route_tag_t tag, struct ospf6 *ospf6, + uint32_t metric); extern void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, struct prefix *prefix, struct ospf6 *ospf6); diff --git a/ospf6d/ospf6_auth_trailer.c b/ospf6d/ospf6_auth_trailer.c index 10e00921f1c6..860d273796c5 100644 --- a/ospf6d/ospf6_auth_trailer.c +++ b/ospf6d/ospf6_auth_trailer.c @@ -4,6 +4,13 @@ */ #include "zebra.h" +#include + +#ifdef CRYPTO_OPENSSL +#include +#include +#endif + #include "config.h" #include "memory.h" #include "ospf6d.h" @@ -23,9 +30,13 @@ #include "ospf6_zebra.h" #include "lib/keychain.h" +#define OSPF6D_COMPAT_AUTHSEQ_NAME "%s/ospf6d-at-seq-no.dat", frr_runstatedir + unsigned char conf_debug_ospf6_auth[2]; DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AUTH_HASH_XOR, "OSPF6 auth hash xor"); +static void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6); + /*Apad is the hexadecimal value 0x878FE1F3. */ const uint8_t ospf6_hash_apad_max[KEYCHAIN_MAX_HASH_SIZE] = { 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, 0xf3, 0x87, 0x8f, 0xe1, @@ -506,6 +517,15 @@ int ospf6_auth_check_digest(struct ospf6_header *oh, struct ospf6_interface *oi, } } else if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) { + if (oi->at_data.key_id != ntohs(ospf6_auth->id)) { + if (IS_OSPF6_DEBUG_AUTH_RX) + zlog_err("RECV[%s]: Auth SA ID mismatch for %s, received %u vs configured %u", + oi->interface->name, + ospf6_message_type(oh->type), + ntohs(ospf6_auth->id), + oi->at_data.key_id); + return OSPF6_AUTH_VALIDATE_FAILURE; + } auth_str = oi->at_data.auth_key; hash_algo = oi->at_data.hash_algo; } @@ -855,23 +875,11 @@ void install_element_ospf6_clear_intf_auth(void) install_element(ENABLE_NODE, &clear_ipv6_ospf6_intf_auth_cmd); } -enum ospf6_auth_err ospf6_auth_nvm_file_exist(void) -{ - struct stat buffer; - int exist; - - exist = stat(OSPF6_AUTH_SEQ_NUM_FILE, &buffer); - if (exist == 0) - return OSPF6_AUTH_FILE_EXIST; - else - return OSPF6_AUTH_FILE_DO_NOT_EXIST; -} - /* * Record in non-volatile memory the given ospf6 process, * authentication trailer higher order sequence number. */ -void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) +static void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) { const char *inst_name; json_object *json; @@ -883,9 +891,7 @@ void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; - json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -905,49 +911,82 @@ void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6) */ json_object_int_add(json_instance, "sequence_number", ospf6->seqnum_h); - json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, - JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } /* * Delete authentication sequence number for a given OSPF6 process * from non-volatile memory. */ -void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6) +__attribute__((unused)) static void +ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6) { const char *inst_name; json_object *json; json_object *json_instances; + json_object *json_instance; zlog_err("Higher order sequence number delete for %s process", ospf6->name); inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; - json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { - json_instances = json_object_new_object(); - json_object_object_add(json, "instances", json_instances); + json_object_put(json); + return; } - json_object_object_del(json_instances, inst_name); + json_object_object_get_ex(json_instances, inst_name, &json_instance); + if (json_instance) { + json_object_put(json); + return; + } - json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, - JSON_C_TO_STRING_PRETTY); - json_object_free(json); + json_object_object_del(json_instance, "sequence_number"); + + frr_daemon_state_save(&json); } +static struct json_object *ospf6_auth_seqno_compat_read(const char *inst_name) +{ + /* try legacy location */ + char compat_path[512]; + json_object *json; + json_object *json_instances = NULL; + json_object *json_instance = NULL; + json_object *json_seqnum = NULL; + + snprintf(compat_path, sizeof(compat_path), OSPF6D_COMPAT_AUTHSEQ_NAME); + json = json_object_from_file(compat_path); + + if (json) + json_object_object_get_ex(json, "instances", &json_instances); + if (json_instances) + json_object_object_get_ex(json_instances, inst_name, + &json_instance); + if (json_instance) + json_object_object_get_ex(json_instance, "sequence_number", + &json_seqnum); + if (json_seqnum) + /* => free the file-level object and still return this */ + json_seqnum = json_object_get(json_seqnum); + + if (json) { + json_object_free(json); + unlink(compat_path); + } + return json_seqnum; +} + /* * Fetch from non-volatile memory the stored ospf6 process * authentication sequence number. */ -void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) +static void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) { const char *inst_name; json_object *json; @@ -957,9 +996,7 @@ void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; - json = json_object_from_file((char *)OSPF6_AUTH_SEQ_NUM_FILE); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -976,13 +1013,34 @@ void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6) json_object_object_get_ex(json_instance, "sequence_number", &json_seqnum); - ospf6->seqnum_h = json_object_get_int(json_seqnum); + + if (json_seqnum) + /* cf. reference taken in compat_read above */ + json_seqnum = json_object_get(json_seqnum); + else + json_seqnum = ospf6_auth_seqno_compat_read(inst_name); + + ospf6->seqnum_l = 0; + if (json_seqnum) { + ospf6->seqnum_h = json_object_get_int(json_seqnum); + ospf6->seqnum_h += 1; + } else { + ospf6->seqnum_h = 0; + } + + if (json_seqnum) + json_object_put(json_seqnum); zlog_err("Higher order sequence number %d read for %s process %s", ospf6->seqnum_h, ospf6->name, strerror(errno)); - json_object_object_del(json_instances, inst_name); - json_object_to_file_ext((char *)OSPF6_AUTH_SEQ_NUM_FILE, json, - JSON_C_TO_STRING_PRETTY); - json_object_free(json); + json_object_object_del(json_instance, "sequence_number"); + + frr_daemon_state_save(&json); +} + +void ospf6_auth_init(struct ospf6 *o) +{ + ospf6_auth_seqno_nvm_read(o); + ospf6_auth_seqno_nvm_update(o); } diff --git a/ospf6d/ospf6_auth_trailer.h b/ospf6d/ospf6_auth_trailer.h index 3f82a7b19774..9073ae47dd68 100644 --- a/ospf6d/ospf6_auth_trailer.h +++ b/ospf6d/ospf6_auth_trailer.h @@ -48,10 +48,10 @@ enum ospf6_auth_err { OSPF6_AUTH_VALIDATE_SUCCESS = 0, OSPF6_AUTH_VALIDATE_FAILURE, OSPF6_AUTH_PROCESS_NORMAL, - OSPF6_AUTH_FILE_EXIST, - OSPF6_AUTH_FILE_DO_NOT_EXIST }; +void ospf6_auth_init(struct ospf6 *o); + void ospf6_auth_hdr_dump_send(struct ospf6_header *ospfh, uint16_t length); void ospf6_auth_hdr_dump_recv(struct ospf6_header *ospfh, uint16_t length, unsigned int lls_len); @@ -73,8 +73,5 @@ void ospf6_auth_digest_send(struct in6_addr *src, struct ospf6_interface *oi, void install_element_ospf6_debug_auth(void); int config_write_ospf6_debug_auth(struct vty *vty); void install_element_ospf6_clear_intf_auth(void); -enum ospf6_auth_err ospf6_auth_nvm_file_exist(void); -void ospf6_auth_seqno_nvm_update(struct ospf6 *ospf6); -void ospf6_auth_seqno_nvm_delete(struct ospf6 *ospf6); -void ospf6_auth_seqno_nvm_read(struct ospf6 *ospf6); + #endif /* __OSPF6_AUTH_TRAILER_H__ */ diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 98d3bbc5197b..b87aa2ffe103 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -295,9 +295,7 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa) lsa->installed = now; /* Topo change handling */ - if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type)) - && !CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)) { - + if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))) { /* check if it is new lsa ? or existing lsa got modified ?*/ if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) ospf6_helper_handle_topo_chg(ospf6, lsa); diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c index 69230e572b06..ab119a4ea4eb 100644 --- a/ospf6d/ospf6_gr.c +++ b/ospf6d/ospf6_gr.c @@ -54,9 +54,7 @@ static int ospf6_gr_lsa_originate(struct ospf6_interface *oi, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - grace_lsa = - (struct ospf6_grace_lsa *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + grace_lsa = (struct ospf6_grace_lsa *)ospf6_lsa_header_end(lsa_header); /* Put grace period. */ grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE); @@ -561,9 +559,7 @@ static void ospf6_gr_nvm_update(struct ospf6 *ospf6, bool prepare) inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; - json = json_object_from_file((char *)OSPF6D_GR_STATE); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -591,9 +587,7 @@ static void ospf6_gr_nvm_update(struct ospf6 *ospf6, bool prepare) json_object_int_add(json_instance, "timestamp", time(NULL) + ospf6->gr_info.grace_period); - json_object_to_file_ext((char *)OSPF6D_GR_STATE, json, - JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } /* @@ -608,9 +602,7 @@ void ospf6_gr_nvm_delete(struct ospf6 *ospf6) inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; - json = json_object_from_file((char *)OSPF6D_GR_STATE); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -620,9 +612,7 @@ void ospf6_gr_nvm_delete(struct ospf6 *ospf6) json_object_object_del(json_instances, inst_name); - json_object_to_file_ext((char *)OSPF6D_GR_STATE, json, - JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } /* @@ -641,9 +631,7 @@ void ospf6_gr_nvm_read(struct ospf6 *ospf6) inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME; - json = json_object_from_file((char *)OSPF6D_GR_STATE); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -687,11 +675,10 @@ void ospf6_gr_nvm_read(struct ospf6 *ospf6) ospf6->gr_info.grace_period); } - json_object_object_del(json_instances, inst_name); + json_object_object_del(json_instance, "gracePeriod"); + json_object_object_del(json_instance, "timestamp"); - json_object_to_file_ext((char *)OSPF6D_GR_STATE, json, - JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } void ospf6_gr_unplanned_start_interface(struct ospf6_interface *oi) diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index 8159ac0cd3d3..f0e5d3a15c24 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -134,7 +134,7 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, uint16_t length = 0; int sum = 0; - lsah = (struct ospf6_lsa_header *)lsa->header; + lsah = lsa->header; if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF6_GR) zlog_debug("%s: undersized (%u B) lsa", __func__, @@ -176,6 +176,7 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, return OSPF6_FAILURE; break; default: + sum += TLV_SIZE(tlvh); if (IS_DEBUG_OSPF6_GR) zlog_debug("%s, Ignoring unknown TLV type:%d", __func__, ntohs(tlvh->type)); @@ -938,15 +939,6 @@ static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6, ? "Enabled" : "Disabled"); -#if CONFDATE > 20240401 - CPP_NOTICE("Remove deprecated json key: restartSupoort") -#endif - json_object_string_add( - json, "restartSupoort", - (ospf6->ospf6_helper_cfg.only_planned_restart) - ? "Planned Restart only" - : "Planned and Unplanned Restarts"); - json_object_string_add( json, "restartSupport", (ospf6->ospf6_helper_cfg.only_planned_restart) @@ -1231,7 +1223,7 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, uint16_t length = 0; int sum = 0; - lsah = (struct ospf6_lsa_header *)lsa->header; + lsah = lsa->header; if (ntohs(lsah->length) <= OSPF6_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF6_GR) zlog_debug("%s: undersized (%u B) lsa", __func__, diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index a20ddf6c1096..7f813ce3cc25 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -49,8 +49,9 @@ DEFINE_HOOK(ospf6_interface_change, unsigned char conf_debug_ospf6_interface = 0; const char *const ospf6_interface_state_str[] = { - "None", "Down", "Loopback", "Waiting", "PointToPoint", - "DROther", "BDR", "DR", NULL}; + "None", "Down", "Loopback", "Waiting", "PointToPoint", + "PtMultipoint", "DROther", "BDR", "DR", NULL +}; int ospf6_interface_neighbor_count(struct ospf6_interface *oi) { @@ -83,8 +84,7 @@ struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex, } /* schedule routing table recalculation */ -static void ospf6_interface_lsdb_hook(struct ospf6_lsa *lsa, - unsigned int reason) +static void ospf6_interface_lsdb_hook(struct ospf6_lsa *lsa, unsigned int reason) { struct ospf6_interface *oi; @@ -131,6 +131,7 @@ static uint32_t ospf6_interface_get_cost(struct ospf6_interface *oi) uint32_t cost; uint32_t bw, refbw; struct ospf6 *ospf6; + /* interface speed and bw can be 0 in some platforms, * use ospf default bw. If bw is configured then it would * be used. @@ -152,6 +153,15 @@ static uint32_t ospf6_interface_get_cost(struct ospf6_interface *oi) cost = (uint32_t)((double)refbw / (double)bw + (double)0.5); if (cost < 1) cost = 1; + + /* If the interface type is point-to-multipoint or the interface + * is in the state Loopback, the global scope IPv6 addresses + * associated with the interface (if any) are copied into the + * intra-area-prefix-LSA with the PrefixOptions LA-bit set, the + * PrefixLength set to 128, and the metric set to 0. + */ + if (if_is_loopback(oi->interface)) + cost = 0; } return cost; @@ -217,9 +227,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp) iobuflen = ospf6_iobuf_size(ifp->mtu6); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) - zlog_debug( - "Interface %s: IfMtu is adjusted to I/O buffer size: %d.", - ifp->name, iobuflen); + zlog_debug("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", + ifp->name, iobuflen); oi->ifmtu = iobuflen; } @@ -232,8 +241,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp) oi->lsdb->hook_remove = ospf6_interface_lsdb_hook_remove; oi->lsdb_self = ospf6_lsdb_create(oi); - oi->route_connected = - OSPF6_ROUTE_TABLE_CREATE(INTERFACE, CONNECTED_ROUTES); + oi->route_connected = OSPF6_ROUTE_TABLE_CREATE(INTERFACE, + CONNECTED_ROUTES); oi->route_connected->scope = oi; /* link both */ @@ -334,12 +343,11 @@ void ospf6_interface_disable(struct ospf6_interface *oi) static struct in6_addr * ospf6_interface_get_linklocal_address(struct interface *ifp) { - struct listnode *n; struct connected *c; struct in6_addr *l = (struct in6_addr *)NULL; /* for each connected address */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) { + frr_each (if_connected, ifp->connected, c) { /* if family not AF_INET6, ignore */ if (c->address->family != AF_INET6) continue; @@ -370,23 +378,21 @@ void ospf6_interface_state_update(struct interface *ifp) iobuflen = ospf6_iobuf_size(ifp->mtu6); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) - zlog_debug( - "Interface %s: IfMtu is adjusted to I/O buffer size: %d.", - ifp->name, iobuflen); + zlog_debug("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", + ifp->name, iobuflen); oi->ifmtu = iobuflen; } } else if (oi->c_ifmtu > ifp->mtu6) { oi->ifmtu = ifp->mtu6; - zlog_warn( - "Configured mtu %u on %s overridden by kernel %u", - oi->c_ifmtu, ifp->name, ifp->mtu6); + zlog_warn("Configured mtu %u on %s overridden by kernel %u", + oi->c_ifmtu, ifp->name, ifp->mtu6); } else oi->ifmtu = oi->c_ifmtu; } - if (if_is_operative(ifp) - && (ospf6_interface_get_linklocal_address(oi->interface) - || if_is_loopback(oi->interface))) + if (if_is_operative(ifp) && + (ospf6_interface_get_linklocal_address(oi->interface) || + if_is_loopback(oi->interface))) event_execute(master, interface_up, oi, 0, NULL); else event_execute(master, interface_down, oi, 0, NULL); @@ -397,9 +403,7 @@ void ospf6_interface_state_update(struct interface *ifp) void ospf6_interface_connected_route_update(struct interface *ifp) { struct ospf6_interface *oi; - struct ospf6_route *route; struct connected *c; - struct listnode *node, *nnode; struct in6_addr nh_addr; oi = (struct ospf6_interface *)ifp->info; @@ -419,7 +423,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp) /* update "route to advertise" interface route table */ ospf6_route_remove_all(oi->route_connected); - for (ALL_LIST_ELEMENTS(oi->interface->connected, node, nnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (c->address->family != AF_INET6) continue; @@ -443,14 +447,43 @@ void ospf6_interface_connected_route_update(struct interface *ifp) ret = prefix_list_apply(plist, (void *)c->address); if (ret == PREFIX_DENY) { if (IS_OSPF6_DEBUG_INTERFACE) - zlog_debug( - "%pFX on %s filtered by prefix-list %s ", - c->address, oi->interface->name, - oi->plist_name); + zlog_debug("%pFX on %s filtered by prefix-list %s ", + c->address, + oi->interface->name, + oi->plist_name); continue; } } + if (oi->type == OSPF_IFTYPE_LOOPBACK || + oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || + oi->type == OSPF_IFTYPE_POINTOPOINT) { + struct ospf6_route *la_route; + + la_route = ospf6_route_create(oi->area->ospf6); + la_route->prefix = *c->address; + la_route->prefix.prefixlen = 128; + la_route->prefix_options |= OSPF6_PREFIX_OPTION_LA; + + la_route->type = OSPF6_DEST_TYPE_NETWORK; + la_route->path.area_id = oi->area->area_id; + la_route->path.type = OSPF6_PATH_TYPE_INTRA; + la_route->path.cost = 0; + inet_pton(AF_INET6, "::1", &nh_addr); + ospf6_route_add_nexthop(la_route, oi->interface->ifindex, + &nh_addr); + ospf6_route_add(la_route, oi->route_connected); + } + + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && + !oi->p2xp_connected_pfx_include) + continue; + if (oi->type == OSPF_IFTYPE_POINTOPOINT && + oi->p2xp_connected_pfx_exclude) + continue; + + struct ospf6_route *route; + route = ospf6_route_create(oi->area->ospf6); memcpy(&route->prefix, c->address, sizeof(struct prefix)); apply_mask(&route->prefix); @@ -459,8 +492,7 @@ void ospf6_interface_connected_route_update(struct interface *ifp) route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.cost = oi->cost; inet_pton(AF_INET6, "::1", &nh_addr); - ospf6_route_add_nexthop(route, oi->interface->ifindex, - &nh_addr); + ospf6_route_add_nexthop(route, oi->interface->ifindex, &nh_addr); ospf6_route_add(route, oi->route_connected); } @@ -496,17 +528,17 @@ static int ospf6_interface_state_change(uint8_t next_state, ospf6 = oi->area->ospf6; - if ((prev_state == OSPF6_INTERFACE_DR - || prev_state == OSPF6_INTERFACE_BDR) - && (next_state != OSPF6_INTERFACE_DR - && next_state != OSPF6_INTERFACE_BDR)) + if ((prev_state == OSPF6_INTERFACE_DR || + prev_state == OSPF6_INTERFACE_BDR) && + (next_state != OSPF6_INTERFACE_DR && + next_state != OSPF6_INTERFACE_BDR)) ospf6_sso(oi->interface->ifindex, &alldrouters6, IPV6_LEAVE_GROUP, ospf6->fd); - if ((prev_state != OSPF6_INTERFACE_DR - && prev_state != OSPF6_INTERFACE_BDR) - && (next_state == OSPF6_INTERFACE_DR - || next_state == OSPF6_INTERFACE_BDR)) + if ((prev_state != OSPF6_INTERFACE_DR && + prev_state != OSPF6_INTERFACE_BDR) && + (next_state == OSPF6_INTERFACE_DR || + next_state == OSPF6_INTERFACE_BDR)) ospf6_sso(oi->interface->ifindex, &alldrouters6, IPV6_JOIN_GROUP, ospf6->fd); @@ -516,13 +548,17 @@ static int ospf6_interface_state_change(uint8_t next_state, OSPF6_NETWORK_LSA_EXECUTE(oi); OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area); - } else if (prev_state == OSPF6_INTERFACE_DR - || next_state == OSPF6_INTERFACE_DR) { + } else if (prev_state == OSPF6_INTERFACE_DR || + next_state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE(oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oi->area); } + if (next_state == OSPF6_INTERFACE_POINTTOPOINT || + next_state == OSPF6_INTERFACE_POINTTOMULTIPOINT) + ospf6_if_p2xp_up(oi); + hook_call(ospf6_interface_change, oi, next_state, prev_state); return 0; @@ -537,8 +573,8 @@ static int ospf6_interface_state_change(uint8_t next_state, static struct ospf6_neighbor *better_bdrouter(struct ospf6_neighbor *a, struct ospf6_neighbor *b) { - if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter == a->router_id) - && (b == NULL || !IS_ELIGIBLE(b) || b->drouter == b->router_id)) + if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter == a->router_id) && + (b == NULL || !IS_ELIGIBLE(b) || b->drouter == b->router_id)) return NULL; else if (a == NULL || !IS_ELIGIBLE(a) || a->drouter == a->router_id) return b; @@ -567,8 +603,8 @@ static struct ospf6_neighbor *better_bdrouter(struct ospf6_neighbor *a, static struct ospf6_neighbor *better_drouter(struct ospf6_neighbor *a, struct ospf6_neighbor *b) { - if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter != a->router_id) - && (b == NULL || !IS_ELIGIBLE(b) || b->drouter != b->router_id)) + if ((a == NULL || !IS_ELIGIBLE(a) || a->drouter != a->router_id) && + (b == NULL || !IS_ELIGIBLE(b) || b->drouter != b->router_id)) return NULL; else if (a == NULL || !IS_ELIGIBLE(a) || a->drouter != a->router_id) return b; @@ -631,10 +667,10 @@ uint8_t dr_election(struct ospf6_interface *oi) drouter = bdrouter; /* the router itself is newly/no longer DR/BDR (4) */ - if ((drouter == &myself && myself.drouter != myself.router_id) - || (drouter != &myself && myself.drouter == myself.router_id) - || (bdrouter == &myself && myself.bdrouter != myself.router_id) - || (bdrouter != &myself && myself.bdrouter == myself.router_id)) { + if ((drouter == &myself && myself.drouter != myself.router_id) || + (drouter != &myself && myself.drouter == myself.router_id) || + (bdrouter == &myself && myself.bdrouter != myself.router_id) || + (bdrouter != &myself && myself.bdrouter == myself.router_id)) { myself.drouter = (drouter ? drouter->router_id : htonl(0)); myself.bdrouter = (bdrouter ? bdrouter->router_id : htonl(0)); @@ -708,8 +744,8 @@ static bool ifmaddr_check(ifindex_t ifindex, struct in6_addr *addr) continue; sdl = (struct sockaddr_dl *)ifma->ifma_name; sin6 = (struct sockaddr_in6 *)ifma->ifma_addr; - if (sdl->sdl_index == ifindex - && memcmp(&sin6->sin6_addr, addr, IPV6_MAX_BYTELEN) == 0) { + if (sdl->sdl_index == ifindex && + memcmp(&sin6->sin6_addr, addr, IPV6_MAX_BYTELEN) == 0) { found = true; break; } @@ -749,16 +785,15 @@ void interface_up(struct event *thread) } /* check interface has a link-local address */ - if (!(ospf6_interface_get_linklocal_address(oi->interface) - || if_is_loopback(oi->interface))) { - zlog_warn( - "Interface %s has no link local address, can't execute [InterfaceUp]", - oi->interface->name); + if (!(ospf6_interface_get_linklocal_address(oi->interface) || + if_is_loopback(oi->interface))) { + zlog_warn("Interface %s has no link local address, can't execute [InterfaceUp]", + oi->interface->name); return; } - /* Recompute cost */ - ospf6_interface_recalculate_cost(oi); + /* Recompute cost & update connected LSAs */ + ospf6_interface_force_recalculate_cost(oi); /* if already enabled, do nothing */ if (oi->state > OSPF6_INTERFACE_DOWN) { @@ -770,9 +805,8 @@ void interface_up(struct event *thread) /* If no area assigned, return */ if (oi->area == NULL) { - zlog_warn( - "%s: Not scheduling Hello for %s as there is no area assigned yet", - __func__, oi->interface->name); + zlog_warn("%s: Not scheduling Hello for %s as there is no area assigned yet", + __func__, oi->interface->name); return; } @@ -797,9 +831,8 @@ void interface_up(struct event *thread) * the interface actually left the group. */ if (ifmaddr_check(oi->interface->ifindex, &allspfrouters6)) { - zlog_info( - "Interface %s is still in all routers group, rescheduling for SSO", - oi->interface->name); + zlog_info("Interface %s is still in all routers group, rescheduling for SSO", + oi->interface->name); event_add_timer(master, interface_up, oi, OSPF6_INTERFACE_SSO_RETRY_INT, &oi->thread_sso); return; @@ -810,12 +843,10 @@ void interface_up(struct event *thread) /* Join AllSPFRouters */ if (ospf6_sso(oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP, - ospf6->fd) - < 0) { + ospf6->fd) < 0) { if (oi->sso_try_cnt++ < OSPF6_INTERFACE_SSO_RETRY_MAX) { - zlog_info( - "Scheduling %s for sso retry, trial count: %d", - oi->interface->name, oi->sso_try_cnt); + zlog_info("Scheduling %s for sso retry, trial count: %d", + oi->interface->name, oi->sso_try_cnt); event_add_timer(master, interface_up, oi, OSPF6_INTERFACE_SSO_RETRY_INT, &oi->thread_sso); @@ -828,8 +859,8 @@ void interface_up(struct event *thread) ospf6_interface_connected_route_update(oi->interface); /* Schedule Hello */ - if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE) - && !if_is_loopback(oi->interface)) { + if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE) && + !if_is_loopback(oi->interface)) { event_add_timer(master, ospf6_hello_send, oi, 0, &oi->thread_send_hello); } @@ -839,6 +870,9 @@ void interface_up(struct event *thread) ospf6_interface_state_change(OSPF6_INTERFACE_LOOPBACK, oi); } else if (oi->type == OSPF_IFTYPE_POINTOPOINT) { ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOPOINT, oi); + } else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { + ospf6_interface_state_change(OSPF6_INTERFACE_POINTTOMULTIPOINT, + oi); } else if (oi->priority == 0) ospf6_interface_state_change(OSPF6_INTERFACE_DROTHER, oi); else { @@ -889,9 +923,8 @@ void neighbor_change(struct event *thread) zlog_debug("Interface Event %s: [NeighborChange]", oi->interface->name); - if (oi->state == OSPF6_INTERFACE_DROTHER - || oi->state == OSPF6_INTERFACE_BDR - || oi->state == OSPF6_INTERFACE_DR) + if (oi->state == OSPF6_INTERFACE_DROTHER || + oi->state == OSPF6_INTERFACE_BDR || oi->state == OSPF6_INTERFACE_DR) ospf6_interface_state_change(dr_election(oi), oi); } @@ -967,6 +1000,8 @@ static const char *ospf6_iftype_str(uint8_t iftype) return "BROADCAST"; case OSPF_IFTYPE_POINTOPOINT: return "POINTOPOINT"; + case OSPF_IFTYPE_POINTOMULTIPOINT: + return "POINTOMULTIPOINT"; } return "UNKNOWN"; } @@ -978,7 +1013,6 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, struct ospf6_interface *oi; struct connected *c; struct prefix *p; - struct listnode *i; char strbuf[PREFIX2STR_BUFFER], drouter[32], bdrouter[32]; uint8_t default_iftype; struct timeval res, now; @@ -1025,7 +1059,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, if (use_json) { json_arr = json_object_new_array(); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, i, c)) { + frr_each (if_connected, ifp->connected, c) { json_addr = json_object_new_object(); p = c->address; prefix2str(p, strbuf, sizeof(strbuf)); @@ -1057,7 +1091,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, } else { vty_out(vty, " Internet Address:\n"); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, i, c)) { + frr_each (if_connected, ifp->connected, c) { p = c->address; prefix2str(p, strbuf, sizeof(strbuf)); switch (p->family) { @@ -1076,12 +1110,10 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, if (use_json) { if (oi->area) { - json_object_boolean_true_add(json_obj, - "attachedToArea"); + json_object_boolean_true_add(json_obj, "attachedToArea"); json_object_int_add(json_obj, "instanceId", oi->instance_id); - json_object_int_add(json_obj, "interfaceMtu", - oi->ifmtu); + json_object_int_add(json_obj, "interfaceMtu", oi->ifmtu); json_object_int_add(json_obj, "autoDetect", ifp->mtu6); json_object_string_add(json_obj, "mtuMismatchDetection", oi->mtu_ignore ? "disabled" @@ -1121,9 +1153,9 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, oi->dead_interval); json_object_int_add(json_obj, "timerIntervalsConfigRetransmit", oi->rxmt_interval); - json_object_boolean_add( - json_obj, "timerPassiveIface", - !!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)); + json_object_boolean_add(json_obj, "timerPassiveIface", + !!CHECK_FLAG(oi->flag, + OSPF6_INTERFACE_PASSIVE)); } else { vty_out(vty, " State %s, Transmit Delay %d sec, Priority %d\n", ospf6_interface_state_str[oi->state], oi->transdelay, @@ -1156,24 +1188,23 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, if (use_json) { timerclear(&res); if (event_is_scheduled(oi->thread_send_lsupdate)) - timersub(&oi->thread_send_lsupdate->u.sands, &now, - &res); + timersub(&oi->thread_send_lsupdate->u.sands, &now, &res); timerstring(&res, duration, sizeof(duration)); json_object_int_add(json_obj, "pendingLsaLsUpdateCount", oi->lsupdate_list->count); json_object_string_add(json_obj, "pendingLsaLsUpdateTime", duration); - json_object_string_add( - json_obj, "lsUpdateSendThread", - (event_is_scheduled(oi->thread_send_lsupdate) ? "on" - : "off")); + json_object_string_add(json_obj, "lsUpdateSendThread", + (event_is_scheduled( + oi->thread_send_lsupdate) + ? "on" + : "off")); json_arr = json_object_new_array(); for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) - json_object_array_add( - json_arr, json_object_new_string(lsa->name)); - json_object_object_add(json_obj, "pendingLsaLsUpdate", - json_arr); + json_object_array_add(json_arr, + json_object_new_string(lsa->name)); + json_object_object_add(json_obj, "pendingLsaLsUpdate", json_arr); timerclear(&res); if (event_is_scheduled(oi->thread_send_lsack)) @@ -1184,15 +1215,15 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, oi->lsack_list->count); json_object_string_add(json_obj, "pendingLsaLsAckTime", duration); - json_object_string_add( - json_obj, "lsAckSendThread", - (event_is_scheduled(oi->thread_send_lsack) ? "on" - : "off")); + json_object_string_add(json_obj, "lsAckSendThread", + (event_is_scheduled(oi->thread_send_lsack) + ? "on" + : "off")); json_arr = json_object_new_array(); for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) - json_object_array_add( - json_arr, json_object_new_string(lsa->name)); + json_object_array_add(json_arr, + json_object_new_string(lsa->name)); json_object_object_add(json_obj, "pendingLsaLsAck", json_arr); if (oi->gr.hello_delay.interval != 0) @@ -1201,8 +1232,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, } else { timerclear(&res); if (event_is_scheduled(oi->thread_send_lsupdate)) - timersub(&oi->thread_send_lsupdate->u.sands, &now, - &res); + timersub(&oi->thread_send_lsupdate->u.sands, &now, &res); timerstring(&res, duration, sizeof(duration)); vty_out(vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n", @@ -1234,9 +1264,8 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, if (use_json) { struct json_object *json_bfd = json_object_new_object(); - json_object_int_add( - json_bfd, "detectMultiplier", - oi->bfd_config.detection_multiplier); + json_object_int_add(json_bfd, "detectMultiplier", + oi->bfd_config.detection_multiplier); json_object_int_add(json_bfd, "rxMinInterval", oi->bfd_config.min_rx); json_object_int_add(json_bfd, "txMinInterval", @@ -1259,8 +1288,7 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, OSPF6_AUTH_TRAILER_KEYCHAIN)) { json_object_string_add(json_auth, "authType", "keychain"); - json_object_string_add(json_auth, - "keychainName", + json_object_string_add(json_auth, "keychainName", oi->at_data.keychain); } else if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_MANUAL_KEY)) @@ -1300,11 +1328,10 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, /* Find the global address to be used as a forwarding address in NSSA LSA.*/ struct in6_addr *ospf6_interface_get_global_address(struct interface *ifp) { - struct listnode *n; struct connected *c; /* for each connected address */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) { + frr_each (if_connected, ifp->connected, c) { /* if family not AF_INET6, ignore */ if (c->address->family != AF_INET6) continue; @@ -1322,7 +1349,6 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, int idx_ifname, int intf_idx, int json_idx, bool uj) { - struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct interface *ifp; json_object *json; @@ -1369,10 +1395,17 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, } /* show interface */ -DEFUN(show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_ifname_cmd, +DEFUN(show_ipv6_ospf6_interface, + show_ipv6_ospf6_interface_ifname_cmd, "show ipv6 ospf6 [vrf ] interface [IFNAME] [json]", - SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR - "All VRFs\n" INTERFACE_STR IFNAME_STR JSON_STR) + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR + "All VRFs\n" + INTERFACE_STR + IFNAME_STR + JSON_STR) { int idx_ifname = 4; int intf_idx = 5; @@ -1452,18 +1485,15 @@ static int ospf6_interface_show_traffic(struct vty *vty, json_object_int_add(json_interface, "lsReqTx", oi->ls_req_out); json_object_int_add(json_interface, - "lsUpdateRx", - oi->ls_upd_in); - json_object_int_add(json_interface, - "lsUpdateTx", + "lsUpdateRx", oi->ls_upd_in); + json_object_int_add(json_interface, "lsUpdateTx", oi->ls_upd_out); json_object_int_add(json_interface, "lsAckRx", oi->ls_ack_in); json_object_int_add(json_interface, "lsAckTx", oi->ls_ack_out); - json_object_object_add(json, - oi->interface->name, + json_object_object_add(json, oi->interface->name, json_interface); } else vty_out(vty, @@ -1575,11 +1605,18 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, } /* show interface */ -DEFUN(show_ipv6_ospf6_interface_traffic, show_ipv6_ospf6_interface_traffic_cmd, +DEFUN(show_ipv6_ospf6_interface_traffic, + show_ipv6_ospf6_interface_traffic_cmd, "show ipv6 ospf6 [vrf ] interface traffic [IFNAME] [json]", - SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR - "All VRFs\n" INTERFACE_STR - "Protocol Packet counters\n" IFNAME_STR JSON_STR) + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR + "All VRFs\n" + INTERFACE_STR + "Protocol Packet counters\n" + IFNAME_STR + JSON_STR) { struct ospf6 *ospf6; struct listnode *node; @@ -1608,17 +1645,21 @@ DEFUN(show_ipv6_ospf6_interface_traffic, show_ipv6_ospf6_interface_traffic_cmd, DEFUN(show_ipv6_ospf6_interface_ifname_prefix, show_ipv6_ospf6_interface_ifname_prefix_cmd, - "show ipv6 ospf6 [vrf ] interface IFNAME prefix\ - [<\ - detail\ - | []\ - >] [json]", - SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR - "All VRFs\n" INTERFACE_STR IFNAME_STR + "show ipv6 ospf6 [vrf ] interface IFNAME prefix " + "[ []>] [json]", + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR + "All VRFs\n" + INTERFACE_STR IFNAME_STR "Display connected prefixes to advertise\n" - "Display details of the prefixes\n" OSPF6_ROUTE_ADDRESS_STR - OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR - "Display details of the prefixes\n" JSON_STR) + "Display details of the prefixes\n" + OSPF6_ROUTE_ADDRESS_STR + OSPF6_ROUTE_PREFIX_STR + OSPF6_ROUTE_MATCH_STR + "Display details of the prefixes\n" + JSON_STR) { int idx_ifname = 4; int idx_prefix = 6; @@ -1649,8 +1690,8 @@ DEFUN(show_ipv6_ospf6_interface_ifname_prefix, } oi = ifp->info; - if (oi == NULL - || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { + if (oi == NULL || + CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { vty_out(vty, "Interface %s not attached to area\n", argv[idx_ifname]->arg); @@ -1670,18 +1711,23 @@ DEFUN(show_ipv6_ospf6_interface_ifname_prefix, return CMD_SUCCESS; } -DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd, - "show ipv6 ospf6 [vrf ] interface prefix\ - [<\ - detail\ - | []\ - >] [json]", - SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR - "All VRFs\n" INTERFACE_STR +DEFUN(show_ipv6_ospf6_interface_prefix, + show_ipv6_ospf6_interface_prefix_cmd, + "show ipv6 ospf6 [vrf ] interface prefix " + "[ []>] [json]", + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR + "All VRFs\n" + INTERFACE_STR "Display connected prefixes to advertise\n" - "Display details of the prefixes\n" OSPF6_ROUTE_ADDRESS_STR - OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR - "Display details of the prefixes\n" JSON_STR) + "Display details of the prefixes\n" + OSPF6_ROUTE_ADDRESS_STR + OSPF6_ROUTE_PREFIX_STR + OSPF6_ROUTE_MATCH_STR + "Display details of the prefixes\n" + JSON_STR) { struct vrf *vrf = NULL; int idx_prefix = 5; @@ -1703,9 +1749,9 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd, vrf = vrf_lookup_by_id(ospf6->vrf_id); FOR_ALL_INTERFACES (vrf, ifp) { oi = (struct ospf6_interface *)ifp->info; - if (oi == NULL - || CHECK_FLAG(oi->flag, - OSPF6_INTERFACE_DISABLE)) + if (oi == NULL || + CHECK_FLAG(oi->flag, + OSPF6_INTERFACE_DISABLE)) continue; ospf6_route_table_show(vty, idx_prefix, argc, @@ -2179,7 +2225,8 @@ ALIAS (ipv6_ospf6_deadinterval, "Interval time after which a neighbor is declared down\n" SECONDS_STR) -DEFPY(ipv6_ospf6_gr_hdelay, ipv6_ospf6_gr_hdelay_cmd, +DEFPY(ipv6_ospf6_gr_hdelay, + ipv6_ospf6_gr_hdelay_cmd, "ipv6 ospf6 graceful-restart hello-delay (1-1800)", IP6_STR OSPF6_STR @@ -2200,7 +2247,8 @@ DEFPY(ipv6_ospf6_gr_hdelay, ipv6_ospf6_gr_hdelay_cmd, return CMD_SUCCESS; } -DEFPY(no_ipv6_ospf6_gr_hdelay, no_ipv6_ospf6_gr_hdelay_cmd, +DEFPY(no_ipv6_ospf6_gr_hdelay, + no_ipv6_ospf6_gr_hdelay_cmd, "no ipv6 ospf6 graceful-restart hello-delay [(1-1800)]", NO_STR IP6_STR @@ -2314,10 +2362,9 @@ DEFUN (ipv6_ospf6_priority, ? OSPF6_INTERFACE_PRIORITY : strtoul(argv[idx_number]->arg, NULL, 10); - if (oi->area - && (oi->state == OSPF6_INTERFACE_DROTHER - || oi->state == OSPF6_INTERFACE_BDR - || oi->state == OSPF6_INTERFACE_DR)) { + if (oi->area && (oi->state == OSPF6_INTERFACE_DROTHER || + oi->state == OSPF6_INTERFACE_BDR || + oi->state == OSPF6_INTERFACE_DR)) { if (ospf6_interface_state_change(dr_election(oi), oi) == -1) OSPF6_LINK_LSA_SCHEDULE(oi); } @@ -2474,15 +2521,14 @@ DEFUN (no_ipv6_ospf6_mtu_ignore, return CMD_SUCCESS; } -DEFUN (ipv6_ospf6_advertise_prefix_list, - ipv6_ospf6_advertise_prefix_list_cmd, - "ipv6 ospf6 advertise prefix-list WORD", - IP6_STR - OSPF6_STR - "Advertising options\n" - "Filter prefix using prefix-list\n" - "Prefix list name\n" - ) +DEFUN(ipv6_ospf6_advertise_prefix_list, + ipv6_ospf6_advertise_prefix_list_cmd, + "ipv6 ospf6 advertise prefix-list PREFIXLIST6_NAME", + IP6_STR + OSPF6_STR + "Advertising options\n" + "Filter prefix using prefix-list\n" + "Prefix list name\n") { VTY_DECLVAR_CONTEXT(interface, ifp); int idx_word = 4; @@ -2512,15 +2558,15 @@ DEFUN (ipv6_ospf6_advertise_prefix_list, return CMD_SUCCESS; } -DEFUN (no_ipv6_ospf6_advertise_prefix_list, - no_ipv6_ospf6_advertise_prefix_list_cmd, - "no ipv6 ospf6 advertise prefix-list [WORD]", - NO_STR - IP6_STR - OSPF6_STR - "Advertising options\n" - "Filter prefix using prefix-list\n" - "Prefix list name\n") +DEFUN(no_ipv6_ospf6_advertise_prefix_list, + no_ipv6_ospf6_advertise_prefix_list_cmd, + "no ipv6 ospf6 advertise prefix-list [PREFIXLIST6_NAME]", + NO_STR + IP6_STR + OSPF6_STR + "Advertising options\n" + "Filter prefix using prefix-list\n" + "Prefix list name\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct ospf6_interface *oi; @@ -2550,12 +2596,13 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_list, DEFUN (ipv6_ospf6_network, ipv6_ospf6_network_cmd, - "ipv6 ospf6 network ", + "ipv6 ospf6 network ", IP6_STR OSPF6_STR "Network type\n" "Specify OSPF6 broadcast network\n" "Specify OSPF6 point-to-point network\n" + "Specify OSPF6 point-to-multipoint network\n" ) { VTY_DECLVAR_CONTEXT(interface, ifp); @@ -2581,6 +2628,11 @@ DEFUN (ipv6_ospf6_network, return CMD_SUCCESS; } oi->type = OSPF_IFTYPE_POINTOPOINT; + } else if (strncmp(argv[idx_network]->arg, "point-to-m", 10) == 0) { + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { + return CMD_SUCCESS; + } + oi->type = OSPF_IFTYPE_POINTOMULTIPOINT; } /* Reset the interface */ @@ -2592,13 +2644,14 @@ DEFUN (ipv6_ospf6_network, DEFUN (no_ipv6_ospf6_network, no_ipv6_ospf6_network_cmd, - "no ipv6 ospf6 network []", + "no ipv6 ospf6 network []", NO_STR IP6_STR OSPF6_STR "Set default network type\n" "Specify OSPF6 broadcast network\n" - "Specify OSPF6 point-to-point network\n") + "Specify OSPF6 point-to-point network\n" + "Specify OSPF6 point-to-multipoint network\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct ospf6_interface *oi; @@ -2607,9 +2660,8 @@ DEFUN (no_ipv6_ospf6_network, assert(ifp); oi = (struct ospf6_interface *)ifp->info; - if (oi == NULL) { + if (oi == NULL) return CMD_SUCCESS; - } oi->type_cfg = false; @@ -2626,6 +2678,107 @@ DEFUN (no_ipv6_ospf6_network, return CMD_SUCCESS; } +DEFPY (ipv6_ospf6_p2xp_only_cfg_neigh, + ipv6_ospf6_p2xp_only_cfg_neigh_cmd, + "[no] ipv6 ospf6 p2p-p2mp config-neighbors-only", + NO_STR + IP6_STR + OSPF6_STR + "Point-to-point and Point-to-Multipoint parameters\n" + "Only form adjacencies with explicitly configured neighbors\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi = ifp->info; + + if (no) { + if (!oi) + return CMD_SUCCESS; + + oi->p2xp_only_cfg_neigh = false; + return CMD_SUCCESS; + } + + if (!oi) + oi = ospf6_interface_create(ifp); + + oi->p2xp_only_cfg_neigh = true; + return CMD_SUCCESS; +} + +DEFPY (ipv6_ospf6_p2xp_no_multicast_hello, + ipv6_ospf6_p2xp_no_multicast_hello_cmd, + "[no] ipv6 ospf6 p2p-p2mp disable-multicast-hello", + NO_STR + IP6_STR + OSPF6_STR + "Point-to-point and Point-to-Multipoint parameters\n" + "Do not send multicast hellos\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi = ifp->info; + + if (no) { + if (!oi) + return CMD_SUCCESS; + + oi->p2xp_no_multicast_hello = false; + return CMD_SUCCESS; + } + + if (!oi) + oi = ospf6_interface_create(ifp); + + oi->p2xp_no_multicast_hello = true; + return CMD_SUCCESS; +} + +DEFPY (ipv6_ospf6_p2xp_connected_pfx, + ipv6_ospf6_p2xp_connected_pfx_cmd, + "[no] ipv6 ospf6 p2p-p2mp connected-prefixes ", + NO_STR + IP6_STR + OSPF6_STR + "Point-to-point and Point-to-Multipoint parameters\n" + "Adjust handling of directly connected prefixes\n" + "Advertise prefixes and own /128 (default for PtP)\n" + "Ignore, only advertise own /128 (default for PtMP)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi = ifp->info; + bool old_incl, old_excl; + + if (no && !oi) + return CMD_SUCCESS; + + if (!oi) + oi = ospf6_interface_create(ifp); + + old_incl = oi->p2xp_connected_pfx_include; + old_excl = oi->p2xp_connected_pfx_exclude; + oi->p2xp_connected_pfx_include = false; + oi->p2xp_connected_pfx_exclude = false; + + if (incl && !no) + oi->p2xp_connected_pfx_include = true; + if (excl && !no) + oi->p2xp_connected_pfx_exclude = true; + + if (oi->p2xp_connected_pfx_include != old_incl || + oi->p2xp_connected_pfx_exclude != old_excl) + ospf6_interface_connected_route_update(ifp); + return CMD_SUCCESS; +} + +ALIAS (ipv6_ospf6_p2xp_connected_pfx, + no_ipv6_ospf6_p2xp_connected_pfx_cmd, + "no ipv6 ospf6 p2p-p2mp connected-prefixes", + NO_STR + IP6_STR + OSPF6_STR + "Point-to-point and Point-to-Multipoint parameters\n" + "Adjust handling of directly connected prefixes\n") + + static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) { struct ospf6_interface *oi; @@ -2685,7 +2838,10 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) if (oi->mtu_ignore) vty_out(vty, " ipv6 ospf6 mtu-ignore\n"); - if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT) + if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + vty_out(vty, + " ipv6 ospf6 network point-to-multipoint\n"); + else if (oi->type_cfg && oi->type == OSPF_IFTYPE_POINTOPOINT) vty_out(vty, " ipv6 ospf6 network point-to-point\n"); else if (oi->type_cfg && oi->type == OSPF_IFTYPE_BROADCAST) vty_out(vty, " ipv6 ospf6 network broadcast\n"); @@ -2694,7 +2850,22 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf) vty_out(vty, " ipv6 ospf6 graceful-restart hello-delay %u\n", oi->gr.hello_delay.interval); + if (oi->p2xp_only_cfg_neigh) + vty_out(vty, + " ipv6 ospf6 p2p-p2mp config-neighbors-only\n"); + + if (oi->p2xp_no_multicast_hello) + vty_out(vty, + " ipv6 ospf6 p2p-p2mp disable-multicast-hello\n"); + if (oi->p2xp_connected_pfx_include) + vty_out(vty, + " ipv6 ospf6 p2p-p2mp connected-prefixes include\n"); + else if (oi->p2xp_connected_pfx_exclude) + vty_out(vty, + " ipv6 ospf6 p2p-p2mp connected-prefixes exclude\n"); + + config_write_ospf6_p2xp_neighbor(vty, oi); ospf6_bfd_write_config(vty, oi); ospf6_auth_write_config(vty, &oi->at_data); @@ -2732,10 +2903,10 @@ static int ospf6_ifp_create(struct interface *ifp) static int ospf6_ifp_up(struct interface *ifp) { if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug( - "Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6, ifp->bandwidth); + zlog_debug("Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d", + ifp->name, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, + ifp->mtu6, ifp->bandwidth); ospf6_interface_state_update(ifp); @@ -2745,10 +2916,10 @@ static int ospf6_ifp_up(struct interface *ifp) static int ospf6_ifp_down(struct interface *ifp) { if (IS_OSPF6_DEBUG_ZEBRA(RECV)) - zlog_debug( - "Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6, ifp->bandwidth); + zlog_debug("Zebra Interface state change: %s index %d flags %llx metric %d mtu %d bandwidth %d", + ifp->name, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, + ifp->mtu6, ifp->bandwidth); ospf6_interface_state_update(ifp); @@ -2775,13 +2946,14 @@ void ospf6_interface_init(void) { /* Install interface node. */ if_cmd_init(config_write_interface); - if_zapi_callbacks(ospf6_ifp_create, ospf6_ifp_up, - ospf6_ifp_down, ospf6_ifp_destroy); + hook_register_prio(if_real, 0, ospf6_ifp_create); + hook_register_prio(if_up, 0, ospf6_ifp_up); + hook_register_prio(if_down, 0, ospf6_ifp_down); + hook_register_prio(if_unreal, 0, ospf6_ifp_destroy); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); - install_element(VIEW_NODE, - &show_ipv6_ospf6_interface_ifname_prefix_cmd); + install_element(VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_interface_traffic_cmd); install_element(INTERFACE_NODE, &ipv6_ospf6_area_cmd); @@ -2819,6 +2991,11 @@ void ospf6_interface_init(void) install_element(INTERFACE_NODE, &ipv6_ospf6_network_cmd); install_element(INTERFACE_NODE, &no_ipv6_ospf6_network_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_only_cfg_neigh_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_no_multicast_hello_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_connected_pfx_cmd); + install_element(INTERFACE_NODE, &no_ipv6_ospf6_p2xp_connected_pfx_cmd); + /* reference bandwidth commands */ install_element(OSPF6_NODE, &auto_cost_reference_bandwidth_cmd); install_element(OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); @@ -2955,7 +3132,8 @@ void ospf6_auth_write_config(struct vty *vty, struct ospf6_auth_data *at_data) DEFUN(ipv6_ospf6_intf_auth_trailer_keychain, ipv6_ospf6_intf_auth_trailer_keychain_cmd, "ipv6 ospf6 authentication keychain KEYCHAIN_NAME", - IP6_STR OSPF6_STR + IP6_STR + OSPF6_STR "Enable authentication on this interface\n" "Keychain\n" "Keychain name\n") @@ -2979,8 +3157,8 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_keychain, if (oi->at_data.keychain) XFREE(MTYPE_OSPF6_AUTH_KEYCHAIN, oi->at_data.keychain); - oi->at_data.keychain = - XSTRDUP(MTYPE_OSPF6_AUTH_KEYCHAIN, argv[keychain_idx]->arg); + oi->at_data.keychain = XSTRDUP(MTYPE_OSPF6_AUTH_KEYCHAIN, + argv[keychain_idx]->arg); return CMD_SUCCESS; } @@ -2988,7 +3166,9 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_keychain, DEFUN(no_ipv6_ospf6_intf_auth_trailer_keychain, no_ipv6_ospf6_intf_auth_trailer_keychain_cmd, "no ipv6 ospf6 authentication keychain [KEYCHAIN_NAME]", - NO_STR IP6_STR OSPF6_STR + NO_STR + IP6_STR + OSPF6_STR "Enable authentication on this interface\n" "Keychain\n" "Keychain name\n") @@ -3013,11 +3193,13 @@ DEFUN(no_ipv6_ospf6_intf_auth_trailer_keychain, return CMD_SUCCESS; } -DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd, +DEFUN(ipv6_ospf6_intf_auth_trailer_key, + ipv6_ospf6_intf_auth_trailer_key_cmd, "ipv6 ospf6 authentication key-id (1-65535) hash-algo " " " "key WORD", - IP6_STR OSPF6_STR + IP6_STR + OSPF6_STR "Authentication\n" "Key ID\n" "Key ID value\n" @@ -3062,8 +3244,8 @@ DEFUN(ipv6_ospf6_intf_auth_trailer_key, ipv6_ospf6_intf_auth_trailer_key_cmd, oi->at_data.key_id = (uint16_t)strtol(argv[key_id_idx]->arg, NULL, 10); if (oi->at_data.auth_key) XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY, oi->at_data.auth_key); - oi->at_data.auth_key = - XSTRDUP(MTYPE_OSPF6_AUTH_MANUAL_KEY, argv[password_idx]->arg); + oi->at_data.auth_key = XSTRDUP(MTYPE_OSPF6_AUTH_MANUAL_KEY, + argv[password_idx]->arg); return CMD_SUCCESS; } @@ -3073,7 +3255,9 @@ DEFUN(no_ipv6_ospf6_intf_auth_trailer_key, "no ipv6 ospf6 authentication key-id [(1-65535) hash-algo " " " "key WORD]", - NO_STR IP6_STR OSPF6_STR + NO_STR + IP6_STR + OSPF6_STR "Authentication\n" "Key ID\n" "Key ID value\n" diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 5942df0ab5df..46a7c90dc74b 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -34,6 +34,25 @@ struct ospf6_auth_data { uint32_t rx_drop; /* Pkt drop due to auth fail while reading */ }; +PREDECL_RBTREE_UNIQ(ospf6_if_p2xp_neighcfgs); + +struct ospf6_if_p2xp_neighcfg { + struct ospf6_if_p2xp_neighcfgs_item item; + + struct ospf6_interface *ospf6_if; + struct in6_addr addr; + + bool cfg_cost : 1; + + uint32_t cost; + uint16_t poll_interval; + + /* NULL if down */ + struct ospf6_neighbor *active; + + struct event *t_unicast_hello; +}; + /* Interface structure */ struct ospf6_interface { /* IF info from zebra */ @@ -66,6 +85,20 @@ struct ospf6_interface { uint8_t type; bool type_cfg; + /* P2P/P2MP behavior: */ + + /* disable hellos on standard multicast? */ + bool p2xp_no_multicast_hello; + /* only allow explicitly configured neighbors? */ + bool p2xp_only_cfg_neigh; + /* override mode default for advertising connected prefixes. + * both false by default (= do include for PtP, exclude for PtMP) + */ + bool p2xp_connected_pfx_include; + bool p2xp_connected_pfx_exclude; + + struct ospf6_if_p2xp_neighcfgs_head p2xp_neighs; + /* Router Priority */ uint8_t priority; @@ -171,15 +204,16 @@ struct ospf6_interface { DECLARE_QOBJ_TYPE(ospf6_interface); /* interface state */ -#define OSPF6_INTERFACE_NONE 0 -#define OSPF6_INTERFACE_DOWN 1 -#define OSPF6_INTERFACE_LOOPBACK 2 -#define OSPF6_INTERFACE_WAITING 3 -#define OSPF6_INTERFACE_POINTTOPOINT 4 -#define OSPF6_INTERFACE_DROTHER 5 -#define OSPF6_INTERFACE_BDR 6 -#define OSPF6_INTERFACE_DR 7 -#define OSPF6_INTERFACE_MAX 8 +#define OSPF6_INTERFACE_NONE 0 +#define OSPF6_INTERFACE_DOWN 1 +#define OSPF6_INTERFACE_LOOPBACK 2 +#define OSPF6_INTERFACE_WAITING 3 +#define OSPF6_INTERFACE_POINTTOPOINT 4 +#define OSPF6_INTERFACE_POINTTOMULTIPOINT 5 +#define OSPF6_INTERFACE_DROTHER 6 +#define OSPF6_INTERFACE_BDR 7 +#define OSPF6_INTERFACE_DR 8 +#define OSPF6_INTERFACE_MAX 9 extern const char *const ospf6_interface_state_str[]; @@ -197,7 +231,7 @@ extern const char *const ospf6_interface_state_str[]; #define OSPF6_INTERFACE_TRANSDELAY 1 #define OSPF6_INTERFACE_INSTANCE_ID 0 #define OSPF6_INTERFACE_BANDWIDTH 10000 /* Mbps */ -#define OSPF6_REFERENCE_BANDWIDTH 100000 /* Mbps */ +#define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ #define OSPF6_INTERFACE_SSO_RETRY_INT 1 #define OSPF6_INTERFACE_SSO_RETRY_MAX 5 diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index eb5514adfb3f..b06796ada02c 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -242,9 +242,7 @@ void ospf6_router_lsa_originate(struct event *thread) memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - router_lsa = - (struct ospf6_router_lsa *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + router_lsa = (struct ospf6_router_lsa *)ospf6_lsa_header_end(lsa_header); ospf6_router_lsa_options_set(oa, router_lsa); @@ -305,10 +303,8 @@ void ospf6_router_lsa_originate(struct event *thread) /* Reset Buffer to fill next Router LSA */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - router_lsa = - (struct ospf6_router_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + router_lsa = (struct ospf6_router_lsa *) + ospf6_lsa_header_end(lsa_header); ospf6_router_lsa_options_set(oa, router_lsa); @@ -321,13 +317,14 @@ void ospf6_router_lsa_originate(struct event *thread) } /* Point-to-Point interfaces */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + if (oi->type == OSPF_IFTYPE_POINTOPOINT + || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) { if (on->state != OSPF6_NEIGHBOR_FULL) continue; lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; - lsdesc->metric = htons(oi->cost); + lsdesc->metric = htons(ospf6_neighbor_cost(on)); lsdesc->interface_id = htonl(oi->interface->ifindex); lsdesc->neighbor_interface_id = @@ -567,16 +564,14 @@ void ospf6_network_lsa_originate(struct event *thread) memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; network_lsa = - (struct ospf6_network_lsa *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + (struct ospf6_network_lsa *)ospf6_lsa_header_end(lsa_header); /* Collect the interface's Link-LSAs to describe network's optional capabilities */ type = htons(OSPF6_LSTYPE_LINK); for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) { - link_lsa = (struct ospf6_link_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end( + lsa->header); network_lsa->options[0] |= link_lsa->options[0]; network_lsa->options[1] |= link_lsa->options[1]; network_lsa->options[2] |= link_lsa->options[2]; @@ -710,7 +705,8 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, } start = (char *)link_lsa + sizeof(struct ospf6_link_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); + end = ospf6_lsa_end(lsa->header); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE(prefix)) { prefix = (struct ospf6_prefix *)current; @@ -799,8 +795,7 @@ void ospf6_link_lsa_originate(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end(lsa_header); /* Fill Link-LSA */ link_lsa->priority = oi->priority; @@ -870,7 +865,7 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, start = (char *)intra_prefix_lsa + sizeof(struct ospf6_intra_prefix_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); + end = ospf6_lsa_end(lsa->header); current = start; while (current + sizeof(struct ospf6_prefix) <= end) { @@ -941,7 +936,8 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, start = (char *)intra_prefix_lsa + sizeof(struct ospf6_intra_prefix_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); + end = ospf6_lsa_end(lsa->header); + for (current = start; current < end; current += OSPF6_PREFIX_SIZE(prefix)) { prefix = (struct ospf6_prefix *)current; @@ -1041,9 +1037,8 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( + lsa_header); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER); @@ -1068,6 +1063,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) if (oi->state != OSPF6_INTERFACE_LOOPBACK && oi->state != OSPF6_INTERFACE_POINTTOPOINT + && oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT && full_count != 0) { if (IS_OSPF6_DEBUG_ORIGINATE(INTRA_PREFIX)) zlog_debug(" Interface %s is not stub, ignore", @@ -1157,10 +1153,8 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) /* Prepare next buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - intra_prefix_lsa = - (struct ospf6_intra_prefix_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) + ospf6_lsa_header_end(lsa_header); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER); @@ -1267,9 +1261,8 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( + lsa_header); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_NETWORK); @@ -1324,7 +1317,8 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread) prefix_num = (unsigned short)ntohl(link_lsa->prefix_num); start = (char *)link_lsa + sizeof(struct ospf6_link_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); + end = ospf6_lsa_end(lsa->header); + for (current = start; current < end && prefix_num; current += OSPF6_PREFIX_SIZE(op)) { op = (struct ospf6_prefix *)current; @@ -1666,7 +1660,8 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa, } intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) - OSPF6_LSA_HEADER_END(lsa->header); + ospf6_lsa_header_end( + lsa->header); if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) { @@ -1747,9 +1742,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) oa = OSPF6_AREA(lsa->lsdb->data); - intra_prefix_lsa = - (struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( + lsa->header); if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER) || intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK)) ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router, @@ -1779,7 +1773,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) prefix_num = ntohs(intra_prefix_lsa->prefix_num); start = (caddr_t)intra_prefix_lsa + sizeof(struct ospf6_intra_prefix_lsa); - end = OSPF6_LSA_END(lsa->header); + end = ospf6_lsa_end(lsa->header); for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) { op = (struct ospf6_prefix *)current; if (prefix_num == 0) @@ -1977,14 +1971,13 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa) oa = OSPF6_AREA(lsa->lsdb->data); - intra_prefix_lsa = - (struct ospf6_intra_prefix_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); + intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( + lsa->header); prefix_num = ntohs(intra_prefix_lsa->prefix_num); start = (caddr_t)intra_prefix_lsa + sizeof(struct ospf6_intra_prefix_lsa); - end = OSPF6_LSA_END(lsa->header); + end = ospf6_lsa_end(lsa->header); for (current = start; current < end; current += OSPF6_PREFIX_SIZE(op)) { op = (struct ospf6_prefix *)current; if (prefix_num == 0) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index bc39579653c0..017751825f6b 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -63,10 +63,10 @@ struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa) static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, json_object *json_obj, bool use_json) { - uint8_t *start, *end, *current; + char *start, *end, *current; - start = (uint8_t *)lsa->header + sizeof(struct ospf6_lsa_header); - end = (uint8_t *)lsa->header + ntohs(lsa->header->length); + start = ospf6_lsa_header_end(lsa->header); + end = ospf6_lsa_end(lsa->header); if (use_json) { json_object_string_add(json_obj, "lsaType", "unknown"); @@ -201,10 +201,10 @@ int ospf6_lsa_is_differ(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) return 1; /* compare body */ - if (ntohs(lsa1->header->length) != ntohs(lsa2->header->length)) + if (ospf6_lsa_size(lsa1->header) != ospf6_lsa_size(lsa2->header)) return 1; - len = ntohs(lsa1->header->length) - sizeof(struct ospf6_lsa_header); + len = ospf6_lsa_size(lsa1->header) - sizeof(struct ospf6_lsa_header); return memcmp(lsa1->header + 1, lsa2->header + 1, len); } @@ -214,7 +214,7 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) if (OSPF6_LSA_IS_MAXAGE(lsa1) ^ OSPF6_LSA_IS_MAXAGE(lsa2)) return 1; - if (ntohs(lsa1->header->length) != ntohs(lsa2->header->length)) + if (ospf6_lsa_size(lsa1->header) != ospf6_lsa_size(lsa2->header)) return 1; /* Going beyond LSA headers to compare the payload only makes sense, * when both LSAs aren't header-only. */ @@ -228,14 +228,14 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) if (CHECK_FLAG(lsa1->flag, OSPF6_LSA_HEADERONLY)) return 0; - length = OSPF6_LSA_SIZE(lsa1->header) - sizeof(struct ospf6_lsa_header); + length = ospf6_lsa_size(lsa1->header) - sizeof(struct ospf6_lsa_header); /* Once upper layer verifies LSAs received, length underrun should * become a warning. */ if (length <= 0) return 0; - return memcmp(OSPF6_LSA_HEADER_END(lsa1->header), - OSPF6_LSA_HEADER_END(lsa2->header), length); + return memcmp(ospf6_lsa_header_end(lsa1->header), + ospf6_lsa_header_end(lsa2->header), length); } /* ospf6 age functions */ @@ -548,7 +548,7 @@ void ospf6_lsa_show_dump(struct vty *vty, struct ospf6_lsa *lsa, json_object *json = NULL; start = (uint8_t *)lsa->header; - end = (uint8_t *)lsa->header + ntohs(lsa->header->length); + end = (uint8_t *)ospf6_lsa_end(lsa->header); if (use_json) { json = json_object_new_object(); @@ -613,7 +613,7 @@ void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa, json_object_int_add(json_obj, "checksum", ntohs(lsa->header->checksum)); json_object_int_add(json_obj, "length", - ntohs(lsa->header->length)); + ospf6_lsa_size(lsa->header)); json_object_int_add(json_obj, "flag", lsa->flag); json_object_int_add(json_obj, "lock", lsa->lock); json_object_int_add(json_obj, "reTxCount", lsa->retrans_count); @@ -630,7 +630,7 @@ void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa, (unsigned long)ntohl(lsa->header->seqnum)); vty_out(vty, "CheckSum: %#06hx Length: %hu\n", ntohs(lsa->header->checksum), - ntohs(lsa->header->length)); + ospf6_lsa_size(lsa->header)); vty_out(vty, "Flag: %x \n", lsa->flag); vty_out(vty, "Lock: %d \n", lsa->lock); vty_out(vty, "ReTx Count: %d\n", lsa->retrans_count); @@ -720,7 +720,7 @@ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header) uint16_t lsa_size = 0; /* size of the entire LSA */ - lsa_size = ntohs(header->length); /* XXX vulnerable */ + lsa_size = ospf6_lsa_size(header); /* XXX vulnerable */ lsa = ospf6_lsa_alloc(lsa_size); @@ -947,7 +947,7 @@ unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *lsa_header) buffer - (uint8_t *)&lsa_header->age; /* should be 2 */ /* Skip the AGE field */ - uint16_t len = ntohs(lsa_header->length) - type_offset; + uint16_t len = ospf6_lsa_size(lsa_header) - type_offset; /* Checksum offset starts from "type" field, not the beginning of the lsa_header struct. The offset is 14, rather than 16. */ @@ -963,7 +963,7 @@ int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *lsa_header) buffer - (uint8_t *)&lsa_header->age; /* should be 2 */ /* Skip the AGE field */ - uint16_t len = ntohs(lsa_header->length) - type_offset; + uint16_t len = ospf6_lsa_size(lsa_header) - type_offset; return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index c9ac27df88e9..4fc2f0dd1889 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -87,10 +87,21 @@ struct ospf6_lsa_header { uint16_t length; /* LSA length */ }; -#define OSPF6_LSA_HEADER_END(h) ((caddr_t)(h) + sizeof(struct ospf6_lsa_header)) -#define OSPF6_LSA_SIZE(h) (ntohs(((struct ospf6_lsa_header *)(h))->length)) -#define OSPF6_LSA_END(h) \ - ((caddr_t)(h) + ntohs(((struct ospf6_lsa_header *)(h))->length)) +static inline char *ospf6_lsa_header_end(struct ospf6_lsa_header *header) +{ + return (char *)header + sizeof(struct ospf6_lsa_header); +} + +static inline char *ospf6_lsa_end(struct ospf6_lsa_header *header) +{ + return (char *)header + ntohs(header->length); +} + +static inline uint16_t ospf6_lsa_size(struct ospf6_lsa_header *header) +{ + return ntohs(header->length); +} + #define OSPF6_LSA_IS_TYPE(t, L) \ ((L)->header->type == htons(OSPF6_LSTYPE_##t) ? 1 : 0) #define OSPF6_LSA_IS_SAME(L1, L2) \ diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index c9cbdf8e928b..9aca5550a671 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -229,9 +229,8 @@ struct ospf6_lsa *ospf6_find_inter_prefix_lsa(struct ospf6 *ospf6, struct ospf6_inter_prefix_lsa *prefix_lsa; struct prefix prefix; - prefix_lsa = - (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END( - lsa->header); + prefix_lsa = (struct ospf6_inter_prefix_lsa *) + ospf6_lsa_header_end(lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa, diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 932304578af1..8320f11f6cce 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -24,6 +24,7 @@ #include "vrf.h" #include "bfd.h" #include "libfrr.h" +#include "libagentx.h" #include "ospf6d.h" #include "ospf6_top.h" @@ -38,8 +39,13 @@ /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" -/* Default port values. */ -#define OSPF6_VTY_PORT 2606 +/* GR and auth trailer persistent state */ +#define OSPF6D_STATE_NAME "%s/ospf6d.json", frr_libstatedir +#define OSPF6D_COMPAT_STATE_NAME "%s/ospf6d-gr.json", frr_runstatedir +/* for extra confusion, "ospf6d-at-seq-no.dat" is handled directly in + * ospf6_auth_trailer.c; the alternative would be somehow merging JSON which + * is excessive for just supporting a legacy compatibility file location + */ /* ospf6d privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_SYS_ADMIN}; @@ -103,7 +109,12 @@ static void __attribute__((noreturn)) ospf6_exit(int status) zclient_free(zclient); } + ospf6_master_delete(); + + keychain_terminate(); + frr_fini(); + exit(status); } @@ -160,18 +171,35 @@ static const struct frr_yang_module_info *const ospf6d_yang_modules[] = { &frr_vrf_info, &frr_ospf_route_map_info, &frr_ospf6_route_map_info, + &ietf_key_chain_info, + &ietf_key_chain_deviation_info, }; -FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT, +/* actual paths filled in main() */ +static char state_path[512]; +static char state_compat_path[512]; +static char *state_paths[] = { + state_path, + state_compat_path, + NULL, +}; +/* clang-format off */ +FRR_DAEMON_INFO(ospf6d, OSPF6, + .vty_port = OSPF6_VTY_PORT, .proghelp = "Implementation of the OSPFv3 routing protocol.", .signals = ospf6_signals, .n_signals = array_size(ospf6_signals), - .privs = &ospf6d_privs, .yang_modules = ospf6d_yang_modules, + .privs = &ospf6d_privs, + + .yang_modules = ospf6d_yang_modules, .n_yang_modules = array_size(ospf6d_yang_modules), -); + + .state_paths = state_paths, + ); +/* clang-format on */ /* Max wait time for config to load before accepting hellos */ #define OSPF6_PRE_CONFIG_MAX_WAIT_SECONDS 600 @@ -229,12 +257,17 @@ int main(int argc, char *argv[], char *envp[]) exit(1); } + snprintf(state_path, sizeof(state_path), OSPF6D_STATE_NAME); + snprintf(state_compat_path, sizeof(state_compat_path), + OSPF6D_COMPAT_STATE_NAME); + /* OSPF6 master init. */ ospf6_master_init(frr_init()); /* thread master */ master = om6->master; + libagentx_init(); keychain_init(); ospf6_vrf_init(); access_list_init(); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 07da9a5ec124..a6ee8d8b0162 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -221,12 +221,12 @@ void ospf6_lsupdate_print(struct ospf6_header *oh, int action) && action == OSPF6_ACTION_RECV) || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND) && action == OSPF6_ACTION_SEND)) { - - for (p = (char *)((caddr_t)lsupdate - + sizeof(struct ospf6_lsupdate)); - p < OSPF6_MESSAGE_END(oh) - && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh); - p += OSPF6_LSA_SIZE(p)) { + for (p = (char *)((caddr_t)lsupdate + + sizeof(struct ospf6_lsupdate)); + p < OSPF6_MESSAGE_END(oh) && + p + ospf6_lsa_size((struct ospf6_lsa_header *)p) <= + OSPF6_MESSAGE_END(oh); + p += ospf6_lsa_size((struct ospf6_lsa_header *)p)) { ospf6_lsa_header_print_raw( (struct ospf6_lsa_header *)p); } @@ -268,6 +268,18 @@ static struct ospf6_packet *ospf6_packet_new(size_t size) return new; } +static struct ospf6_packet *ospf6_packet_dup(struct ospf6_packet *old) +{ + struct ospf6_packet *new; + + new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet)); + new->s = stream_dup(old->s); + new->dst = old->dst; + new->length = old->length; + + return new; +} + static void ospf6_packet_free(struct ospf6_packet *op) { if (op->s) @@ -407,6 +419,25 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, hello = (struct ospf6_hello *)((caddr_t)oh + sizeof(struct ospf6_header)); + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT + || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT) + && oi->p2xp_only_cfg_neigh) { + /* NEVER, never, ever, do this on broadcast (or NBMA)! + * DR/BDR election requires everyone to talk to everyone else + * only for PtP/PtMP we can be selective in adjacencies! + */ + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + + p2xp_cfg = ospf6_if_p2xp_find(oi, src); + if (!p2xp_cfg) { + if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) + zlog_debug( + "ignoring PtP/PtMP hello from %pI6, neighbor not configured", + src); + return; + } + } + /* HelloInterval check */ if (ntohs(hello->hello_interval) != oi->hello_interval) { zlog_warn( @@ -479,7 +510,7 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, on->hello_in++; /* Always override neighbor's source address */ - memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr)); + ospf6_neighbor_lladdr_set(on, src); /* Neighbor ifindex check */ if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) { @@ -631,8 +662,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, "Neighbor state is not ExStart, ignore"); return; } - /* else fall through to ExStart */ - /* fallthru */ + /* else fall through to ExStart */ + fallthrough; case OSPF6_NEIGHBOR_EXSTART: /* if neighbor obeys us as our slave, schedule negotiation_done and process LSA Headers. Otherwise, ignore this message */ @@ -650,8 +681,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, on->ospf6_if->interface->vrf->name, on->name); return; } - /* fall through to exchange */ - + /* fall through to exchange */ + fallthrough; case OSPF6_NEIGHBOR_EXCHANGE: if (!memcmp(dbdesc, &on->dbdesc_last, sizeof(struct ospf6_dbdesc))) { @@ -835,8 +866,8 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh, "Neighbor state is not ExStart, ignore"); return; } - /* else fall through to ExStart */ - /* fallthru */ + /* else fall through to ExStart */ + fallthrough; case OSPF6_NEIGHBOR_EXSTART: /* If the neighbor is Master, act as Slave. Schedule negotiation_done @@ -1383,7 +1414,7 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */ return MSG_NG; } /* save on ntohs() calls here and in the LSA validator */ - lsalen = OSPF6_LSA_SIZE(lsah); + lsalen = ospf6_lsa_size(lsah); if (lsalen < OSPF6_LSA_HEADER_SIZE) { zlog_warn( "%s: malformed LSA header #%u, declared length is %u B", @@ -1615,9 +1646,10 @@ static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst, /* Process LSAs */ for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate)); - p < OSPF6_MESSAGE_END(oh) - && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh); - p += OSPF6_LSA_SIZE(p)) { + p < OSPF6_MESSAGE_END(oh) && + p + ospf6_lsa_size((struct ospf6_lsa_header *)p) <= + OSPF6_MESSAGE_END(oh); + p += ospf6_lsa_size((struct ospf6_lsa_header *)p)) { ospf6_receive_lsa(on, (struct ospf6_lsa_header *)p); } @@ -2239,8 +2271,6 @@ static void ospf6_write(struct event *thread) void ospf6_hello_send(struct event *thread) { struct ospf6_interface *oi; - struct ospf6_packet *op; - uint16_t length = OSPF6_HEADER_SIZE; oi = (struct ospf6_interface *)EVENT_ARG(thread); @@ -2266,6 +2296,20 @@ void ospf6_hello_send(struct event *thread) return; } + event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval, + &oi->thread_send_hello); + + ospf6_hello_send_addr(oi, NULL); +} + +/* used to send polls for PtP/PtMP too */ +void ospf6_hello_send_addr(struct ospf6_interface *oi, + const struct in6_addr *addr) +{ + struct ospf6_packet *op; + uint16_t length = OSPF6_HEADER_SIZE; + bool anything = false; + op = ospf6_packet_new(oi->ifmtu); ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s); @@ -2284,20 +2328,40 @@ void ospf6_hello_send(struct event *thread) /* Set packet length. */ op->length = length; - op->dst = allspfrouters6; - - ospf6_fill_hdr_checksum(oi, op); + if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT + || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT) + && !addr && oi->p2xp_no_multicast_hello) { + struct listnode *node; + struct ospf6_neighbor *on; + struct ospf6_packet *opdup; + + for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) { + if (on->state < OSPF6_NEIGHBOR_INIT) + /* poll-interval for these */ + continue; + + opdup = ospf6_packet_dup(op); + opdup->dst = on->linklocal_addr; + ospf6_fill_hdr_checksum(oi, opdup); + ospf6_packet_add_top(oi, opdup); + anything = true; + } - /* Add packet to the top of the interface output queue, so that they - * can't get delayed by things like long queues of LS Update packets - */ - ospf6_packet_add_top(oi, op); + ospf6_packet_free(op); + } else { + op->dst = addr ? *addr : allspfrouters6; - /* set next thread */ - event_add_timer(master, ospf6_hello_send, oi, oi->hello_interval, - &oi->thread_send_hello); + /* Add packet to the top of the interface output queue, so that + * they can't get delayed by things like long queues of LS + * Update packets + */ + ospf6_fill_hdr_checksum(oi, op); + ospf6_packet_add_top(oi, op); + anything = true; + } - OSPF6_MESSAGE_WRITE_ON(oi); + if (anything) + OSPF6_MESSAGE_WRITE_ON(oi); } static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s) @@ -2639,7 +2703,7 @@ static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) { - if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) > + if ((length + ospf6_lsa_size(lsa->header) + OSPF6_HEADER_SIZE) > ospf6_packet_max(on->ospf6_if)) { ospf6_fill_header(on->ospf6_if, (*op)->s, length + OSPF6_HEADER_SIZE); @@ -2656,9 +2720,9 @@ static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); } ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay); - stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header)); + stream_put((*op)->s, lsa->header, ospf6_lsa_size(lsa->header)); (*lsa_cnt)++; - length += OSPF6_LSA_SIZE(lsa->header); + length += ospf6_lsa_size(lsa->header); assert(lsa->lock == 2); ospf6_lsdb_remove(lsa, on->lsupdate_list); } @@ -2676,7 +2740,7 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(on->retrans_list, lsa, lsanext)) { - if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) > + if ((length + ospf6_lsa_size(lsa->header) + OSPF6_HEADER_SIZE) > ospf6_packet_max(on->ospf6_if)) { ospf6_fill_header(on->ospf6_if, (*op)->s, length + OSPF6_HEADER_SIZE); @@ -2700,9 +2764,9 @@ static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); } ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay); - stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header)); + stream_put((*op)->s, lsa->header, ospf6_lsa_size(lsa->header)); (*lsa_cnt)++; - length += OSPF6_LSA_SIZE(lsa->header); + length += ospf6_lsa_size(lsa->header); } return length; } @@ -2786,9 +2850,9 @@ int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on, /* skip over fixed header */ stream_forward_endp(op->s, OSPF6_LS_UPD_MIN_SIZE); ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay); - stream_put(op->s, lsa->header, OSPF6_LSA_SIZE(lsa->header)); - length = OSPF6_HEADER_SIZE + OSPF6_LS_UPD_MIN_SIZE - + OSPF6_LSA_SIZE(lsa->header); + stream_put(op->s, lsa->header, ospf6_lsa_size(lsa->header)); + length = OSPF6_HEADER_SIZE + OSPF6_LS_UPD_MIN_SIZE + + ospf6_lsa_size(lsa->header); ospf6_fill_header(on->ospf6_if, op->s, length); ospf6_fill_lsupdate_header(op->s, 1); op->length = length; @@ -2814,7 +2878,7 @@ static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi, stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE); for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) { - if (length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE > + if (length + ospf6_lsa_size(lsa->header) + OSPF6_HEADER_SIZE > ospf6_packet_max(oi)) { ospf6_fill_header(oi, (*op)->s, length + OSPF6_HEADER_SIZE); @@ -2832,9 +2896,9 @@ static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi, } ospf6_lsa_age_update_to_send(lsa, oi->transdelay); - stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header)); + stream_put((*op)->s, lsa->header, ospf6_lsa_size(lsa->header)); (*lsa_cnt)++; - length += OSPF6_LSA_SIZE(lsa->header); + length += ospf6_lsa_size(lsa->header); assert(lsa->lock == 2); ospf6_lsdb_remove(lsa, oi->lsupdate_list); diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h index 2b25b074457b..24340793fffb 100644 --- a/ospf6d/ospf6_message.h +++ b/ospf6d/ospf6_message.h @@ -50,6 +50,8 @@ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ #define OSPF6_MESSAGE_TYPE_MAX 0x6 /* same as OSPF6_MESSAGE_TYPE_ALL */ +struct ospf6_interface; + struct ospf6_packet { struct ospf6_packet *next; @@ -169,6 +171,9 @@ extern void ospf6_lsupdate_send_neighbor(struct event *thread); extern void ospf6_lsack_send_interface(struct event *thread); extern void ospf6_lsack_send_neighbor(struct event *thread); +extern void ospf6_hello_send_addr(struct ospf6_interface *oi, + const struct in6_addr *addr); + extern int config_write_ospf6_debug_message(struct vty *); extern void install_element_ospf6_debug_message(void); extern const char *ospf6_message_type(int type); diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index e1aec06f8e8b..0e44f2a1428b 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -34,6 +34,16 @@ #include "lib/json.h" DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR_P2XP_CFG, + "OSPF6 PtP/PtMP neighbor config"); + +static int ospf6_if_p2xp_neighcfg_cmp(const struct ospf6_if_p2xp_neighcfg *a, + const struct ospf6_if_p2xp_neighcfg *b); + +DECLARE_RBTREE_UNIQ(ospf6_if_p2xp_neighcfgs, struct ospf6_if_p2xp_neighcfg, + item, ospf6_if_p2xp_neighcfg_cmp); + +static void p2xp_neigh_refresh(struct ospf6_neighbor *on, uint32_t prev_cost); DEFINE_HOOK(ospf6_neighbor_change, (struct ospf6_neighbor * on, int state, int next_state), @@ -42,13 +52,14 @@ DEFINE_HOOK(ospf6_neighbor_change, unsigned char conf_debug_ospf6_neighbor = 0; const char *const ospf6_neighbor_state_str[] = { - "None", "Down", "Attempt", "Init", "Twoway", - "ExStart", "ExChange", "Loading", "Full", NULL}; + "None", "Down", "Attempt", "Init", "Twoway", + "ExStart", "ExChange", "Loading", "Full", NULL +}; const char *const ospf6_neighbor_event_str[] = { - "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", - "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", - "BadLSReq", "1-WayReceived", "InactivityTimer", + "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", + "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", + "BadLSReq", "1-WayReceived", "InactivityTimer", }; int ospf6_neighbor_cmp(void *va, void *vb) @@ -119,8 +130,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, on = XCALLOC(MTYPE_OSPF6_NEIGHBOR, sizeof(struct ospf6_neighbor)); inet_ntop(AF_INET, &router_id, buf, sizeof(buf)); - snprintf(on->name, sizeof(on->name), "%s%%%s", buf, - oi->interface->name); + snprintf(on->name, sizeof(on->name), "%s%%%s", buf, oi->interface->name); on->ospf6_if = oi; on->state = OSPF6_NEIGHBOR_DOWN; on->state_change = 0; @@ -150,6 +160,9 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, void ospf6_neighbor_delete(struct ospf6_neighbor *on) { + if (on->p2xp_cfg) + on->p2xp_cfg->active = NULL; + ospf6_neighbor_clear_ls_lists(on); ospf6_lsdb_remove_all(on->dbdesc_list); @@ -182,6 +195,22 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on) XFREE(MTYPE_OSPF6_NEIGHBOR, on); } +void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on, + const struct in6_addr *addr) +{ + if (IPV6_ADDR_SAME(addr, &on->linklocal_addr)) + return; + + memcpy(&on->linklocal_addr, addr, sizeof(struct in6_addr)); + + if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT || + on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT) { + uint32_t prev_cost = ospf6_neighbor_cost(on); + + p2xp_neigh_refresh(on, prev_cost); + } +} + static void ospf6_neighbor_state_change(uint8_t next_state, struct ospf6_neighbor *on, int event) { @@ -198,31 +227,28 @@ static void ospf6_neighbor_state_change(uint8_t next_state, /* log */ if (IS_OSPF6_DEBUG_NEIGHBOR(STATE)) { - zlog_debug( - "Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)", - on->name, &on->router_id, - ospf6_neighbor_state_str[prev_state], - ospf6_neighbor_state_str[next_state], - ospf6_neighbor_event_string(event)); + zlog_debug("Neighbor state change %s (Router-ID: %pI4): [%s]->[%s] (%s)", + on->name, &on->router_id, + ospf6_neighbor_state_str[prev_state], + ospf6_neighbor_state_str[next_state], + ospf6_neighbor_event_string(event)); } /* Optionally notify about adjacency changes */ if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, - OSPF6_LOG_ADJACENCY_CHANGES) - && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, - OSPF6_LOG_ADJACENCY_DETAIL) - || (next_state == OSPF6_NEIGHBOR_FULL) - || (next_state < prev_state))) - zlog_notice( - "AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)", - &on->router_id, - vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id), - on->name, ospf6_neighbor_state_str[prev_state], - ospf6_neighbor_state_str[next_state], - ospf6_neighbor_event_string(event)); - - if (prev_state == OSPF6_NEIGHBOR_FULL - || next_state == OSPF6_NEIGHBOR_FULL) { + OSPF6_LOG_ADJACENCY_CHANGES) && + (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, + OSPF6_LOG_ADJACENCY_DETAIL) || + (next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state))) + zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)", + &on->router_id, + vrf_id_to_name(on->ospf6_if->interface->vrf->vrf_id), + on->name, ospf6_neighbor_state_str[prev_state], + ospf6_neighbor_state_str[next_state], + ospf6_neighbor_event_string(event)); + + if (prev_state == OSPF6_NEIGHBOR_FULL || + next_state == OSPF6_NEIGHBOR_FULL) { if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) { OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area); if (on->ospf6_if->state == OSPF6_INTERFACE_DR) { @@ -235,12 +261,11 @@ static void ospf6_neighbor_state_change(uint8_t next_state, on->ospf6_if->area->intra_prefix_originate = 1; if (!OSPF6_GR_IS_ACTIVE_HELPER(on)) - OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB( - on->ospf6_if->area); + OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(on->ospf6_if->area); - if ((prev_state == OSPF6_NEIGHBOR_LOADING - || prev_state == OSPF6_NEIGHBOR_EXCHANGE) - && next_state == OSPF6_NEIGHBOR_FULL) { + if ((prev_state == OSPF6_NEIGHBOR_LOADING || + prev_state == OSPF6_NEIGHBOR_EXCHANGE) && + next_state == OSPF6_NEIGHBOR_FULL) { OSPF6_AS_EXTERN_LSA_SCHEDULE(on->ospf6_if); on->ospf6_if->area->full_nbrs++; } @@ -249,10 +274,10 @@ static void ospf6_neighbor_state_change(uint8_t next_state, on->ospf6_if->area->full_nbrs--; } - if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE - || prev_state == OSPF6_NEIGHBOR_LOADING) - && (next_state != OSPF6_NEIGHBOR_EXCHANGE - && next_state != OSPF6_NEIGHBOR_LOADING)) + if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE || + prev_state == OSPF6_NEIGHBOR_LOADING) && + (next_state != OSPF6_NEIGHBOR_EXCHANGE && + next_state != OSPF6_NEIGHBOR_LOADING)) ospf6_maxage_remove(on->ospf6_if->area->ospf6); hook_call(ospf6_neighbor_change, on, next_state, prev_state); @@ -262,13 +287,14 @@ static void ospf6_neighbor_state_change(uint8_t next_state, /* RFC2328 section 10.4 */ static int need_adjacency(struct ospf6_neighbor *on) { - if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT - || on->ospf6_if->state == OSPF6_INTERFACE_DR - || on->ospf6_if->state == OSPF6_INTERFACE_BDR) + if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT || + on->ospf6_if->state == OSPF6_INTERFACE_POINTTOMULTIPOINT || + on->ospf6_if->state == OSPF6_INTERFACE_DR || + on->ospf6_if->state == OSPF6_INTERFACE_BDR) return 1; - if (on->ospf6_if->drouter == on->router_id - || on->ospf6_if->bdrouter == on->router_id) + if (on->ospf6_if->drouter == on->router_id || + on->ospf6_if->bdrouter == on->router_id) return 1; return 0; @@ -422,13 +448,12 @@ void exchange_done(struct event *thread) /* Check loading state. */ void ospf6_check_nbr_loading(struct ospf6_neighbor *on) { - /* RFC2328 Section 10.9: When the neighbor responds to these requests with the proper Link State Update packet(s), the Link state request list is truncated and a new Link State Request packet is sent. */ - if ((on->state == OSPF6_NEIGHBOR_LOADING) - || (on->state == OSPF6_NEIGHBOR_EXCHANGE)) { + if ((on->state == OSPF6_NEIGHBOR_LOADING) || + (on->state == OSPF6_NEIGHBOR_EXCHANGE)) { if (on->request_list->count == 0) event_add_event(master, loading_done, on, 0, &on->event_loading_done); @@ -587,9 +612,8 @@ void inactivity_timer(struct event *thread) on->drouter = on->prev_drouter = 0; on->bdrouter = on->prev_bdrouter = 0; - ospf6_neighbor_state_change( - OSPF6_NEIGHBOR_DOWN, on, - OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); + ospf6_neighbor_state_change(OSPF6_NEIGHBOR_DOWN, on, + OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); event_add_event(master, neighbor_change, on->ospf6_if, 0, NULL); listnode_delete(on->ospf6_if->neighbor_list, on); @@ -597,9 +621,8 @@ void inactivity_timer(struct event *thread) } else { if (IS_DEBUG_OSPF6_GR) - zlog_debug( - "%s, Acting as HELPER for this neighbour, So restart the dead timer.", - __PRETTY_FUNCTION__); + zlog_debug("%s, Acting as HELPER for this neighbour, So restart the dead timer.", + __PRETTY_FUNCTION__); event_add_timer(master, inactivity_timer, on, on->ospf6_if->dead_interval, @@ -607,8 +630,235 @@ void inactivity_timer(struct event *thread) } } +/* P2P/P2MP stuff */ + +uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on) +{ + if (on->p2xp_cfg && on->p2xp_cfg->cfg_cost) + return on->p2xp_cfg->cost; + return on->ospf6_if->cost; +} + +static int ospf6_if_p2xp_neighcfg_cmp(const struct ospf6_if_p2xp_neighcfg *a, + const struct ospf6_if_p2xp_neighcfg *b) +{ + return IPV6_ADDR_CMP(&a->addr, &b->addr); +} + +struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi, + const struct in6_addr *addr) +{ + struct ospf6_if_p2xp_neighcfg ref; + + if (!oi) + return NULL; + + ref.addr = *addr; + return ospf6_if_p2xp_neighcfgs_find(&oi->p2xp_neighs, &ref); +} + +static struct ospf6_if_p2xp_neighcfg * +ospf6_if_p2xp_get(struct ospf6_interface *oi, const struct in6_addr *addr) +{ + struct ospf6_if_p2xp_neighcfg ref, *ret; + + if (!oi) + return NULL; + + ref.addr = *addr; + ret = ospf6_if_p2xp_neighcfgs_find(&oi->p2xp_neighs, &ref); + if (!ret) { + ret = XCALLOC(MTYPE_OSPF6_NEIGHBOR_P2XP_CFG, sizeof(*ret)); + ret->addr = *addr; + ret->ospf6_if = oi; + + ospf6_if_p2xp_neighcfgs_add(&oi->p2xp_neighs, ret); + } + + return ret; +} + +static void ospf6_if_p2xp_destroy(struct ospf6_if_p2xp_neighcfg *p2xp_cfg) +{ + EVENT_OFF(p2xp_cfg->t_unicast_hello); + ospf6_if_p2xp_neighcfgs_del(&p2xp_cfg->ospf6_if->p2xp_neighs, p2xp_cfg); + + XFREE(MTYPE_OSPF6_NEIGHBOR_P2XP_CFG, p2xp_cfg); +} + +static void p2xp_neigh_refresh(struct ospf6_neighbor *on, uint32_t prev_cost) +{ + if (on->p2xp_cfg) + on->p2xp_cfg->active = NULL; + on->p2xp_cfg = ospf6_if_p2xp_find(on->ospf6_if, &on->linklocal_addr); + if (on->p2xp_cfg) + on->p2xp_cfg->active = on; + + if (ospf6_neighbor_cost(on) != prev_cost) + OSPF6_ROUTER_LSA_SCHEDULE(on->ospf6_if->area); +} /* vty functions */ + +#ifndef VTYSH_EXTRACT_PL +#include "ospf6d/ospf6_neighbor_clippy.c" +#endif + +DEFPY (ipv6_ospf6_p2xp_neigh, + ipv6_ospf6_p2xp_neigh_cmd, + "[no] ipv6 ospf6 neighbor X:X::X:X", + NO_STR + IP6_STR + OSPF6_STR + "Configure static neighbor\n" + "Neighbor link-local address\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi = ifp->info; + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + + if (!oi) { + if (no) + return CMD_SUCCESS; + oi = ospf6_interface_create(ifp); + } + + if (no) { + struct ospf6_neighbor *on; + uint32_t prev_cost = 0; + + p2xp_cfg = ospf6_if_p2xp_find(oi, &neighbor); + if (!p2xp_cfg) + return CMD_SUCCESS; + + on = p2xp_cfg->active; + if (on) + prev_cost = ospf6_neighbor_cost(on); + + p2xp_cfg->active = NULL; + ospf6_if_p2xp_destroy(p2xp_cfg); + + if (on) { + on->p2xp_cfg = NULL; + p2xp_neigh_refresh(on, prev_cost); + } + return CMD_SUCCESS; + } + + (void)ospf6_if_p2xp_get(oi, &neighbor); + return CMD_SUCCESS; +} + +DEFPY (ipv6_ospf6_p2xp_neigh_cost, + ipv6_ospf6_p2xp_neigh_cost_cmd, + "[no] ipv6 ospf6 neighbor X:X::X:X cost (1-65535)", + NO_STR + IP6_STR + OSPF6_STR + "Configure static neighbor\n" + "Neighbor link-local address\n" + "Outgoing metric for this neighbor\n" + "Outgoing metric for this neighbor\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi = ifp->info; + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + uint32_t prev_cost = 0; + + if (!oi) { + if (no) + return CMD_SUCCESS; + oi = ospf6_interface_create(ifp); + } + + p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor); + + if (p2xp_cfg->active) + prev_cost = ospf6_neighbor_cost(p2xp_cfg->active); + + if (no) { + p2xp_cfg->cfg_cost = false; + p2xp_cfg->cost = 0; + } else { + p2xp_cfg->cfg_cost = true; + p2xp_cfg->cost = cost; + } + + if (p2xp_cfg->active) + p2xp_neigh_refresh(p2xp_cfg->active, prev_cost); + return CMD_SUCCESS; +} + +static void p2xp_unicast_hello_send(struct event *event); + +static void p2xp_unicast_hello_sched(struct ospf6_if_p2xp_neighcfg *p2xp_cfg) +{ + if (!p2xp_cfg->poll_interval || + (p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOMULTIPOINT && + p2xp_cfg->ospf6_if->state != OSPF6_INTERFACE_POINTTOPOINT)) + /* state check covers DOWN state too */ + EVENT_OFF(p2xp_cfg->t_unicast_hello); + else + event_add_timer(master, p2xp_unicast_hello_send, p2xp_cfg, + p2xp_cfg->poll_interval, + &p2xp_cfg->t_unicast_hello); +} + +void ospf6_if_p2xp_up(struct ospf6_interface *oi) +{ + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + + frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg) + p2xp_unicast_hello_sched(p2xp_cfg); +} + +static void p2xp_unicast_hello_send(struct event *event) +{ + struct ospf6_if_p2xp_neighcfg *p2xp_cfg = EVENT_ARG(event); + struct ospf6_interface *oi = p2xp_cfg->ospf6_if; + + if (oi->state != OSPF6_INTERFACE_POINTTOPOINT && + oi->state != OSPF6_INTERFACE_POINTTOMULTIPOINT) + return; + + p2xp_unicast_hello_sched(p2xp_cfg); + + if (p2xp_cfg->active && p2xp_cfg->active->state >= OSPF6_NEIGHBOR_INIT) + return; + + ospf6_hello_send_addr(oi, &p2xp_cfg->addr); +} + +DEFPY (ipv6_ospf6_p2xp_neigh_poll_interval, + ipv6_ospf6_p2xp_neigh_poll_interval_cmd, + "[no] ipv6 ospf6 neighbor X:X::X:X poll-interval (1-65535)", + NO_STR + IP6_STR + OSPF6_STR + "Configure static neighbor\n" + "Neighbor link-local address\n" + "Send unicast hellos to neighbor when down\n" + "Unicast hello interval when down (seconds)\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf6_interface *oi = ifp->info; + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + + if (!oi) { + if (no) + return CMD_SUCCESS; + oi = ospf6_interface_create(ifp); + } + if (no) + poll_interval = 0; + + p2xp_cfg = ospf6_if_p2xp_get(oi, &neighbor); + p2xp_cfg->poll_interval = poll_interval; + + p2xp_unicast_hello_sched(p2xp_cfg); + return CMD_SUCCESS; +} + /* show neighbor structure */ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on, json_object *json_array, bool use_json) @@ -631,8 +881,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on, /* Dead time */ h = m = s = 0; if (on->inactivity_timer) { - s = monotime_until(&on->inactivity_timer->u.sands, NULL) - / 1000000LL; + s = monotime_until(&on->inactivity_timer->u.sands, NULL) / + 1000000LL; h = s / 3600; s -= h * 3600; m = s / 60; @@ -643,6 +893,8 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on, /* Neighbor State */ if (on->ospf6_if->type == OSPF_IFTYPE_POINTOPOINT) snprintf(nstate, sizeof(nstate), "PointToPoint"); + else if (on->ospf6_if->type == OSPF_IFTYPE_POINTOMULTIPOINT) + snprintf(nstate, sizeof(nstate), "PtMultipoint"); else { if (on->router_id == on->drouter) snprintf(nstate, sizeof(nstate), "DR"); @@ -673,9 +925,9 @@ static void ospf6_neighbor_show(struct vty *vty, struct ospf6_neighbor *on, json_object_string_add(json_route, "duration", duration); json_object_string_add(json_route, "interfaceName", on->ospf6_if->interface->name); - json_object_string_add( - json_route, "interfaceState", - ospf6_interface_state_str[on->ospf6_if->state]); + json_object_string_add(json_route, "interfaceState", + ospf6_interface_state_str + [on->ospf6_if->state]); json_object_array_add(json_array, json_route); } else @@ -720,9 +972,9 @@ static void ospf6_neighbor_show_drchoice(struct vty *vty, json_object_string_add(json_route, "bdRouter", bdrouter); json_object_string_add(json_route, "interfaceName", on->ospf6_if->interface->name); - json_object_string_add( - json_route, "interfaceState", - ospf6_interface_state_str[on->ospf6_if->state]); + json_object_string_add(json_route, "interfaceState", + ospf6_interface_state_str + [on->ospf6_if->state]); json_object_array_add(json_array, json_route); } else @@ -763,6 +1015,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty, on->ospf6_if->interface->ifindex); json_object_int_add(json_neighbor, "neighborInterfaceIndex", on->ifindex); + json_object_string_addf(json_neighbor, "localLinkLocalAddress", + "%pI6", on->ospf6_if->linklocal_addr); json_object_string_add(json_neighbor, "linkLocalAddress", linklocal_addr); json_object_string_add(json_neighbor, "neighborState", @@ -777,9 +1031,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty, (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) ? "Initial " : ""), - (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) - ? "More" - : ""), + (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More" + : ""), (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) ? "Master" : "Slave")); @@ -793,8 +1046,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty, json_object_int_add(json_neighbor, "summaryListCount", on->summary_list->count); for (ALL_LSDB(on->summary_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "summaryListLsa", json_array); @@ -802,8 +1055,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty, json_object_int_add(json_neighbor, "requestListCount", on->request_list->count); for (ALL_LSDB(on->request_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "requestListLsa", json_array); @@ -811,8 +1064,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty, json_object_int_add(json_neighbor, "reTransListCount", on->retrans_list->count); for (ALL_LSDB(on->retrans_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "reTransListLsa", json_array); @@ -825,14 +1078,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty, on->dbdesc_list->count); json_object_string_add(json_neighbor, "pendingLsaDbDescTime", duration); - json_object_string_add( - json_neighbor, "dbDescSendThread", - (event_is_scheduled(on->thread_send_dbdesc) ? "on" - : "off")); + json_object_string_add(json_neighbor, "dbDescSendThread", + (event_is_scheduled(on->thread_send_dbdesc) + ? "on" + : "off")); json_array = json_object_new_array(); for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "pendingLsaDbDesc", json_array); @@ -844,35 +1097,35 @@ static void ospf6_neighbor_show_detail(struct vty *vty, on->request_list->count); json_object_string_add(json_neighbor, "pendingLsaLsReqTime", duration); - json_object_string_add( - json_neighbor, "lsReqSendThread", - (event_is_scheduled(on->thread_send_lsreq) ? "on" - : "off")); + json_object_string_add(json_neighbor, "lsReqSendThread", + (event_is_scheduled(on->thread_send_lsreq) + ? "on" + : "off")); json_array = json_object_new_array(); for (ALL_LSDB(on->request_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "pendingLsaLsReq", json_array); timerclear(&res); if (event_is_scheduled(on->thread_send_lsupdate)) - timersub(&on->thread_send_lsupdate->u.sands, &now, - &res); + timersub(&on->thread_send_lsupdate->u.sands, &now, &res); timerstring(&res, duration, sizeof(duration)); json_object_int_add(json_neighbor, "pendingLsaLsUpdateCount", on->lsupdate_list->count); json_object_string_add(json_neighbor, "pendingLsaLsUpdateTime", duration); - json_object_string_add( - json_neighbor, "lsUpdateSendThread", - (event_is_scheduled(on->thread_send_lsupdate) ? "on" - : "off")); + json_object_string_add(json_neighbor, "lsUpdateSendThread", + (event_is_scheduled( + on->thread_send_lsupdate) + ? "on" + : "off")); json_array = json_object_new_array(); for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "pendingLsaLsUpdate", json_array); @@ -884,14 +1137,14 @@ static void ospf6_neighbor_show_detail(struct vty *vty, on->lsack_list->count); json_object_string_add(json_neighbor, "pendingLsaLsAckTime", duration); - json_object_string_add( - json_neighbor, "lsAckSendThread", - (event_is_scheduled(on->thread_send_lsack) ? "on" - : "off")); + json_object_string_add(json_neighbor, "lsAckSendThread", + (event_is_scheduled(on->thread_send_lsack) + ? "on" + : "off")); json_array = json_object_new_array(); for (ALL_LSDB(on->lsack_list, lsa, lsanext)) - json_object_array_add( - json_array, json_object_new_string(lsa->name)); + json_object_array_add(json_array, + json_object_new_string(lsa->name)); json_object_object_add(json_neighbor, "pendingLsaLsAck", json_array); @@ -900,36 +1153,36 @@ static void ospf6_neighbor_show_detail(struct vty *vty, if (on->auth_present == true) { json_object_string_add(json_neighbor, "authStatus", "enabled"); - json_object_int_add( - json_neighbor, "recvdHelloHigherSeqNo", - on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]); - json_object_int_add( - json_neighbor, "recvdHelloLowerSeqNo", - on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]); - json_object_int_add( - json_neighbor, "recvdDBDescHigherSeqNo", - on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]); - json_object_int_add( - json_neighbor, "recvdDBDescLowerSeqNo", - on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]); - json_object_int_add( - json_neighbor, "recvdLSReqHigherSeqNo", - on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]); - json_object_int_add( - json_neighbor, "recvdLSReqLowerSeqNo", - on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]); - json_object_int_add( - json_neighbor, "recvdLSUpdHigherSeqNo", - on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]); - json_object_int_add( - json_neighbor, "recvdLSUpdLowerSeqNo", - on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]); - json_object_int_add( - json_neighbor, "recvdLSAckHigherSeqNo", - on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); - json_object_int_add( - json_neighbor, "recvdLSAckLowerSeqNo", - on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); + json_object_int_add(json_neighbor, + "recvdHelloHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add(json_neighbor, + "recvdHelloLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_HELLO]); + json_object_int_add(json_neighbor, + "recvdDBDescHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add(json_neighbor, + "recvdDBDescLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_DBDESC]); + json_object_int_add(json_neighbor, + "recvdLSReqHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add(json_neighbor, + "recvdLSReqLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSREQ]); + json_object_int_add(json_neighbor, + "recvdLSUpdHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add(json_neighbor, + "recvdLSUpdLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSUPDATE]); + json_object_int_add(json_neighbor, + "recvdLSAckHigherSeqNo", + on->seqnum_h[OSPF6_MESSAGE_TYPE_LSACK]); + json_object_int_add(json_neighbor, + "recvdLSAckLowerSeqNo", + on->seqnum_l[OSPF6_MESSAGE_TYPE_LSACK]); } else json_object_string_add(json_neighbor, "authStatus", "disabled"); @@ -951,9 +1204,8 @@ static void ospf6_neighbor_show_detail(struct vty *vty, (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT) ? "Initial " : ""), - (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) - ? "More " - : ""), + (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More " + : ""), (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) ? "Master" : "Slave"), @@ -1000,8 +1252,7 @@ static void ospf6_neighbor_show_detail(struct vty *vty, timerclear(&res); if (event_is_scheduled(on->thread_send_lsupdate)) - timersub(&on->thread_send_lsupdate->u.sands, &now, - &res); + timersub(&on->thread_send_lsupdate->u.sands, &now, &res); timerstring(&res, duration, sizeof(duration)); vty_out(vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]\n", @@ -1100,13 +1351,18 @@ static void ospf6_neighbor_show_detail_common(struct vty *vty, } } -DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd, +DEFUN(show_ipv6_ospf6_neighbor, + show_ipv6_ospf6_neighbor_cmd, "show ipv6 ospf6 [vrf ] neighbor [] [json]", - SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR "All VRFs\n" "Neighbor list\n" "Display details\n" - "Display DR choices\n" JSON_STR) + "Display DR choices\n" + JSON_STR) { struct ospf6 *ospf6; struct listnode *node; @@ -1141,8 +1397,7 @@ DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd, static int ospf6_neighbor_show_common(struct vty *vty, int argc, struct cmd_token **argv, - struct ospf6 *ospf6, int idx_ipv4, - bool uj) + struct ospf6 *ospf6, int idx_ipv4, bool uj) { struct ospf6_neighbor *on; struct ospf6_interface *oi; @@ -1176,12 +1431,17 @@ static int ospf6_neighbor_show_common(struct vty *vty, int argc, return CMD_SUCCESS; } -DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd, +DEFUN(show_ipv6_ospf6_neighbor_one, + show_ipv6_ospf6_neighbor_one_cmd, "show ipv6 ospf6 [vrf ] neighbor A.B.C.D [json]", - SHOW_STR IP6_STR OSPF6_STR VRF_CMD_HELP_STR + SHOW_STR + IP6_STR + OSPF6_STR + VRF_CMD_HELP_STR "All VRFs\n" "Neighbor list\n" - "Specify Router-ID as IPv4 address notation\n" JSON_STR) + "Specify Router-ID as IPv4 address notation\n" + JSON_STR) { int idx_ipv4 = 4; struct ospf6 *ospf6; @@ -1214,6 +1474,11 @@ void ospf6_neighbor_init(void) { install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_neighbor_one_cmd); + + install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cmd); + install_element(INTERFACE_NODE, &ipv6_ospf6_p2xp_neigh_cost_cmd); + install_element(INTERFACE_NODE, + &ipv6_ospf6_p2xp_neigh_poll_interval_cmd); } DEFUN (debug_ospf6_neighbor, @@ -1287,12 +1552,11 @@ DEFUN (no_debug_ospf6, ospf6_lsa_debug_set_all(false); for (i = 0; i < 6; i++) - OSPF6_DEBUG_MESSAGE_OFF(i, - OSPF6_DEBUG_NEIGHBOR_STATE - | OSPF6_DEBUG_NEIGHBOR_EVENT); + OSPF6_DEBUG_MESSAGE_OFF(i, OSPF6_DEBUG_NEIGHBOR_STATE | + OSPF6_DEBUG_NEIGHBOR_EVENT); - OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE - | OSPF6_DEBUG_NEIGHBOR_EVENT); + OSPF6_DEBUG_NEIGHBOR_OFF(OSPF6_DEBUG_NEIGHBOR_STATE | + OSPF6_DEBUG_NEIGHBOR_EVENT); OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_TABLE); OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTRA); OSPF6_DEBUG_ROUTE_OFF(OSPF6_DEBUG_ROUTE_INTER); @@ -1316,6 +1580,25 @@ int config_write_ospf6_debug_neighbor(struct vty *vty) return 0; } +int config_write_ospf6_p2xp_neighbor(struct vty *vty, struct ospf6_interface *oi) +{ + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + + frr_each (ospf6_if_p2xp_neighcfgs, &oi->p2xp_neighs, p2xp_cfg) { + vty_out(vty, " ipv6 ospf6 neighbor %pI6\n", &p2xp_cfg->addr); + + if (p2xp_cfg->poll_interval) + vty_out(vty, + " ipv6 ospf6 neighbor %pI6 poll-interval %u\n", + &p2xp_cfg->addr, p2xp_cfg->poll_interval); + + if (p2xp_cfg->cfg_cost) + vty_out(vty, " ipv6 ospf6 neighbor %pI6 cost %u\n", + &p2xp_cfg->addr, p2xp_cfg->cost); + } + return 0; +} + void install_element_ospf6_debug_neighbor(void) { install_element(ENABLE_NODE, &debug_ospf6_neighbor_cmd); diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 226f4c1322b9..60a76215b7d9 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -6,8 +6,11 @@ #ifndef OSPF6_NEIGHBOR_H #define OSPF6_NEIGHBOR_H +#include "typesafe.h" #include "hook.h" +#include "ospf6_message.h" + /* Forward declaration(s). */ struct ospf6_area; @@ -52,6 +55,8 @@ struct ospf6_helper_info { uint32_t rejected_reason; }; +struct ospf6_if_p2xp_neighcfg; + /* Neighbor structure */ struct ospf6_neighbor { /* Neighbor Router ID String */ @@ -60,6 +65,11 @@ struct ospf6_neighbor { /* OSPFv3 Interface this neighbor belongs to */ struct ospf6_interface *ospf6_if; + /* P2P/P2MP config for this neighbor. + * can be NULL if not explicitly configured! + */ + struct ospf6_if_p2xp_neighcfg *p2xp_cfg; + /* Neighbor state */ uint8_t state; @@ -190,6 +200,14 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id, struct ospf6_interface *oi); void ospf6_neighbor_delete(struct ospf6_neighbor *on); +void ospf6_neighbor_lladdr_set(struct ospf6_neighbor *on, + const struct in6_addr *addr); +struct ospf6_if_p2xp_neighcfg *ospf6_if_p2xp_find(struct ospf6_interface *oi, + const struct in6_addr *addr); +void ospf6_if_p2xp_up(struct ospf6_interface *oi); + +uint32_t ospf6_neighbor_cost(struct ospf6_neighbor *on); + /* Neighbor event */ extern void hello_received(struct event *thread); extern void twoway_received(struct event *thread); @@ -205,6 +223,8 @@ extern void ospf6_check_nbr_loading(struct ospf6_neighbor *on); extern void ospf6_neighbor_init(void); extern int config_write_ospf6_debug_neighbor(struct vty *vty); +extern int config_write_ospf6_p2xp_neighbor(struct vty *vty, + struct ospf6_interface *oi); extern void install_element_ospf6_debug_neighbor(void); DECLARE_HOOK(ospf6_neighbor_change, diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c index 405ae9052893..ea2be20cf355 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -52,10 +52,8 @@ static int ospf6_abr_nssa_am_elected(struct ospf6_area *oa) /* Verify all the router LSA to compare the router ID */ for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) { - - router_lsa = (struct ospf6_router_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + router_lsa = (struct ospf6_router_lsa *)ospf6_lsa_header_end( + lsa->header); /* ignore non-ABR routers */ if (!CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B)) @@ -416,7 +414,7 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, } /* find the translated Type-5 for this Type-7 */ - nssa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + nssa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( type7->header); prefix.family = AF_INET6; prefix.prefixlen = nssa->prefix.prefix_length; @@ -437,12 +435,10 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - extnew = (struct ospf6_as_external_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); - ext = (struct ospf6_as_external_lsa - *)((caddr_t)(type7->header) - + sizeof(struct ospf6_lsa_header)); + extnew = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( + lsa_header); + ext = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( + type7->header); old_ptr = (caddr_t)((caddr_t)ext + sizeof(struct ospf6_as_external_lsa)); new_ptr = (caddr_t)((caddr_t)extnew @@ -550,7 +546,7 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, "%s: try to find translated Type-5 LSA for %s", __func__, type7->name); - ext_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + ext_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( type7->header); prefix.family = AF_INET6; prefix.prefixlen = ext_lsa->prefix.prefix_length; @@ -618,7 +614,7 @@ static void ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6 *ospf6; ospf6 = area->ospf6; - nssa_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + nssa_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); if (!CHECK_FLAG(nssa_lsa->prefix.prefix_options, @@ -1244,9 +1240,8 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - as_external_lsa = (struct ospf6_as_external_lsa - *)((caddr_t)lsa_header - + sizeof(struct ospf6_lsa_header)); + as_external_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( + lsa_header); p = (caddr_t)((caddr_t)as_external_lsa + sizeof(struct ospf6_as_external_lsa)); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 443032933d0f..10a1208e938d 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -363,7 +363,7 @@ void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route, case NEXTHOP_TYPE_IPV6_IFINDEX: nexthops[i].ifindex = nh->ifindex; - /* FALLTHROUGH */ + fallthrough; case NEXTHOP_TYPE_IPV6: nexthops[i].gate.ipv6 = nh->address; break; @@ -540,6 +540,10 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb) if (ra->path.area_id != rb->path.area_id) return (ntohl(ra->path.area_id) - ntohl(rb->path.area_id)); + if ((ra->prefix_options & OSPF6_PREFIX_OPTION_LA) + != (rb->prefix_options & OSPF6_PREFIX_OPTION_LA)) + return ra->prefix_options & OSPF6_PREFIX_OPTION_LA ? -1 : 1; + return 0; } diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index c2125951ec52..88813491e48d 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -67,7 +67,7 @@ static inline bool ospf6_nexthop_is_same(const struct ospf6_nexthop *nha, case NEXTHOP_TYPE_IPV6_IFINDEX: if (nha->ifindex != nhb->ifindex) return false; - /* FALLTHROUGH */ + fallthrough; case NEXTHOP_TYPE_IPV6: if (!IN6_ARE_ADDR_EQUAL(&nha->address, &nhb->address)) return false; @@ -115,6 +115,7 @@ struct ospf6_path { /* Cost */ uint8_t metric_type; uint32_t cost; + uint32_t redistribute_cost; struct prefix ls_prefix; @@ -139,6 +140,8 @@ struct ospf6_path { #define OSPF6_PATH_COST_IS_CONFIGURED(path) (path.u.cost_config != OSPF_AREA_RANGE_COST_UNSPEC) +#define OSPF6_EXT_PATH_METRIC_MAX 0x00ffffff + #include "prefix.h" #include "table.h" #include "bitfield.h" @@ -287,6 +290,7 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; prefix_same(&(ra)->prefix, &(rb)->prefix) && \ (ra)->path.type == (rb)->path.type && \ (ra)->path.cost == (rb)->path.cost && \ + (ra)->path.router_bits == (rb)->path.router_bits && \ (ra)->path.u.cost_e2 == (rb)->path.u.cost_e2 && \ listcount(ra->paths) == listcount(rb->paths) && \ ospf6_route_cmp_nexthops(ra, rb)) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index f88667bfd077..36864d2a7de7 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -697,8 +697,8 @@ static uint8_t *ospfv3GeneralGroup(struct variable *v, oid *name, case OSPFv3REFERENCEBANDWIDTH: if (ospf6) return SNMP_INTEGER(ospf6->ref_bandwidth); - /* Otherwise, like for "not implemented". */ - /* fallthru */ + /* Otherwise, like for "not implemented". */ + return NULL; case OSPFv3RESTARTSUPPORT: case OSPFv3RESTARTINTERVAL: case OSPFv3RESTARTSTRICTLSACHECKING: @@ -1017,7 +1017,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length, case OSPFv3WWLSDBCHECKSUM: return SNMP_INTEGER(ntohs(lsa->header->checksum)); case OSPFv3WWLSDBADVERTISEMENT: - *var_len = ntohs(lsa->header->length); + *var_len = ospf6_lsa_size(lsa->header); return (uint8_t *)lsa->header; case OSPFv3WWLSDBTYPEKNOWN: return SNMP_INTEGER(OSPF6_LSA_IS_KNOWN(lsa->header->type) @@ -1126,6 +1126,8 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, return SNMP_INTEGER(1); else if (oi->type == OSPF_IFTYPE_POINTOPOINT) return SNMP_INTEGER(3); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + return SNMP_INTEGER(5); else break; /* Unknown, don't put anything */ case OSPFv3IFADMINSTATUS: @@ -1367,6 +1369,7 @@ static int ospf6TrapIfStateChange(struct ospf6_interface *oi, int next_state, /* Terminal state or regression */ if ((next_state != OSPF6_INTERFACE_POINTTOPOINT) + && (next_state != OSPF6_INTERFACE_POINTTOMULTIPOINT) && (next_state != OSPF6_INTERFACE_DROTHER) && (next_state != OSPF6_INTERFACE_BDR) && (next_state != OSPF6_INTERFACE_DR) && (next_state >= prev_state)) diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index e39ae504a238..7879dae8d7cc 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -130,10 +130,10 @@ static struct ospf6_vertex *ospf6_vertex_create(struct ospf6_lsa *lsa) v->lsa = lsa; /* capability bits + options */ - v->capability = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header)); - v->options[0] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 1); - v->options[1] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 2); - v->options[2] = *(uint8_t *)(OSPF6_LSA_HEADER_END(lsa->header) + 3); + v->capability = *(uint8_t *)(ospf6_lsa_header_end(lsa->header)); + v->options[0] = *(uint8_t *)(ospf6_lsa_header_end(lsa->header) + 1); + v->options[1] = *(uint8_t *)(ospf6_lsa_header_end(lsa->header) + 2); + v->options[2] = *(uint8_t *)(ospf6_lsa_header_end(lsa->header) + 3); v->nh_list = list_new(); v->nh_list->cmp = (int (*)(void *, void *))ospf6_nexthop_cmp; @@ -187,7 +187,7 @@ static struct ospf6_lsa *ospf6_lsdesc_lsa(caddr_t lsdesc, inet_ntop(AF_INET, &adv_router, abuf, sizeof(abuf)); if (lsa) zlog_debug(" Link to: %s len %u, V %s", lsa->name, - ntohs(lsa->header->length), v->name); + ospf6_lsa_size(lsa->header), v->name); else zlog_debug(" Link to: [%s Id:%s Adv:%s] No LSA , V %s", ospf6_lstype_name(type), ibuf, abuf, @@ -206,8 +206,8 @@ static char *ospf6_lsdesc_backlink(struct ospf6_lsa *lsa, caddr_t lsdesc, size = (OSPF6_LSA_IS_TYPE(ROUTER, lsa) ? sizeof(struct ospf6_router_lsdesc) : sizeof(struct ospf6_network_lsdesc)); - for (backlink = OSPF6_LSA_HEADER_END(lsa->header) + 4; - backlink + size <= OSPF6_LSA_END(lsa->header); backlink += size) { + for (backlink = ospf6_lsa_header_end(lsa->header) + 4; + backlink + size <= ospf6_lsa_end(lsa->header); backlink += size) { assert(!(OSPF6_LSA_IS_TYPE(NETWORK, lsa) && VERTEX_IS_TYPE(NETWORK, v))); @@ -290,7 +290,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v, != lsa->header->id) continue; - link_lsa = (struct ospf6_link_lsa *)OSPF6_LSA_HEADER_END( + link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end( lsa->header); if (IS_OSPF6_DEBUG_SPF(PROCESS)) { inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, @@ -510,8 +510,8 @@ void ospf6_spf_calculation(uint32_t router_id, size = (VERTEX_IS_TYPE(ROUTER, v) ? sizeof(struct ospf6_router_lsdesc) : sizeof(struct ospf6_network_lsdesc)); - for (lsdesc = OSPF6_LSA_HEADER_END(v->lsa->header) + 4; - lsdesc + size <= OSPF6_LSA_END(v->lsa->header); + for (lsdesc = ospf6_lsa_header_end(v->lsa->header) + 4; + lsdesc + size <= ospf6_lsa_end(v->lsa->header); lsdesc += size) { lsa = ospf6_lsdesc_lsa(lsdesc, v); if (lsa == NULL) @@ -1011,7 +1011,7 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, continue; } lsa_header = rtr_lsa->header; - total_lsa_length += (ntohs(lsa_header->length) - lsa_length); + total_lsa_length += (ospf6_lsa_size(lsa_header) - lsa_length); num_lsa++; rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); } @@ -1044,11 +1044,11 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, if (!OSPF6_LSA_IS_MAXAGE(rtr_lsa)) { /* Append first Link State ID LSA */ lsa_header = rtr_lsa->header; - memcpy(new_header, lsa_header, ntohs(lsa_header->length)); + memcpy(new_header, lsa_header, ospf6_lsa_size(lsa_header)); /* Assign new lsa length as aggregated length. */ ((struct ospf6_lsa_header *)new_header)->length = htons(total_lsa_length); - new_header += ntohs(lsa_header->length); + new_header += ospf6_lsa_size(lsa_header); num_lsa--; } @@ -1063,20 +1063,19 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, } if (IS_OSPF6_DEBUG_SPF(PROCESS)) { - lsd = OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4; + lsd = ospf6_lsa_header_end(rtr_lsa->header) + 4; interface_id = ROUTER_LSDESC_GET_IFID(lsd); inet_ntop(AF_INET, &interface_id, ifbuf, sizeof(ifbuf)); - zlog_debug( - "%s: Next Router LSA %s to aggreat with len %u interface_id %s", - __func__, rtr_lsa->name, - ntohs(lsa_header->length), ifbuf); + zlog_debug("%s: Next Router LSA %s to aggreat with len %u interface_id %s", + __func__, rtr_lsa->name, + ospf6_lsa_size(lsa_header), ifbuf); } /* Append Next Link State ID LSA */ lsa_header = rtr_lsa->header; - memcpy(new_header, (OSPF6_LSA_HEADER_END(rtr_lsa->header) + 4), - (ntohs(lsa_header->length) - lsa_length)); - new_header += (ntohs(lsa_header->length) - lsa_length); + memcpy(new_header, (ospf6_lsa_header_end(rtr_lsa->header) + 4), + (ospf6_lsa_size(lsa_header) - lsa_length)); + new_header += (ospf6_lsa_size(lsa_header) - lsa_length); num_lsa--; rtr_lsa = ospf6_lsdb_next(end, rtr_lsa); @@ -1091,8 +1090,8 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, if (IS_OSPF6_DEBUG_SPF(PROCESS)) zlog_debug("%s: LSA %s id %u type 0%x len %u num_lsa %u", __func__, lsa->name, ntohl(lsa->header->id), - ntohs(lsa->header->type), ntohs(lsa->header->length), - num_lsa); + ntohs(lsa->header->type), + ospf6_lsa_size(lsa->header), num_lsa); return lsa; } @@ -1137,7 +1136,7 @@ int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa, return 0; } - external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( lsa->header); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 4c40298799e9..a3fb2053749e 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -16,6 +16,7 @@ #include "defaults.h" #include "lib/json.h" #include "lib_errors.h" +#include "frrdistance.h" #include "ospf6_proto.h" #include "ospf6_message.h" @@ -429,17 +430,7 @@ static struct ospf6 *ospf6_create(const char *name) /* Make ospf protocol socket. */ ospf6_serv_sock(o); - /* If sequence number is stored in persistent storage, read it. - */ - if (ospf6_auth_nvm_file_exist() == OSPF6_AUTH_FILE_EXIST) { - ospf6_auth_seqno_nvm_read(o); - o->seqnum_h = o->seqnum_h + 1; - ospf6_auth_seqno_nvm_update(o); - } else { - o->seqnum_l = o->seqnum_h = 0; - ospf6_auth_seqno_nvm_update(o); - } - + ospf6_auth_init(o); return o; } @@ -485,6 +476,7 @@ void ospf6_delete(struct ospf6 *o) struct ospf6_area *oa; struct vrf *vrf; struct ospf6_external_aggr_rt *aggr; + uint32_t i; QOBJ_UNREG(o); @@ -531,6 +523,13 @@ void ospf6_delete(struct ospf6 *o) } route_table_finish(o->rt_aggr_tbl); + for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { + if (!o->redist[i]) + continue; + + list_delete(&o->redist[i]); + } + XFREE(MTYPE_OSPF6_TOP, o->name); XFREE(MTYPE_OSPF6_TOP, o); } @@ -575,6 +574,11 @@ void ospf6_master_init(struct event_loop *master) om6->master = master; } +void ospf6_master_delete(void) +{ + list_delete(&om6->ospf6); +} + static void ospf6_maxage_remover(struct event *thread) { struct ospf6 *o = (struct ospf6 *)EVENT_ARG(thread); @@ -1056,148 +1060,6 @@ DEFUN (no_ospf6_distance_ospf6, return CMD_SUCCESS; } -DEFUN_HIDDEN (ospf6_interface_area, - ospf6_interface_area_cmd, - "interface IFNAME area ", - "Enable routing on an IPv6 interface\n" - IFNAME_STR - "Specify the OSPF6 area ID\n" - "OSPF6 area ID in IPv4 address notation\n" - "OSPF6 area ID in decimal notation\n" - ) -{ - VTY_DECLVAR_CONTEXT(ospf6, ospf6); - int idx_ifname = 1; - int idx_ipv4 = 3; - struct ospf6_area *oa; - struct ospf6_interface *oi; - struct interface *ifp; - uint32_t area_id; - int format; - - vty_out(vty, - "This command is deprecated, because it is not VRF-aware.\n"); - vty_out(vty, - "Please, use \"ipv6 ospf6 area\" on an interface instead.\n"); - - /* find/create ospf6 interface */ - ifp = if_get_by_name(argv[idx_ifname]->arg, ospf6->vrf_id, ospf6->name); - oi = (struct ospf6_interface *)ifp->info; - if (oi == NULL) - oi = ospf6_interface_create(ifp); - if (oi->area) { - vty_out(vty, "%s already attached to Area %s\n", - oi->interface->name, oi->area->name); - return CMD_SUCCESS; - } - - if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) { - vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - - oi->area_id = area_id; - oi->area_id_format = format; - - oa = ospf6_area_lookup(area_id, ospf6); - if (oa == NULL) - oa = ospf6_area_create(area_id, ospf6, format); - - /* attach interface to area */ - listnode_add(oa->if_list, oi); /* sort ?? */ - oi->area = oa; - - SET_FLAG(oa->flag, OSPF6_AREA_ENABLE); - - /* ospf6 process is currently disabled, not much more to do */ - if (CHECK_FLAG(ospf6->flag, OSPF6_DISABLED)) - return CMD_SUCCESS; - - /* start up */ - ospf6_interface_enable(oi); - - /* If the router is ABR, originate summary routes */ - if (ospf6_check_and_set_router_abr(ospf6)) { - ospf6_abr_enable_area(oa); - ospf6_schedule_abr_task(oa->ospf6); - } - - return CMD_SUCCESS; -} - -DEFUN_HIDDEN (no_ospf6_interface_area, - no_ospf6_interface_area_cmd, - "no interface IFNAME area ", - NO_STR - "Disable routing on an IPv6 interface\n" - IFNAME_STR - "Specify the OSPF6 area ID\n" - "OSPF6 area ID in IPv4 address notation\n" - "OSPF6 area ID in decimal notation\n" - ) -{ - VTY_DECLVAR_CONTEXT(ospf6, ospf6); - int idx_ifname = 2; - int idx_ipv4 = 4; - struct ospf6_interface *oi; - struct ospf6_area *oa; - struct interface *ifp; - uint32_t area_id; - - vty_out(vty, - "This command is deprecated, because it is not VRF-aware.\n"); - vty_out(vty, - "Please, use \"no ipv6 ospf6 area\" on an interface instead.\n"); - - /* find/create ospf6 interface */ - ifp = if_get_by_name(argv[idx_ifname]->arg, ospf6->vrf_id, ospf6->name); - - if (ifp == NULL) { - vty_out(vty, "No such interface %s\n", argv[idx_ifname]->arg); - return CMD_SUCCESS; - } - - oi = (struct ospf6_interface *)ifp->info; - if (oi == NULL) { - vty_out(vty, "Interface %s not enabled\n", ifp->name); - return CMD_SUCCESS; - } - - /* parse Area-ID */ - if (inet_pton(AF_INET, argv[idx_ipv4]->arg, &area_id) != 1) - area_id = htonl(strtoul(argv[idx_ipv4]->arg, NULL, 10)); - - /* Verify Area */ - if (oi->area == NULL) { - vty_out(vty, "%s not attached to area %s\n", - oi->interface->name, argv[idx_ipv4]->arg); - return CMD_SUCCESS; - } - - if (oi->area->area_id != area_id) { - vty_out(vty, "Wrong Area-ID: %s is attached to area %s\n", - oi->interface->name, oi->area->name); - return CMD_SUCCESS; - } - - ospf6_interface_disable(oi); - - oa = oi->area; - listnode_delete(oi->area->if_list, oi); - oi->area = (struct ospf6_area *)NULL; - - /* Withdraw inter-area routes from this area, if necessary */ - if (oa->if_list->count == 0) { - UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE); - ospf6_abr_disable_area(oa); - } - - oi->area_id = 0; - oi->area_id_format = OSPF6_AREA_FMT_UNSET; - - return CMD_SUCCESS; -} - DEFUN (ospf6_stub_router_admin, ospf6_stub_router_admin_cmd, "stub-router administrative", @@ -2015,7 +1877,7 @@ ospf6_show_summary_address(struct vty *vty, struct ospf6 *ospf6, if (!uj) { ospf6_show_vrf_name(vty, ospf6, json_vrf); - vty_out(vty, "aggregation delay interval :%u(in seconds)\n\n", + vty_out(vty, "aggregation delay interval: %u(in seconds)\n\n", ospf6->aggr_delay_interval); vty_out(vty, "%s\n", header); } else { @@ -2346,8 +2208,6 @@ void ospf6_top_init(void) install_element(OSPF6_NODE, &ospf6_timers_lsa_cmd); install_element(OSPF6_NODE, &no_ospf6_timers_lsa_cmd); - install_element(OSPF6_NODE, &ospf6_interface_area_cmd); - install_element(OSPF6_NODE, &no_ospf6_interface_area_cmd); install_element(OSPF6_NODE, &ospf6_stub_router_admin_cmd); install_element(OSPF6_NODE, &no_ospf6_stub_router_admin_cmd); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index a38dad8fcedd..8288413c1056 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -236,6 +236,8 @@ extern struct ospf6_master *om6; /* prototypes */ extern void ospf6_master_init(struct event_loop *master); +extern void ospf6_master_delete(void); + extern void install_element_ospf6_clear_process(void); extern void ospf6_top_init(void); extern void ospf6_delete(struct ospf6 *o); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 8bd0d8f0b58b..911f3567d453 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -147,30 +147,22 @@ void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg) __func__); } -static int ospf6_zebra_import_check_update(ZAPI_CALLBACK_ARGS) +static void ospf6_zebra_import_check_update(struct vrf *vrf, + struct prefix *matched, + struct zapi_route *nhr) { struct ospf6 *ospf6; - struct zapi_route nhr; - struct prefix matched; - ospf6 = ospf6_lookup_by_vrf_id(vrf_id); + ospf6 = (struct ospf6 *)vrf->info; if (ospf6 == NULL || !IS_OSPF6_ASBR(ospf6)) - return 0; - - if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { - zlog_err("%s[%u]: Failure to decode route", __func__, - ospf6->vrf_id); - return -1; - } + return; - if (matched.family != AF_INET6 || matched.prefixlen != 0 || - nhr.type == ZEBRA_ROUTE_OSPF6) - return 0; + if (matched->family != AF_INET6 || matched->prefixlen != 0 || + nhr->type == ZEBRA_ROUTE_OSPF6) + return; - ospf6->nssa_default_import_check.status = !!nhr.nexthop_num; + ospf6->nssa_default_import_check.status = !!nhr->nexthop_num; ospf6_abr_nssa_type_7_defaults(ospf6); - - return 0; } static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS) @@ -297,7 +289,7 @@ static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) ospf6_asbr_redistribute_add(api.type, ifindex, &api.prefix, api.nexthop_num, nexthop, api.tag, - ospf6); + ospf6, api.metric); else ospf6_asbr_redistribute_remove(api.type, ifindex, &api.prefix, ospf6); @@ -763,7 +755,6 @@ static zclient_handler *const ospf6_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_DELETE] = ospf6_zebra_if_address_update_delete, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ospf6_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ospf6_zebra_read_route, - [ZEBRA_NEXTHOP_UPDATE] = ospf6_zebra_import_check_update, }; void ospf6_zebra_init(struct event_loop *master) @@ -773,6 +764,7 @@ void ospf6_zebra_init(struct event_loop *master) array_size(ospf6_handlers)); zclient_init(zclient, ZEBRA_ROUTE_OSPF6, 0, &ospf6d_privs); zclient->zebra_connected = ospf6_zebra_connected; + zclient->nexthop_update = ospf6_zebra_import_check_update; /* Install command element for zebra node. */ install_element(VIEW_NODE, &show_ospf6_zebra_cmd); diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index f6d27c84cd5f..5f89af950890 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -83,8 +83,10 @@ clippy_scan += \ ospf6d/ospf6_lsa.c \ ospf6d/ospf6_gr_helper.c \ ospf6d/ospf6_gr.c \ + ospf6d/ospf6_interface.c \ ospf6d/ospf6_nssa.c \ ospf6d/ospf6_route.c \ + ospf6d/ospf6_neighbor.c \ # end nodist_ospf6d_ospf6d_SOURCES = \ diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 28d526870b80..93779991b5fd 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1750,11 +1750,10 @@ static void ospf_abr_announce_non_dna_routers(struct event *thread) OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "%s: Area %pI4 FR enabled: %d", __func__, &area->area_id, area->fr_info.enabled); - OSPF_LOG_DEBUG( - IS_DEBUG_OSPF_EVENT, - "LSA with DC bit clear: %d Recived indication LSA: %d", - area->fr_info.area_dc_clear, - area->fr_info.area_ind_lsa_recvd); + OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, + "LSA with DC bit clear: %d Received indication LSA: %d", + area->fr_info.area_dc_clear, + area->fr_info.area_ind_lsa_recvd); OSPF_LOG_DEBUG(IS_DEBUG_OSPF_EVENT, "FR state change: %d", area->fr_info.state_changed); if (!OSPF_IS_AREA_BACKBONE(area) && diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index 6c8bed3d8fc5..6160a0f1fa03 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -21,10 +21,6 @@ #define MTYPE_OSPF_API_MSG MTYPE_TMP #define MTYPE_OSPF_API_FIFO MTYPE_TMP -/* Default API server port to accept connection request from client-side. */ -/* This value could be overridden by "ospfapi" entry in "/etc/services". */ -#define OSPF_API_SYNC_PORT 2607 - /* ----------------------------------------------------------- * Generic messages * ----------------------------------------------------------- diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 34e59c545b7e..fcc28c6f9f82 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -62,6 +62,11 @@ DEFINE_MTYPE_STATIC(OSPFD, APISERVER_MSGFILTER, "API Server Message Filter"); /* List of all active connections. */ struct list *apiserver_list; +/* Indicates that API the server socket local addresss has been + * specified. + */ +struct in_addr ospf_apiserver_addr; + /* ----------------------------------------------------------- * Functions to lookup interfaces * ----------------------------------------------------------- @@ -109,7 +114,21 @@ struct ospf_interface *ospf_apiserver_if_lookup_by_ifp(struct interface *ifp) unsigned short ospf_apiserver_getport(void) { - struct servent *sp = getservbyname("ospfapi", "tcp"); + struct servent *sp = NULL; + char sbuf[16]; + + /* + * Allow the OSPF API server port to be specified per-instance by + * including the instance ID in the /etc/services name. Use the + * prior name if no per-instance service is specified. + */ + if (ospf_instance) { + snprintfrr(sbuf, sizeof(sbuf), "ospfapi-%d", ospf_instance); + sp = getservbyname(sbuf, "tcp"); + } + + if (!sp) + sp = getservbyname("ospfapi", "tcp"); return sp ? ntohs(sp->s_port) : OSPF_API_SYNC_PORT; } @@ -557,8 +576,10 @@ int ospf_apiserver_serv_sock_family(unsigned short port, int family) sockopt_reuseaddr(accept_sock); sockopt_reuseport(accept_sock); - /* Bind socket to address and given port. */ - rc = sockunion_bind(accept_sock, &su, port, NULL); + /* Bind socket to optional lcoal address and port. */ + if (ospf_apiserver_addr.s_addr) + sockunion2ip(&su) = ospf_apiserver_addr.s_addr; + rc = sockunion_bind(accept_sock, &su, port, &su); if (rc < 0) { close(accept_sock); /* Close socket */ return rc; @@ -2092,7 +2113,7 @@ void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv, lsa, (void *)¶m, 0); break; case OSPF_OPAQUE_AS_LSA: - LSDB_LOOP (OPAQUE_LINK_LSDB(ospf), rn, lsa) + LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *)¶m, 0); break; diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index 0aaf67c1f3cd..4341a9d38023 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -66,6 +66,14 @@ enum ospf_apiserver_event { OSPF_APISERVER_ASYNC_WRITE }; +/* ----------------------------------------------------------- + * External definitions for OSPF API ospfd parameters. + * ----------------------------------------------------------- + */ + +extern int ospf_apiserver_enable; +extern struct in_addr ospf_apiserver_addr; + /* ----------------------------------------------------------- * Following are functions to manage client connections. * ----------------------------------------------------------- diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index bf6f0b161490..b47c39008819 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -110,7 +110,8 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance, new = rn->info; if ((new->ifindex == ifindex) && (new->nexthop.s_addr == nexthop.s_addr) - && (new->tag == tag)) { + && (new->tag == tag) + && (new->metric == metric)) { route_unlock_node(rn); return NULL; /* NULL => no LSA to refresh */ } @@ -987,6 +988,7 @@ static void ospf_handle_external_aggr_update(struct ospf *ospf) &aggr->match_extnl_hash, (void *)ospf_aggr_handle_external_info); + ospf_external_aggregator_free(aggr); } else if (aggr->action == OSPF_ROUTE_AGGR_MODIFY) { aggr->action = OSPF_ROUTE_AGGR_NONE; @@ -1076,9 +1078,8 @@ static void ospf_external_aggr_timer(struct ospf *ospf, if (ospf->aggr_action == OSPF_ROUTE_AGGR_ADD) { if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) - zlog_debug( - "%s: Not required to retsart timer,set is already added.", - __func__); + zlog_debug("%s: Not required to restart timer,set is already added.", + __func__); return; } diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index 610b5fc08e92..9e26a2ac2ddb 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -480,7 +480,7 @@ static int ospf_ase_route_match_same(struct route_table *rt, assert(or); - if (or->path_type != newor->path_type) + if (or->changed || (or->path_type != newor->path_type)) return 0; switch (or->path_type) { diff --git a/ospfd/ospf_auth.c b/ospfd/ospf_auth.c index 2d13d4e9ad21..2b090dca1efd 100644 --- a/ospfd/ospf_auth.c +++ b/ospfd/ospf_auth.c @@ -5,6 +5,12 @@ */ #include +#include + +#ifdef CRYPTO_OPENSSL +#include +#include +#endif #include "linklist.h" #include "if.h" @@ -89,7 +95,7 @@ static int ospf_auth_check_hmac_sha_digest(struct ospf_interface *oi, uint16_t length = ntohs(ospfh->length); uint16_t hash_length = keychain_get_hash_len(key->hash_algo); #ifdef CRYPTO_OPENSSL - unsigned int openssl_hash_length = hash_length; + uint32_t openssl_hash_length = hash_length; HMAC_CTX *ctx; const EVP_MD *md_alg = ospf_auth_get_openssl_evp_md_from_key(key); @@ -159,6 +165,13 @@ static int ospf_auth_check_md5_digest(struct ospf_interface *oi, struct crypt_key *ck = NULL; uint16_t length = ntohs(ospfh->length); + if (length < sizeof(struct ospf_header)) {/* for coverity's sake */ + flog_warn(EC_OSPF_AUTH, + "%s: Invalid packet length of %u received on interface %s, Router-ID: %pI4", + __func__, length, IF_NAME(oi), &ospfh->router_id); + return 0; + } + if (key == NULL) { ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt), ospfh->u.crypt.key_id); @@ -189,7 +202,7 @@ static int ospf_auth_check_md5_digest(struct ospf_interface *oi, strlcpy(auth_key, (char *)ck->auth_key, OSPF_AUTH_MD5_SIZE + 1); /* Generate a digest for the ospf packet - their digest + our digest. */ #ifdef CRYPTO_OPENSSL - unsigned int md5_size = OSPF_AUTH_MD5_SIZE; + uint32_t md5_size = OSPF_AUTH_MD5_SIZE; ctx = EVP_MD_CTX_new(); EVP_DigestInit(ctx, EVP_md5()); @@ -222,10 +235,10 @@ static int ospf_auth_check_md5_digest(struct ospf_interface *oi, static int ospf_auth_make_md5_digest(struct ospf_interface *oi, struct ospf_packet *op, struct key *key) { - void *ibuf; - struct ospf_header *ospfh; + void *ibuf = STREAM_DATA(op->s); + struct ospf_header *ospfh = (struct ospf_header *)ibuf; unsigned char digest[OSPF_AUTH_MD5_SIZE]; - uint16_t length; + uint16_t length = ntohs(ospfh->length); #ifdef CRYPTO_OPENSSL EVP_MD_CTX *ctx; #elif CRYPTO_INTERNAL @@ -233,14 +246,18 @@ static int ospf_auth_make_md5_digest(struct ospf_interface *oi, #endif char auth_key[OSPF_AUTH_MD5_SIZE + 1]; + if ((length < (sizeof(struct ospf_header))) || (length > op->length)) { /* for coverity's sake */ + flog_warn(EC_OSPF_AUTH, + "%s: Invalid packet length of %u received on interface %s, Router-ID: %pI4", + __func__, length, IF_NAME(oi), &ospfh->router_id); + return 0; + } + memset(auth_key, 0, OSPF_AUTH_MD5_SIZE + 1); strlcpy(auth_key, key->string, OSPF_AUTH_MD5_SIZE + 1); - ibuf = STREAM_DATA(op->s); - ospfh = (struct ospf_header *)ibuf; - length = ntohs(ospfh->length); /* Generate a digest for the ospf packet - their digest + our digest. */ #ifdef CRYPTO_OPENSSL - unsigned int md5_size = OSPF_AUTH_MD5_SIZE; + uint32_t md5_size = OSPF_AUTH_MD5_SIZE; ctx = EVP_MD_CTX_new(); EVP_DigestInit(ctx, EVP_md5()); @@ -282,7 +299,7 @@ static int ospf_auth_make_hmac_sha_digest(struct ospf_interface *oi, ibuf = STREAM_DATA(op->s); ospfh = (struct ospf_header *)ibuf; #ifdef CRYPTO_OPENSSL - unsigned int openssl_hash_length = hash_length; + uint32_t openssl_hash_length = hash_length; HMAC_CTX *ctx; const EVP_MD *md_alg = ospf_auth_get_openssl_evp_md_from_key(key); @@ -491,7 +508,7 @@ int ospf_auth_make(struct ospf_interface *oi, struct ospf_packet *op) if (auth_key) { /* Generate a digest for the entire packet + our secret key. */ #ifdef CRYPTO_OPENSSL - unsigned int md5_size = OSPF_AUTH_MD5_SIZE; + uint32_t md5_size = OSPF_AUTH_MD5_SIZE; ctx = EVP_MD_CTX_new(); EVP_DigestInit(ctx, EVP_md5()); diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 75b58035a3d5..df0b3b908152 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -31,6 +31,7 @@ #include "network.h" #include "if.h" #include "libospf.h" /* for ospf interface types */ +#include #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -1715,85 +1716,138 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op) /* Cisco experimental SubTLV */ static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ext_subtlv_rmt_itf_addr *top = (struct ext_subtlv_rmt_itf_addr *)tlvh; check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address"); - vty_out(vty, - " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n", - ntohs(top->header.length), &top->value); + if (!json) + vty_out(vty, + " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n", + ntohs(top->header.length), &top->value); + else + json_object_string_addf(json, "remoteInterfaceAddress", "%pI4", + &top->value); return TLV_SIZE(tlvh); } /* Adjacency SID SubTLV */ static uint16_t show_vty_ext_link_adj_sid(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh; + uint8_t tlv_size; - check_tlv_size(EXT_SUBTLV_ADJ_SID_SIZE, "Adjacency SID"); + tlv_size = CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? SID_LABEL_SIZE(EXT_SUBTLV_ADJ_SID_SIZE) + : SID_INDEX_SIZE(EXT_SUBTLV_ADJ_SID_SIZE); + check_tlv_size(tlv_size, "Adjacency SID"); - vty_out(vty, - " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n", - ntohs(top->header.length), top->flags, top->mtid, top->weight, - CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" - : "Index", - CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) - ? GET_LABEL(ntohl(top->value)) - : ntohl(top->value)); + if (!json) + vty_out(vty, + " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n", + ntohs(top->header.length), top->flags, top->mtid, + top->weight, + CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? "Label" + : "Index", + CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? GET_LABEL(ntohl(top->value)) + : ntohl(top->value)); + else { + json_object_string_addf(json, "flags", "0x%x", top->flags); + json_object_string_addf(json, "mtID", "0x%x", top->mtid); + json_object_string_addf(json, "weight", "0x%x", top->weight); + if (CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + json_object_int_add(json, "label", + GET_LABEL(ntohl(top->value))); + else + json_object_int_add(json, "index", ntohl(top->value)); + } return TLV_SIZE(tlvh); } /* LAN Adjacency SubTLV */ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ext_subtlv_lan_adj_sid *top = (struct ext_subtlv_lan_adj_sid *)tlvh; + uint8_t tlv_size; - check_tlv_size(EXT_SUBTLV_LAN_ADJ_SID_SIZE, "Lan-Adjacency SID"); + tlv_size = CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? SID_LABEL_SIZE(EXT_SUBTLV_LAN_ADJ_SID_SIZE) + : SID_INDEX_SIZE(EXT_SUBTLV_LAN_ADJ_SID_SIZE); + check_tlv_size(tlv_size, "LAN-Adjacency SID"); - vty_out(vty, - " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n", - ntohs(top->header.length), top->flags, top->mtid, top->weight, - &top->neighbor_id, - CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label" - : "Index", - CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) - ? GET_LABEL(ntohl(top->value)) - : ntohl(top->value)); + if (!json) + vty_out(vty, + " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n", + ntohs(top->header.length), top->flags, top->mtid, + top->weight, &top->neighbor_id, + CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? "Label" + : "Index", + CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? GET_LABEL(ntohl(top->value)) + : ntohl(top->value)); + else { + json_object_string_addf(json, "flags", "0x%x", top->flags); + json_object_string_addf(json, "mtID", "0x%x", top->mtid); + json_object_string_addf(json, "weight", "0x%x", top->weight); + json_object_string_addf(json, "neighborID", "%pI4", + &top->neighbor_id); + if (CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)) + json_object_int_add(json, "label", + GET_LABEL(ntohl(top->value))); + else + json_object_int_add(json, "index", ntohl(top->value)); + } return TLV_SIZE(tlvh); } static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, - size_t buf_size) + size_t buf_size, json_object *json) { + json_object *obj; + if (TLV_SIZE(tlvh) > buf_size) { vty_out(vty, " TLV size %d exceeds buffer size. Abort!", TLV_SIZE(tlvh)); return buf_size; } - - vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", - ntohs(tlvh->type), ntohs(tlvh->length)); + if (!json) + vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", + ntohs(tlvh->type), ntohs(tlvh->length)); + else { + obj = json_object_new_object(); + json_object_string_addf(obj, "type", "0x%x", + ntohs(tlvh->type)); + json_object_string_addf(obj, "length", "0x%x", + ntohs(tlvh->length)); + json_object_object_add(json, "unknownTLV", obj); + } return TLV_SIZE(tlvh); } /* Extended Link Sub TLVs */ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, - size_t buf_size) + size_t buf_size, json_object *json) { struct ext_tlv_link *top = (struct ext_tlv_link *)ext; struct tlv_header *tlvh; uint16_t length = ntohs(top->header.length); uint16_t sum = 0; + json_object *jadj = NULL, *obj = NULL; /* Verify that TLV length is valid against remaining buffer size */ if (length > buf_size) { @@ -1803,12 +1857,22 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, return buf_size; } - vty_out(vty, - " Extended Link TLV: Length %u\n Link Type: 0x%x\n" - " Link ID: %pI4\n", - ntohs(top->header.length), top->link_type, - &top->link_id); - vty_out(vty, " Link data: %pI4\n", &top->link_data); + if (!json) { + vty_out(vty, + " Extended Link TLV: Length %u\n Link Type: 0x%x\n" + " Link ID: %pI4\n", + ntohs(top->header.length), top->link_type, + &top->link_id); + vty_out(vty, " Link data: %pI4\n", &top->link_data); + } else { + json_object_string_addf(json, "linkType", "0x%x", + top->link_type); + json_object_string_addf(json, "linkID", "%pI4", &top->link_id); + json_object_string_addf(json, "linkData", "%pI4", + &top->link_data); + jadj = json_object_new_array(); + json_object_object_add(json, "adjacencySID", jadj); + } /* Skip Extended TLV and parse sub-TLVs */ length -= EXT_TLV_LINK_SIZE; @@ -1817,16 +1881,27 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_SUBTLV_ADJ_SID: - sum += show_vty_ext_link_adj_sid(vty, tlvh); + if (json) { + obj = json_object_new_object(); + json_object_array_add(jadj, obj); + } else + obj = NULL; + sum += show_vty_ext_link_adj_sid(vty, tlvh, obj); break; case EXT_SUBTLV_LAN_ADJ_SID: - sum += show_vty_ext_link_lan_adj_sid(vty, tlvh); + if (json) { + obj = json_object_new_object(); + json_object_array_add(jadj, obj); + } else + obj = NULL; + sum += show_vty_ext_link_lan_adj_sid(vty, tlvh, obj); break; case EXT_SUBTLV_RMT_ITF_ADDR: - sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh); + sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh, json); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, length - sum); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum, + json); break; } } @@ -1841,9 +1916,12 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + json_object *jlink = NULL; - if (json) - return; + if (json) { + jlink = json_object_new_object(); + json_object_object_add(json, "extendedLink", jlink); + } /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -1852,10 +1930,12 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_TLV_LINK: - sum += show_vty_link_info(vty, tlvh, length - sum); + sum += show_vty_link_info(vty, tlvh, length - sum, + jlink); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, length - sum); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum, + jlink); break; } } @@ -1863,34 +1943,51 @@ static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, /* Prefix SID SubTLV */ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ext_subtlv_prefix_sid *top = (struct ext_subtlv_prefix_sid *)tlvh; + uint8_t tlv_size; - check_tlv_size(EXT_SUBTLV_PREFIX_SID_SIZE, "Prefix SID"); - - vty_out(vty, - " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n", - ntohs(top->header.length), top->algorithm, top->flags, - top->mtid, - CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label" - : "Index", - CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) - ? GET_LABEL(ntohl(top->value)) - : ntohl(top->value)); + tlv_size = CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) + ? SID_LABEL_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE) + : SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE); + check_tlv_size(tlv_size, "Prefix SID"); + if (!json) + vty_out(vty, + " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n", + ntohs(top->header.length), top->algorithm, top->flags, + top->mtid, + CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) + ? "Label" + : "Index", + CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) + ? GET_LABEL(ntohl(top->value)) + : ntohl(top->value)); + else { + json_object_int_add(json, "algorithm", top->algorithm); + json_object_string_addf(json, "flags", "0x%x", top->flags); + json_object_string_addf(json, "mtID", "0x%x", top->mtid); + if (CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)) + json_object_int_add(json, "label", + GET_LABEL(ntohl(top->value))); + else + json_object_int_add(json, "index", ntohl(top->value)); + } return TLV_SIZE(tlvh); } /* Extended Prefix SubTLVs */ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, - size_t buf_size) + size_t buf_size, json_object *json) { struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext; struct tlv_header *tlvh; uint16_t length = ntohs(top->header.length); uint16_t sum = 0; + json_object *jsid = NULL; /* Verify that TLV length is valid against remaining buffer size */ if (length > buf_size) { @@ -1900,11 +1997,21 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, return buf_size; } - vty_out(vty, - " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n" - "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n", - ntohs(top->header.length), top->route_type, top->af, top->flags, - &top->address, top->pref_length); + if (!json) + vty_out(vty, + " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n" + "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n", + ntohs(top->header.length), top->route_type, top->af, + top->flags, &top->address, top->pref_length); + else { + json_object_int_add(json, "routeType", top->route_type); + json_object_string_addf(json, "addressFamily", "0x%x", top->af); + json_object_string_addf(json, "flags", "0x%x", top->flags); + json_object_string_addf(json, "address", "%pI4", &top->address); + json_object_int_add(json, "prefixLength", top->pref_length); + jsid = json_object_new_object(); + json_object_object_add(json, "prefixSID", jsid); + } /* Skip Extended Prefix TLV and parse sub-TLVs */ length -= EXT_TLV_PREFIX_SIZE; @@ -1913,10 +2020,11 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_SUBTLV_PREFIX_SID: - sum += show_vty_ext_pref_pref_sid(vty, tlvh); + sum += show_vty_ext_pref_pref_sid(vty, tlvh, jsid); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, length - sum); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum, + json); break; } } @@ -1931,9 +2039,12 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + json_object *jpref = NULL; - if (json) - return; + if (json) { + jpref = json_object_new_object(); + json_object_object_add(json, "extendedPrefix", jpref); + } /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -1942,10 +2053,12 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_TLV_PREFIX: - sum += show_vty_pref_info(vty, tlvh, length - sum); + sum += show_vty_pref_info(vty, tlvh, length - sum, + jpref); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, length - sum); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum, + jpref); break; } } diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index dd8c9268f108..2af4ae317098 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -110,6 +110,9 @@ void ospf_area_update_fr_state(struct ospf_area *area) static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_interface *oi = inbr->oi; + /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgment sent. If interface is in Backup state @@ -122,12 +125,27 @@ static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, worked out previously */ /* Deal with router as BDR */ - if (inbr->oi->state == ISM_Backup && !NBR_IS_DR(inbr)) + if (oi->state == ISM_Backup && !NBR_IS_DR(inbr)) return; - /* Schedule a delayed LSA Ack to be sent */ - listnode_add(inbr->oi->ls_ack, - ospf_lsa_lock(lsa)); /* delayed LSA Ack */ + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &inbr->router_id, + IF_NAME(inbr->oi)); + + /* Add the LSA to the interface delayed Ack list. */ + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&oi->ls_ack_delayed, ls_ack_list_entry); + + /* Set LS Ack timer if it is not already scheduled. */ + if (!oi->t_ls_ack_delayed) + OSPF_ISM_TIMER_ON(oi->t_ls_ack_delayed, + ospf_ls_ack_delayed_timer, + oi->v_ls_ack_delayed); } /* Check LSA is related to external info. */ @@ -765,8 +783,9 @@ int ospf_flood_through_interface(struct ospf_interface *oi, packets must be sent, as unicasts, to each adjacent neighbor (i.e., those in state Exchange or greater). The destination IP addresses for these packets are the neighbors' IP - addresses. */ - if (oi->type == OSPF_IFTYPE_NBMA) { + addresses. This behavior is extended to P2MP networks which + don't support broadcast. */ + if (OSPF_IF_NON_BROADCAST(oi)) { struct ospf_neighbor *nbr; for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { @@ -954,7 +973,7 @@ int ospf_flood_through(struct ospf *ospf, struct ospf_neighbor *inbr, if (IS_DEBUG_OSPF_NSSA) zlog_debug("%s: LOCAL NSSA FLOOD of Type-7.", __func__); - /* Fallthrough */ + fallthrough; default: lsa_ack_flag = ospf_flood_through_area(lsa->area, inbr, lsa); break; @@ -1014,7 +1033,7 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) ospf_lsdb_delete(&nbr->ls_req, lsa); } -/* Remove all LSA from neighbor's ls-requenst list. */ +/* Remove all LSAs from neighbor's ls-request list. */ void ospf_ls_request_delete_all(struct ospf_neighbor *nbr) { ospf_lsa_unlock(&nbr->ls_req_last); @@ -1060,58 +1079,114 @@ int ospf_ls_retransmit_isempty(struct ospf_neighbor *nbr) /* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - struct ospf_lsa *old; + struct ospf_lsdb_linked_node *ls_rxmt_node; + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct ospf_lsa *old = NULL; + bool rxmt_head_replaced = false; - old = ospf_ls_retransmit_lookup(nbr, lsa); + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + if (ls_rxmt_node) + old = ls_rxmt_node->info; if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_head_replaced = true; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, old); if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Old Delete LSA[%s] on Add", ospf_ls_retransmit_count(nbr), &nbr->router_id, ospf_get_name(nbr->oi->ospf), - dump_lsa_key(old)); - ospf_lsdb_delete(&nbr->ls_rxmt, old); + dump_lsa_key(lsa)); + ospf_lsa_unlock(&old); } lsa->retransmit_counter++; + ls_rxmt_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + /* + * Set the LSA retransmission time for the neighbor; + */ + monotime(&ls_rxmt_list_entry->list_entry_time); + ls_rxmt_list_entry->list_entry_time.tv_sec += nbr->v_ls_rxmt; + /* - * We cannot make use of the newly introduced callback function - * "lsdb->new_lsa_hook" to replace debug output below, just - * because - * it seems no simple and smart way to pass neighbor information - * to - * the common function "ospf_lsdb_add()" -- endo. + * Add the LSA to the neighbor retransmission list. */ + ls_rxmt_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsdb_add(&nbr->ls_rxmt, lsa); + + /* + * Look up the newly added node and set the list pointer. + */ + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + ls_rxmt_node->lsa_list_entry = ls_rxmt_list_entry; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Add LSA[%s] retrans at (%ld/%ld)", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), - dump_lsa_key(lsa)); - ospf_lsdb_add(&nbr->ls_rxmt, lsa); + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + dump_lsa_key(lsa), + (long)ls_rxmt_list_entry->list_entry_time + .tv_sec, + (long)ls_rxmt_list_entry->list_entry_time + .tv_usec); + /* + * Reset the neighbor LSA retransmission timer if isn't currently + * running or the LSA at the head of the list was updated. + */ + if (!nbr->t_ls_rxmt || rxmt_head_replaced) + ospf_ls_retransmit_set_timer(nbr); } } /* Remove LSA from neibghbor's ls-retransmit list. */ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - if (ospf_ls_retransmit_lookup(nbr, lsa)) { + struct ospf_lsdb_linked_node *ls_rxmt_node; + + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + + if (ls_rxmt_node) { + bool rxmt_timer_reset; + + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_timer_reset = true; + else + rxmt_timer_reset = false; + lsa->retransmit_counter--; - if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Delete LSA[%s]", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); - ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + ospf_lsa_unlock(&lsa); + + /* + * If the LS retransmission entry at the head of the list was + * deleted, reset the timer. + */ + if (rxmt_timer_reset) + ospf_ls_retransmit_set_timer(nbr); } } /* Clear neighbor's ls-retransmit list. */ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; struct ospf_lsdb *lsdb; int i; @@ -1127,10 +1202,54 @@ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) ospf_ls_retransmit_delete(nbr, lsa); } + frr_each_safe (ospf_lsa_list, &nbr->ls_rxmt_list, ls_rxmt_list_entry) { + ospf_lsa_list_del(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsa_unlock(&ls_rxmt_list_entry->lsa); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_list_entry); + } + ospf_lsa_unlock(&nbr->ls_req_last); nbr->ls_req_last = NULL; } +/* + * Set the neighbor's ls-retransmit timer based on the next + * LSA retransmit time. + */ +void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr) +{ + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + + if (nbr->t_ls_rxmt) + EVENT_OFF(nbr->t_ls_rxmt); + + ls_rxmt_list_entry = ospf_lsa_list_first(&nbr->ls_rxmt_list); + if (ls_rxmt_list_entry) { + struct timeval current_time, delay; + unsigned long delay_milliseconds; + + monotime(¤t_time); + if (timercmp(¤t_time, + &ls_rxmt_list_entry->list_entry_time, >=)) + delay_milliseconds = 10; + else { + timersub(&ls_rxmt_list_entry->list_entry_time, + ¤t_time, &delay); + delay_milliseconds = (delay.tv_sec * 1000) + + (delay.tv_usec / 1000); + } + + event_add_timer_msec(master, ospf_ls_rxmt_timer, nbr, + delay_milliseconds, &nbr->t_ls_rxmt); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) retrans timer set in %ld msecs - Head LSA(%s)", + ospf_ls_retransmit_count(nbr), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + delay_milliseconds, + dump_lsa_key(ls_rxmt_list_entry->lsa)); + } +} + /* Lookup LSA from neighbor's ls-retransmit list. */ struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h index 3757400d0cec..241205297000 100644 --- a/ospfd/ospf_flood.h +++ b/ospfd/ospf_flood.h @@ -7,6 +7,39 @@ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H +#include "typesafe.h" + +/* + * OSPF Temporal LSA List + */ +PREDECL_DLIST(ospf_lsa_list); + +struct ospf_lsa_list_entry { + /* Linkage for LSA List */ + struct ospf_lsa_list_item list_linkage; + + union { + /* + * Time associated with the list entry. For example, for a + * neigbhor link retransmission list, this is the + * retransmission time. + */ + struct timeval list_entry_timeval; + + /* + * Destanation address specific to the LSA list. For example, + * the distination for an associated direct LS acknowledgment. + */ + struct in_addr list_entry_dst_addr; + } u; + + struct ospf_lsa *lsa; +}; +#define list_entry_time u.list_entry_timeval +#define list_entry_dst u.list_entry_dst_addr + +DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage); + extern int ospf_flood(struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through(struct ospf *, struct ospf_neighbor *, @@ -36,6 +69,8 @@ extern void ospf_ls_retransmit_add(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear(struct ospf_neighbor *); +extern void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr); + extern struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *, diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c index c23c42052fc7..0a4d579fc976 100644 --- a/ospfd/ospf_gr.c +++ b/ospfd/ospf_gr.c @@ -555,21 +555,6 @@ static void ospf_gr_grace_period_expired(struct event *thread) ospf_gr_restart_exit(ospf, "grace period has expired"); } -/* - * Returns the path of the file (non-volatile memory) that contains GR status - * information. - */ -static char *ospf_gr_nvm_filepath(struct ospf *ospf) -{ - static char filepath[MAXPATHLEN]; - char instance[16] = ""; - - if (ospf->instance) - snprintf(instance, sizeof(instance), "-%d", ospf->instance); - snprintf(filepath, sizeof(filepath), OSPFD_GR_STATE, instance); - return filepath; -} - /* Send extra Grace-LSA out the interface (unplanned outages only). */ void ospf_gr_iface_send_grace_lsa(struct event *thread) { @@ -591,18 +576,14 @@ void ospf_gr_iface_send_grace_lsa(struct event *thread) */ static void ospf_gr_nvm_update(struct ospf *ospf, bool prepare) { - char *filepath; const char *inst_name; json_object *json; json_object *json_instances; json_object *json_instance; - filepath = ospf_gr_nvm_filepath(ospf); inst_name = ospf_get_name(ospf); - json = json_object_from_file(filepath); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -630,8 +611,7 @@ static void ospf_gr_nvm_update(struct ospf *ospf, bool prepare) json_object_int_add(json_instance, "timestamp", time(NULL) + ospf->gr_info.grace_period); - json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } /* @@ -640,17 +620,13 @@ static void ospf_gr_nvm_update(struct ospf *ospf, bool prepare) */ void ospf_gr_nvm_delete(struct ospf *ospf) { - char *filepath; const char *inst_name; json_object *json; json_object *json_instances; - filepath = ospf_gr_nvm_filepath(ospf); inst_name = ospf_get_name(ospf); - json = json_object_from_file(filepath); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -660,8 +636,7 @@ void ospf_gr_nvm_delete(struct ospf *ospf) json_object_object_del(json_instances, inst_name); - json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } /* @@ -670,7 +645,6 @@ void ospf_gr_nvm_delete(struct ospf *ospf) */ void ospf_gr_nvm_read(struct ospf *ospf) { - char *filepath; const char *inst_name; json_object *json; json_object *json_instances; @@ -679,12 +653,9 @@ void ospf_gr_nvm_read(struct ospf *ospf) json_object *json_grace_period; time_t timestamp = 0; - filepath = ospf_gr_nvm_filepath(ospf); inst_name = ospf_get_name(ospf); - json = json_object_from_file(filepath); - if (json == NULL) - json = json_object_new_object(); + json = frr_daemon_state_load(); json_object_object_get_ex(json, "instances", &json_instances); if (!json_instances) { @@ -730,8 +701,7 @@ void ospf_gr_nvm_read(struct ospf *ospf) json_object_object_del(json_instances, inst_name); - json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY); - json_object_free(json); + frr_daemon_state_save(&json); } void ospf_gr_unplanned_start_interface(struct ospf_interface *oi) diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 7601419325d5..c4210eb70c7c 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -19,6 +19,7 @@ #include "zclient.h" #include "bfd.h" #include "ldp_sync.h" +#include "plist.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_bfd.h" @@ -67,6 +68,34 @@ int ospf_interface_neighbor_count(struct ospf_interface *oi) return count; } + +void ospf_intf_neighbor_filter_apply(struct ospf_interface *oi) +{ + struct route_node *rn; + struct ospf_neighbor *nbr = NULL; + struct prefix nbr_src_prefix = { AF_INET, IPV4_MAX_BITLEN, { 0 } }; + + if (!oi->nbr_filter) + return; + + /* + * Kill neighbors that don't match the neighbor filter prefix-list + * excluding the neighbor for the router itself and any neighbors + * that are already down. + */ + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + if (nbr && nbr != oi->nbr_self && nbr->state != NSM_Down) { + nbr_src_prefix.u.prefix4 = nbr->src; + if (prefix_list_apply(oi->nbr_filter, + (struct prefix *)&( + nbr_src_prefix)) != + PREFIX_PERMIT) + OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); + } + } +} + int ospf_if_get_output_cost(struct ospf_interface *oi) { /* If all else fails, use default OSPF cost */ @@ -147,26 +176,22 @@ void ospf_if_reset(struct interface *ifp) } } -void ospf_if_reset_variables(struct ospf_interface *oi) +static void ospf_if_default_variables(struct ospf_interface *oi) { /* Set default values. */ - /* don't clear this flag. oi->flag = OSPF_IF_DISABLE; */ - if (oi->vl_data) - oi->type = OSPF_IFTYPE_VIRTUALLINK; - else - /* preserve network-type */ - if (oi->type != OSPF_IFTYPE_NBMA) - oi->type = OSPF_IFTYPE_BROADCAST; + oi->type = OSPF_IFTYPE_BROADCAST; oi->state = ISM_Down; oi->crypt_seqnum = 0; - /* This must be short, (less than RxmtInterval) - - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being - held back for too long - MAG */ - oi->v_ls_ack = 1; + /* + * The OSPF LS ACK Delay timer must be less than the LS Retransmision + * timer. As per RFC 2328 Section 13.5 paragraph 3, Set to 1 second + * to avoid Acks being held back for too long + */ + oi->v_ls_ack_delayed = OSPF_ACK_DELAY_DEFAULT; } /* lookup oi for specified prefix/ifp */ @@ -249,12 +274,12 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, /* Initialize static neighbor list. */ oi->nbr_nbma = list_new(); - /* Initialize Link State Acknowledgment list. */ - oi->ls_ack = list_new(); - oi->ls_ack_direct.ls_ack = list_new(); + /* Initialize Link State Acknowledgment lists. */ + ospf_lsa_list_init(&oi->ls_ack_delayed); + ospf_lsa_list_init(&oi->ls_ack_direct); /* Set default values. */ - ospf_if_reset_variables(oi); + ospf_if_default_variables(oi); /* Set pseudo neighbor to Null */ oi->nbr_self = NULL; @@ -283,6 +308,22 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, return oi; } +/* + * Cleanup Interface Ack List + */ +static void ospf_if_cleanup_ack_list(struct ospf_lsa_list_head *ls_ack_list) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup(struct ospf_interface *oi) @@ -291,7 +332,6 @@ void ospf_if_cleanup(struct ospf_interface *oi) struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; - struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ @@ -315,10 +355,9 @@ void ospf_if_cleanup(struct ospf_interface *oi) OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); } - /* Cleanup Link State Acknowlegdment list. */ - for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa)) - ospf_lsa_unlock(&lsa); /* oi->ls_ack */ - list_delete_all_node(oi->ls_ack); + /* Cleanup Link State Delayed Acknowlegdment list. */ + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); oi->crypt_seqnum = 0; @@ -339,6 +378,8 @@ void ospf_if_free(struct ospf_interface *oi) assert(oi->state == ISM_Down); + ospf_opaque_type9_lsa_if_cleanup(oi); + ospf_opaque_type9_lsa_term(oi); QOBJ_UNREG(oi); @@ -352,8 +393,8 @@ void ospf_if_free(struct ospf_interface *oi) /* Free any lists that should be freed */ list_delete(&oi->nbr_nbma); - list_delete(&oi->ls_ack); - list_delete(&oi->ls_ack_direct.ls_ack); + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u deleted", @@ -380,26 +421,6 @@ int ospf_if_is_up(struct ospf_interface *oi) return if_is_up(oi->ifp); } -struct ospf_interface *ospf_if_exists(struct ospf_interface *oic) -{ - struct listnode *node; - struct ospf *ospf; - struct ospf_interface *oi; - - if (!oic) - return NULL; - - ospf = oic->ospf; - if (ospf == NULL) - return NULL; - - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) - if (oi == oic) - return oi; - - return NULL; -} - /* Lookup OSPF interface by router LSA posistion */ struct ospf_interface *ospf_if_lookup_by_lsa_pos(struct ospf_area *area, int lsa_pos) @@ -537,6 +558,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, output_cost_cmd); UNSET_IF_PARAM(oip, transmit_delay); UNSET_IF_PARAM(oip, retransmit_interval); + UNSET_IF_PARAM(oip, retransmit_window); UNSET_IF_PARAM(oip, passive_interface); UNSET_IF_PARAM(oip, v_hello); UNSET_IF_PARAM(oip, fast_hello); @@ -550,6 +572,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, if_area); UNSET_IF_PARAM(oip, opaque_capable); UNSET_IF_PARAM(oip, keychain_name); + UNSET_IF_PARAM(oip, nbr_filter_name); oip->auth_crypt = list_new(); @@ -568,6 +591,7 @@ static void ospf_del_if_params(struct interface *ifp, { list_delete(&oip->auth_crypt); XFREE(MTYPE_OSPF_IF_PARAMS, oip->keychain_name); + XFREE(MTYPE_OSPF_IF_PARAMS, oip->nbr_filter_name); ospf_interface_disable_bfd(ifp, oip); ldp_sync_info_free(&(oip->ldp_sync_info)); XFREE(MTYPE_OSPF_IF_PARAMS, oip); @@ -592,6 +616,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_window) && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && @@ -603,7 +628,8 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) !OSPF_IF_PARAM_CONFIGURED(oip, if_area) && !OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) && !OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) && - !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) && + !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) && + !OSPF_IF_PARAM_CONFIGURED(oip, nbr_filter_name) && listcount(oip->auth_crypt) == 0) { ospf_del_if_params(ifp, oip); rn->info = NULL; @@ -687,6 +713,9 @@ int ospf_if_new_hook(struct interface *ifp) IF_DEF_PARAMS(ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), priority); IF_DEF_PARAMS(ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; @@ -839,14 +868,41 @@ int ospf_if_up(struct ospf_interface *oi) return 1; } -int ospf_if_down(struct ospf_interface *oi) +/* This function will mark routes with next-hops matching the down + * OSPF interface as changed. It is used to assure routes that get + * removed from the zebra RIB when an interface goes down are + * reinstalled if the interface comes back up prior to an intervening + * SPF calculation. + */ +static void ospf_if_down_mark_routes_changed(struct route_table *table, + struct ospf_interface *oi) { - struct ospf *ospf; struct route_node *rn; struct ospf_route *or; struct listnode *nh; struct ospf_path *op; + for (rn = route_top(table); rn; rn = route_next(rn)) { + or = rn->info; + + if (or == NULL) + continue; + + for (nh = listhead(or->paths); nh; + nh = listnextnode_unchecked(nh)) { + op = listgetdata(nh); + if (op->ifindex == oi->ifp->ifindex) { + or->changed = true; + break; + } + } + } +} + +int ospf_if_down(struct ospf_interface *oi) +{ + struct ospf *ospf; + if (oi == NULL) return 0; @@ -882,23 +938,11 @@ int ospf_if_down(struct ospf_interface *oi) /* Shutdown packet reception and sending */ ospf_if_stream_unset(oi); - if (!ospf->new_table) - return 1; - for (rn = route_top(ospf->new_table); rn; rn = route_next(rn)) { - or = rn->info; - - if (!or) - continue; + if (ospf->new_table) + ospf_if_down_mark_routes_changed(ospf->new_table, oi); - for (nh = listhead(or->paths); nh; - nh = listnextnode_unchecked(nh)) { - op = listgetdata(nh); - if (op->ifindex == oi->ifp->ifindex) { - or->changed = true; - break; - } - } - } + if (ospf->new_external_route) + ospf_if_down_mark_routes_changed(ospf->new_external_route, oi); return 1; } @@ -932,7 +976,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, { struct ospf_interface *voi; struct interface *vi; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; struct ospf_area *area; struct in_addr area_id; struct connected *co; @@ -962,7 +1006,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, UNSET_FLAG(vi->status, ZEBRA_INTERFACE_LINKDETECTION); co = connected_new(); co->ifp = vi; - listnode_add(vi->connected, co); + if_connected_add_tail(vi->connected, co); p = prefix_ipv4_new(); p->family = AF_INET; @@ -1167,7 +1211,7 @@ static int ospf_vl_set_params(struct ospf_area *area, if (IS_DEBUG_OSPF_EVENT) zlog_debug( "found back link through VL"); - /* fallthru */ + fallthrough; case LSA_LINK_TYPE_TRANSIT: case LSA_LINK_TYPE_POINTOPOINT: if (!IPV4_ADDR_SAME(&vl_data->peer_addr, @@ -1391,7 +1435,8 @@ static int ospf_ifp_create(struct interface *ifp) (!OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp), type) || if_is_loopback(ifp))) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), type); - IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp); + if (!IF_DEF_PARAMS(ifp)->type_cfg) + IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp); } ospf = ifp->vrf->info; @@ -1562,8 +1607,10 @@ void ospf_reset_hello_timer(struct interface *ifp, struct in_addr addr, void ospf_if_init(void) { - if_zapi_callbacks(ospf_ifp_create, ospf_ifp_up, - ospf_ifp_down, ospf_ifp_destroy); + hook_register_prio(if_real, 0, ospf_ifp_create); + hook_register_prio(if_up, 0, ospf_ifp_up); + hook_register_prio(if_down, 0, ospf_ifp_down); + hook_register_prio(if_unreal, 0, ospf_ifp_destroy); /* Initialize Zebra interface data structure. */ hook_register_prio(if_add, 0, ospf_if_new_hook); diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index e2290a881cc4..78a4fb9e59f9 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -13,6 +13,7 @@ #include "keychain.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" +#include #define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) @@ -47,6 +48,8 @@ struct ospf_if_params { output_cost_cmd); /* Command Interface Output Cost */ DECLARE_IF_PARAM(uint32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM(uint32_t, + retransmit_window); /* Retransmission Window */ DECLARE_IF_PARAM(uint8_t, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to @@ -57,6 +60,7 @@ struct ospf_if_params { DECLARE_IF_PARAM(struct in_addr, if_area); uint32_t if_area_id_fmt; + bool type_cfg; DECLARE_IF_PARAM(uint8_t, type); /* type of interface */ #define OSPF_IF_ACTIVE 0 #define OSPF_IF_PASSIVE 1 @@ -119,8 +123,14 @@ struct ospf_if_params { /* point-to-multipoint delayed reflooding configuration */ bool p2mp_delay_reflood; + /* point-to-multipoint doesn't support broadcast */ + bool p2mp_non_broadcast; + /* Opaque LSA capability at interface level (see RFC5250) */ DECLARE_IF_PARAM(bool, opaque_capable); + + /* Name of prefix-list name for packet source address filtering. */ + DECLARE_IF_PARAM(char *, nbr_filter_name); }; enum { MEMBER_ALLROUTERS = 0, @@ -185,6 +195,10 @@ struct ospf_interface { /* OSPF Network Type. */ uint8_t type; +#define OSPF_IF_NON_BROADCAST(O) \ + (((O)->type == OSPF_IFTYPE_NBMA) || \ + ((((O)->type == OSPF_IFTYPE_POINTOMULTIPOINT) && \ + (O)->p2mp_non_broadcast))) /* point-to-point DMVPN configuration */ uint8_t ptp_dmvpn; @@ -192,6 +206,9 @@ struct ospf_interface { /* point-to-multipoint delayed reflooding */ bool p2mp_delay_reflood; + /* point-to-multipoint doesn't support broadcast */ + bool p2mp_non_broadcast; + /* State of Interface State Machine. */ uint8_t state; @@ -232,6 +249,9 @@ struct ospf_interface { /* List of configured NBMA neighbor. */ struct list *nbr_nbma; + /* Configured prefix-list for filtering neighbors. */ + struct prefix_list *nbr_filter; + /* Graceful-Restart data. */ struct { struct { @@ -246,20 +266,20 @@ struct ospf_interface { struct route_table *ls_upd_queue; - struct list *ls_ack; /* Link State Acknowledgment list. */ - - struct { - struct list *ls_ack; - struct in_addr dst; - } ls_ack_direct; + /* + * List of LSAs for delayed and direct link + * state acknowledgment transmission. + */ + struct ospf_lsa_list_head ls_ack_delayed; + struct ospf_lsa_list_head ls_ack_direct; /* Timer values. */ - uint32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + uint32_t v_ls_ack_delayed; /* Delayed Link State Acknowledgment */ /* Threads. */ struct event *t_hello; /* timer */ struct event *t_wait; /* timer */ - struct event *t_ls_ack; /* timer */ + struct event *t_ls_ack_delayed; /* timer */ struct event *t_ls_ack_direct; /* event */ struct event *t_ls_upd_event; /* event */ struct event *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ @@ -279,6 +299,7 @@ struct ospf_interface { uint32_t ls_ack_out; /* LS Ack message output count. */ uint32_t discarded; /* discarded input count by error. */ uint32_t state_change; /* Number of status change. */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmitted. */ uint32_t full_nbrs; @@ -300,7 +321,6 @@ extern int ospf_if_up(struct ospf_interface *oi); extern int ospf_if_down(struct ospf_interface *oi); extern int ospf_if_is_up(struct ospf_interface *oi); -extern struct ospf_interface *ospf_if_exists(struct ospf_interface *oi); extern struct ospf_interface *ospf_if_lookup_by_lsa_pos(struct ospf_area *area, int lsa_pos); extern struct ospf_interface * @@ -327,7 +347,6 @@ extern void ospf_if_update_params(struct interface *ifp, struct in_addr addr); extern int ospf_if_new_hook(struct interface *ifp); extern void ospf_if_init(void); extern void ospf_if_stream_unset(struct ospf_interface *oi); -extern void ospf_if_reset_variables(struct ospf_interface *oi); extern int ospf_if_is_enable(struct ospf_interface *oi); extern int ospf_if_get_output_cost(struct ospf_interface *oi); extern void ospf_if_recalculate_output_cost(struct interface *ifp); @@ -359,6 +378,7 @@ extern void ospf_crypt_key_add(struct list *list, struct crypt_key *key); extern int ospf_crypt_key_delete(struct list *list, uint8_t key_id); extern uint8_t ospf_default_iftype(struct interface *ifp); extern int ospf_interface_neighbor_count(struct ospf_interface *oi); +extern void ospf_intf_neighbor_filter_apply(struct ospf_interface *oi); /* Set all multicast memberships appropriately based on the type and state of the interface. */ diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 2516fa75db43..377e7a6bcc20 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -285,7 +285,7 @@ static void ism_timer_set(struct ospf_interface *oi) reset also. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Loopback: @@ -293,7 +293,7 @@ static void ism_timer_set(struct ospf_interface *oi) unavailable for regular data traffic. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Waiting: @@ -304,7 +304,7 @@ static void ism_timer_set(struct ospf_interface *oi) OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer, OSPF_IF_PARAM(oi, v_wait)); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); break; case ISM_PointToPoint: /* The interface connects to a physical Point-to-point network @@ -314,8 +314,6 @@ static void ism_timer_set(struct ospf_interface *oi) /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DROther: /* The network type of the interface is broadcast or NBMA @@ -324,8 +322,6 @@ static void ism_timer_set(struct ospf_interface *oi) Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_Backup: /* The network type of the interface is broadcast os NBMA @@ -333,8 +329,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DR: /* The network type of the interface is broadcast or NBMA @@ -342,8 +336,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; } } @@ -367,7 +359,7 @@ static int ism_interface_up(struct ospf_interface *oi) /* Otherwise, the state transitions to Waiting. */ next_state = ISM_Waiting; - if (oi->type == OSPF_IFTYPE_NBMA) + if (OSPF_IF_NON_BROADCAST(oi)) ospf_nbr_nbma_if_update(oi->ospf, oi); /* ospf_ism_event (t); */ diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index 4aab880d2280..496ae5b4bdc9 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -774,7 +774,7 @@ DEFPY (no_ospf_mpls_ldp_sync, "Disable MPLS LDP-IGP Sync\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - ospf_ldp_sync_gbl_exit(ospf, false); + ospf_ldp_sync_gbl_exit(ospf, true); return CMD_SUCCESS; } @@ -901,7 +901,7 @@ DEFPY (no_mpls_ldp_sync, * stop holddown timer if running * restore ospf cost */ - SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG); + UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG); ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT; ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED; EVENT_OFF(ldp_sync_info->t_holddown); diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index e47f83272892..f125fa93b1e4 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -3096,13 +3096,14 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi, /* Incoming "oi" for this LSA has set at LSUpd * reception. */ } - /* Fallthrough */ + fallthrough; case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_install(lsa, rt_recalc); break; case OSPF_AS_NSSA_LSA: new = ospf_external_lsa_install(ospf, lsa, rt_recalc); + break; default: /* type-6,8,9....nothing special */ break; } diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index 0111c4924ec2..d1b3eb0d354b 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -34,6 +34,59 @@ void ospf_lsdb_init(struct ospf_lsdb *lsdb) lsdb->type[i].db = route_table_init(); } +static struct route_node * +ospf_lsdb_linked_node_create(route_table_delegate_t *delegate, + struct route_table *table) +{ + struct ospf_lsdb_linked_node *node; + + node = XCALLOC(MTYPE_OSPF_LSDB_NODE, + sizeof(struct ospf_lsdb_linked_node)); + + return (struct route_node *)node; +} + +static void ospf_lsdb_linked_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node = + (struct ospf_lsdb_linked_node *)node; + + XFREE(MTYPE_OSPF_LSDB_NODE, lsdb_linked_node); +} + +static route_table_delegate_t ospf_lsdb_linked_table_delegate = { + .create_node = ospf_lsdb_linked_node_create, + .destroy_node = ospf_lsdb_linked_node_destroy, +}; + +void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init_with_delegate( + &ospf_lsdb_linked_table_delegate); +} + +struct ospf_lsdb_linked_node *ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, + struct ospf_lsa *lsa) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node; + struct route_table *table; + struct prefix_ls lp; + + table = lsdb->type[lsa->data->type].db; + ls_prefix_set(&lp, lsa); + lsdb_linked_node = (struct ospf_lsdb_linked_node *) + route_node_lookup(table, (struct prefix *)&lp); + if (lsdb_linked_node) + route_unlock_node((struct route_node *)lsdb_linked_node); + + return lsdb_linked_node; +} + void ospf_lsdb_free(struct ospf_lsdb *lsdb) { ospf_lsdb_cleanup(lsdb); diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h index bf295ca8306a..e5e3be8baa0b 100644 --- a/ospfd/ospf_lsdb.h +++ b/ospfd/ospf_lsdb.h @@ -7,6 +7,9 @@ #ifndef _ZEBRA_OSPF_LSDB_H #define _ZEBRA_OSPF_LSDB_H +#include "prefix.h" +#include "table.h" + /* OSPF LSDB structure. */ struct ospf_lsdb { struct { @@ -43,9 +46,29 @@ struct ospf_lsdb { #define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) #define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) +/* + * Alternate route node structure for LSDB nodes linked to + * list elements. + */ +struct ospf_lsdb_linked_node { + /* + * Caution these must be the very first fields + */ + ROUTE_NODE_FIELDS + + /* + * List entry on an LSA list, e.g., a neighbor + * retransmission list. + */ + struct ospf_lsa_list_entry *lsa_list_entry; +}; + /* OSPF LSDB related functions. */ extern struct ospf_lsdb *ospf_lsdb_new(void); extern void ospf_lsdb_init(struct ospf_lsdb *); +extern void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb); +extern struct ospf_lsdb_linked_node * +ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa); extern void ospf_lsdb_free(struct ospf_lsdb *); extern void ospf_lsdb_cleanup(struct ospf_lsdb *); extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index dd000241f403..5c11027506dd 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -28,6 +28,7 @@ #include "libfrr.h" #include "routemap.h" #include "keychain.h" +#include "libagentx.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -44,6 +45,23 @@ #include "ospfd/ospf_errors.h" #include "ospfd/ospf_ldp_sync.h" #include "ospfd/ospf_routemap_nb.h" +#include "ospfd/ospf_apiserver.h" + +#define OSPFD_STATE_NAME "%s/ospfd.json", frr_libstatedir +#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_libstatedir, i + +/* this one includes the path... because the instance number was in the path + * before :( ... which totally didn't have a mkdir anywhere. + * + * ... and libstatedir & runstatedir got switched around while changing this; + * for non-instance it read the wrong path, for instance it wrote the wrong + * path. (There is no COMPAT2 for non-instance because it was writing to the + * right place, i.e. no extra path to check exists from reading a wrong path.) + */ +#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_runstatedir +#define OSPFD_COMPAT1_INST_STATE_NAME(i) \ + "%s-%d/ospfd-gr.json", frr_runstatedir, i +#define OSPFD_COMPAT2_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i /* ospfd privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, @@ -65,6 +83,7 @@ struct zebra_privs_t ospfd_privs = { const struct option longopts[] = { {"instance", required_argument, NULL, 'n'}, {"apiserver", no_argument, NULL, 'a'}, + {"apiserver_addr", required_argument, NULL, 'l'}, {0} }; @@ -73,10 +92,6 @@ const struct option longopts[] = { /* Master of threads. */ struct event_loop *master; -#ifdef SUPPORT_OSPF_API -extern int ospf_apiserver_enable; -#endif /* SUPPORT_OSPF_API */ - /* SIGHUP handler. */ static void sighup(void) { @@ -89,6 +104,7 @@ static void sigint(void) zlog_notice("Terminating on signal"); bfd_protocol_integration_set_shutdown(true); ospf_terminate(); + exit(0); } @@ -123,17 +139,37 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = { &frr_route_map_info, &frr_vrf_info, &frr_ospf_route_map_info, + &ietf_key_chain_info, + &ietf_key_chain_deviation_info, +}; + +/* actual paths filled in main() */ +static char state_path[512]; +static char state_compat1_path[512]; +static char state_compat2_path[512]; +static char *state_paths[] = { + state_path, + state_compat1_path, + state_compat2_path, /* NULLed out if not needed */ + NULL, }; -FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(ospfd, OSPF, + .vty_port = OSPF_VTY_PORT, + .proghelp = "Implementation of the OSPFv2 routing protocol.", + + .signals = ospf_signals, + .n_signals = array_size(ospf_signals), - .proghelp = "Implementation of the OSPFv2 routing protocol.", + .privs = &ospfd_privs, - .signals = ospf_signals, .n_signals = array_size(ospf_signals), + .yang_modules = ospfd_yang_modules, + .n_yang_modules = array_size(ospfd_yang_modules), - .privs = &ospfd_privs, .yang_modules = ospfd_yang_modules, - .n_yang_modules = array_size(ospfd_yang_modules), + .state_paths = state_paths, ); +/* clang-format on */ /** Max wait time for config to load before accepting hellos */ #define OSPF_PRE_CONFIG_MAX_WAIT_SECONDS 600 @@ -164,15 +200,11 @@ static void ospf_config_end(void) /* OSPFd main routine. */ int main(int argc, char **argv) { -#ifdef SUPPORT_OSPF_API - /* OSPF apiserver is disabled by default. */ - ospf_apiserver_enable = 0; -#endif /* SUPPORT_OSPF_API */ - frr_preinit(&ospfd_di, argc, argv); - frr_opt_add("n:a", longopts, + frr_opt_add("n:al:", longopts, " -n, --instance Set the instance id\n" - " -a, --apiserver Enable OSPF apiserver\n"); + " -a, --apiserver Enable OSPF apiserver\n" + " -l, --apiserver_addr Set OSPF apiserver bind address\n"); while (1) { int opt; @@ -194,6 +226,14 @@ int main(int argc, char **argv) case 'a': ospf_apiserver_enable = 1; break; + case 'l': + if (inet_pton(AF_INET, optarg, &ospf_apiserver_addr) <= + 0) { + zlog_err("OSPF: Invalid API Server IPv4 address %s specified", + optarg); + exit(0); + } + break; #endif /* SUPPORT_OSPF_API */ default: frr_help_exit(1); @@ -207,6 +247,23 @@ int main(int argc, char **argv) exit(1); } + if (ospf_instance) { + snprintf(state_path, sizeof(state_path), + OSPFD_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat1_path, sizeof(state_compat1_path), + OSPFD_COMPAT1_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat2_path, sizeof(state_compat2_path), + OSPFD_COMPAT2_INST_STATE_NAME(ospf_instance)); + } else { + snprintf(state_path, sizeof(state_path), OSPFD_STATE_NAME); + snprintf(state_compat1_path, sizeof(state_compat1_path), + OSPFD_COMPAT_STATE_NAME); + /* no COMPAT2 here since it was reading that was broken, + * there is no additional path that would've been written + */ + state_paths[2] = NULL; + } + /* OSPF master init. */ ospf_master_init(frr_init()); @@ -214,6 +271,7 @@ int main(int argc, char **argv) master = om->master; /* Library inits. */ + libagentx_init(); ospf_debug_init(); ospf_vrf_init(); diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 9854c8cae80b..478af323d30b 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -45,3 +45,5 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper"); DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation"); DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space"); DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space"); +DEFINE_MTYPE(OSPFD, OSPF_LSA_LIST, "OSPF LSA List"); +DEFINE_MTYPE(OSPFD, OSPF_LSDB_NODE, "OSPF LSDB Linked Node"); diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index d11b69abb01b..e2139b517b17 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -44,5 +44,7 @@ DECLARE_MTYPE(OSPF_GR_HELPER); DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR); DECLARE_MTYPE(OSPF_P_SPACE); DECLARE_MTYPE(OSPF_Q_SPACE); +DECLARE_MTYPE(OSPF_LSA_LIST); +DECLARE_MTYPE(OSPF_LSDB_NODE); #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index c238f051dfeb..2514fc0ab3b9 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -68,7 +68,7 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); nbr->priority = -1; /* DD flags. */ @@ -80,8 +80,10 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->nbr_nbma = NULL; ospf_lsdb_init(&nbr->db_sum); - ospf_lsdb_init(&nbr->ls_rxmt); + + ospf_lsdb_linked_init(&nbr->ls_rxmt); ospf_lsdb_init(&nbr->ls_req); + ospf_lsa_list_init(&nbr->ls_rxmt_list); nbr->crypt_seqnum = 0; @@ -128,7 +130,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) EVENT_OFF(nbr->t_inactivity); EVENT_OFF(nbr->t_db_desc); EVENT_OFF(nbr->t_ls_req); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); /* Cancel all events. */ /* Thread lookup cost would be negligible. */ event_cancel_event(master, nbr); @@ -431,7 +433,7 @@ static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi, memcpy(&nbr->address, p, sizeof(struct prefix)); nbr->nbr_nbma = NULL; - if (oi->type == OSPF_IFTYPE_NBMA) { + if (OSPF_IF_NON_BROADCAST(oi)) { struct ospf_nbr_nbma *nbr_nbma; struct listnode *node; @@ -485,7 +487,7 @@ struct ospf_neighbor *ospf_nbr_get(struct ospf_interface *oi, route_unlock_node(rn); nbr = rn->info; - if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt) { + if (OSPF_IF_NON_BROADCAST(nbr->oi) && nbr->state == NSM_Attempt) { nbr->src = iph->ip_src; memcpy(&nbr->address, p, sizeof(struct prefix)); } diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 07d095f03d1b..0e041f9e6df2 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -9,6 +9,7 @@ #include #include +#include /* Neighbor Data Structure */ struct ospf_neighbor { @@ -44,6 +45,7 @@ struct ospf_neighbor { /* LSA data. */ struct ospf_lsdb ls_rxmt; + struct ospf_lsa_list_head ls_rxmt_list; struct ospf_lsdb db_sum; struct ospf_lsdb ls_req; struct ospf_lsa *ls_req_last; @@ -54,13 +56,13 @@ struct ospf_neighbor { uint32_t v_inactivity; uint32_t v_db_desc; uint32_t v_ls_req; - uint32_t v_ls_upd; + uint32_t v_ls_rxmt; /* Threads. */ struct event *t_inactivity; struct event *t_db_desc; struct event *t_ls_req; - struct event *t_ls_upd; + struct event *t_ls_rxmt; struct event *t_hello_reply; /* NBMA configured neighbour */ @@ -71,6 +73,7 @@ struct ospf_neighbor { struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ uint32_t state_change; /* NSM state change counter */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmited. */ /* BFD information */ struct bfd_session_params *bfd_session; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index bcbe02879575..079a1fa55ed3 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -107,23 +107,21 @@ static void nsm_timer_set(struct ospf_neighbor *nbr) case NSM_Down: EVENT_OFF(nbr->t_inactivity); EVENT_OFF(nbr->t_hello_reply); - /* fallthru */ + fallthrough; case NSM_Attempt: case NSM_Init: case NSM_TwoWay: EVENT_OFF(nbr->t_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_ExStart: OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_Exchange: - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, - nbr->v_ls_upd); if (!IS_SET_DD_MS(nbr->dd_flags)) EVENT_OFF(nbr->t_db_desc); break; @@ -166,7 +164,7 @@ static int nsm_hello_received(struct ospf_neighbor *nbr) OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer, nbr->v_inactivity); - if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma) + if (OSPF_IF_NON_BROADCAST(nbr->oi) && nbr->nbr_nbma != NULL) EVENT_OFF(nbr->nbr_nbma->t_poll); /* Send proactive ARP requests */ @@ -219,7 +217,7 @@ static int ospf_db_summary_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) case OSPF_OPAQUE_LINK_LSA: /* Exclude type-9 LSAs that does not have the same "oi" with * "nbr". */ - if (ospf_if_exists(lsa->oi) != nbr->oi) + if (lsa->oi != nbr->oi) return 0; break; case OSPF_OPAQUE_AREA_LSA: @@ -377,7 +375,7 @@ static int nsm_kill_nbr(struct ospf_neighbor *nbr) return 0; } - if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) { + if (OSPF_IF_NON_BROADCAST(nbr->oi) && nbr->nbr_nbma != NULL) { struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma; nbr_nbma->nbr = NULL; diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 27f47a6d79a3..5d2d65658f6e 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -257,7 +257,7 @@ static void free_opaque_info_per_type(struct opaque_info_per_type *oipt, struct ospf_opaque_functab { uint8_t opaque_type; - struct opaque_info_per_type *oipt; + uint32_t ref_count; int (*new_if_hook)(struct interface *ifp); int (*del_if_hook)(struct interface *ifp); @@ -280,9 +280,28 @@ static struct list *ospf_opaque_type9_funclist; static struct list *ospf_opaque_type10_funclist; static struct list *ospf_opaque_type11_funclist; +static void ospf_opaque_functab_ref(struct ospf_opaque_functab *functab) +{ + functab->ref_count++; +} + +static void ospf_opaque_functab_deref(struct ospf_opaque_functab *functab) +{ + assert(functab->ref_count); + functab->ref_count--; + if (functab->ref_count == 0) + XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, functab); +} + static void ospf_opaque_del_functab(void *val) { - XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, val); + struct ospf_opaque_functab *functab = (struct ospf_opaque_functab *)val; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Opaque LSA functab list deletion callback type %u (%p)", + __func__, functab->opaque_type, functab); + + ospf_opaque_functab_deref(functab); return; } @@ -290,6 +309,9 @@ static void ospf_opaque_funclist_init(void) { struct list *funclist; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Function list initialize", __func__); + funclist = ospf_opaque_wildcard_funclist = list_new(); funclist->del = ospf_opaque_del_functab; @@ -308,6 +330,9 @@ static void ospf_opaque_funclist_term(void) { struct list *funclist; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Function list terminate", __func__); + funclist = ospf_opaque_wildcard_funclist; list_delete(&funclist); @@ -383,18 +408,24 @@ int ospf_register_opaque_functab( for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab)) if (functab->opaque_type == opaque_type) { - flog_warn( - EC_OSPF_LSA, - "%s: Duplicated entry?: lsa_type(%u), opaque_type(%u)", - __func__, lsa_type, opaque_type); - return -1; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Opaque LSA functab found type %u, (%p)", + __func__, functab->opaque_type, + functab); + break; } - new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB, - sizeof(struct ospf_opaque_functab)); + if (functab == NULL) + new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB, + sizeof(struct ospf_opaque_functab)); + else { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Re-register Opaque LSA type %u, opaque type %u, (%p)", + __func__, lsa_type, opaque_type, functab); + return 0; + } new->opaque_type = opaque_type; - new->oipt = NULL; new->new_if_hook = new_if_hook; new->del_if_hook = del_if_hook; new->ism_change_hook = ism_change_hook; @@ -408,7 +439,12 @@ int ospf_register_opaque_functab( new->new_lsa_hook = new_lsa_hook; new->del_lsa_hook = del_lsa_hook; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Register Opaque LSA type %u, opaque type %u, (%p)", + __func__, lsa_type, opaque_type, new); + listnode_add(funclist, new); + ospf_opaque_functab_ref(new); return 0; } @@ -422,15 +458,18 @@ void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type) if ((funclist = ospf_get_opaque_funclist(lsa_type)) != NULL) for (ALL_LIST_ELEMENTS(funclist, node, nnode, functab)) { if (functab->opaque_type == opaque_type) { - /* Cleanup internal control information, if it - * still remains. */ - if (functab->oipt != NULL) - free_opaque_info_per_type(functab->oipt, - true); - /* Dequeue listnode entry from the list. */ + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Delete Opaque functab LSA type %u, opaque type %u, (%p)", + __func__, lsa_type, + opaque_type, functab); + + /* Dequeue listnode entry from the function table + * list coreesponding to the opaque LSA type. + * Note that the list deletion callback frees + * the functab entry memory. + */ listnode_delete(funclist, functab); - - XFREE(MTYPE_OSPF_OPAQUE_FUNCTAB, functab); + ospf_opaque_functab_deref(functab); break; } } @@ -565,10 +604,15 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab, oipt->opaque_type = GET_OPAQUE_TYPE(ntohl(new->data->id.s_addr)); oipt->status = PROC_NORMAL; oipt->functab = functab; - functab->oipt = oipt; + ospf_opaque_functab_ref(functab); oipt->id_list = list_new(); oipt->id_list->del = free_opaque_info_per_id; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Register Opaque info-per-type LSA type %u, opaque type %u, (%p), Functab (%p)", + __func__, oipt->lsa_type, oipt->opaque_type, oipt, + oipt->functab); + out: return oipt; } @@ -614,6 +658,15 @@ static void free_opaque_info_per_type(struct opaque_info_per_type *oipt, } listnode_delete(l, oipt); } + + if (oipt->functab) + ospf_opaque_functab_deref(oipt->functab); + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Free Opaque info-per-type LSA type %u, opaque type %u, (%p), Functab (%p)", + __func__, oipt->lsa_type, oipt->opaque_type, oipt, + oipt->functab); + XFREE(MTYPE_OPAQUE_INFO_PER_TYPE, oipt); return; } @@ -746,6 +799,45 @@ int ospf_opaque_is_owned(struct ospf_lsa *lsa) return (oipt != NULL && lookup_opaque_info_by_id(oipt, lsa) != NULL); } +/* + * Cleanup Link-Local LSAs assocaited with an interface that is being deleted. + * Since these LSAs are stored in the area link state database (LSDB) as opposed + * to a separate per-interface, they must be deleted from the area database. + * Since their flooding scope is solely the deleted OSPF interface, there is no + * need to attempt to flush them from the routing domain. For link local LSAs + * originated via the OSPF server API, LSA deletion before interface deletion + * is required so that the callback can access the OSPF interface address. + */ +void ospf_opaque_type9_lsa_if_cleanup(struct ospf_interface *oi) +{ + struct route_node *rn; + struct ospf_lsdb *lsdb; + struct ospf_lsa *lsa; + + lsdb = oi->area->lsdb; + LSDB_LOOP (OPAQUE_LINK_LSDB(oi->area), rn, lsa) + /* + * While the LSA shouldn't be referenced on any LSA + * lists since the flooding scoped is confined to the + * interface being deleted, clear the pointer to the + * deleted interface to avoid references and set the + * age to MAXAGE to avoid flush processing when the LSA + * is removed from the interface opaque info list. + */ + if (lsa->oi == oi) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("Delete Type-9 Opaque-LSA on interface delete: [opaque-type=%u, opaque-id=%x]", + GET_OPAQUE_TYPE( + ntohl(lsa->data->id.s_addr)), + GET_OPAQUE_ID(ntohl( + lsa->data->id.s_addr))); + ospf_lsdb_delete(lsdb, lsa); + lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); + lsa->oi = NULL; + ospf_lsa_discard(lsa); + } +} + /*------------------------------------------------------------------------* * Following are (vty) configuration functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ @@ -1159,12 +1251,12 @@ void ospf_opaque_config_write_debug(struct vty *vty) void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, json_object *json) { - char buf[128], *bp; struct lsa_header *lsah = lsa->data; uint32_t lsid = ntohl(lsah->id.s_addr); uint8_t opaque_type = GET_OPAQUE_TYPE(lsid); uint32_t opaque_id = GET_OPAQUE_ID(lsid); struct ospf_opaque_functab *functab; + json_object *jopaque = NULL; int len, lenValid; /* Switch output functionality by vty address. */ @@ -1185,17 +1277,14 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, ospf_opaque_type_name(opaque_type)); json_object_int_add(json, "opaqueId", opaque_id); len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; - json_object_int_add(json, "opaqueDataLength", len); + json_object_int_add(json, "opaqueLength", len); lenValid = VALID_OPAQUE_INFO_LEN(lsah); - json_object_boolean_add(json, "opaqueDataLengthValid", + json_object_boolean_add(json, "opaqueLengthValid", lenValid); if (lenValid) { - bp = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), - "%*pHXn", (int)len, - (lsah + 1)); - json_object_string_add(json, "opaqueData", buf); - if (bp != buf) - XFREE(MTYPE_TMP, bp); + jopaque = json_object_new_object(); + json_object_object_add(json, "opaqueValues", + jopaque); } } } else { @@ -1212,7 +1301,7 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, /* Call individual output functions. */ if ((functab = ospf_opaque_functab_lookup(lsa)) != NULL) if (functab->show_opaque_info != NULL) - (*functab->show_opaque_info)(vty, json, lsa); + (*functab->show_opaque_info)(vty, jopaque, lsa); return; } diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index e0c78cd6dc95..54651f8f58a6 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -109,6 +109,7 @@ extern void ospf_opaque_term(void); extern void ospf_opaque_finish(void); extern int ospf_opaque_type9_lsa_init(struct ospf_interface *oi); extern void ospf_opaque_type9_lsa_term(struct ospf_interface *oi); +extern void ospf_opaque_type9_lsa_if_cleanup(struct ospf_interface *oi); extern int ospf_opaque_type10_lsa_init(struct ospf_area *area); extern void ospf_opaque_type10_lsa_term(struct ospf_area *area); extern int ospf_opaque_type11_lsa_init(struct ospf *ospf); diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index b37efa3efa21..e336435cbd72 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -23,6 +23,7 @@ #endif #include "vrf.h" #include "lib_errors.h" +#include "plist.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_network.h" @@ -291,54 +292,66 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr) event_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req); } -/* Cyclic timer function. Fist registered in ospf_nbr_new () in - ospf_neighbor.c */ -void ospf_ls_upd_timer(struct event *thread) +/* + * OSPF neighbor link state retransmission timer handler. Unicast + * unacknowledged LSAs to the neigbhors. + */ +void ospf_ls_rxmt_timer(struct event *thread) { struct ospf_neighbor *nbr; + int retransmit_interval, retransmit_window, rxmt_lsa_count = 0; nbr = EVENT_ARG(thread); - nbr->t_ls_upd = NULL; + nbr->t_ls_rxmt = NULL; + retransmit_interval = nbr->v_ls_rxmt; + retransmit_window = OSPF_IF_PARAM(nbr->oi, retransmit_window); /* Send Link State Update. */ if (ospf_ls_retransmit_count(nbr) > 0) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct timeval current_time, latest_rxmt_time, next_rxmt_time; + struct timeval rxmt_interval = { retransmit_interval, 0 }; + struct timeval rxmt_window; struct list *update; - struct ospf_lsdb *lsdb; - int i; - int retransmit_interval; - retransmit_interval = - OSPF_IF_PARAM(nbr->oi, retransmit_interval); + /* + * Set the retransmission window based on the configured value + * in milliseconds. + */ + rxmt_window.tv_sec = retransmit_window / 1000; + rxmt_window.tv_usec = (retransmit_window % 1000) * 1000; + + /* + * Calculate the latest retransmit time for LSAs transmited in + * this timer pass by adding the retransmission window to the + * current time. Calculate the next retransmission time by adding + * the retransmit interval to the current time. + */ + monotime(¤t_time); + timeradd(¤t_time, &rxmt_window, &latest_rxmt_time); + timeradd(¤t_time, &rxmt_interval, &next_rxmt_time); - lsdb = &nbr->ls_rxmt; update = list_new(); + while ((ls_rxmt_list_entry = + ospf_lsa_list_first(&nbr->ls_rxmt_list))) { + if (timercmp(&ls_rxmt_list_entry->list_entry_time, + &latest_rxmt_time, >)) + break; - for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { - struct route_table *table = lsdb->type[i].db; - struct route_node *rn; - - for (rn = route_top(table); rn; rn = route_next(rn)) { - struct ospf_lsa *lsa; - - if ((lsa = rn->info) != NULL) { - /* Don't retransmit an LSA if we - received it within - the last RxmtInterval seconds - this - is to allow the - neighbour a chance to acknowledge the - LSA as it may - have ben just received before the - retransmit timer - fired. This is a small tweak to what - is in the RFC, - but it will cut out out a lot of - retransmit traffic - - MAG */ - if (monotime_since(&lsa->tv_recv, NULL) - >= retransmit_interval * 1000000LL) - listnode_add(update, rn->info); - } - } + listnode_add(update, ls_rxmt_list_entry->lsa); + rxmt_lsa_count++; + + /* + * Set the next retransmit time for the LSA and move it + * to the end of the neighbor's retransmission list. + */ + ls_rxmt_list_entry->list_entry_time = next_rxmt_time; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + nbr->ls_rxmt_lsa++; + nbr->oi->ls_rxmt_lsa++; } if (listcount(update) > 0) @@ -347,23 +360,25 @@ void ospf_ls_upd_timer(struct event *thread) list_delete(&update); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) timer event - sent %u LSAs", + ospf_ls_retransmit_count(nbr), &nbr->router_id, + ospf_get_name(nbr->oi->ospf), rxmt_lsa_count); + /* Set LS Update retransmission timer. */ - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + ospf_ls_retransmit_set_timer(nbr); } -void ospf_ls_ack_timer(struct event *thread) +void ospf_ls_ack_delayed_timer(struct event *thread) { struct ospf_interface *oi; oi = EVENT_ARG(thread); - oi->t_ls_ack = NULL; + oi->t_ls_ack_delayed = NULL; /* Send Link State Acknowledgment. */ - if (listcount(oi->ls_ack) > 0) + if (ospf_lsa_list_count(&oi->ls_ack_delayed)) ospf_ls_ack_send_delayed(oi); - - /* Set LS Ack timer. */ - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); } #ifdef WANT_OSPF_WRITE_FRAGMENT @@ -1042,7 +1057,7 @@ static void ospf_db_desc_proc(struct stream *s, struct ospf_interface *oi, /* Neighbour has a more recent LSA, we must request it */ ospf_ls_request_add(nbr, new); - /* fallthru */ + fallthrough; case 0: /* If we have a copy of this LSA, it's either less * recent @@ -1231,7 +1246,7 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, through to case ExStart below. */ if (nbr->state != NSM_ExStart) break; - /* fallthru */ + fallthrough; case NSM_ExStart: /* Initial DBD */ if ((IS_SET_DD_ALL(dd->flags) == OSPF_DD_FLAG_ALL) @@ -1486,12 +1501,8 @@ static void ospf_ls_req(struct ip *iph, struct ospf_header *ospfh, /* Packet overflows MTU size, send immediately. */ if (length + ntohs(find->data->length) > ospf_packet_max(oi)) { - if (oi->type == OSPF_IFTYPE_NBMA) - ospf_ls_upd_send(nbr, ls_upd, - OSPF_SEND_PACKET_DIRECT, 0); - else - ospf_ls_upd_send(nbr, ls_upd, - OSPF_SEND_PACKET_INDIRECT, 0); + ospf_ls_upd_send(nbr, ls_upd, + OSPF_SEND_PACKET_DIRECT, 0); /* Only remove list contents. Keep ls_upd. */ list_delete_all_node(ls_upd); @@ -1508,12 +1519,7 @@ static void ospf_ls_req(struct ip *iph, struct ospf_header *ospfh, /* Send rest of Link State Update. */ if (listcount(ls_upd) > 0) { - if (oi->type == OSPF_IFTYPE_NBMA) - ospf_ls_upd_send(nbr, ls_upd, OSPF_SEND_PACKET_DIRECT, - 0); - else - ospf_ls_upd_send(nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT, - 0); + ospf_ls_upd_send(nbr, ls_upd, OSPF_SEND_PACKET_DIRECT, 0); list_delete(&ls_upd); } else @@ -1641,7 +1647,7 @@ static struct list *ospf_ls_upd_list_lsa(struct ospf_neighbor *nbr, case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ - /* Fallthrough */ + fallthrough; default: lsa->area = oi->area; break; @@ -1811,7 +1817,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa) && !current && ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF(lsa, LSA)) { @@ -1836,7 +1842,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa)) { zlog_info("LSA[%s]: Boomerang effect?", dump_lsa_key(lsa)); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); ospf_lsa_discard(lsa); if (current != NULL && !IS_LSA_MAXAGE(current)) @@ -1870,7 +1876,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, SET_FLAG(lsa->flags, OSPF_LSA_SELF); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); if (!ospf->gr_info.restart_in_progress) { ospf_opaque_self_originated_lsa_received( @@ -2009,9 +2015,8 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, */ if (oi->state == ISM_Backup) if (NBR_IS_DR(nbr)) - listnode_add( - oi->ls_ack, - ospf_lsa_lock(lsa)); + ospf_ls_ack_send_direct(nbr, + lsa); DISCARD_LSA(lsa, 6); } else @@ -2020,7 +2025,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, receiving interface. */ { - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); DISCARD_LSA(lsa, 7); } } @@ -2755,6 +2760,20 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp); + /* + * If a neighbor filter prefix-list is configured, apply it to the IP + * source address and ignore the packet if it doesn't match. + */ + if (oi && oi->nbr_filter) { + struct prefix ip_src_prefix = { AF_INET, IPV4_MAX_BITLEN, { 0 } }; + + ip_src_prefix.u.prefix4 = iph->ip_src; + if (prefix_list_apply(oi->nbr_filter, + (struct prefix *)&(ip_src_prefix)) != + PREFIX_PERMIT) + return OSPF_READ_CONTINUE; + } + /* * ospf_verify_header() relies on a valid "oi" and thus can be called * only after the passive/backbone/other checks below are passed. @@ -3308,17 +3327,35 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, return length; } -static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, - struct stream *s) +static int ospf_make_ls_ack(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct stream *s) { - struct listnode *node, *nnode; + struct ospf_lsa_list_entry *ls_ack_list_first; + struct ospf_lsa_list_entry *ls_ack_list_entry; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; + struct in_addr first_dst_addr = { INADDR_ANY }; - for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { + /* + * For direct LS Acks, assure the destination address doesn't + * change between queued acknowledgments. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + if (ls_ack_list_first) + first_dst_addr.s_addr = + ls_ack_list_first->list_entry_dst.s_addr; + } + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; assert(lsa); + if (direct_ack && (ls_ack_list_entry->list_entry_dst.s_addr != + first_dst_addr.s_addr)) + break; + /* LS Ack packet overflows interface MTU * delta is just number of bytes required for * 1 LS Ack(1 LS Hdr) ospf_packet_max will return @@ -3327,19 +3364,46 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, * against ospf_packet_max to check if it can fit * another ls header in the same packet. */ - if ((length + delta) > ospf_packet_max(oi)) + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; - listnode_delete(ack, lsa); - ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */ + if (delete_ack) { + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } } return length; } +/* + * On non-braodcast networks, the same LS acks must be sent to multiple + * neighbors and deletion must be deferred until after the LS Ack packet + * is sent to all neighbors. + */ +static void ospf_delete_ls_ack_delayed(struct ospf_interface *oi) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + uint16_t length = OSPF_LS_ACK_MIN_SIZE; + + frr_each_safe (ospf_lsa_list, &oi->ls_ack_delayed, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + assert(lsa); + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) + break; + + length += OSPF_LSA_HEADER_SIZE; + ospf_lsa_list_del(&oi->ls_ack_delayed, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr) { struct ospf_packet *op; @@ -3404,17 +3468,19 @@ static void ospf_poll_send(struct ospf_nbr_nbma *nbr_nbma) if (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) return; - if (oi->type != OSPF_IFTYPE_NBMA) - return; - if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down) return; - if (PRIORITY(oi) == 0) - return; + if (oi->type == OSPF_IFTYPE_NBMA) { + if (PRIORITY(oi) == 0) + return; - if (nbr_nbma->priority == 0 && oi->state != ISM_DR - && oi->state != ISM_Backup) + if (nbr_nbma->priority == 0 && oi->state != ISM_DR && + oi->state != ISM_Backup) + return; + + } else if (oi->type != OSPF_IFTYPE_POINTOMULTIPOINT || + !oi->p2mp_non_broadcast) return; ospf_hello_send_sub(oi, nbr_nbma->addr.s_addr); @@ -3460,7 +3526,7 @@ void ospf_hello_send(struct ospf_interface *oi) if (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) return; - if (oi->type == OSPF_IFTYPE_NBMA) { + if (OSPF_IF_NON_BROADCAST(oi)) { struct ospf_neighbor *nbr; struct route_node *rn; @@ -3476,31 +3542,44 @@ void ospf_hello_send(struct ospf_interface *oi) continue; /* - * RFC 2328 Section 9.5.1 - * If the router is not eligible to become Designated - * Router, it must periodically send Hello Packets to - * both the Designated Router and the Backup - * Designated Router (if they exist). + * Always send to all neighbors on Point-to-Multipoint + * non-braodcast networks. */ - if (PRIORITY(oi) == 0 && - IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) && - IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4)) - continue; + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + ospf_hello_send_sub(oi, nbr->address.u.prefix4 + .s_addr); + else { + /* + * RFC 2328 Section 9.5.1 + * If the router is not eligible to become Designated + * Router, it must periodically send Hello Packets to + * both the Designated Router and the Backup + * Designated Router (if they exist). + */ + if (PRIORITY(oi) == 0 && + IPV4_ADDR_CMP(&DR(oi), + &nbr->address.u.prefix4) && + IPV4_ADDR_CMP(&BDR(oi), + &nbr->address.u.prefix4)) + continue; - /* - * If the router is eligible to become Designated - * Router, it must periodically send Hello Packets to - * all neighbors that are also eligible. In addition, - * if the router is itself the Designated Router or - * Backup Designated Router, it must also send periodic - * Hello Packets to all other neighbors. - */ - if (nbr->priority == 0 && oi->state == ISM_DROther) - continue; + /* + * If the router is eligible to become Designated + * Router, it must periodically send Hello Packets to + * all neighbors that are also eligible. In addition, + * if the router is itself the Designated Router or + * Backup Designated Router, it must also send periodic + * Hello Packets to all other neighbors. + */ + if (nbr->priority == 0 && + oi->state == ISM_DROther) + continue; - /* if oi->state == Waiting, send - * hello to all neighbors */ - ospf_hello_send_sub(oi, nbr->address.u.prefix4.s_addr); + /* if oi->state == Waiting, send + * hello to all neighbors */ + ospf_hello_send_sub(oi, nbr->address.u.prefix4 + .s_addr); + } } } else { /* Decide destination address. */ @@ -3857,11 +3936,10 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, else p.prefix.s_addr = htonl(OSPF_ALLDROUTERS); - if (oi->type == OSPF_IFTYPE_NBMA) { + if (OSPF_IF_NON_BROADCAST(oi)) { if (flag == OSPF_SEND_PACKET_INDIRECT) - flog_warn( - EC_OSPF_PACKET, - "* LS-Update is directly sent on NBMA network."); + flog_warn(EC_OSPF_PACKET, + "* LS-Update is directly sent on non-broadcast network."); if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix)) flog_warn(EC_OSPF_PACKET, "* LS-Update is sent to myself."); @@ -3897,10 +3975,13 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, &oi->t_ls_upd_event); } -static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, +static void ospf_ls_ack_send_list(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct in_addr dst) { struct ospf_packet *op; + struct ospf_lsa_list_entry *ls_ack_list_first; uint16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new(oi->ifp->mtu); @@ -3908,8 +3989,18 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Prepare OSPF common header. */ ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s); + /* Determine the destination address - for direct acks, + * the list entries always include the distination address. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + op->dst.s_addr = ls_ack_list_first->list_entry_dst.s_addr; + } else + op->dst.s_addr = dst.s_addr; + /* Prepare OSPF Link State Acknowledgment body. */ - length += ospf_make_ls_ack(oi, ack, op->s); + length += ospf_make_ls_ack(oi, ls_ack_list, direct_ack, delete_ack, + op->s); /* Fill OSPF header. */ ospf_fill_header(oi, op->s, length); @@ -3917,13 +4008,6 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Decide destination address. */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT || - oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - op->dst.s_addr = dst.s_addr; - /* Add packet to the interface output queue. */ ospf_packet_add(oi, op); @@ -3931,34 +4015,96 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, OSPF_ISM_WRITE_ON(oi->ospf); } -static void ospf_ls_ack_send_event(struct event *thread) +static void ospf_ls_ack_send_direct_event(struct event *thread) { struct ospf_interface *oi = EVENT_ARG(thread); + struct in_addr dst = { INADDR_ANY }; oi->t_ls_ack_direct = NULL; - while (listcount(oi->ls_ack_direct.ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack, - oi->ls_ack_direct.dst); + while (ospf_lsa_list_count(&oi->ls_ack_direct)) + ospf_ls_ack_send_list(oi, &(oi->ls_ack_direct), true, true, dst); } -void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; struct ospf_interface *oi = nbr->oi; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &nbr->router_id, + IF_NAME(nbr->oi)); + + /* + * On Point-to-Multipoint broadcast-capabile interfaces, + * where direct acks from are sent to the ALLSPFRouters + * address and one direct ack send event, may include LSAs + * from multiple neighbors, there is a possibility of the same + * LSA being processed more than once in the same send event. + * In this case, the instances subsequent to the first can be + * ignored. + */ + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && !oi->p2mp_non_broadcast) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *ack_queue_lsa; + + frr_each (ospf_lsa_list, &oi->ls_ack_direct, ls_ack_list_entry) { + ack_queue_lsa = ls_ack_list_entry->lsa; + if ((lsa == ack_queue_lsa) || + ((lsa->data->type == ack_queue_lsa->data->type) && + (lsa->data->id.s_addr == + ack_queue_lsa->data->id.s_addr) && + (lsa->data->adv_router.s_addr == + ack_queue_lsa->data->adv_router.s_addr) && + (lsa->data->ls_seqnum == + ack_queue_lsa->data->ls_seqnum))) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue duplicate", + __func__, lsa->data->type, + &lsa->data->id, + &lsa->data->adv_router, + ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), + &nbr->router_id, + IF_NAME(nbr->oi)); + return; + } + } + } + if (IS_GRACE_LSA(lsa)) { if (IS_DEBUG_OSPF_GR) zlog_debug("%s, Sending GRACE ACK to Restarter.", __func__); } - if (listcount(oi->ls_ack_direct.ls_ack) == 0) - oi->ls_ack_direct.dst = nbr->address.u.prefix4; + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + + /* + * Determine the destination address - Direct LS acknowledgments + * are sent the AllSPFRouters multicast address on Point-to-Point + * and Point-to-Multipoint broadcast-capable interfaces. For all other + * interface types, they are unicast directly to the neighbor. + */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && + !oi->p2mp_non_broadcast)) + ls_ack_list_entry->list_entry_dst.s_addr = + htonl(OSPF_ALLSPFROUTERS); + else + ls_ack_list_entry->list_entry_dst.s_addr = + nbr->address.u.prefix4.s_addr; - listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->oi->ls_ack_direct, ls_ack_list_entry); - event_add_event(master, ospf_ls_ack_send_event, oi, 0, - &oi->t_ls_ack_direct); + if (oi->t_ls_ack_direct == NULL) + event_add_event(master, ospf_ls_ack_send_direct_event, oi, 0, + &oi->t_ls_ack_direct); } /* Send Link State Acknowledgment delayed. */ @@ -3971,37 +4117,43 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi) networks, delayed Link State Acknowledgment packets must be unicast separately over each adjacency (i.e., neighbor whose state is >= Exchange). */ - if (oi->type == OSPF_IFTYPE_NBMA) { + if (OSPF_IF_NON_BROADCAST(oi)) { struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - nbr = rn->info; + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) { + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; - if (!nbr) - continue; + if (!nbr) + continue; - if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list( - oi, oi->ls_ack, - nbr->address.u.prefix4); + if (nbr != oi->nbr_self && + nbr->state >= NSM_Exchange) + ospf_ls_ack_send_list(oi, + &oi->ls_ack_delayed, + false, false, + nbr->address.u + .prefix4); + } + ospf_delete_ls_ack_delayed(oi); } - return; - } - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - dst.s_addr = oi->vl_data->peer_addr.s_addr; - else if (oi->state == ISM_DR || oi->state == ISM_Backup) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - dst.s_addr = htonl(OSPF_ALLDROUTERS); + } else { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl(OSPF_ALLDROUTERS); - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack, dst); + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) + ospf_ls_ack_send_list(oi, &oi->ls_ack_delayed, false, + true, dst); + } } /* diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 234738979e95..84e4b027e694 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -135,13 +135,14 @@ extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int); extern void ospf_ls_upd_queue_send(struct ospf_interface *oi, struct list *update, struct in_addr addr, int send_lsupd_now); -extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *); +extern void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, + struct ospf_lsa *lsa); extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); -extern void ospf_ls_upd_timer(struct event *thread); -extern void ospf_ls_ack_timer(struct event *thread); +extern void ospf_ls_rxmt_timer(struct event *thread); +extern void ospf_ls_ack_delayed_timer(struct event *thread); extern void ospf_poll_timer(struct event *thread); extern void ospf_hello_reply_timer(struct event *thread); diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 725443f49078..76e6efeb833e 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -24,6 +24,7 @@ #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "mpls.h" +#include #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -153,6 +154,7 @@ static int ospf_router_info_unregister(void) void ospf_router_info_term(void) { + list_delete(&OspfRI.area_info); list_delete(&OspfRI.pce_info.pce_domain); list_delete(&OspfRI.pce_info.pce_neighbor); @@ -1215,15 +1217,20 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa) } \ } while (0) -static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh, + json_object *json) { struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh; check_tlv_size(RI_TLV_CAPABILITIES_SIZE, "Router Capabilities"); if (vty != NULL) - vty_out(vty, " Router Capabilities: 0x%x\n", - ntohl(top->value)); + if (!json) + vty_out(vty, " Router Capabilities: 0x%x\n", + ntohl(top->value)); + else + json_object_string_addf(json, "routerCapabilities", + "0x%x", ntohl(top->value)); else zlog_debug(" Router Capabilities: 0x%x", ntohl(top->value)); @@ -1231,7 +1238,8 @@ static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh) } static uint16_t show_vty_pce_subtlv_address(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ri_pce_subtlv_address *top = (struct ri_pce_subtlv_address *)tlvh; @@ -1239,20 +1247,28 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty, if (ntohs(top->address.type) == PCE_ADDRESS_IPV4) { check_tlv_size(PCE_ADDRESS_IPV4_SIZE, "PCE Address"); if (vty != NULL) - vty_out(vty, " PCE Address: %pI4\n", - &top->address.value); + if (!json) + vty_out(vty, " PCE Address: %pI4\n", + &top->address.value); + else + json_object_string_addf(json, "pceAddress", + "%pI4", + &top->address.value); else zlog_debug(" PCE Address: %pI4", &top->address.value); } else if (ntohs(top->address.type) == PCE_ADDRESS_IPV6) { - /* TODO: Add support to IPv6 with inet_ntop() */ check_tlv_size(PCE_ADDRESS_IPV6_SIZE, "PCE Address"); if (vty != NULL) - vty_out(vty, " PCE Address: 0x%x\n", - ntohl(top->address.value.s_addr)); + if (!json) + vty_out(vty, + " PCE Address: unsupported IPv6\n"); + else + json_object_string_add(json, "pceAddress", + "unsupported IPv6"); + else - zlog_debug(" PCE Address: 0x%x", - ntohl(top->address.value.s_addr)); + zlog_debug(" PCE Address: unsupported IPv6"); } else { if (vty != NULL) vty_out(vty, " Wrong PCE Address type: 0x%x\n", @@ -1266,7 +1282,8 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty, } static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ri_pce_subtlv_path_scope *top = (struct ri_pce_subtlv_path_scope *)tlvh; @@ -1274,7 +1291,12 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty, check_tlv_size(RI_PCE_SUBTLV_PATH_SCOPE_SIZE, "PCE Path Scope"); if (vty != NULL) - vty_out(vty, " PCE Path Scope: 0x%x\n", ntohl(top->value)); + if (!json) + vty_out(vty, " PCE Path Scope: 0x%x\n", + ntohl(top->value)); + else + json_object_string_addf(json, "pcePathScope", "0x%x", + ntohl(top->value)); else zlog_debug(" PCE Path Scope: 0x%x", ntohl(top->value)); @@ -1282,7 +1304,8 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty, } static uint16_t show_vty_pce_subtlv_domain(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh; struct in_addr tmp; @@ -1292,13 +1315,21 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty, if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = top->value; if (vty != NULL) - vty_out(vty, " PCE Domain Area: %pI4\n", &tmp); + if (!json) + vty_out(vty, " PCE Domain Area: %pI4\n", &tmp); + else + json_object_string_addf(json, "pceDomainArea", + "%pI4", &tmp); else zlog_debug(" PCE Domain Area: %pI4", &tmp); } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) { if (vty != NULL) - vty_out(vty, " PCE Domain AS: %d\n", - ntohl(top->value)); + if (!json) + vty_out(vty, " PCE Domain AS: %d\n", + ntohl(top->value)); + else + json_object_int_add(json, "pceDomainAS", + ntohl(top->value)); else zlog_debug(" PCE Domain AS: %d", ntohl(top->value)); } else { @@ -1314,7 +1345,8 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty, } static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ri_pce_subtlv_neighbor *top = @@ -1326,13 +1358,22 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty, if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = top->value; if (vty != NULL) - vty_out(vty, " PCE Neighbor Area: %pI4\n", &tmp); + if (!json) + vty_out(vty, " PCE Neighbor Area: %pI4\n", + &tmp); + else + json_object_string_addf(json, "pceNeighborArea", + "%pI4", &tmp); else zlog_debug(" PCE Neighbor Area: %pI4", &tmp); } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) { if (vty != NULL) - vty_out(vty, " PCE Neighbor AS: %d\n", - ntohl(top->value)); + if (!json) + vty_out(vty, " PCE Neighbor AS: %d\n", + ntohl(top->value)); + else + json_object_int_add(json, "pceNeighborAS", + ntohl(top->value)); else zlog_debug(" PCE Neighbor AS: %d", ntohl(top->value)); @@ -1349,7 +1390,8 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty, } static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct ri_pce_subtlv_cap_flag *top = (struct ri_pce_subtlv_cap_flag *)tlvh; @@ -1357,8 +1399,12 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, check_tlv_size(RI_PCE_SUBTLV_CAP_FLAG_SIZE, "PCE Capabilities"); if (vty != NULL) - vty_out(vty, " PCE Capabilities Flag: 0x%x\n", - ntohl(top->value)); + if (!json) + vty_out(vty, " PCE Capabilities Flag: 0x%x\n", + ntohl(top->value)); + else + json_object_string_addf(json, "pceCapabilities", + "0x%x", ntohl(top->value)); else zlog_debug(" PCE Capabilities Flag: 0x%x", ntohl(top->value)); @@ -1367,8 +1413,10 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, } static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, - size_t buf_size) + size_t buf_size, json_object *json) { + json_object *obj; + if (TLV_SIZE(tlvh) > buf_size) { if (vty != NULL) vty_out(vty, @@ -1382,8 +1430,18 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, } if (vty != NULL) - vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", - ntohs(tlvh->type), ntohs(tlvh->length)); + if (!json) + vty_out(vty, + " Unknown TLV: [type(0x%x), length(0x%x)]\n", + ntohs(tlvh->type), ntohs(tlvh->length)); + else { + obj = json_object_new_object(); + json_object_string_addf(obj, "type", "0x%x", + ntohs(tlvh->type)); + json_object_string_addf(obj, "length", "0x%x", + ntohs(tlvh->length)); + json_object_object_add(json, "unknownTLV", obj); + } else zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs(tlvh->type), ntohs(tlvh->length)); @@ -1392,7 +1450,7 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, } static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, - size_t buf_size) + size_t buf_size, json_object *json) { struct tlv_header *tlvh; uint16_t length = ntohs(ri->length); @@ -1409,22 +1467,23 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, for (tlvh = ri; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case RI_PCE_SUBTLV_ADDRESS: - sum += show_vty_pce_subtlv_address(vty, tlvh); + sum += show_vty_pce_subtlv_address(vty, tlvh, json); break; case RI_PCE_SUBTLV_PATH_SCOPE: - sum += show_vty_pce_subtlv_path_scope(vty, tlvh); + sum += show_vty_pce_subtlv_path_scope(vty, tlvh, json); break; case RI_PCE_SUBTLV_DOMAIN: - sum += show_vty_pce_subtlv_domain(vty, tlvh); + sum += show_vty_pce_subtlv_domain(vty, tlvh, json); break; case RI_PCE_SUBTLV_NEIGHBOR: - sum += show_vty_pce_subtlv_neighbor(vty, tlvh); + sum += show_vty_pce_subtlv_neighbor(vty, tlvh, json); break; case RI_PCE_SUBTLV_CAP_FLAG: - sum += show_vty_pce_subtlv_cap_flag(vty, tlvh); + sum += show_vty_pce_subtlv_cap_flag(vty, tlvh, json); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, length - sum); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum, + json); break; } } @@ -1432,33 +1491,62 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, } /* Display Segment Routing Algorithm TLV information */ -static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh, + json_object *json) { struct ri_sr_tlv_sr_algorithm *algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; int i; + json_object *json_algo, *obj; + char buf[2]; check_tlv_size(ALGORITHM_COUNT, "Segment Routing Algorithm"); - if (vty != NULL) { - vty_out(vty, " Segment Routing Algorithm TLV:\n"); - for (i = 0; i < ntohs(algo->header.length); i++) { - switch (algo->value[i]) { - case 0: - vty_out(vty, " Algorithm %d: SPF\n", i); - break; - case 1: - vty_out(vty, " Algorithm %d: Strict SPF\n", - i); - break; - default: - vty_out(vty, - " Algorithm %d: Unknown value %d\n", i, - algo->value[i]); - break; + if (vty != NULL) + if (!json) { + vty_out(vty, " Segment Routing Algorithm TLV:\n"); + for (i = 0; i < ntohs(algo->header.length); i++) { + switch (algo->value[i]) { + case 0: + vty_out(vty, + " Algorithm %d: SPF\n", i); + break; + case 1: + vty_out(vty, + " Algorithm %d: Strict SPF\n", + i); + break; + default: + vty_out(vty, + " Algorithm %d: Unknown value %d\n", i, + algo->value[i]); + break; + } + } + } else { + json_algo = json_object_new_array(); + json_object_object_add(json, "algorithms", + json_algo); + for (i = 0; i < ntohs(algo->header.length); i++) { + obj = json_object_new_object(); + snprintfrr(buf, 2, "%d", i); + switch (algo->value[i]) { + case 0: + json_object_string_add(obj, buf, "SPF"); + break; + case 1: + json_object_string_add(obj, buf, + "strictSPF"); + break; + default: + json_object_string_add(obj, buf, + "unknown"); + break; + } + json_object_array_add(json_algo, obj); } } - } else { + else { zlog_debug(" Segment Routing Algorithm TLV:"); for (i = 0; i < ntohs(algo->header.length); i++) switch (algo->value[i]) { @@ -1479,24 +1567,47 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) } /* Display Segment Routing SID/Label Range TLV information */ -static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh, + json_object *json) { struct ri_sr_tlv_sid_label_range *range = (struct ri_sr_tlv_sid_label_range *)tlvh; + json_object *obj; + uint32_t upper; check_tlv_size(RI_SR_TLV_LABEL_RANGE_SIZE, "SR Label Range"); - if (vty != NULL) { - vty_out(vty, - " Segment Routing %s Range TLV:\n" - " Range Size = %d\n" - " SID Label = %d\n\n", - ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE - ? "Global" - : "Local", - GET_RANGE_SIZE(ntohl(range->size)), - GET_LABEL(ntohl(range->lower.value))); - } else { + if (vty != NULL) + if (!json) { + vty_out(vty, + " Segment Routing %s Range TLV:\n" + " Range Size = %d\n" + " SID Label = %d\n\n", + ntohs(range->header.type) == + RI_SR_TLV_SRGB_LABEL_RANGE + ? "Global" + : "Local", + GET_RANGE_SIZE(ntohl(range->size)), + GET_LABEL(ntohl(range->lower.value))); + } else { + /* + * According to draft-ietf-teas-yang-sr-te-topo, SRGB + * and SRLB are describe with lower and upper bounds + */ + upper = GET_LABEL(ntohl(range->lower.value)) + + GET_RANGE_SIZE(ntohl(range->size)) - 1; + obj = json_object_new_object(); + json_object_int_add(obj, "upperBound", upper); + json_object_int_add(obj, "lowerBound", + GET_LABEL(ntohl(range->lower.value))); + json_object_object_add(json, + ntohs(range->header.type) == + RI_SR_TLV_SRGB_LABEL_RANGE + ? "srgb" + : "srlb", + obj); + } + else { zlog_debug( " Segment Routing %s Range TLV: Range Size = %d SID Label = %d", ntohs(range->header.type) == RI_SR_TLV_SRGB_LABEL_RANGE @@ -1510,22 +1621,25 @@ static uint16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh) } /* Display Segment Routing Maximum Stack Depth TLV information */ -static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh, + json_object *json) { struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh; check_tlv_size(RI_SR_TLV_NODE_MSD_SIZE, "Node Maximum Stack Depth"); - if (vty != NULL) { - vty_out(vty, - " Segment Routing MSD TLV:\n" - " Node Maximum Stack Depth = %d\n", - msd->value); - } else { + if (vty != NULL) + if (!json) + vty_out(vty, + " Segment Routing MSD TLV:\n" + " Node Maximum Stack Depth = %d\n", + msd->value); + else + json_object_int_add(json, "nodeMsd", msd->value); + else zlog_debug( " Segment Routing MSD TLV: Node Maximum Stack Depth = %d", msd->value); - } return TLV_SIZE(tlvh); } @@ -1537,9 +1651,14 @@ static void ospf_router_info_show_info(struct vty *vty, struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + json_object *jri = NULL, *jpce = NULL, *jsr = NULL; - if (json) - return; + if (json) { + jri = json_object_new_object(); + json_object_object_add(json, "routerInformation", jri); + jpce = json_object_new_object(); + jsr = json_object_new_object(); + } /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -1548,30 +1667,36 @@ static void ospf_router_info_show_info(struct vty *vty, tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case RI_TLV_CAPABILITIES: - sum += show_vty_router_cap(vty, tlvh); + sum += show_vty_router_cap(vty, tlvh, jri); break; case RI_TLV_PCE: tlvh++; sum += TLV_HDR_SIZE; - sum += show_vty_pce_info(vty, tlvh, length - sum); + sum += show_vty_pce_info(vty, tlvh, length - sum, jpce); break; case RI_SR_TLV_SR_ALGORITHM: - sum += show_vty_sr_algorithm(vty, tlvh); + sum += show_vty_sr_algorithm(vty, tlvh, jsr); break; case RI_SR_TLV_SRGB_LABEL_RANGE: case RI_SR_TLV_SRLB_LABEL_RANGE: - sum += show_vty_sr_range(vty, tlvh); + sum += show_vty_sr_range(vty, tlvh, jsr); break; case RI_SR_TLV_NODE_MSD: - sum += show_vty_sr_msd(vty, tlvh); + sum += show_vty_sr_msd(vty, tlvh, jsr); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, length); + sum += show_vty_unknown_tlv(vty, tlvh, length, jri); break; } } + if (json) { + if (json_object_object_length(jpce) > 1) + json_object_object_add(jri, "pceInformation", jpce); + if (json_object_object_length(jsr) > 1) + json_object_object_add(jri, "segmentRouting", jsr); + } return; } @@ -1659,11 +1784,10 @@ static void ospf_router_info_schedule(enum lsa_opcode opcode) DEFUN (router_info, router_info_area_cmd, - "router-info ", + "router-info ", OSPF_RI_STR "Enable the Router Information functionality with AS flooding scope\n" - "Enable the Router Information functionality with Area flooding scope\n" - "OSPF area ID in IP format (deprecated)\n") + "Enable the Router Information functionality with Area flooding scope\n") { int idx_mode = 1; uint8_t scope; @@ -1719,12 +1843,13 @@ DEFUN (router_info, return CMD_SUCCESS; } - DEFUN (no_router_info, no_router_info_cmd, - "no router-info", + "no router-info []", NO_STR - "Disable the Router Information functionality\n") + "Disable the Router Information functionality\n" + "Disable the Router Information functionality with AS flooding scope\n" + "Disable the Router Information functionality with Area flooding scope\n") { if (!OspfRI.enabled) @@ -2042,7 +2167,7 @@ DEFUN (show_ip_ospf_router_info, if (OspfRI.enabled) { vty_out(vty, "--- Router Information parameters ---\n"); - show_vty_router_cap(vty, &OspfRI.router_cap.header); + show_vty_router_cap(vty, &OspfRI.router_cap.header, NULL); } else { if (vty != NULL) vty_out(vty, @@ -2071,27 +2196,32 @@ DEFUN (show_ip_opsf_router_info_pce, if (pce->pce_address.header.type != 0) show_vty_pce_subtlv_address(vty, - &pce->pce_address.header); + &pce->pce_address.header, + NULL); if (pce->pce_scope.header.type != 0) show_vty_pce_subtlv_path_scope(vty, - &pce->pce_scope.header); + &pce->pce_scope.header, + NULL); for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { if (domain->header.type != 0) show_vty_pce_subtlv_domain(vty, - &domain->header); + &domain->header, + NULL); } for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { if (neighbor->header.type != 0) show_vty_pce_subtlv_neighbor(vty, - &neighbor->header); + &neighbor->header, + NULL); } if (pce->pce_cap_flag.header.type != 0) show_vty_pce_subtlv_cap_flag(vty, - &pce->pce_cap_flag.header); + &pce->pce_cap_flag.header, + NULL); } else { vty_out(vty, " PCE info is disabled on this router\n"); diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index c9aaa9f97891..4e1f15361e3a 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -906,7 +906,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, area = ospf_area_lookup_by_area_id(ospf, *area_id); if (!area) return NULL; - offset++; + offset += IN_ADDR_SIZE; /* Type. */ *type = *offset; @@ -914,7 +914,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, /* LS ID. */ oid2in_addr(offset, IN_ADDR_SIZE, ls_id); - offset++; + offset += IN_ADDR_SIZE; /* Router ID. */ oid2in_addr(offset, IN_ADDR_SIZE, router_id); @@ -971,7 +971,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, } /* Router ID. */ - offset++; + offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; len = offsetlen; @@ -996,11 +996,11 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, /* Fill in value. */ offset = name + v->namelen; oid_copy_in_addr(offset, area_id); - offset++; + offset += IN_ADDR_SIZE; *offset = lsa->data->type; offset++; oid_copy_in_addr(offset, &lsa->data->id); - offset++; + offset += IN_ADDR_SIZE; oid_copy_in_addr(offset, &lsa->data->adv_router); @@ -1106,7 +1106,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, if (!area) return NULL; - offset++; + offset += IN_ADDR_SIZE; /* Lookup area range. */ oid2in_addr(offset, IN_ADDR_SIZE, range_net); @@ -1135,7 +1135,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, return NULL; do { - offset++; + offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; len = offsetlen; @@ -1157,7 +1157,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, /* Fill in value. */ offset = name + v->namelen; oid_copy_in_addr(offset, area_id); - offset++; + offset += IN_ADDR_SIZE; oid_copy_in_addr(offset, range_net); return range; @@ -1348,7 +1348,7 @@ static int ospf_snmp_if_update(struct interface *ifp) ifindex = 0; /* Lookup first IPv4 address entry. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { p = CONNECTED_ID(ifc); if (p->family == AF_INET) { @@ -1396,11 +1396,10 @@ static int ospf_snmp_if_update(struct interface *ifp) static int ospf_snmp_is_if_have_addr(struct interface *ifp) { - struct listnode *nn; struct connected *ifc; /* Is this interface having any connected IPv4 address ? */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { if (CONNECTED_PREFIX(ifc)->family == AF_INET) return 1; } @@ -1560,7 +1559,7 @@ static struct ospf_interface *ospfIfLookup(struct variable *v, oid *name, *length = v->namelen + IN_ADDR_SIZE + 1; offset = name + v->namelen; oid_copy_in_addr(offset, ifaddr); - offset++; + offset += IN_ADDR_SIZE; *offset = *ifindex; return oi; } @@ -1704,7 +1703,7 @@ static struct ospf_interface *ospfIfMetricLookup(struct variable *v, oid *name, *length = v->namelen + IN_ADDR_SIZE + 1 + 1; offset = name + v->namelen; oid_copy_in_addr(offset, ifaddr); - offset++; + offset += IN_ADDR_SIZE; *offset = *ifindex; offset++; *offset = OSPF_SNMP_METRIC_VALUE; @@ -2242,7 +2241,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, /* LS ID. */ oid2in_addr(offset, IN_ADDR_SIZE, ls_id); - offset++; + offset += IN_ADDR_SIZE; /* Router ID. */ oid2in_addr(offset, IN_ADDR_SIZE, router_id); @@ -2270,7 +2269,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, oid2in_addr(offset, len, ls_id); - offset++; + offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; /* Router ID. */ @@ -2293,7 +2292,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, *offset = OSPF_AS_EXTERNAL_LSA; offset++; oid_copy_in_addr(offset, &lsa->data->id); - offset++; + offset += IN_ADDR_SIZE; oid_copy_in_addr(offset, &lsa->data->adv_router); return lsa; diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 467cb0504d95..198309c1eff8 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -580,6 +580,7 @@ static void ospf_sr_stop(void) hash_clean(OspfSR.neighbors, (void *)sr_node_del); OspfSR.self = NULL; OspfSR.status = SR_OFF; + OspfSR.msd = 0; } /* @@ -2739,9 +2740,9 @@ static void show_sr_node(struct vty *vty, struct json_object *json, if (srn->algo[i] == SR_ALGORITHM_UNSET) continue; json_obj = json_object_new_object(); - char tmp[2]; + char tmp[12]; - snprintf(tmp, sizeof(tmp), "%u", i); + snprintf(tmp, sizeof(tmp), "%d", i); json_object_string_add(json_obj, tmp, srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 3cf39e5fb542..d57990e1a174 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -31,6 +31,7 @@ #include "link_state.h" #include "zclient.h" #include "printfrr.h" +#include #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -980,8 +981,8 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) struct ospf_interface *oi = nbr->oi; struct mpls_te_link *lp; - /* Process Neighbor only when its state is NSM Full */ - if (nbr->state != NSM_Full) + /* Process Link only when neighbor old or new state is NSM Full */ + if (nbr->state != NSM_Full && old_state != NSM_Full) return; /* Get interface information for Traffic Engineering */ @@ -1669,6 +1670,11 @@ static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_node_id adv, struct ls_edge *edge; struct ls_attributes *attr; + /* Check that Link ID and Node ID are valid */ + if (IPV4_NET0(link_id.s_addr) || IPV4_NET0(adv.id.ip.addr.s_addr) || + adv.origin != OSPFv2) + return NULL; + /* Search Edge that corresponds to the Link ID */ key.family = AF_INET; IPV4_ADDR_COPY(&key.k.addr, &link_id); @@ -1742,6 +1748,10 @@ static void ospf_te_update_link(struct ls_ted *ted, struct ls_vertex *vertex, /* Get Corresponding Edge from Link State Data Base */ edge = get_edge(ted, vertex->node->adv, link_data); + if (!edge) { + ote_debug(" |- Found no edge from Link Data. Abort!"); + return; + } attr = edge->attributes; /* re-attached edge to vertex if needed */ @@ -1839,6 +1849,7 @@ static void ospf_te_delete_subnet(struct ls_ted *ted, struct in_addr addr) p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = addr; + ote_debug(" |- Delete Subnet info. for Prefix %pFX", &p); subnet = ls_find_subnet(ted, &p); /* Remove subnet if found */ @@ -1851,8 +1862,7 @@ static void ospf_te_delete_subnet(struct ls_ted *ted, struct in_addr addr) /** * Parse Router LSA. This function will create or update corresponding Vertex, - * Edge and Subnet. It also remove Edge and Subnet if they are marked as Orphan - * once Router LSA is parsed. + * Edge and Subnet. * * @param ted Link State Traffic Engineering Database * @param lsa OSPF Link State Advertisement @@ -1864,9 +1874,6 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) struct router_lsa *rl; enum ls_node_type type; struct ls_vertex *vertex; - struct ls_edge *edge; - struct ls_subnet *subnet; - struct listnode *node; int len, links; /* Sanity Check */ @@ -1909,13 +1916,6 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) vertex->status = SYNC; } - /* Mark outgoing Edge and Subnet as ORPHAN to detect deletion */ - for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) - edge->status = ORPHAN; - - for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet)) - subnet->status = ORPHAN; - /* Then, process Link Information */ len = lsa->size - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE; links = ntohs(rl->links); @@ -1948,11 +1948,6 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) break; } } - /* Clean remaining Orphan Edges or Subnets */ - if (OspfMplsTE.export) - ls_vertex_clean(ted, vertex, zclient); - else - ls_vertex_clean(ted, vertex, NULL); return 0; } @@ -2261,6 +2256,10 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) /* Get corresponding Edge from Link State Data Base */ edge = get_edge(ted, attr.adv, attr.standard.local); + if (!edge) { + ote_debug(" |- Found no edge from Link local add./ID. Abort!"); + return -1; + } old = edge->attributes; ote_debug(" |- Process Traffic Engineering LSA %pI4 for Edge %pI4", @@ -2405,7 +2404,10 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) ote_debug(" |- Delete TE info. for Edge %pI4", &edge->attributes->standard.local); - /* Remove Link State Attributes TE information */ + /* First remove the associated Subnet */ + ospf_te_delete_subnet(ted, attr->standard.local); + + /* Then ,remove Link State Attributes TE information */ memset(&attr->standard, 0, sizeof(struct ls_standard)); attr->flags &= 0x0FFFF; memset(&attr->extended, 0, sizeof(struct ls_extended)); @@ -2420,7 +2422,6 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) edge->status = SYNC; } else { /* Remove completely the Edge if Segment Routing is not set */ - ospf_te_delete_subnet(ted, attr->standard.local); edge->status = DELETE; ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); ls_edge_del_all(ted, edge); @@ -2464,6 +2465,9 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: + if (TLV_BODY_SIZE(tlvh) < 1 || + TLV_BODY_SIZE(tlvh) > ALGORITHM_COUNT) + break; algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; for (int i = 0; i < ntohs(algo->header.length); i++) { @@ -2488,6 +2492,8 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) break; case RI_SR_TLV_SRGB_LABEL_RANGE: + if (TLV_BODY_SIZE(tlvh) != RI_SR_TLV_LABEL_RANGE_SIZE) + break; range = (struct ri_sr_tlv_sid_label_range *)tlvh; size = GET_RANGE_SIZE(ntohl(range->size)); lower = GET_LABEL(ntohl(range->lower.value)); @@ -2505,6 +2511,8 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) break; case RI_SR_TLV_SRLB_LABEL_RANGE: + if (TLV_BODY_SIZE(tlvh) != RI_SR_TLV_LABEL_RANGE_SIZE) + break; range = (struct ri_sr_tlv_sid_label_range *)tlvh; size = GET_RANGE_SIZE(ntohl(range->size)); lower = GET_LABEL(ntohl(range->lower.value)); @@ -2522,6 +2530,8 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) break; case RI_SR_TLV_NODE_MSD: + if (TLV_BODY_SIZE(tlvh) < RI_SR_TLV_NODE_MSD_SIZE) + break; msd = (struct ri_sr_tlv_node_msd *)tlvh; if ((CHECK_FLAG(node->flags, LS_NODE_MSD)) && (node->msd == msd->value)) @@ -2619,6 +2629,7 @@ static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) struct ext_tlv_prefix *ext; struct ext_subtlv_prefix_sid *pref_sid; uint32_t label; + uint16_t len, size; /* Get corresponding Subnet from Link State Data Base */ ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); @@ -2640,6 +2651,18 @@ static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) ote_debug(" |- Process Extended Prefix LSA %pI4 for subnet %pFX", &lsa->data->id, &pref); + /* + * Check Extended Prefix TLV size against LSA size + * as only one TLV is allowed per LSA + */ + len = TLV_BODY_SIZE(&ext->header); + size = lsa->size - (OSPF_LSA_HEADER_SIZE + TLV_HDR_SIZE); + if (len != size || len <= 0) { + ote_debug(" |- Wrong TLV size: %u instead of %u", + (uint32_t)len, (uint32_t)size); + return -1; + } + /* Initialize TLV browsing */ ls_pref = subnet->ls_pref; pref_sid = (struct ext_subtlv_prefix_sid *)((char *)(ext) + TLV_HDR_SIZE @@ -2745,13 +2768,29 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) lnid.id.ip.area_id = lsa->area->area_id; ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); edge = get_edge(ted, lnid, ext->link_data); + if (!edge) { + ote_debug(" |- Found no edge from Extended Link Data. Abort!"); + return -1; + } atr = edge->attributes; ote_debug(" |- Process Extended Link LSA %pI4 for edge %pI4", &lsa->data->id, &edge->attributes->standard.local); - /* Initialize TLV browsing */ - len = TLV_BODY_SIZE(&ext->header) - EXT_TLV_LINK_SIZE; + /* + * Check Extended Link TLV size against LSA size + * as only one TLV is allowed per LSA + */ + len = TLV_BODY_SIZE(&ext->header); + i = lsa->size - (OSPF_LSA_HEADER_SIZE + TLV_HDR_SIZE); + if (len != i || len <= 0) { + ote_debug(" |- Wrong TLV size: %u instead of %u", + (uint32_t)len, (uint32_t)i); + return -1; + } + + /* Initialize subTLVs browsing */ + len -= EXT_TLV_LINK_SIZE; tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE); for (; sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { @@ -2761,6 +2800,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) switch (ntohs(tlvh->type)) { case EXT_SUBTLV_ADJ_SID: + if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_ADJ_SID_SIZE) + break; adj = (struct ext_subtlv_adj_sid *)tlvh; label = CHECK_FLAG(adj->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) @@ -2787,6 +2828,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) break; case EXT_SUBTLV_LAN_ADJ_SID: + if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_LAN_ADJ_SID_SIZE) + break; ladj = (struct ext_subtlv_lan_adj_sid *)tlvh; label = CHECK_FLAG(ladj->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) @@ -2816,6 +2859,8 @@ static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) break; case EXT_SUBTLV_RMT_ITF_ADDR: + if (TLV_BODY_SIZE(tlvh) != EXT_SUBTLV_RMT_ITF_ADDR_SIZE) + break; rmt = (struct ext_subtlv_rmt_itf_addr *)tlvh; if (CHECK_FLAG(atr->flags, LS_ATTR_NEIGH_ADDR) && IPV4_ADDR_SAME(&atr->standard.remote, @@ -3154,14 +3199,19 @@ static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf) } \ } while (0) -static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh, + json_object *json) { struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh; check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Router Address"); if (vty != NULL) - vty_out(vty, " Router-Address: %pI4\n", &top->value); + if (!json) + vty_out(vty, " Router-Address: %pI4\n", &top->value); + else + json_object_string_addf(json, "routerAddress", "%pI4", + &top->value); else zlog_debug(" Router-Address: %pI4", &top->value); @@ -3169,7 +3219,7 @@ static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh) } static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh, - size_t buf_size) + size_t buf_size, json_object *json) { struct te_tlv_link *top = (struct te_tlv_link *)tlvh; @@ -3186,8 +3236,12 @@ static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh, } if (vty != NULL) - vty_out(vty, " Link: %u octets of data\n", - ntohs(top->header.length)); + if (!json) + vty_out(vty, " Link: %u octets of data\n", + ntohs(top->header.length)); + else + json_object_int_add(json, "teLinkDataLength", + ntohs(top->header.length)); else zlog_debug(" Link: %u octets of data", ntohs(top->header.length)); @@ -3196,7 +3250,8 @@ static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh, } static uint16_t show_vty_link_subtlv_link_type(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_link_type *top; const char *cp = "Unknown"; @@ -3216,8 +3271,11 @@ static uint16_t show_vty_link_subtlv_link_type(struct vty *vty, } if (vty != NULL) - vty_out(vty, " Link-Type: %s (%u)\n", cp, - top->link_type.value); + if (!json) + vty_out(vty, " Link-Type: %s (%u)\n", cp, + top->link_type.value); + else + json_object_string_add(json, "accessType", cp); else zlog_debug(" Link-Type: %s (%u)", cp, top->link_type.value); @@ -3225,7 +3283,8 @@ static uint16_t show_vty_link_subtlv_link_type(struct vty *vty, } static uint16_t show_vty_link_subtlv_link_id(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_link_id *top; @@ -3233,7 +3292,11 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty, top = (struct te_link_subtlv_link_id *)tlvh; if (vty != NULL) - vty_out(vty, " Link-ID: %pI4\n", &top->value); + if (!json) + vty_out(vty, " Link-ID: %pI4\n", &top->value); + else + json_object_string_addf(json, "linkID", "%pI4", + &top->value); else zlog_debug(" Link-ID: %pI4", &top->value); @@ -3242,9 +3305,12 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty, static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, struct tlv_header *tlvh, - size_t buf_size) + size_t buf_size, + json_object *json) { struct te_link_subtlv_lclif_ipaddr *top; + json_object *json_addr, *json_obj; + char buf[4]; int i, n; if (TLV_SIZE(tlvh) > buf_size) { @@ -3263,13 +3329,29 @@ static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, n = ntohs(tlvh->length) / sizeof(top->value[0]); if (vty != NULL) - vty_out(vty, " Local Interface IP Address(es): %d\n", n); + if (!json) + vty_out(vty, " Local Interface IP Address(es): %d\n", + n); + else { + json_addr = json_object_new_array(); + json_object_object_add(json, "localIPAddresses", + json_addr); + } else zlog_debug(" Local Interface IP Address(es): %d", n); for (i = 0; i < n; i++) { if (vty != NULL) - vty_out(vty, " #%d: %pI4\n", i, &top->value[i]); + if (!json) + vty_out(vty, " #%d: %pI4\n", i, + &top->value[i]); + else { + json_obj = json_object_new_object(); + snprintfrr(buf, 2, "%d", i); + json_object_string_addf(json_obj, buf, "%pI4", + &top->value[i]); + json_object_array_add(json_addr, json_obj); + } else zlog_debug(" #%d: %pI4", i, &top->value[i]); } @@ -3278,9 +3360,12 @@ static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, struct tlv_header *tlvh, - size_t buf_size) + size_t buf_size, + json_object *json) { struct te_link_subtlv_rmtif_ipaddr *top; + json_object *json_addr, *json_obj; + char buf[4]; int i, n; if (TLV_SIZE(tlvh) > buf_size) { @@ -3298,13 +3383,29 @@ static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, top = (struct te_link_subtlv_rmtif_ipaddr *)tlvh; n = ntohs(tlvh->length) / sizeof(top->value[0]); if (vty != NULL) - vty_out(vty, " Remote Interface IP Address(es): %d\n", n); + if (!json) + vty_out(vty, " Remote Interface IP Address(es): %d\n", + n); + else { + json_addr = json_object_new_array(); + json_object_object_add(json, "remoteIPAddresses", + json_addr); + } else zlog_debug(" Remote Interface IP Address(es): %d", n); for (i = 0; i < n; i++) { if (vty != NULL) - vty_out(vty, " #%d: %pI4\n", i, &top->value[i]); + if (!json) + vty_out(vty, " #%d: %pI4\n", i, + &top->value[i]); + else { + json_obj = json_object_new_object(); + snprintfrr(buf, 2, "%d", i); + json_object_string_addf(json_obj, buf, "%pI4", + &top->value[i]); + json_object_array_add(json_addr, json_obj); + } else zlog_debug(" #%d: %pI4", i, &top->value[i]); } @@ -3312,7 +3413,8 @@ static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, } static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_te_metric *top; @@ -3320,8 +3422,12 @@ static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty, top = (struct te_link_subtlv_te_metric *)tlvh; if (vty != NULL) - vty_out(vty, " Traffic Engineering Metric: %u\n", - (uint32_t)ntohl(top->value)); + if (!json) + vty_out(vty, " Traffic Engineering Metric: %u\n", + (uint32_t)ntohl(top->value)); + else + json_object_int_add(json, "teDefaultMetric", + (uint32_t)ntohl(top->value)); else zlog_debug(" Traffic Engineering Metric: %u", (uint32_t)ntohl(top->value)); @@ -3330,7 +3436,8 @@ static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty, } static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_max_bw *top; float fval; @@ -3341,7 +3448,11 @@ static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty, fval = ntohf(top->value); if (vty != NULL) - vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n", fval); + if (!json) + vty_out(vty, " Maximum Bandwidth: %g (Bytes/sec)\n", + fval); + else + json_object_double_add(json, "maxLinkBandwidth", fval); else zlog_debug(" Maximum Bandwidth: %g (Bytes/sec)", fval); @@ -3349,7 +3460,8 @@ static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty, } static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_max_rsv_bw *top; float fval; @@ -3360,8 +3472,12 @@ static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, fval = ntohf(top->value); if (vty != NULL) - vty_out(vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n", - fval); + if (!json) + vty_out(vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)\n", + fval); + else + json_object_double_add(json, "maxResvLinkBandwidth", + fval); else zlog_debug(" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); @@ -3370,18 +3486,27 @@ static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, } static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_unrsv_bw *top; + json_object *json_bw, *json_obj; float fval1, fval2; + char buf[16]; int i; check_tlv_size(TE_LINK_SUBTLV_UNRSV_SIZE, "Unreserved Bandwidth"); top = (struct te_link_subtlv_unrsv_bw *)tlvh; if (vty != NULL) - vty_out(vty, - " Unreserved Bandwidth per Class Type in Byte/s:\n"); + if (!json) + vty_out(vty, + " Unreserved Bandwidth per Class Type in Byte/s:\n"); + else { + json_bw = json_object_new_array(); + json_object_object_add(json, "unreservedBandwidth", + json_bw); + } else zlog_debug( " Unreserved Bandwidth per Class Type in Byte/s:"); @@ -3390,9 +3515,20 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, fval2 = ntohf(top->value[i + 1]); if (vty != NULL) - vty_out(vty, - " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", - i, fval1, i + 1, fval2); + if (!json) + vty_out(vty, + " [%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n", + i, fval1, i + 1, fval2); + else { + json_obj = json_object_new_object(); + snprintfrr(buf, 12, "classType-%u", i); + json_object_double_add(json_obj, buf, fval1); + json_object_array_add(json_bw, json_obj); + json_obj = json_object_new_object(); + snprintfrr(buf, 12, "classType-%u", i + 1); + json_object_double_add(json_obj, buf, fval2); + json_object_array_add(json_bw, json_obj); + } else zlog_debug( " [%d]: %g (Bytes/sec), [%d]: %g (Bytes/sec)", @@ -3403,7 +3539,8 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, } static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_rsc_clsclr *top; @@ -3411,8 +3548,13 @@ static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, top = (struct te_link_subtlv_rsc_clsclr *)tlvh; if (vty != NULL) - vty_out(vty, " Resource class/color: 0x%x\n", - (uint32_t)ntohl(top->value)); + if (!json) + vty_out(vty, " Resource class/color: 0x%x\n", + (uint32_t)ntohl(top->value)); + else + json_object_string_addf(json, "administrativeGroup", + "0x%x", + (uint32_t)ntohl(top->value)); else zlog_debug(" Resource Class/Color: 0x%x", (uint32_t)ntohl(top->value)); @@ -3421,7 +3563,8 @@ static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, } static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_lrrid *top; @@ -3430,10 +3573,17 @@ static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty, top = (struct te_link_subtlv_lrrid *)tlvh; if (vty != NULL) { - vty_out(vty, " Local TE Router ID: %pI4\n", - &top->local); - vty_out(vty, " Remote TE Router ID: %pI4\n", - &top->remote); + if (!json) { + vty_out(vty, " Local TE Router ID: %pI4\n", + &top->local); + vty_out(vty, " Remote TE Router ID: %pI4\n", + &top->remote); + } else { + json_object_string_addf(json, "localTeRouterID", "%pI4", + &top->local); + json_object_string_addf(json, "remoteTeRouterID", + "%pI4", &top->remote); + } } else { zlog_debug(" Local TE Router ID: %pI4", &top->local); @@ -3445,7 +3595,8 @@ static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty, } static uint16_t show_vty_link_subtlv_llri(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_llri *top; @@ -3454,10 +3605,17 @@ static uint16_t show_vty_link_subtlv_llri(struct vty *vty, top = (struct te_link_subtlv_llri *)tlvh; if (vty != NULL) { - vty_out(vty, " Link Local ID: %d\n", - (uint32_t)ntohl(top->local)); - vty_out(vty, " Link Remote ID: %d\n", - (uint32_t)ntohl(top->remote)); + if (!json) { + vty_out(vty, " Link Local ID: %d\n", + (uint32_t)ntohl(top->local)); + vty_out(vty, " Link Remote ID: %d\n", + (uint32_t)ntohl(top->remote)); + } else { + json_object_int_add(json, "localLinkID", + (uint32_t)ntohl(top->local)); + json_object_int_add(json, "remoteLinkID", + (uint32_t)ntohl(top->remote)); + } } else { zlog_debug(" Link Local ID: %d", (uint32_t)ntohl(top->local)); @@ -3469,7 +3627,8 @@ static uint16_t show_vty_link_subtlv_llri(struct vty *vty, } static uint16_t show_vty_link_subtlv_rip(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_rip *top; @@ -3478,8 +3637,12 @@ static uint16_t show_vty_link_subtlv_rip(struct vty *vty, top = (struct te_link_subtlv_rip *)tlvh; if (vty != NULL) - vty_out(vty, " Inter-AS TE Remote ASBR IP address: %pI4\n", - &top->value); + if (!json) + vty_out(vty, " Inter-AS TE Remote ASBR IP address: %pI4\n", + &top->value); + else + json_object_string_addf(json, "remoteAsbrAddress", + "%pI4", &top->value); else zlog_debug(" Inter-AS TE Remote ASBR IP address: %pI4", &top->value); @@ -3488,7 +3651,8 @@ static uint16_t show_vty_link_subtlv_rip(struct vty *vty, } static uint16_t show_vty_link_subtlv_ras(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_ras *top; @@ -3497,8 +3661,12 @@ static uint16_t show_vty_link_subtlv_ras(struct vty *vty, top = (struct te_link_subtlv_ras *)tlvh; if (vty != NULL) - vty_out(vty, " Inter-AS TE Remote AS number: %u\n", - ntohl(top->value)); + if (!json) + vty_out(vty, " Inter-AS TE Remote AS number: %u\n", + ntohl(top->value)); + else + json_object_int_add(json, "remoteAsbrNumber", + ntohl(top->value)); else zlog_debug(" Inter-AS TE Remote AS number: %u", ntohl(top->value)); @@ -3507,7 +3675,8 @@ static uint16_t show_vty_link_subtlv_ras(struct vty *vty, } static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_av_delay *top; uint32_t delay; @@ -3520,8 +3689,15 @@ static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty, anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL; if (vty != NULL) - vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n", - anomalous ? "Anomalous" : "Normal", delay); + if (!json) + vty_out(vty, " %s Average Link Delay: %d (micro-sec)\n", + anomalous ? "Anomalous" : "Normal", delay); + else { + json_object_int_add(json, "oneWayDelay", delay); + json_object_string_add(json, "oneWayDelayNormality", + anomalous ? "abnormal" + : "normal"); + } else zlog_debug(" %s Average Link Delay: %d (micro-sec)", anomalous ? "Anomalous" : "Normal", delay); @@ -3530,7 +3706,8 @@ static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty, } static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_mm_delay *top; uint32_t low, high; @@ -3544,8 +3721,20 @@ static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty, high = (uint32_t)ntohl(top->high); if (vty != NULL) - vty_out(vty, " %s Min/Max Link Delay: %d/%d (micro-sec)\n", - anomalous ? "Anomalous" : "Normal", low, high); + if (!json) + vty_out(vty, + " %s Min/Max Link Delay: %d/%d (micro-sec)\n", + anomalous ? "Anomalous" : "Normal", low, high); + else { + json_object_int_add(json, "oneWayMinDelay", low); + json_object_string_add(json, "oneWayMinDelayNormality", + anomalous ? "abnormal" + : "normal"); + json_object_int_add(json, "oneWayMaxDelay", high); + json_object_string_add(json, "oneWayMaxDelayNormality", + anomalous ? "abnormal" + : "normal"); + } else zlog_debug(" %s Min/Max Link Delay: %d/%d (micro-sec)", anomalous ? "Anomalous" : "Normal", low, high); @@ -3554,7 +3743,8 @@ static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty, } static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_delay_var *top; uint32_t jitter; @@ -3565,7 +3755,12 @@ static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty, jitter = (uint32_t)ntohl(top->value) & TE_EXT_MASK; if (vty != NULL) - vty_out(vty, " Delay Variation: %d (micro-sec)\n", jitter); + if (!json) + vty_out(vty, " Delay Variation: %d (micro-sec)\n", + jitter); + else + json_object_int_add(json, "oneWayDelayVariation", + jitter); else zlog_debug(" Delay Variation: %d (micro-sec)", jitter); @@ -3573,7 +3768,8 @@ static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty, } static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_pkt_loss *top; uint32_t loss; @@ -3588,8 +3784,16 @@ static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL; if (vty != NULL) - vty_out(vty, " %s Link Loss: %g (%%)\n", - anomalous ? "Anomalous" : "Normal", fval); + if (!json) + vty_out(vty, " %s Link Loss: %g (%%)\n", + anomalous ? "Anomalous" : "Normal", fval); + else { + json_object_double_add(json, "oneWayPacketLoss", fval); + json_object_string_add(json, + "oneWayPacketLossNormality", + anomalous ? "abnormal" + : "normal"); + } else zlog_debug(" %s Link Loss: %g (%%)", anomalous ? "Anomalous" : "Normal", fval); @@ -3598,7 +3802,8 @@ static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, } static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_res_bw *top; float fval; @@ -3609,9 +3814,13 @@ static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty, fval = ntohf(top->value); if (vty != NULL) - vty_out(vty, - " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", - fval); + if (!json) + vty_out(vty, + " Unidirectional Residual Bandwidth: %g (Bytes/sec)\n", + fval); + else + json_object_double_add(json, "oneWayResidualBandwidth", + fval); else zlog_debug( " Unidirectional Residual Bandwidth: %g (Bytes/sec)", @@ -3621,7 +3830,8 @@ static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty, } static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_ava_bw *top; float fval; @@ -3632,9 +3842,13 @@ static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty, fval = ntohf(top->value); if (vty != NULL) - vty_out(vty, - " Unidirectional Available Bandwidth: %g (Bytes/sec)\n", - fval); + if (!json) + vty_out(vty, + " Unidirectional Available Bandwidth: %g (Bytes/sec)\n", + fval); + else + json_object_double_add(json, "oneWayAvailableBandwidth", + fval); else zlog_debug( " Unidirectional Available Bandwidth: %g (Bytes/sec)", @@ -3644,7 +3858,8 @@ static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty, } static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + json_object *json) { struct te_link_subtlv_use_bw *top; float fval; @@ -3655,9 +3870,13 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty, fval = ntohf(top->value); if (vty != NULL) - vty_out(vty, - " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", - fval); + if (!json) + vty_out(vty, + " Unidirectional Utilized Bandwidth: %g (Bytes/sec)\n", + fval); + else + json_object_double_add(json, "oneWayUtilizedBandwidth", + fval); else zlog_debug( " Unidirectional Utilized Bandwidth: %g (Bytes/sec)", @@ -3667,8 +3886,10 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty, } static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, - size_t buf_size) + size_t buf_size, json_object *json) { + json_object *obj; + if (TLV_SIZE(tlvh) > buf_size) { if (vty != NULL) vty_out(vty, @@ -3682,8 +3903,17 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, } if (vty != NULL) - vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", - ntohs(tlvh->type), ntohs(tlvh->length)); + if (!json) + vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", + ntohs(tlvh->type), ntohs(tlvh->length)); + else { + obj = json_object_new_object(); + json_object_string_addf(obj, "type", "0x%x", + ntohs(tlvh->type)); + json_object_string_addf(obj, "length", "0x%x", + ntohs(tlvh->length)); + json_object_object_add(json, "unknownTLV", obj); + } else zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs(tlvh->type), ntohs(tlvh->length)); @@ -3693,7 +3923,8 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, struct tlv_header *tlvh0, - uint16_t subtotal, uint16_t total) + uint16_t subtotal, uint16_t total, + json_object *json) { struct tlv_header *tlvh; uint16_t sum = subtotal; @@ -3701,69 +3932,72 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, for (tlvh = tlvh0; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case TE_LINK_SUBTLV_LINK_TYPE: - sum += show_vty_link_subtlv_link_type(vty, tlvh); + sum += show_vty_link_subtlv_link_type(vty, tlvh, json); break; case TE_LINK_SUBTLV_LINK_ID: - sum += show_vty_link_subtlv_link_id(vty, tlvh); + sum += show_vty_link_subtlv_link_id(vty, tlvh, json); break; case TE_LINK_SUBTLV_LCLIF_IPADDR: sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh, - total - sum); + total - sum, + json); break; case TE_LINK_SUBTLV_RMTIF_IPADDR: sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh, - total - sum); + total - sum, + json); break; case TE_LINK_SUBTLV_TE_METRIC: - sum += show_vty_link_subtlv_te_metric(vty, tlvh); + sum += show_vty_link_subtlv_te_metric(vty, tlvh, json); break; case TE_LINK_SUBTLV_MAX_BW: - sum += show_vty_link_subtlv_max_bw(vty, tlvh); + sum += show_vty_link_subtlv_max_bw(vty, tlvh, json); break; case TE_LINK_SUBTLV_MAX_RSV_BW: - sum += show_vty_link_subtlv_max_rsv_bw(vty, tlvh); + sum += show_vty_link_subtlv_max_rsv_bw(vty, tlvh, json); break; case TE_LINK_SUBTLV_UNRSV_BW: - sum += show_vty_link_subtlv_unrsv_bw(vty, tlvh); + sum += show_vty_link_subtlv_unrsv_bw(vty, tlvh, json); break; case TE_LINK_SUBTLV_RSC_CLSCLR: - sum += show_vty_link_subtlv_rsc_clsclr(vty, tlvh); + sum += show_vty_link_subtlv_rsc_clsclr(vty, tlvh, json); break; case TE_LINK_SUBTLV_LRRID: - sum += show_vty_link_subtlv_lrrid(vty, tlvh); + sum += show_vty_link_subtlv_lrrid(vty, tlvh, json); break; case TE_LINK_SUBTLV_LLRI: - sum += show_vty_link_subtlv_llri(vty, tlvh); + sum += show_vty_link_subtlv_llri(vty, tlvh, json); break; case TE_LINK_SUBTLV_RIP: - sum += show_vty_link_subtlv_rip(vty, tlvh); + sum += show_vty_link_subtlv_rip(vty, tlvh, json); break; case TE_LINK_SUBTLV_RAS: - sum += show_vty_link_subtlv_ras(vty, tlvh); + sum += show_vty_link_subtlv_ras(vty, tlvh, json); break; case TE_LINK_SUBTLV_AV_DELAY: - sum += show_vty_link_subtlv_av_delay(vty, tlvh); + sum += show_vty_link_subtlv_av_delay(vty, tlvh, json); break; case TE_LINK_SUBTLV_MM_DELAY: - sum += show_vty_link_subtlv_mm_delay(vty, tlvh); + sum += show_vty_link_subtlv_mm_delay(vty, tlvh, json); break; case TE_LINK_SUBTLV_DELAY_VAR: - sum += show_vty_link_subtlv_delay_var(vty, tlvh); + sum += show_vty_link_subtlv_delay_var(vty, tlvh, json); break; case TE_LINK_SUBTLV_PKT_LOSS: - sum += show_vty_link_subtlv_pkt_loss(vty, tlvh); + sum += show_vty_link_subtlv_pkt_loss(vty, tlvh, json); break; case TE_LINK_SUBTLV_RES_BW: - sum += show_vty_link_subtlv_res_bw(vty, tlvh); + sum += show_vty_link_subtlv_res_bw(vty, tlvh, json); break; case TE_LINK_SUBTLV_AVA_BW: - sum += show_vty_link_subtlv_ava_bw(vty, tlvh); + sum += show_vty_link_subtlv_ava_bw(vty, tlvh, json); break; case TE_LINK_SUBTLV_USE_BW: - sum += show_vty_link_subtlv_use_bw(vty, tlvh); + sum += show_vty_link_subtlv_use_bw(vty, tlvh, json); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, total - sum); + sum += show_vty_unknown_tlv(vty, tlvh, total - sum, + json); break; } } @@ -3775,12 +4009,11 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh, *next; - uint16_t sum, total; + uint16_t sum, sub, total; uint16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh, - uint16_t subtotal, uint16_t total) = NULL; - - if (json) - return; + uint16_t subtotal, uint16_t total, + struct json_object *json) = NULL; + json_object *jobj = NULL; sum = 0; total = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -3788,24 +4021,34 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, for (tlvh = TLV_HDR_TOP(lsah); sum < total && tlvh; tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { if (subfunc != NULL) { - sum = (*subfunc)(vty, tlvh, sum, total); + sum = (*subfunc)(vty, tlvh, sum, total, jobj); next = (struct tlv_header *)((char *)tlvh + sum); subfunc = NULL; continue; } next = NULL; + sub = total - sum; switch (ntohs(tlvh->type)) { case TE_TLV_ROUTER_ADDR: - sum += show_vty_router_addr(vty, tlvh); + if (json) { + jobj = json_object_new_object(); + json_object_object_add(json, "teRouterAddress", + jobj); + } + sum += show_vty_router_addr(vty, tlvh, jobj); break; case TE_TLV_LINK: - sum += show_vty_link_header(vty, tlvh, total - sum); + if (json) { + jobj = json_object_new_object(); + json_object_object_add(json, "teLink", jobj); + } + sum += show_vty_link_header(vty, tlvh, sub, jobj); subfunc = ospf_mpls_te_show_link_subtlv; next = TLV_DATA(tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh, total - sum); + sum += show_vty_unknown_tlv(vty, tlvh, sub, json); break; } } @@ -4139,7 +4382,8 @@ DEFUN (show_ip_ospf_mpls_te_router, if (ntohs(OspfMplsTE.router_addr.header.type) != 0) show_vty_router_addr(vty, - &OspfMplsTE.router_addr.header); + &OspfMplsTE.router_addr.header, + NULL); else vty_out(vty, " Router address is not set\n"); vty_out(vty, " Link State distribution is %s\n", @@ -4148,7 +4392,8 @@ DEFUN (show_ip_ospf_mpls_te_router, return CMD_SUCCESS; } -static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp) +static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp, + json_object *json) { struct mpls_te_link *lp; @@ -4178,53 +4423,69 @@ static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp) if (TLV_TYPE(lp->link_type) != 0) show_vty_link_subtlv_link_type(vty, - &lp->link_type.header); + &lp->link_type.header, + json); if (TLV_TYPE(lp->link_id) != 0) - show_vty_link_subtlv_link_id(vty, &lp->link_id.header); + show_vty_link_subtlv_link_id(vty, &lp->link_id.header, + json); if (TLV_TYPE(lp->lclif_ipaddr) != 0) show_vty_link_subtlv_lclif_ipaddr( vty, &lp->lclif_ipaddr.header, - lp->lclif_ipaddr.header.length); + lp->lclif_ipaddr.header.length, + json); if (TLV_TYPE(lp->rmtif_ipaddr) != 0) show_vty_link_subtlv_rmtif_ipaddr( vty, &lp->rmtif_ipaddr.header, - lp->rmtif_ipaddr.header.length); + lp->rmtif_ipaddr.header.length, + json); if (TLV_TYPE(lp->rip) != 0) - show_vty_link_subtlv_rip(vty, &lp->rip.header); + show_vty_link_subtlv_rip(vty, &lp->rip.header, json); if (TLV_TYPE(lp->ras) != 0) - show_vty_link_subtlv_ras(vty, &lp->ras.header); + show_vty_link_subtlv_ras(vty, &lp->ras.header, json); if (TLV_TYPE(lp->te_metric) != 0) show_vty_link_subtlv_te_metric(vty, - &lp->te_metric.header); + &lp->te_metric.header, + json); if (TLV_TYPE(lp->max_bw) != 0) - show_vty_link_subtlv_max_bw(vty, &lp->max_bw.header); + show_vty_link_subtlv_max_bw(vty, &lp->max_bw.header, + json); if (TLV_TYPE(lp->max_rsv_bw) != 0) show_vty_link_subtlv_max_rsv_bw(vty, - &lp->max_rsv_bw.header); + &lp->max_rsv_bw.header, + json); if (TLV_TYPE(lp->unrsv_bw) != 0) show_vty_link_subtlv_unrsv_bw(vty, - &lp->unrsv_bw.header); + &lp->unrsv_bw.header, + json); if (TLV_TYPE(lp->rsc_clsclr) != 0) show_vty_link_subtlv_rsc_clsclr(vty, - &lp->rsc_clsclr.header); + &lp->rsc_clsclr.header, + json); if (TLV_TYPE(lp->av_delay) != 0) show_vty_link_subtlv_av_delay(vty, - &lp->av_delay.header); + &lp->av_delay.header, + json); if (TLV_TYPE(lp->mm_delay) != 0) show_vty_link_subtlv_mm_delay(vty, - &lp->mm_delay.header); + &lp->mm_delay.header, + json); if (TLV_TYPE(lp->delay_var) != 0) show_vty_link_subtlv_delay_var(vty, - &lp->delay_var.header); + &lp->delay_var.header, + json); if (TLV_TYPE(lp->pkt_loss) != 0) show_vty_link_subtlv_pkt_loss(vty, - &lp->pkt_loss.header); + &lp->pkt_loss.header, + json); if (TLV_TYPE(lp->res_bw) != 0) - show_vty_link_subtlv_res_bw(vty, &lp->res_bw.header); + show_vty_link_subtlv_res_bw(vty, &lp->res_bw.header, + json); if (TLV_TYPE(lp->ava_bw) != 0) - show_vty_link_subtlv_ava_bw(vty, &lp->ava_bw.header); + show_vty_link_subtlv_ava_bw(vty, &lp->ava_bw.header, + json); if (TLV_TYPE(lp->use_bw) != 0) - show_vty_link_subtlv_use_bw(vty, &lp->use_bw.header); + show_vty_link_subtlv_use_bw(vty, &lp->use_bw.header, + json); vty_out(vty, "---------------\n\n"); } else { vty_out(vty, " %s: MPLS-TE is disabled on this interface\n", @@ -4253,7 +4514,6 @@ DEFUN (show_ip_ospf_mpls_te_link, ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) return CMD_SUCCESS; - vrf = vrf_lookup_by_id(VRF_DEFAULT); if (!vrf) return CMD_SUCCESS; @@ -4267,11 +4527,11 @@ DEFUN (show_ip_ospf_mpls_te_link, } if (!ifp) { FOR_ALL_INTERFACES (vrf, ifp) - show_mpls_te_link_sub(vty, ifp); + show_mpls_te_link_sub(vty, ifp, NULL); return CMD_SUCCESS; } - show_mpls_te_link_sub(vty, ifp); + show_mpls_te_link_sub(vty, ifp, NULL); return CMD_SUCCESS; } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 8c3ad7f372d5..13138914fa66 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -22,6 +22,7 @@ #include "defaults.h" #include "lib/printfrr.h" #include "keychain.h" +#include "frrdistance.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" @@ -814,6 +815,7 @@ struct ospf_vl_config_data { int del_keychain; int hello_interval; /* Obvious what these are... */ int retransmit_interval; + int retransmit_window; int transmit_delay; int dead_interval; }; @@ -956,6 +958,12 @@ static int ospf_vl_set_timers(struct ospf_vl_data *vl_data, vl_config->retransmit_interval; } + if (vl_config->retransmit_window) { + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = + vl_config->retransmit_window; + } + if (vl_config->transmit_delay) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), transmit_delay); IF_DEF_PARAMS(ifp)->transmit_delay = vl_config->transmit_delay; @@ -1011,14 +1019,16 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config) "Use null authentication\n" \ "Use message-digest authentication\n" -#define VLINK_HELPSTR_TIME_PARAM \ - "Time between HELLO packets\n" \ - "Seconds\n" \ - "Time between retransmitting lost link state advertisements\n" \ - "Seconds\n" \ - "Link state transmit delay\n" \ - "Seconds\n" \ - "Interval time after which a neighbor is declared down\n" \ +#define VLINK_HELPSTR_TIME_PARAM \ + "Time between HELLO packets\n" \ + "Seconds\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Seconds\n" \ + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" \ + "Milliseconds\n" \ + "Link state transmit delay\n" \ + "Seconds\n" \ + "Interval time after which a neighbor is declared down\n" \ "Seconds\n" #define VLINK_HELPSTR_AUTH_SIMPLE \ @@ -1203,7 +1213,7 @@ DEFUN (no_ospf_area_vlink, DEFUN (ospf_area_vlink_intervals, ospf_area_vlink_intervals_cmd, - "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-10000)|transmit-delay (1-65535)|dead-interval (1-65535)}", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { @@ -1235,6 +1245,9 @@ DEFUN (ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = strtol(argv[++idx]->arg, NULL, 10); + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = strtol(argv[++idx]->arg, + NULL, 10); else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = strtol(argv[++idx]->arg, NULL, 10); @@ -1249,7 +1262,7 @@ DEFUN (ospf_area_vlink_intervals, DEFUN (no_ospf_area_vlink_intervals, no_ospf_area_vlink_intervals_cmd, - "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-1000)|transmit-delay (1-65535)|dead-interval (1-65535)}", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) @@ -1281,6 +1294,9 @@ DEFUN (no_ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = + OSPF_RETRANSMIT_WINDOW_DEFAULT; else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; else if (strmatch(argv[idx]->text, "dead-interval")) @@ -1871,7 +1887,7 @@ DEFUN (no_ospf_area_import_list, DEFUN (ospf_area_filter_list, ospf_area_filter_list_cmd, - "area filter-list prefix PREFIXLIST_NAME ", + "area filter-list prefix PREFIXLIST4_NAME ", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" @@ -1916,7 +1932,7 @@ DEFUN (ospf_area_filter_list, DEFUN (no_ospf_area_filter_list, no_ospf_area_filter_list_cmd, - "no area filter-list prefix PREFIXLIST_NAME ", + "no area filter-list prefix PREFIXLIST4_NAME ", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -2405,130 +2421,30 @@ DEFUN (no_ospf_timers_lsa_min_arrival, return CMD_SUCCESS; } -DEFUN (ospf_neighbor, - ospf_neighbor_cmd, - "neighbor A.B.C.D [priority (0-255) [poll-interval (1-65535)]]", - NEIGHBOR_STR - "Neighbor IP address\n" - "Neighbor Priority\n" - "Priority\n" - "Dead Neighbor Polling interval\n" - "Seconds\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - int idx_ipv4 = 1; - int idx_pri = 3; - int idx_poll = 5; - struct in_addr nbr_addr; - unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; - unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT; - - if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { - vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (argc > 2) - priority = strtoul(argv[idx_pri]->arg, NULL, 10); - - if (argc > 4) - interval = strtoul(argv[idx_poll]->arg, NULL, 10); - - ospf_nbr_nbma_set(ospf, nbr_addr); - - if (argc > 2) - ospf_nbr_nbma_priority_set(ospf, nbr_addr, priority); - - if (argc > 4) - ospf_nbr_nbma_poll_interval_set(ospf, nbr_addr, interval); - - return CMD_SUCCESS; -} - -DEFUN (ospf_neighbor_poll_interval, - ospf_neighbor_poll_interval_cmd, - "neighbor A.B.C.D poll-interval (1-65535) [priority (0-255)]", - NEIGHBOR_STR - "Neighbor IP address\n" - "Dead Neighbor Polling interval\n" - "Seconds\n" - "OSPF priority of non-broadcast neighbor\n" - "Priority\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - int idx_ipv4 = 1; - int idx_poll = 3; - int idx_pri = 5; - struct in_addr nbr_addr; - unsigned int priority; - unsigned int interval; - - if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { - vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - interval = strtoul(argv[idx_poll]->arg, NULL, 10); - - priority = argc > 4 ? strtoul(argv[idx_pri]->arg, NULL, 10) - : OSPF_NEIGHBOR_PRIORITY_DEFAULT; - - ospf_nbr_nbma_set(ospf, nbr_addr); - ospf_nbr_nbma_poll_interval_set(ospf, nbr_addr, interval); - - if (argc > 4) - ospf_nbr_nbma_priority_set(ospf, nbr_addr, priority); - - return CMD_SUCCESS; -} - -DEFUN (no_ospf_neighbor, - no_ospf_neighbor_cmd, - "no neighbor A.B.C.D [priority (0-255) [poll-interval (1-65525)]]", - NO_STR - NEIGHBOR_STR - "Neighbor IP address\n" - "Neighbor Priority\n" - "Priority\n" - "Dead Neighbor Polling interval\n" - "Seconds\n") +DEFPY(ospf_neighbor, ospf_neighbor_cmd, + "[no] neighbor A.B.C.D$nbr_address [{priority (0-255)$priority | poll-interval (1-65535)$interval}]", + NO_STR + NEIGHBOR_STR + "Neighbor IP address\n" + "Neighbor Priority\n" + "Priority\n" + "Dead Neighbor Polling interval\n" + "Seconds\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - int idx_ipv4 = 2; - struct in_addr nbr_addr; - if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { - vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - (void)ospf_nbr_nbma_unset(ospf, nbr_addr); - - return CMD_SUCCESS; -} - -DEFUN (no_ospf_neighbor_poll, - no_ospf_neighbor_poll_cmd, - "no neighbor A.B.C.D poll-interval (1-65535) [priority (0-255)]", - NO_STR - NEIGHBOR_STR - "Neighbor IP address\n" - "Dead Neighbor Polling interval\n" - "Seconds\n" - "Neighbor Priority\n" - "Priority\n") -{ - VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); - int idx_ipv4 = 2; - struct in_addr nbr_addr; + if (no) + ospf_nbr_nbma_unset(ospf, nbr_address); + else { + ospf_nbr_nbma_set(ospf, nbr_address); + if (priority_str) + ospf_nbr_nbma_priority_set(ospf, nbr_address, priority); - if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { - vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); - return CMD_WARNING_CONFIG_FAILED; + if (interval_str) + ospf_nbr_nbma_poll_interval_set(ospf, nbr_address, + interval); } - (void)ospf_nbr_nbma_unset(ospf, nbr_addr); - return CMD_SUCCESS; } @@ -2679,7 +2595,7 @@ DEFUN (no_ospf_write_multiplier, } ALIAS(no_ospf_write_multiplier, no_write_multiplier_cmd, - "no write-multiplier (1-100)", NO_STR + "no write-multiplier [(1-100)]", NO_STR "Write multiplier\n" "Maximum number of interface serviced per write\n") @@ -2753,9 +2669,10 @@ DEFUN (ospf_max_multipath, DEFUN (no_ospf_max_multipath, no_ospf_max_multipath_cmd, - "no maximum-paths", + "no maximum-paths [" CMD_RANGE_STR(1, MULTIPATH_NUM)"]", NO_STR - "Max no of multiple paths for ECMP support\n") + "Max no of multiple paths for ECMP support\n" + "Number of paths\n") { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); uint16_t maxpaths = MULTIPATH_NUM; @@ -3674,8 +3591,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, struct route_node *rn; uint32_t bandwidth = ifp->bandwidth ? ifp->bandwidth : ifp->speed; struct ospf_if_params *params; - json_object *json_ois = NULL; - json_object *json_oi = NULL; /* Is interface up? */ if (use_json) { @@ -3726,33 +3641,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } } - if (use_json) { - json_ois = json_object_new_object(); - json_object_object_add(json_interface_sub, "interfaceIp", - json_ois); - } - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; -#if CONFDATE > 20240601 - CPP_NOTICE( - "Use all fields following ospfEnabled from interfaceIp hierarchy") -#endif - - if (use_json) - json_oi = json_object_new_object(); - if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { - if (use_json) { + if (use_json) json_object_boolean_true_add(json_interface_sub, "ifUnnumbered"); - json_object_boolean_true_add(json_oi, - "ifUnnumbered"); - } else + else vty_out(vty, " This interface is UNNUMBERED,"); } else { struct in_addr dest; @@ -3766,13 +3665,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "ipAddressPrefixlen", oi->address->prefixlen); - - json_object_string_addf( - json_oi, "ipAddress", "%pI4", - &oi->address->u.prefix4); - json_object_int_add(json_oi, - "ipAddressPrefixlen", - oi->address->prefixlen); } else vty_out(vty, " Internet Address %pFX,", oi->address); @@ -3798,26 +3690,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "ospfIfType", dstr); - json_object_string_add(json_oi, "ospfIfType", - dstr); - - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) json_object_string_addf( json_interface_sub, "vlinkPeer", "%pI4", &dest); - - json_object_string_addf(json_oi, - "vlinkPeer", - "%pI4", &dest); - } else { + else json_object_string_addf( json_interface_sub, "localIfUsed", "%pI4", &dest); - - json_object_string_addf(json_oi, - "localIfUsed", - "%pI4", &dest); - } } else vty_out(vty, " %s %pI4,", dstr, &dest); @@ -3826,16 +3706,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "area", ospf_area_desc_string(oi->area)); - json_object_string_add(json_oi, "area", - ospf_area_desc_string(oi->area)); - - if (OSPF_IF_PARAM(oi, mtu_ignore)) { - json_object_boolean_true_add( - json_oi, "mtuMismatchDetect"); + if (OSPF_IF_PARAM(oi, mtu_ignore)) json_object_boolean_true_add( json_interface_sub, "mtuMismatchDetect"); - } json_object_string_addf(json_interface_sub, "routerId", "%pI4", &ospf->router_id); @@ -3852,18 +3726,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, oi->state, NULL)); json_object_int_add(json_interface_sub, "priority", PRIORITY(oi)); - - json_object_string_addf(json_oi, "routerId", "%pI4", - &ospf->router_id); - json_object_string_add(json_oi, "networkType", - ospf_network_type_str[oi->type]); - json_object_int_add(json_oi, "cost", oi->output_cost); - json_object_int_add(json_oi, "transmitDelaySecs", - OSPF_IF_PARAM(oi, transmit_delay)); - json_object_string_add(json_oi, "state", - lookup_msg(ospf_ism_state_msg, - oi->state, NULL)); - json_object_int_add(json_oi, "priority", PRIORITY(oi)); json_object_boolean_add( json_interface_sub, "opaqueCapable", OSPF_IF_PARAM(oi, opaque_capable)); @@ -3907,13 +3769,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "drAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "drId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "drAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Designated Router (ID) %pI4", @@ -3939,13 +3794,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "bdrAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "bdrId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "bdrAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Backup Designated Router (ID) %pI4,", @@ -3961,43 +3809,28 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (oi->params && ntohl(oi->params->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) { - if (use_json) { + if (use_json) json_object_int_add( json_interface_sub, "networkLsaSequence", ntohl(oi->params->network_lsa_seqnum)); - - json_object_int_add( - json_oi, "networkLsaSequence", - ntohl(oi->params->network_lsa_seqnum)); - } else { + else vty_out(vty, " Saved Network-LSA sequence number 0x%x\n", ntohl(oi->params->network_lsa_seqnum)); - } } if (use_json) { if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { - if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfAllRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfAllRouters"); - } - if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfDesignatedRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfDesignatedRouters"); - } } } else { vty_out(vty, " Multicast group memberships:"); @@ -4013,23 +3846,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } if (use_json) { - if (OSPF_IF_PARAM(oi, fast_hello) == 0) { + if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", OSPF_IF_PARAM(oi, v_hello) * 1000); - - json_object_int_add(json_oi, "timerMsecs", - OSPF_IF_PARAM(oi, v_hello) * - 1000); - } else { + else json_object_int_add( json_interface_sub, "timerMsecs", 1000 / OSPF_IF_PARAM(oi, fast_hello)); - - json_object_int_add( - json_oi, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, fast_hello)); - } json_object_int_add(json_interface_sub, "timerDeadSecs", OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, "timerWaitSecs", @@ -4037,14 +3861,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add( json_interface_sub, "timerRetransmitSecs", OSPF_IF_PARAM(oi, retransmit_interval)); - - json_object_int_add(json_oi, "timerDeadSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add(json_oi, "timerWaitSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add( - json_oi, "timerRetransmitSecs", - OSPF_IF_PARAM(oi, retransmit_interval)); + json_object_int_add(json_interface_sub, + "timerRetransmitWindowMsecs", + OSPF_IF_PARAM(oi, + retransmit_window)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -4073,23 +3893,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store); - json_object_int_add(json_oi, - "timerHelloInMsecs", - time_store); } else vty_out(vty, " Hello due in %s\n", ospf_timer_dump(oi->t_hello, timebuf, sizeof(timebuf))); } else /* passive-interface is set */ { - if (use_json) { + if (use_json) json_object_boolean_true_add( json_interface_sub, "timerPassiveIface"); - - json_object_boolean_true_add( - json_oi, "timerPassiveIface"); - } else + else vty_out(vty, " No Hellos (Passive interface)\n"); } @@ -4100,11 +3914,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "nbrAdjacentCount", ospf_nbr_count(oi, NSM_Full)); - - json_object_int_add(json_oi, "nbrCount", - ospf_nbr_count(oi, 0)); - json_object_int_add(json_oi, "nbrAdjacentCount", - ospf_nbr_count(oi, NSM_Full)); } else vty_out(vty, " Neighbor Count is %d, Adjacent neighbor count is %d\n", @@ -4114,14 +3923,11 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, params = IF_DEF_PARAMS(ifp); if (params && OSPF_IF_PARAM_CONFIGURED(params, v_gr_hello_delay)) { - if (use_json) { + if (use_json) json_object_int_add(json_interface_sub, "grHelloDelaySecs", params->v_gr_hello_delay); - - json_object_int_add(json_oi, "grHelloDelaySecs", - params->v_gr_hello_delay); - } else + else vty_out(vty, " Graceful Restart hello delay: %us\n", params->v_gr_hello_delay); @@ -4129,45 +3935,64 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, ospf_interface_bfd_show(vty, ifp, json_interface_sub); - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "prefixSuppression", OSPF_IF_PARAM(oi, prefix_suppression)); - json_object_boolean_add(json_oi, "prefixSuppression", - OSPF_IF_PARAM(oi, - prefix_suppression)); - } else { - if (OSPF_IF_PARAM(oi, prefix_suppression)) - vty_out(vty, - " Suppress advertisement of interface IP prefix\n"); - } + else if (OSPF_IF_PARAM(oi, prefix_suppression)) + vty_out(vty, + " Suppress advertisement of interface IP prefix\n"); /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); - ospf_interface_auth_show(vty, oi, json_oi, use_json); + /* Point-to-Multipoint Interface options. */ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpDelayReflood", oi->p2mp_delay_reflood); - - json_object_boolean_add(json_oi, - "p2mpDelayReflood", - oi->p2mp_delay_reflood); - } else { + else vty_out(vty, " %sDelay reflooding LSAs received on P2MP interface\n", oi->p2mp_delay_reflood ? "" : "Don't "); - } + if (use_json) + json_object_boolean_add(json_interface_sub, + "p2mpNonBroadcast", + oi->p2mp_non_broadcast); + else + vty_out(vty, + " P2MP interface does %ssupport broadcast\n", + oi->p2mp_non_broadcast ? "not " : ""); + } + + if (oi->nbr_filter) { + if (use_json) + json_object_string_add(json_interface_sub, + "nbrFilterPrefixList", + prefix_list_name( + oi->nbr_filter)); + else + vty_out(vty, + " Neighbor filter prefix-list: %s\n", + prefix_list_name(oi->nbr_filter)); + } else { + if (use_json) + json_object_string_add(json_interface_sub, + "nbrFilterPrefixList", + "N/A"); } - /* Add ospf_interface object to main json blob using SIP as key + /* Non-Traffic interface counters */ if (use_json) - json_object_object_addf(json_ois, json_oi, "%pI4", - &oi->address->u.prefix4); + json_object_int_add(json_interface_sub, + "lsaRetransmissions", + oi->ls_rxmt_lsa); + else + vty_out(vty, " LSA retransmissions: %u\n", + oi->ls_rxmt_lsa); } } @@ -5381,12 +5206,20 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr), NULL)); } + /* Show state changes. */ if (use_json) json_object_int_add(json_neigh, "stateChangeCounter", nbr->state_change); else - vty_out(vty, " %d state changes\n", nbr->state_change); + vty_out(vty, " %d state changes\n", nbr->state_change); + + /* Show LSA retransmissions. */ + if (use_json) + json_object_int_add(json_neigh, "lsaRetransmissions", + nbr->ls_rxmt_lsa); + else + vty_out(vty, " %u LSA retransmissions\n", nbr->ls_rxmt_lsa); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res; @@ -5435,7 +5268,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (DR(oi).s_addr == INADDR_ANY) { if (!use_json) vty_out(vty, - " No designated router on this network\n"); + " No designated router on this network\n"); } else { nbr_dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); if (nbr_dr) { @@ -5454,14 +5287,14 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (nbr_bdr == NULL) { if (!use_json) vty_out(vty, - " No backup designated router on this network\n"); + " No backup designated router on this network\n"); } else { if (use_json) json_object_string_addf(json_neigh, "routerDesignatedBackupId", "%pI4", &nbr_bdr->router_id); else - vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); + vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); } /* Show options. */ @@ -5551,7 +5384,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show Link State Update Retransmission thread. */ if (use_json) { - if (nbr->t_ls_upd != NULL) + if (nbr->t_ls_rxmt != NULL) json_object_string_add( json_neigh, "threadLinkStateUpdateRetransmission", @@ -5559,7 +5392,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, } else vty_out(vty, " Thread Link State Update Retransmission %s\n\n", - nbr->t_ls_upd != NULL ? "on" : "off"); + nbr->t_ls_rxmt != NULL ? "on" : "off"); if (!use_json) { vty_out(vty, " Graceful restart Helper info:\n"); @@ -5709,7 +5542,7 @@ DEFPY(show_ip_ospf_neighbor_id, "%% OSPF is not enabled in vrf %s\n", vrf_name); else - vty_json_empty(vty); + vty_json_empty(vty, NULL); return CMD_SUCCESS; } ret = show_ip_ospf_neighbor_id_common( @@ -5969,7 +5802,7 @@ static int show_ip_ospf_neighbor_detail_all_common(struct vty *vty, prev_nbr = nbr; } - if (oi->type != OSPF_IFTYPE_NBMA) + if (!OSPF_IF_NON_BROADCAST(oi)) continue; struct listnode *nd; @@ -6210,7 +6043,7 @@ DEFPY(show_ip_ospf_neighbor_int, if (!ospf || !ospf->oi_running) { if (json) - vty_json_empty(vty); + vty_json_empty(vty, NULL); return ret; } @@ -6220,7 +6053,7 @@ DEFPY(show_ip_ospf_neighbor_int, ifp = if_lookup_by_name(ifname, vrf_id); if (!ifp) { if (json) - vty_json_empty(vty); + vty_json_empty(vty, NULL); else vty_out(vty, "No such interface.\n"); return ret; @@ -6257,7 +6090,7 @@ DEFPY(show_ip_ospf_neighbor_int_detail, "%% OSPF is not enabled in vrf %s\n", vrf_name); else - vty_json_empty(vty); + vty_json_empty(vty, NULL); return CMD_SUCCESS; } return show_ip_ospf_neighbor_int_detail_common( @@ -8197,7 +8030,7 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); } } @@ -8208,7 +8041,7 @@ static int ospf_vty_dead_interval_set(struct vty *vty, const char *interval_str, VTY_DECLVAR_CONTEXT(interface, ifp); uint32_t seconds; uint8_t hellomult; - struct in_addr addr; + struct in_addr addr = { INADDR_ANY }; int ret; struct ospf_if_params *params; struct ospf_interface *oi; @@ -8266,6 +8099,8 @@ static int ospf_vty_dead_interval_set(struct vty *vty, const char *interval_str, ospf_nbr_timer_update(oi); } + if (params->fast_hello != OSPF_FAST_HELLO_DEFAULT) + ospf_reset_hello_timer(ifp, addr, false); return CMD_SUCCESS; } @@ -8301,7 +8136,7 @@ DEFUN_HIDDEN (ospf_dead_interval, DEFUN (ip_ospf_dead_interval_minimal, ip_ospf_dead_interval_minimal_addr_cmd, - "ip ospf dead-interval minimal hello-multiplier (1-10) [A.B.C.D]", + "ip ospf dead-interval minimal hello-multiplier (2-20) [A.B.C.D]", "IP Information\n" "OSPF interface commands\n" "Interval time after which a neighbor is declared down\n" @@ -8322,7 +8157,7 @@ DEFUN (ip_ospf_dead_interval_minimal, DEFUN (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_cmd, - "no ip ospf dead-interval [<(1-65535)|minimal hello-multiplier (1-10)> [A.B.C.D]]", + "no ip ospf dead-interval [<(1-65535)|minimal hello-multiplier (2-20)> [A.B.C.D]]", NO_STR "IP Information\n" "OSPF interface commands\n" @@ -8389,7 +8224,7 @@ DEFUN (no_ip_ospf_dead_interval, DEFUN_HIDDEN (no_ospf_dead_interval, no_ospf_dead_interval_cmd, - "no ospf dead-interval [<(1-65535)|minimal hello-multiplier (1-10)> [A.B.C.D]]", + "no ospf dead-interval [<(1-65535)|minimal hello-multiplier (2-20)> [A.B.C.D]]", NO_STR "OSPF interface commands\n" "Interval time after which a neighbor is declared down\n" @@ -8547,7 +8382,7 @@ DEFUN_HIDDEN (no_ospf_hello_interval, DEFUN(ip_ospf_network, ip_ospf_network_cmd, "ip ospf network ", "IP Information\n" "OSPF interface commands\n" @@ -8556,6 +8391,7 @@ DEFUN(ip_ospf_network, ip_ospf_network_cmd, "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF delayed reflooding of LSAs received on P2MP interface\n" + "Specify OSPF point-to-multipoint network doesn't support broadcast\n" "Specify OSPF point-to-point network\n" "Specify OSPF point-to-point DMVPN network\n") { @@ -8564,6 +8400,7 @@ DEFUN(ip_ospf_network, ip_ospf_network_cmd, int old_type = IF_DEF_PARAMS(ifp)->type; uint8_t old_ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn; uint8_t old_p2mp_delay_reflood = IF_DEF_PARAMS(ifp)->p2mp_delay_reflood; + uint8_t old_p2mp_non_broadcast = IF_DEF_PARAMS(ifp)->p2mp_non_broadcast; struct route_node *rn; if (old_type == OSPF_IFTYPE_LOOPBACK) { @@ -8575,24 +8412,30 @@ DEFUN(ip_ospf_network, ip_ospf_network_cmd, IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0; IF_DEF_PARAMS(ifp)->p2mp_delay_reflood = OSPF_P2MP_DELAY_REFLOOD_DEFAULT; + IF_DEF_PARAMS(ifp)->p2mp_non_broadcast = OSPF_P2MP_NON_BROADCAST_DEFAULT; if (argv_find(argv, argc, "broadcast", &idx)) IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_BROADCAST; - else if (argv_find(argv, argc, "non-broadcast", &idx)) - IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_NBMA; else if (argv_find(argv, argc, "point-to-multipoint", &idx)) { IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT; if (argv_find(argv, argc, "delay-reflood", &idx)) IF_DEF_PARAMS(ifp)->p2mp_delay_reflood = true; - } else if (argv_find(argv, argc, "point-to-point", &idx)) { + if (argv_find(argv, argc, "non-broadcast", &idx)) + IF_DEF_PARAMS(ifp)->p2mp_non_broadcast = true; + } else if (argv_find(argv, argc, "non-broadcast", &idx)) + IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_NBMA; + else if (argv_find(argv, argc, "point-to-point", &idx)) { IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOPOINT; if (argv_find(argv, argc, "dmvpn", &idx)) IF_DEF_PARAMS(ifp)->ptp_dmvpn = 1; } + IF_DEF_PARAMS(ifp)->type_cfg = true; + if (IF_DEF_PARAMS(ifp)->type == old_type && IF_DEF_PARAMS(ifp)->ptp_dmvpn == old_ptp_dmvpn && - IF_DEF_PARAMS(ifp)->p2mp_delay_reflood == old_p2mp_delay_reflood) + IF_DEF_PARAMS(ifp)->p2mp_delay_reflood == old_p2mp_delay_reflood && + IF_DEF_PARAMS(ifp)->p2mp_non_broadcast == old_p2mp_non_broadcast) return CMD_SUCCESS; SET_IF_PARAM(IF_DEF_PARAMS(ifp), type); @@ -8606,13 +8449,16 @@ DEFUN(ip_ospf_network, ip_ospf_network_cmd, oi->type = IF_DEF_PARAMS(ifp)->type; oi->ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn; oi->p2mp_delay_reflood = IF_DEF_PARAMS(ifp)->p2mp_delay_reflood; + oi->p2mp_non_broadcast = IF_DEF_PARAMS(ifp)->p2mp_non_broadcast; /* * The OSPF interface only needs to be flapped if the network * type or DMVPN parameter changes. */ if (IF_DEF_PARAMS(ifp)->type != old_type || - IF_DEF_PARAMS(ifp)->ptp_dmvpn != old_ptp_dmvpn) { + IF_DEF_PARAMS(ifp)->ptp_dmvpn != old_ptp_dmvpn || + IF_DEF_PARAMS(ifp)->p2mp_non_broadcast != + old_p2mp_non_broadcast) { if (oi->state > ISM_Down) { OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown); OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceUp); @@ -8653,9 +8499,11 @@ DEFUN (no_ip_ospf_network, struct route_node *rn; IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp); + IF_DEF_PARAMS(ifp)->type_cfg = false; IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0; IF_DEF_PARAMS(ifp)->p2mp_delay_reflood = OSPF_P2MP_DELAY_REFLOOD_DEFAULT; + IF_DEF_PARAMS(ifp)->p2mp_non_broadcast = OSPF_P2MP_NON_BROADCAST_DEFAULT; if (IF_DEF_PARAMS(ifp)->type == old_type) return CMD_SUCCESS; @@ -8917,6 +8765,40 @@ DEFUN_HIDDEN (no_ospf_retransmit_interval, return no_ip_ospf_retransmit_interval(self, vty, argc, argv); } +DEFPY(ip_ospf_retransmit_window, ip_ospf_retransmit_window_addr_cmd, + "[no] ip ospf retransmit-window ![(20-1000)]$retransmit-window [A.B.C.D]$ip_addr", NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" + "Milliseconds\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + if (no) { + UNSET_IF_PARAM(params, retransmit_window); + params->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + } else { + SET_IF_PARAM(params, retransmit_window); + params->retransmit_window = retransmit_window; + } + + /* + * There is nothing to do when the retransmit-window changes, any + * change will take effect the next time the interface LSA retransmision + * timer expires. + */ + return CMD_SUCCESS; +} + DEFPY (ip_ospf_gr_hdelay, ip_ospf_gr_hdelay_cmd, "ip ospf graceful-restart hello-delay (1-1800)", @@ -9964,7 +9846,7 @@ DEFPY(ip_ospf_prefix_suppression, ip_ospf_prefix_suppression_addr_cmd, "[no] ip ospf prefix-suppression [A.B.C.D]$ip_addr", NO_STR "IP Information\n" "OSPF interface commands\n" - "Supress OSPF prefix advertisement on this interface\n" + "Suppress OSPF prefix advertisement on this interface\n" "Address of interface\n") { VTY_DECLVAR_CONTEXT(interface, ifp); @@ -10010,6 +9892,58 @@ DEFPY(ip_ospf_prefix_suppression, ip_ospf_prefix_suppression_addr_cmd, return CMD_SUCCESS; } +DEFPY(ip_ospf_neighbor_filter, ip_ospf_neighbor_filter_addr_cmd, + "[no] ip ospf neighbor-filter ![PREFIXLIST4_NAME]$prefix_list [A.B.C.D]$ip_addr", NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Filter OSPF neighbor packets\n" + "Prefix-List used for filtering\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + struct prefix_list *nbr_filter = NULL; + struct route_node *rn; + + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + if (params->nbr_filter_name) + XFREE(MTYPE_OSPF_IF_PARAMS, params->nbr_filter_name); + + if (no) { + UNSET_IF_PARAM(params, nbr_filter_name); + params->nbr_filter_name = NULL; + } else { + SET_IF_PARAM(params, nbr_filter_name); + params->nbr_filter_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS, + prefix_list); + nbr_filter = prefix_list_lookup(AFI_IP, params->nbr_filter_name); + } + + /* + * Determine if there is a change in neighbor filter prefix-list for the + * interface. + */ + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { + struct ospf_interface *oi = rn->info; + + if (oi && + (ip_addr.s_addr == INADDR_ANY || + IPV4_ADDR_SAME(&oi->address->u.prefix4, &ip_addr)) && + oi->nbr_filter != nbr_filter) { + oi->nbr_filter = nbr_filter; + if (oi->nbr_filter) + ospf_intf_neighbor_filter_apply(oi); + } + } + return CMD_SUCCESS; +} + DEFUN (ospf_max_metric_router_lsa_admin, ospf_max_metric_router_lsa_admin_cmd, "max-metric router-lsa administrative", @@ -10520,15 +10454,6 @@ static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf, json_object_string_add(json_vrf, "strictLsaCheck", (ospf->strict_lsa_check) ? "Enabled" : "Disabled"); -#if CONFDATE > 20240401 - CPP_NOTICE("Remove deprecated json key: restartSupoort") -#endif - json_object_string_add( - json_vrf, "restartSupoort", - (ospf->only_planned_restart) - ? "Planned Restart only" - : "Planned and Unplanned Restarts"); - json_object_string_add( json_vrf, "restartSupport", (ospf->only_planned_restart) @@ -10755,10 +10680,11 @@ DEFUN (ospf_route_aggregation_timer, DEFPY (show_ip_ospf_gr_helper, show_ip_ospf_gr_helper_cmd, - "show ip ospf [vrf ] graceful-restart helper [detail] [json]", + "show ip ospf [{(1-65535)$instance|vrf }] graceful-restart helper [detail] [json]", SHOW_STR IP_STR "OSPF information\n" + "Instance ID\n" VRF_CMD_HELP_STR "All VRFs\n" "OSPF Graceful Restart\n" @@ -10779,8 +10705,20 @@ DEFPY (show_ip_ospf_gr_helper, int inst = 0; bool detail = false; + if (instance && instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; + + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) + return CMD_SUCCESS; + OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (instance && vrf_name) { + vty_out(vty, "%% VRF is not supported in instance mode\n"); + return CMD_WARNING; + } + if (argv_find(argv, argc, "detail", &idx)) detail = true; @@ -10807,38 +10745,23 @@ DEFPY (show_ip_ospf_gr_helper, } ospf = ospf_lookup_by_inst_name(inst, vrf_name); - - if (ospf == NULL || !ospf->oi_running) { - - if (uj) - vty_json(vty, json); - else - vty_out(vty, - "%% OSPF is not enabled in vrf %s\n", - vrf_name); - - return CMD_SUCCESS; - } - } else { /* Default Vrf */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + } - if (ospf == NULL || !ospf->oi_running) { + if (ospf == NULL || !ospf->oi_running) { - if (uj) - vty_json(vty, json); - else - vty_out(vty, - "%% OSPF is not enabled in vrf default\n"); - - return CMD_SUCCESS; - } + if (uj) + vty_json(vty, json); + else + vty_out(vty, + "%% OSPF is not enabled in vrf %s\n", vrf_name ? vrf_name : "default"); - ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj, - detail); + return CMD_SUCCESS; } + ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj, detail); if (uj) vty_json(vty, json); @@ -11994,7 +11917,7 @@ static int ospf_show_summary_address(struct vty *vty, struct ospf *ospf, ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); if (!uj) { - vty_out(vty, "aggregation delay interval :%u(in seconds)\n\n", + vty_out(vty, "aggregation delay interval: %u(in seconds)\n\n", ospf->aggr_delay_interval); } else { json_object_int_add(json_vrf, "aggregationDelayInterval", @@ -12225,25 +12148,25 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) do { /* Interface Network print. */ - if (OSPF_IF_PARAM_CONFIGURED(params, type) - && params->type != OSPF_IFTYPE_LOOPBACK) { - if (params->type != ospf_default_iftype(ifp)) { - vty_out(vty, " ip ospf network %s", - ospf_int_type_str - [params->type]); - if (params->type - == OSPF_IFTYPE_POINTOPOINT - && params->ptp_dmvpn) - vty_out(vty, " dmvpn"); - if (params->type == - OSPF_IFTYPE_POINTOMULTIPOINT && - params->p2mp_delay_reflood) - vty_out(vty, " delay-reflood"); - if (params != IF_DEF_PARAMS(ifp) && rn) - vty_out(vty, " %pI4", - &rn->p.u.prefix4); - vty_out(vty, "\n"); - } + if (OSPF_IF_PARAM_CONFIGURED(params, type) && + params->type != OSPF_IFTYPE_LOOPBACK && + params->type_cfg) { + vty_out(vty, " ip ospf network %s", + ospf_int_type_str[params->type]); + if (params->type == OSPF_IFTYPE_POINTOPOINT && + params->ptp_dmvpn) + vty_out(vty, " dmvpn"); + if (params->type == + OSPF_IFTYPE_POINTOMULTIPOINT && + params->p2mp_delay_reflood) + vty_out(vty, " delay-reflood"); + if (params->type == + OSPF_IFTYPE_POINTOMULTIPOINT && + params->p2mp_non_broadcast) + vty_out(vty, " non-broadcast"); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); } /* OSPF interface authentication print */ @@ -12358,6 +12281,17 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) vty_out(vty, "\n"); } + /* Retransmit Window print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, retransmit_window) && + params->retransmit_window != + OSPF_RETRANSMIT_WINDOW_DEFAULT) { + vty_out(vty, " ip ospf retransmit-window %u", + params->retransmit_window); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + /* Transmit Delay print. */ if (OSPF_IF_PARAM_CONFIGURED(params, transmit_delay) && params->transmit_delay @@ -12453,6 +12387,15 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) vty_out(vty, "\n"); } + /* neighbor-filter print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, nbr_filter_name)) { + vty_out(vty, " ip ospf neighbor-filter %s", + params->nbr_filter_name); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + while (1) { if (rn == NULL) rn = route_top(IF_OIFS_PARAMS(ifp)); @@ -12706,19 +12649,22 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) oi = vl_data->vl_oi; /* timers */ - if (OSPF_IF_PARAM(oi, v_hello) - != OSPF_HELLO_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, v_wait) - != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, retransmit_interval) - != OSPF_RETRANSMIT_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, transmit_delay) - != OSPF_TRANSMIT_DELAY_DEFAULT) + if (OSPF_IF_PARAM(oi, v_hello) != + OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, v_wait) != + OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_interval) != + OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_window) != + OSPF_RETRANSMIT_WINDOW_DEFAULT || + OSPF_IF_PARAM(oi, transmit_delay) != + OSPF_TRANSMIT_DELAY_DEFAULT) vty_out(vty, - " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d\n", + " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d retransmit-window %d transmit-delay %d dead-interval %d\n", buf, &vl_data->vl_peer, OSPF_IF_PARAM(oi, v_hello), OSPF_IF_PARAM(oi, retransmit_interval), + OSPF_IF_PARAM(oi, retransmit_window), OSPF_IF_PARAM(oi, transmit_delay), OSPF_IF_PARAM(oi, v_wait)); else @@ -13251,6 +13197,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + /* "ip ospf retransmit-window" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_retransmit_window_addr_cmd); + /* "ip ospf transmit-delay" commands. */ install_element(INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); @@ -13269,6 +13218,9 @@ static void ospf_vty_if_init(void) /* "ip ospf prefix-suppression" commands. */ install_element(INTERFACE_NODE, &ip_ospf_prefix_suppression_addr_cmd); + /* "ip ospf neighbor-filter" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_neighbor_filter_addr_cmd); + /* These commands are compatibitliy for previous version. */ install_element(INTERFACE_NODE, &ospf_authentication_key_cmd); install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd); @@ -13767,11 +13719,8 @@ void ospf_vty_init(void) install_element(OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd); install_element(OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd); - /* "neighbor" commands. */ + /* "neighbor" command. */ install_element(OSPF_NODE, &ospf_neighbor_cmd); - install_element(OSPF_NODE, &ospf_neighbor_poll_interval_cmd); - install_element(OSPF_NODE, &no_ospf_neighbor_cmd); - install_element(OSPF_NODE, &no_ospf_neighbor_poll_cmd); /* write multiplier commands */ install_element(OSPF_NODE, &ospf_write_multiplier_cmd); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index abc580b13ef4..2c518f2c9eee 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -162,29 +162,6 @@ static int ospf_interface_link_params(ZAPI_CALLBACK_ARGS) return 0; } -/* VRF update for an interface. */ -static int ospf_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp = NULL; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "%s: Rx Interface %s VRF change vrf_id %u New vrf %s id %u", - __func__, ifp->name, vrf_id, - ospf_vrf_id_to_name(new_vrf_id), new_vrf_id); - - /*if_update(ifp, ifp->name, strlen(ifp->name), new_vrf_id);*/ - if_update_to_new_vrf(ifp, new_vrf_id); - - return 0; -} - /* Nexthop, ifindex, distance and metric information. */ static void ospf_zebra_add_nexthop(struct ospf *ospf, struct ospf_path *path, struct zapi_route *api) @@ -1510,30 +1487,20 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg) __func__); } -static int ospf_zebra_import_check_update(ZAPI_CALLBACK_ARGS) +static void ospf_zebra_import_check_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr) { - struct ospf *ospf; - struct zapi_route nhr; - struct prefix matched; + struct ospf *ospf = vrf->info; - ospf = ospf_lookup_by_vrf_id(vrf_id); if (ospf == NULL || !IS_OSPF_ASBR(ospf)) - return 0; - - if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { - zlog_err("%s[%u]: Failure to decode route", __func__, - ospf->vrf_id); - return -1; - } + return; - if (matched.family != AF_INET || matched.prefixlen != 0 || - nhr.type == ZEBRA_ROUTE_OSPF) - return 0; + if (match->family != AF_INET || match->prefixlen != 0 || + nhr->type == ZEBRA_ROUTE_OSPF) + return; - ospf->nssa_default_import_check.status = !!nhr.nexthop_num; + ospf->nssa_default_import_check.status = !!nhr->nexthop_num; ospf_abr_nssa_type7_defaults(ospf); - - return 0; } int ospf_distribute_list_out_set(struct ospf *ospf, int type, const char *name) @@ -1802,6 +1769,7 @@ static void ospf_prefix_list_update(struct prefix_list *plist) int type; int abr_inv = 0; struct ospf_area *area; + struct ospf_interface *oi; struct listnode *node, *n1; /* If OSPF instatnce does not exist, return right now. */ @@ -1857,6 +1825,19 @@ static void ospf_prefix_list_update(struct prefix_list *plist) } } + /* Update interface neighbor-filter lists. */ + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + if (OSPF_IF_PARAM(oi, nbr_filter_name) && + strcmp(OSPF_IF_PARAM(oi, nbr_filter_name), + prefix_list_name(plist)) == 0) { + oi->nbr_filter = prefix_list_lookup( + AFI_IP, + OSPF_IF_PARAM(oi, nbr_filter_name)); + if (oi->nbr_filter) + ospf_intf_neighbor_filter_apply(oi); + } + } + /* Schedule ABR task. */ if (IS_OSPF_ABR(ospf) && abr_inv) ospf_schedule_abr_task(ospf); @@ -2203,11 +2184,9 @@ static zclient_handler *const ospf_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = ospf_interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = ospf_interface_address_delete, [ZEBRA_INTERFACE_LINK_PARAMS] = ospf_interface_link_params, - [ZEBRA_INTERFACE_VRF_UPDATE] = ospf_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ospf_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ospf_zebra_read_route, - [ZEBRA_NEXTHOP_UPDATE] = ospf_zebra_import_check_update, [ZEBRA_OPAQUE_MESSAGE] = ospf_opaque_msg_handler, @@ -2221,11 +2200,10 @@ void ospf_zebra_init(struct event_loop *master, unsigned short instance) array_size(ospf_handlers)); zclient_init(zclient, ZEBRA_ROUTE_OSPF, instance, &ospfd_privs); zclient->zebra_connected = ospf_zebra_connected; + zclient->nexthop_update = ospf_zebra_import_check_update; /* Initialize special zclient for synchronous message exchanges. */ - struct zclient_options options = zclient_options_default; - options.synchronous = true; - zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_OSPF; zclient_sync->instance = instance; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index e3ed4f2f346d..1d013b260ee6 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -575,39 +575,12 @@ static struct ospf *ospf_lookup_by_name(const char *vrf_name) return NULL; } -/* Handle the second half of deferred shutdown. This is called either - * from the deferred-shutdown timer thread, or directly through - * ospf_deferred_shutdown_check. - * - * Function is to cleanup G-R state, if required then call ospf_finish_final - * to complete shutdown of this ospf instance. Possibly exit if the - * whole process is being shutdown and this was the last OSPF instance. - */ -static void ospf_deferred_shutdown_finish(struct ospf *ospf) -{ - ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; - EVENT_OFF(ospf->t_deferred_shutdown); - - ospf_finish_final(ospf); - - /* *ospf is now invalid */ - - /* ospfd being shut-down? If so, was this the last ospf instance? */ - if (CHECK_FLAG(om->options, OSPF_MASTER_SHUTDOWN) - && (listcount(om->ospf) == 0)) { - frr_fini(); - exit(0); - } - - return; -} - -/* Timer thread for G-R */ +/* Timer thread for deferred shutdown */ static void ospf_deferred_shutdown_timer(struct event *t) { struct ospf *ospf = EVENT_ARG(t); - ospf_deferred_shutdown_finish(ospf); + ospf_finish_final(ospf); } /* Check whether deferred-shutdown must be scheduled, otherwise call @@ -634,15 +607,12 @@ static void ospf_deferred_shutdown_check(struct ospf *ospf) ospf_router_lsa_update_area(area); } timeout = ospf->stub_router_shutdown_time; + OSPF_TIMER_ON(ospf->t_deferred_shutdown, + ospf_deferred_shutdown_timer, timeout); } else { /* No timer needed */ - ospf_deferred_shutdown_finish(ospf); - return; + ospf_finish_final(ospf); } - - OSPF_TIMER_ON(ospf->t_deferred_shutdown, ospf_deferred_shutdown_timer, - timeout); - return; } /* Shut down the entire process */ @@ -657,10 +627,6 @@ void ospf_terminate(void) SET_FLAG(om->options, OSPF_MASTER_SHUTDOWN); - /* Skip some steps if OSPF not actually running */ - if (listcount(om->ospf) == 0) - goto done; - for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf)) ospf_finish(ospf); @@ -678,6 +644,11 @@ void ospf_terminate(void) /* Cleanup vrf info */ ospf_vrf_terminate(); + keychain_terminate(); + + ospf_opaque_term(); + list_delete(&om->ospf); + /* Deliberately go back up, hopefully to thread scheduler, as * One or more ospf_finish()'s may have deferred shutdown to a timer * thread @@ -687,20 +658,17 @@ void ospf_terminate(void) zclient_stop(zclient_sync); zclient_free(zclient_sync); -done: frr_fini(); } void ospf_finish(struct ospf *ospf) { - /* let deferred shutdown decide */ - ospf_deferred_shutdown_check(ospf); - - /* if ospf_deferred_shutdown returns, then ospf_finish_final is - * deferred to expiry of G-S timer thread. Return back up, hopefully - * to thread scheduler. - */ - return; + if (CHECK_FLAG(om->options, OSPF_MASTER_SHUTDOWN)) + ospf_finish_final(ospf); + else { + /* let deferred shutdown decide */ + ospf_deferred_shutdown_check(ospf); + } } /* Final cleanup of ospf instance */ @@ -900,6 +868,7 @@ static void ospf_finish_final(struct ospf *ospf) EVENT_OFF(ospf->t_ase_calc); EVENT_OFF(ospf->t_maxage); EVENT_OFF(ospf->t_maxage_walker); + EVENT_OFF(ospf->t_deferred_shutdown); EVENT_OFF(ospf->t_abr_task); EVENT_OFF(ospf->t_abr_fr); EVENT_OFF(ospf->t_asbr_check); @@ -1127,6 +1096,7 @@ struct ospf_interface *add_ospf_interface(struct connected *co, oi->type = IF_DEF_PARAMS(co->ifp)->type; oi->ptp_dmvpn = IF_DEF_PARAMS(co->ifp)->ptp_dmvpn; oi->p2mp_delay_reflood = IF_DEF_PARAMS(co->ifp)->p2mp_delay_reflood; + oi->p2mp_non_broadcast = IF_DEF_PARAMS(co->ifp)->p2mp_non_broadcast; /* Add pseudo neighbor. */ ospf_nbr_self_reset(oi, oi->ospf->router_id); @@ -1257,8 +1227,9 @@ int ospf_network_unset(struct ospf *ospf, struct prefix_ipv4 *p, { struct route_node *rn; struct ospf_network *network; - struct listnode *node, *nnode; + struct listnode *node; struct ospf_interface *oi; + struct list *ospf_oiflist = NULL; rn = route_node_lookup(ospf->networks, (struct prefix *)p); if (rn == NULL) @@ -1273,8 +1244,9 @@ int ospf_network_unset(struct ospf *ospf, struct prefix_ipv4 *p, rn->info = NULL; route_unlock_node(rn); /* initial reference */ - /* Find interfaces that are not configured already. */ - for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi)) { + ospf_oiflist = list_dup(ospf->oiflist); + /* Find interfaces that are not configured already. */ + for (ALL_LIST_ELEMENTS_RO(ospf_oiflist, node, oi)) { if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; @@ -1282,6 +1254,8 @@ int ospf_network_unset(struct ospf *ospf, struct prefix_ipv4 *p, ospf_network_run_subnet(ospf, oi->connected, NULL, NULL); } + list_delete(&ospf_oiflist); + /* Update connected redistribute. */ update_redistributed(ospf, 0); /* interfaces possibly removed */ ospf_area_check_free(ospf, area_id); @@ -1289,6 +1263,7 @@ int ospf_network_unset(struct ospf *ospf, struct prefix_ipv4 *p, return 1; } + /* Ensure there's an OSPF instance, as "ip ospf area" enabled OSPF means * there might not be any 'router ospf' config. * @@ -1437,7 +1412,6 @@ static void ospf_network_run_interface(struct ospf *ospf, struct interface *ifp, struct prefix *p, struct ospf_area *given_area) { - struct listnode *cnode; struct connected *co; if (memcmp(ifp->name, "VLINK", 5) == 0) @@ -1449,7 +1423,7 @@ static void ospf_network_run_interface(struct ospf *ospf, struct interface *ifp, /* if interface prefix is match specified prefix, then create socket and join multicast group. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) + frr_each (if_connected, ifp->connected, co) ospf_network_run_subnet(ospf, co, p, given_area); } @@ -2016,7 +1990,7 @@ static void ospf_nbr_nbma_add(struct ospf_nbr_nbma *nbr_nbma, struct route_node *rn; struct prefix p; - if (oi->type != OSPF_IFTYPE_NBMA) + if (!OSPF_IF_NON_BROADCAST(oi)) return; if (nbr_nbma->nbr != NULL) @@ -2063,7 +2037,7 @@ void ospf_nbr_nbma_if_update(struct ospf *ospf, struct ospf_interface *oi) struct route_node *rn; struct prefix_ipv4 p; - if (oi->type != OSPF_IFTYPE_NBMA) + if (!OSPF_IF_NON_BROADCAST(oi)) return; for (rn = route_top(ospf->nbr_nbma); rn; rn = route_next(rn)) @@ -2122,7 +2096,7 @@ int ospf_nbr_nbma_set(struct ospf *ospf, struct in_addr nbr_addr) rn->info = nbr_nbma; for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { - if (oi->type == OSPF_IFTYPE_NBMA) + if (OSPF_IF_NON_BROADCAST(oi)) if (prefix_match(oi->address, (struct prefix *)&p)) { ospf_nbr_nbma_add(nbr_nbma, oi); break; diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 2ab7db119e46..6051dff7095c 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -22,9 +22,6 @@ #define OSPF_VERSION 2 -/* VTY port number. */ -#define OSPF_VTY_PORT 2604 - /* IP TTL for OSPF protocol. */ #define OSPF_IP_TTL 1 #define OSPF_VL_IP_TTL 100 diff --git a/pathd/path_cli.c b/pathd/path_cli.c index 45f4ac7ab8da..e22931c13e1e 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -287,7 +287,7 @@ void cli_show_srte_segment_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " segment-list %s\n", - yang_dnode_get_string(dnode, "./name")); + yang_dnode_get_string(dnode, "name")); } void cli_show_srte_segment_list_end(struct vty *vty, @@ -546,37 +546,37 @@ void cli_show_srte_segment_list_segment(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - vty_out(vty, " index %s", yang_dnode_get_string(dnode, "./index")); - if (yang_dnode_exists(dnode, "./sid-value")) { + vty_out(vty, " index %s", yang_dnode_get_string(dnode, "index")); + if (yang_dnode_exists(dnode, "sid-value")) { vty_out(vty, " mpls label %s", - yang_dnode_get_string(dnode, "./sid-value")); + yang_dnode_get_string(dnode, "sid-value")); } - if (yang_dnode_exists(dnode, "./nai")) { + if (yang_dnode_exists(dnode, "nai")) { struct ipaddr addr; struct ipaddr addr_rmt; - switch (yang_dnode_get_enum(dnode, "./nai/type")) { + switch (yang_dnode_get_enum(dnode, "nai/type")) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: - yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr, dnode, "nai/local-address"); vty_out(vty, " nai prefix %pI4", &addr.ipaddr_v4); break; case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: - yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr, dnode, "nai/local-address"); vty_out(vty, " nai prefix %pI6", &addr.ipaddr_v6); break; case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY: - yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr, dnode, "nai/local-address"); yang_dnode_get_ip(&addr_rmt, dnode, "./nai/remote-address"); vty_out(vty, " nai adjacency %pI4", &addr.ipaddr_v4); vty_out(vty, " %pI4", &addr_rmt.ipaddr_v4); break; case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: - yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr, dnode, "nai/local-address"); yang_dnode_get_ip(&addr_rmt, dnode, "./nai/remote-address"); vty_out(vty, " nai adjacency %pI6", &addr.ipaddr_v6); @@ -585,17 +585,17 @@ void cli_show_srte_segment_list_segment(struct vty *vty, default: break; } - if (yang_dnode_exists(dnode, "./nai/local-prefix-len")) { + if (yang_dnode_exists(dnode, "nai/local-prefix-len")) { vty_out(vty, "/%s", yang_dnode_get_string( dnode, "./nai/local-prefix-len")); } - if (yang_dnode_exists(dnode, "./nai/local-interface")) { + if (yang_dnode_exists(dnode, "nai/local-interface")) { vty_out(vty, " iface %s", yang_dnode_get_string(dnode, "./nai/local-interface")); } - if (yang_dnode_exists(dnode, "./nai/algorithm")) { + if (yang_dnode_exists(dnode, "nai/algorithm")) { vty_out(vty, " algorithm %s", yang_dnode_get_string(dnode, "./nai/algorithm")); @@ -658,8 +658,8 @@ void cli_show_srte_policy(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " policy color %s endpoint %s\n", - yang_dnode_get_string(dnode, "./color"), - yang_dnode_get_string(dnode, "./endpoint")); + yang_dnode_get_string(dnode, "color"), + yang_dnode_get_string(dnode, "endpoint")); } void cli_show_srte_policy_end(struct vty *vty, const struct lyd_node *dnode) @@ -860,7 +860,7 @@ DEFPY(srte_candidate_no_affinity_filter, srte_candidate_no_affinity_filter_cmd, DEFPY(srte_candidate_metric, srte_candidate_metric_cmd, - "metric [bound$bound] $type METRIC$value [required$required]", + "metric [bound$bound] $type METRIC$value [required$required] [computed$computed]", "Define a metric constraint\n" "If the metric is bounded\n" "IGP metric\n" @@ -885,7 +885,8 @@ DEFPY(srte_candidate_metric, "Domain Count metric\n" "Border Node Count metric\n" "Metric value\n" - "Required constraint\n") + "Required constraint\n" + "Force the PCE to provide the computed path metric\n") { char xpath[XPATH_CANDIDATE_MAXLEN]; snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']/value", @@ -899,12 +900,16 @@ DEFPY(srte_candidate_metric, "./constraints/metrics[type='%s']/required", type); nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, required ? "true" : "false"); + snprintf(xpath, sizeof(xpath), + "./constraints/metrics[type='%s']/is-computed", type); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + computed ? "true" : "false"); return nb_cli_apply_changes(vty, NULL); } DEFPY(srte_candidate_no_metric, srte_candidate_no_metric_cmd, - "no metric [bound] $type [METRIC$value] [required$required]", + "no metric [bound] $type [METRIC$value] [required$required] [computed$computed]", NO_STR "Remove a metric constraint\n" "If the metric is bounded\n" @@ -930,7 +935,8 @@ DEFPY(srte_candidate_no_metric, "Domain Count metric\n" "Border Node Count metric\n" "Metric value\n" - "Required constraint\n") + "Required constraint\n" + "Force the PCE to provide the computed path metric\n") { char xpath[XPATH_CANDIDATE_MAXLEN]; snprintf(xpath, sizeof(xpath), "./constraints/metrics[type='%s']", @@ -1164,7 +1170,8 @@ static void config_write_float(struct vty *vty, float value) static void config_write_metric(struct vty *vty, enum srte_candidate_metric_type type, - float value, bool required, bool is_bound) + float value, bool required, bool is_bound, + bool is_computed) { const char *name = metric_type_name(type); if (name == NULL) @@ -1173,6 +1180,7 @@ static void config_write_metric(struct vty *vty, metric_type_name(type)); config_write_float(vty, value); vty_out(vty, required ? " required" : ""); + vty_out(vty, is_computed ? " computed" : ""); vty_out(vty, "\n"); } @@ -1180,16 +1188,18 @@ static int config_write_metric_cb(const struct lyd_node *dnode, void *arg) { struct vty *vty = arg; enum srte_candidate_metric_type type; - bool required, is_bound = false; + bool required, is_bound = false, is_computed = false; float value; - type = yang_dnode_get_enum(dnode, "./type"); - value = (float)yang_dnode_get_dec64(dnode, "./value"); - required = yang_dnode_get_bool(dnode, "./required"); - if (yang_dnode_exists(dnode, "./is-bound")) - is_bound = yang_dnode_get_bool(dnode, "./is-bound"); + type = yang_dnode_get_enum(dnode, "type"); + value = (float)yang_dnode_get_dec64(dnode, "value"); + required = yang_dnode_get_bool(dnode, "required"); + if (yang_dnode_exists(dnode, "is-bound")) + is_bound = yang_dnode_get_bool(dnode, "is-bound"); + if (yang_dnode_exists(dnode, "is-computed")) + is_computed = yang_dnode_get_bool(dnode, "is-computed"); - config_write_metric(vty, type, value, required, is_bound); + config_write_metric(vty, type, value, required, is_bound, is_computed); return YANG_ITER_CONTINUE; } @@ -1201,18 +1211,18 @@ void cli_show_srte_policy_candidate_path(struct vty *vty, uint32_t affinity; bool required; enum objfun_type objfun_type; - const char *type = yang_dnode_get_string(dnode, "./type"); + const char *type = yang_dnode_get_string(dnode, "type"); vty_out(vty, " candidate-path preference %s name %s %s", - yang_dnode_get_string(dnode, "./preference"), - yang_dnode_get_string(dnode, "./name"), type); + yang_dnode_get_string(dnode, "preference"), + yang_dnode_get_string(dnode, "name"), type); if (strmatch(type, "explicit")) vty_out(vty, " segment-list %s", - yang_dnode_get_string(dnode, "./segment-list-name")); + yang_dnode_get_string(dnode, "segment-list-name")); vty_out(vty, "\n"); if (strmatch(type, "dynamic")) { - if (yang_dnode_exists(dnode, "./constraints/bandwidth")) { + if (yang_dnode_exists(dnode, "constraints/bandwidth")) { bandwidth = (float)yang_dnode_get_dec64( dnode, "./constraints/bandwidth/value"); required = yang_dnode_get_bool( @@ -1262,7 +1272,7 @@ void cli_show_srte_policy_candidate_path(struct vty *vty, void cli_show_srte_policy_candidate_path_end(struct vty *vty, const struct lyd_node *dnode) { - const char *type = yang_dnode_get_string(dnode, "./type"); + const char *type = yang_dnode_get_string(dnode, "type"); if (strmatch(type, "dynamic")) vty_out(vty, " exit\n"); diff --git a/pathd/path_main.c b/pathd/path_main.c index c333162f2b4f..23cbb9ccedc6 100644 --- a/pathd/path_main.c +++ b/pathd/path_main.c @@ -58,7 +58,7 @@ static void sighup(void) static void sigint(void) { zlog_notice("Terminating on signal"); - zlog_notice("Unregisterfrom opaque,etc "); + zlog_notice("Unregister from opaque,etc "); pathd_shutdown(); exit(0); @@ -95,17 +95,20 @@ static const struct frr_yang_module_info *pathd_yang_modules[] = { &frr_pathd_info, }; -#define PATH_VTY_PORT 2621 +/* clang-format off */ +FRR_DAEMON_INFO(pathd, PATH, + .vty_port = PATH_VTY_PORT, + .proghelp = "Implementation of PATH.", -FRR_DAEMON_INFO(pathd, PATH, .vty_port = PATH_VTY_PORT, + .signals = path_signals, + .n_signals = array_size(path_signals), - .proghelp = "Implementation of PATH.", + .privs = &pathd_privs, - .signals = path_signals, .n_signals = array_size(path_signals), - - .privs = &pathd_privs, .yang_modules = pathd_yang_modules, - .n_yang_modules = array_size(pathd_yang_modules), + .yang_modules = pathd_yang_modules, + .n_yang_modules = array_size(pathd_yang_modules), ); +/* clang-format on */ int main(int argc, char **argv, char **envp) { diff --git a/pathd/path_nb.c b/pathd/path_nb.c index 9e919571dd12..e1c0cc3efa6c 100644 --- a/pathd/path_nb.c +++ b/pathd/path_nb.c @@ -313,8 +313,8 @@ int iter_objfun_cb(const struct lyd_node *dnode, void *arg) pref = &of_arg->prefs[of_arg->free_slot++]; - pref->index = yang_dnode_get_uint32(dnode, "./index"); - pref->type = yang_dnode_get_enum(dnode, "./type"); + pref->index = yang_dnode_get_uint32(dnode, "index"); + pref->type = yang_dnode_get_enum(dnode, "type"); /* Simplistic insertion sort */ p = &of_arg->first; diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c index ad24f23dd9f9..48531ba43339 100644 --- a/pathd/path_nb_config.c +++ b/pathd/path_nb_config.c @@ -31,7 +31,7 @@ int pathd_srte_segment_list_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - name = yang_dnode_get_string(args->dnode, "./name"); + name = yang_dnode_get_string(args->dnode, "name"); segment_list = srte_segment_list_add(name); nb_running_set_entry(args->dnode, segment_list); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW); @@ -104,7 +104,7 @@ int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args) return NB_OK; segment_list = nb_running_get_entry(args->dnode, NULL, true); - index = yang_dnode_get_uint32(args->dnode, "./index"); + index = yang_dnode_get_uint32(args->dnode, "index"); segment = srte_segment_entry_add(segment_list, index); nb_running_set_entry(args->dnode, segment); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED); @@ -191,9 +191,9 @@ void pathd_srte_segment_list_segment_nai_apply_finish( const char *algo_buf, *local_prefix_len_buf; segment = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./type"); + type = yang_dnode_get_enum(args->dnode, "type"); - yang_dnode_get_ip(&local_addr, args->dnode, "./local-address"); + yang_dnode_get_ip(&local_addr, args->dnode, "local-address"); switch (type) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: @@ -208,12 +208,12 @@ void pathd_srte_segment_list_segment_nai_apply_finish( yang_dnode_get_ip(&remote_addr, args->dnode, "./remote-address"); local_iface = - yang_dnode_get_uint32(args->dnode, "./local-interface"); + yang_dnode_get_uint32(args->dnode, "local-interface"); remote_iface = yang_dnode_get_uint32(args->dnode, "./remote-interface"); break; case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: - algo_buf = yang_dnode_get_string(args->dnode, "./algorithm"); + algo_buf = yang_dnode_get_string(args->dnode, "algorithm"); algo = atoi(algo_buf); local_prefix_len_buf = yang_dnode_get_string( args->dnode, "./local-prefix-len"); @@ -221,7 +221,7 @@ void pathd_srte_segment_list_segment_nai_apply_finish( break; case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: local_iface = - yang_dnode_get_uint32(args->dnode, "./local-interface"); + yang_dnode_get_uint32(args->dnode, "local-interface"); local_prefix_len_buf = yang_dnode_get_string( args->dnode, "./local-prefix-len"); local_prefix_len = atoi(local_prefix_len_buf); @@ -254,8 +254,8 @@ int pathd_srte_policy_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - color = yang_dnode_get_uint32(args->dnode, "./color"); - yang_dnode_get_ip(&endpoint, args->dnode, "./endpoint"); + color = yang_dnode_get_uint32(args->dnode, "color"); + yang_dnode_get_ip(&endpoint, args->dnode, "endpoint"); policy = srte_policy_add(color, &endpoint, SRTE_ORIGIN_LOCAL, NULL); nb_running_set_entry(args->dnode, policy); @@ -377,7 +377,7 @@ int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args) return NB_OK; policy = nb_running_get_entry(args->dnode, NULL, true); - preference = yang_dnode_get_uint32(args->dnode, "./preference"); + preference = yang_dnode_get_uint32(args->dnode, "preference"); candidate = srte_candidate_add(policy, preference, SRTE_ORIGIN_LOCAL, NULL); nb_running_set_entry(args->dnode, candidate); @@ -539,7 +539,7 @@ int pathd_srte_policy_candidate_path_metrics_destroy( assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./type"); + type = yang_dnode_get_enum(args->dnode, "type"); srte_candidate_unset_metric(candidate, type); return NB_OK; @@ -557,13 +557,13 @@ void pathd_srte_policy_candidate_path_metrics_apply_finish( candidate = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./type"); - value = (float)yang_dnode_get_dec64(args->dnode, "./value"); - required = yang_dnode_get_bool(args->dnode, "./required"); - if (yang_dnode_exists(args->dnode, "./is-bound")) - is_bound = yang_dnode_get_bool(args->dnode, "./is-bound"); - if (yang_dnode_exists(args->dnode, "./is-computed")) - is_computed = yang_dnode_get_bool(args->dnode, "./is-computed"); + type = yang_dnode_get_enum(args->dnode, "type"); + value = (float)yang_dnode_get_dec64(args->dnode, "value"); + required = yang_dnode_get_bool(args->dnode, "required"); + if (yang_dnode_exists(args->dnode, "is-bound")) + is_bound = yang_dnode_get_bool(args->dnode, "is-bound"); + if (yang_dnode_exists(args->dnode, "is-computed")) + is_computed = yang_dnode_get_bool(args->dnode, "is-computed"); srte_candidate_set_metric(candidate, type, value, required, is_bound, is_computed); @@ -597,8 +597,8 @@ void pathd_srte_policy_candidate_path_objfun_apply_finish( bool required; candidate = nb_running_get_entry(args->dnode, NULL, true); - required = yang_dnode_get_bool(args->dnode, "./required"); - type = yang_dnode_get_enum(args->dnode, "./type"); + required = yang_dnode_get_bool(args->dnode, "required"); + type = yang_dnode_get_enum(args->dnode, "type"); srte_candidate_set_objfun(candidate, required, type); } @@ -739,8 +739,8 @@ void pathd_srte_policy_candidate_path_bandwidth_apply_finish( assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); - value = (float)yang_dnode_get_dec64(args->dnode, "./value"); - required = yang_dnode_get_bool(args->dnode, "./required"); + value = (float)yang_dnode_get_dec64(args->dnode, "value"); + required = yang_dnode_get_bool(args->dnode, "required"); srte_candidate_set_bandwidth(candidate, value, required); } diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h index 5c6a02372f23..d6dbcb5c08c9 100644 --- a/pathd/path_pcep.h +++ b/pathd/path_pcep.h @@ -25,6 +25,7 @@ DECLARE_MTYPE(PCEP); #define PCEP_DEBUG_MODE_PATH 0x02 #define PCEP_DEBUG_MODE_PCEP 0x04 #define PCEP_DEBUG_MODE_PCEPLIB 0x08 +#define PCEP_DEBUG_MODE_ALL 0x0F #define PCEP_DEBUG(fmt, ...) \ do { \ if (DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC)) \ diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index 9880081f35e8..47a811d144f1 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -43,6 +43,8 @@ #define DEFAULT_TIMER_SESSION_TIMEOUT_INTERVAL 30 #define DEFAULT_DELEGATION_TIMEOUT_INTERVAL 10 +#define BUFFER_PCC_PCE_SIZE 1024 + /* CLI Function declarations */ static int pcep_cli_debug_config_write(struct vty *vty); static int pcep_cli_debug_set_all(uint32_t flags, bool set); @@ -73,6 +75,9 @@ static void print_pcep_capabilities(char *buf, size_t buf_len, pcep_configuration *config); static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts, struct pcep_pcc_info *pcc_info); +static void print_pcep_session_json(struct vty *vty, struct pce_opts *pce_opts, + struct pcep_pcc_info *pcc_info, + json_object *json); static bool pcep_cli_pcc_has_pce(const char *pce_name); static void pcep_cli_add_pce_connection(struct pce_opts *pce_opts); static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts); @@ -458,28 +463,32 @@ static void pcep_cli_remove_pce_connection(struct pce_opts *pce_opts) * VTY command implementations */ -static int path_pcep_cli_debug(struct vty *vty, const char *no_str, - const char *basic_str, const char *path_str, - const char *message_str, const char *pceplib_str) +static int path_pcep_cli_debug(struct vty *vty, const char *debug_type, bool set) { uint32_t mode = DEBUG_NODE2MODE(vty->node); - bool no = (no_str != NULL); - - DEBUG_MODE_SET(&pcep_g->dbg, mode, !no); - if (basic_str != NULL) { - DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC, !no); - } - if (path_str != NULL) { - DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH, !no); - } - if (message_str != NULL) { - DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP, !no); - } - if (pceplib_str != NULL) { - DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB, !no); + /* Global Set */ + if (debug_type == NULL) { + DEBUG_MODE_SET(&pcep_g->dbg, mode, set); + DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_ALL, set); + return CMD_SUCCESS; } + DEBUG_MODE_SET(&pcep_g->dbg, mode, true); + + if (strcmp(debug_type, "basic") == 0) + DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_BASIC, set); + else if (strcmp(debug_type, "path") == 0) + DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PATH, set); + else if (strcmp(debug_type, "message") == 0) + DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEP, set); + else if (strcmp(debug_type, "pceplib") == 0) + DEBUG_FLAGS_SET(&pcep_g->dbg, PCEP_DEBUG_MODE_PCEPLIB, set); + + /* Unset the pcep debug mode if there is no flag at least set*/ + if (!DEBUG_FLAGS_CHECK(&pcep_g->dbg, PCEP_DEBUG_MODE_ALL)) + DEBUG_MODE_SET(&pcep_g->dbg, mode, false); + return CMD_SUCCESS; } @@ -1018,10 +1027,14 @@ static int path_pcep_cli_pcc_delete(struct vty *vty) } static int path_pcep_cli_pcc_pcc_msd(struct vty *vty, const char *msd_str, - long msd) + long msd, bool reset) { - pcc_msd_configured_g = true; - PCEP_VTYSH_INT_ARG_CHECK(msd_str, msd, pcc_msd_g, 0, 33); + if (reset) + pcc_msd_configured_g = false; + else if (msd_str) { + pcc_msd_configured_g = true; + PCEP_VTYSH_INT_ARG_CHECK(msd_str, msd, pcc_msd_g, 0, 33); + } return CMD_SUCCESS; } @@ -1178,11 +1191,189 @@ static void print_pcep_capabilities(char *buf, size_t buf_len, } } +/* Internal util function to print a pcep session */ +static void print_pcep_session_json(struct vty *vty, struct pce_opts *pce_opts, + struct pcep_pcc_info *pcc_info, + json_object *json) +{ + char buf[BUFFER_PCC_PCE_SIZE] = {}; + int index = 0; + pcep_session *session; + struct pcep_config_group_opts *config_opts; + struct counters_group *group; + + /* PCE IP */ + if (IS_IPADDR_V4(&pce_opts->addr)) + json_object_string_addf(json, "pceAddress", "%pI4", + &pce_opts->addr.ipaddr_v4); + else if (IS_IPADDR_V6(&pce_opts->addr)) + json_object_string_addf(json, "pceAddress", "%pI6", + &pce_opts->addr.ipaddr_v6); + json_object_int_add(json, "pcePort", pce_opts->port); + + /* PCC IP */ + if (IS_IPADDR_V4(&pcc_info->pcc_addr)) + json_object_string_addf(json, "pccAddress", "%pI4", + &pcc_info->pcc_addr.ipaddr_v4); + else if (IS_IPADDR_V6(&pcc_info->pcc_addr)) + json_object_string_addf(json, "pccAddress", "%pI6", + &pcc_info->pcc_addr.ipaddr_v6); + + json_object_int_add(json, "pccPort", pcc_info->pcc_port); + json_object_int_add(json, "pccMsd", pcc_info->msd); + + if (pcc_info->status == PCEP_PCC_OPERATING) + json_object_string_add(json, "sessionStatus", "UP"); + else + json_object_string_add(json, "sessionStatus", + pcc_status_name(pcc_info->status)); + + json_object_boolean_add(json, "bestMultiPce", + pcc_info->is_best_multi_pce); + json_object_int_add(json, "precedence", + pcc_info->precedence > 0 ? pcc_info->precedence + : DEFAULT_PCE_PRECEDENCE); + json_object_string_add(json, "confidence", + pcc_info->previous_best ? "low" : "normal"); + + /* PCEPlib pcep session values, get a thread safe copy of the counters + */ + session = pcep_ctrl_get_pcep_session(pcep_g->fpt, pcc_info->pcc_id); + + /* Config Options values */ + config_opts = &pce_opts->config_opts; + json_object_int_add(json, "keepaliveConfig", + config_opts->keep_alive_seconds); + json_object_int_add(json, "deadTimerConfig", + config_opts->dead_timer_seconds); + json_object_int_add(json, "pccPcepRequestTimerConfig", + config_opts->pcep_request_time_seconds); + json_object_int_add(json, "sessionTimeoutIntervalSec", + config_opts->session_timeout_inteval_seconds); + json_object_int_add(json, "delegationTimeout", + config_opts->delegation_timeout_seconds); + json_object_boolean_add(json, "tcpMd5Authentication", + (strlen(config_opts->tcp_md5_auth) > 0)); + if (strlen(config_opts->tcp_md5_auth) > 0) + json_object_string_add(json, "tcpMd5AuthenticationString", + config_opts->tcp_md5_auth); + json_object_boolean_add(json, "draft07", !!config_opts->draft07); + json_object_boolean_add(json, "draft16AndRfc8408", + !config_opts->draft07); + + json_object_int_add(json, "nextPcRequestId", pcc_info->next_reqid); + /* original identifier used by the PCC for LSP instantiation */ + json_object_int_add(json, "nextPLspId", pcc_info->next_plspid); + + if (session != NULL) { + json_object_int_add(json, "sessionKeepalivePceNegotiatedSec", + session->pcc_config + .keep_alive_pce_negotiated_timer_seconds); + json_object_int_add(json, "sessionDeadTimerPceNegotiatedSec", + session->pcc_config + .dead_timer_pce_negotiated_seconds); + if (pcc_info->status == PCEP_PCC_SYNCHRONIZING || + pcc_info->status == PCEP_PCC_OPERATING) { + time_t current_time = time(NULL); + struct tm lt = { 0 }; + /* Just for the timezone */ + localtime_r(¤t_time, <); + gmtime_r(&session->time_connected, <); + json_object_int_add(json, "sessionConnectionDurationSec", + (uint32_t)(current_time - + session->time_connected)); + json_object_string_addf(json, + "sessionConnectionStartTimeUTC", + "%d-%02d-%02d %02d:%02d:%02d", + lt.tm_year + 1900, lt.tm_mon + 1, + lt.tm_mday, lt.tm_hour, + lt.tm_min, lt.tm_sec); + } + + /* PCC capabilities */ + buf[0] = '\0'; + + if (config_opts->pce_initiated) + index += csnprintfrr(buf, sizeof(buf), "%s", + PCEP_CLI_CAP_PCC_PCE_INITIATED); + else + index += csnprintfrr(buf, sizeof(buf), "%s", + PCEP_CLI_CAP_PCC_INITIATED); + print_pcep_capabilities(buf, sizeof(buf) - index, + &session->pcc_config); + json_object_string_add(json, "pccCapabilities", buf); + + /* PCE capabilities */ + buf[0] = '\0'; + print_pcep_capabilities(buf, sizeof(buf), &session->pce_config); + if (buf[0] != '\0') + json_object_string_add(json, "pceCapabilities", buf); + XFREE(MTYPE_PCEP, session); + } else { + json_object_string_add(json, "warningSession", + "Detailed session information not available."); + } + + /* Message Counters, get a thread safe copy of the counters */ + group = pcep_ctrl_get_counters(pcep_g->fpt, pcc_info->pcc_id); + + if (group != NULL) { + struct counters_subgroup *rx_msgs = + find_subgroup(group, COUNTER_SUBGROUP_ID_RX_MSG); + struct counters_subgroup *tx_msgs = + find_subgroup(group, COUNTER_SUBGROUP_ID_TX_MSG); + json_object *json_counter; + struct counter *tx_counter, *rx_counter; + + if (rx_msgs != NULL) { + json_counter = json_object_new_object(); + for (int i = 0; i < rx_msgs->max_counters; i++) { + rx_counter = rx_msgs->counters[i]; + + if (rx_counter && + rx_counter->counter_name_json[0] != '\0') + json_object_int_add( + json_counter, + rx_counter->counter_name_json, + rx_counter->counter_value); + } + json_object_int_add(json_counter, "total", + subgroup_counters_total(rx_msgs)); + json_object_object_add(json, "messageStatisticsReceived", + json_counter); + } + if (tx_msgs != NULL) { + json_counter = json_object_new_object(); + for (int i = 0; i < tx_msgs->max_counters; i++) { + tx_counter = tx_msgs->counters[i]; + + if (tx_counter && + tx_counter->counter_name_json[0] != '\0') + json_object_int_add( + json_counter, + tx_counter->counter_name_json, + tx_counter->counter_value); + } + json_object_int_add(json_counter, "total", + subgroup_counters_total(tx_msgs)); + json_object_object_add(json, "messageStatisticsSent", + json_counter); + } + pcep_lib_free_counters(group); + } else { + json_object_string_add(json, "messageStatisticsWarning", + "Counters not available."); + } + + XFREE(MTYPE_PCEP, pcc_info); +} + /* Internal util function to print a pcep session */ static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts, struct pcep_pcc_info *pcc_info) { char buf[1024]; + buf[0] = '\0'; vty_out(vty, "\nPCE %s\n", pce_opts->pce_name); @@ -1233,6 +1424,7 @@ static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts, /* Config Options values */ struct pcep_config_group_opts *config_opts = &pce_opts->config_opts; + if (session != NULL) { vty_out(vty, " Timer: KeepAlive config %d, pce-negotiated %d\n", config_opts->keep_alive_seconds, @@ -1348,34 +1540,66 @@ static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts, } static int path_pcep_cli_show_srte_pcep_session(struct vty *vty, - const char *pcc_peer) + const char *pcc_peer, bool uj) { struct pce_opts_cli *pce_opts_cli; struct pcep_pcc_info *pcc_info; + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); /* Only show 1 PCEP session */ if (pcc_peer != NULL) { + if (json) + json_object_string_add(json, "pceName", pcc_peer); pce_opts_cli = pcep_cli_find_pce(pcc_peer); if (pce_opts_cli == NULL) { - vty_out(vty, "%% PCE [%s] does not exist.\n", pcc_peer); + if (json) { + json_object_string_addf(json, "warning", + "PCE [%s] does not exist.", + pcc_peer); + vty_json(vty, json); + } else + vty_out(vty, "%% PCE [%s] does not exist.\n", + pcc_peer); return CMD_WARNING; } if (!pcep_cli_pcc_has_pce(pcc_peer)) { - vty_out(vty, "%% PCC is not connected to PCE [%s].\n", - pcc_peer); + if (json) { + json_object_string_addf(json, "warning", + "PCC is not connected to PCE [%s].", + pcc_peer); + vty_json(vty, json); + } else + vty_out(vty, + "%% PCC is not connected to PCE [%s].\n", + pcc_peer); return CMD_WARNING; } pcc_info = pcep_ctrl_get_pcc_info(pcep_g->fpt, pcc_peer); if (pcc_info == NULL) { - vty_out(vty, - "%% Cannot retrieve PCEP session info for PCE [%s]\n", - pcc_peer); + if (json) { + json_object_string_addf(json, "warning", + "Cannot retrieve PCEP session info for PCE [%s].", + pcc_peer); + vty_json(vty, json); + } else + vty_out(vty, + "%% Cannot retrieve PCEP session info for PCE [%s]\n", + pcc_peer); return CMD_WARNING; } - print_pcep_session(vty, &pce_opts_cli->pce_opts, pcc_info); + if (json) { + print_pcep_session_json(vty, &pce_opts_cli->pce_opts, + pcc_info, json); + vty_json(vty, json); + } else + print_pcep_session(vty, &pce_opts_cli->pce_opts, + pcc_info); return CMD_SUCCESS; } @@ -1384,29 +1608,56 @@ static int path_pcep_cli_show_srte_pcep_session(struct vty *vty, struct pce_opts *pce_opts; int num_pcep_sessions_conf = 0; int num_pcep_sessions_conn = 0; + json_object *json_array = NULL, *json_entry = NULL; + + if (json) + json_array = json_object_new_array(); for (int i = 0; i < MAX_PCC; i++) { pce_opts = pce_connections_g.connections[i]; if (pce_opts == NULL) { continue; } + if (json) { + json_entry = json_object_new_object(); + json_object_string_add(json_entry, "pceName", + pce_opts->pce_name); + } pcc_info = pcep_ctrl_get_pcc_info(pcep_g->fpt, pce_opts->pce_name); if (pcc_info == NULL) { - vty_out(vty, - "%% Cannot retrieve PCEP session info for PCE [%s]\n", - pce_opts->pce_name); + if (json_entry) { + json_object_string_addf(json_entry, "warning", + "Cannot retrieve PCEP session info for PCE [%s].", + pce_opts->pce_name); + json_object_array_add(json_array, json_entry); + } else + vty_out(vty, + "%% Cannot retrieve PCEP session info for PCE [%s]\n", + pce_opts->pce_name); continue; } num_pcep_sessions_conn += pcc_info->status == PCEP_PCC_OPERATING ? 1 : 0; num_pcep_sessions_conf++; - print_pcep_session(vty, pce_opts, pcc_info); - } - - vty_out(vty, "PCEP Sessions => Configured %d ; Connected %d\n", - num_pcep_sessions_conf, num_pcep_sessions_conn); + if (json_entry) { + print_pcep_session_json(vty, pce_opts, pcc_info, + json_entry); + json_object_array_add(json_array, json_entry); + } else + print_pcep_session(vty, pce_opts, pcc_info); + } + if (json) { + json_object_object_add(json, "pcepSessions", json_array); + json_object_int_add(json, "pcepSessionsConfigured", + num_pcep_sessions_conf); + json_object_int_add(json, "pcepSessionsConnected", + num_pcep_sessions_conn); + vty_json(vty, json); + } else + vty_out(vty, "PCEP Sessions => Configured %d ; Connected %d\n", + num_pcep_sessions_conf, num_pcep_sessions_conn); return CMD_SUCCESS; } @@ -1698,7 +1949,7 @@ int pcep_cli_pce_config_write(struct vty *vty) &pce_opts->addr.ipaddr_v4); } if (pce_opts->port != PCEP_DEFAULT_PORT) { - vty_out(vty, " %s %d", PCEP_VTYSH_ARG_PORT, + vty_out(vty, " %s %d", PCEP_VTYSH_ARG_PORT, pce_opts->port); } vty_out(vty, "%s\n", buf); @@ -1784,7 +2035,7 @@ DEFPY(show_debugging_pathd_pcep, DEFPY(pcep_cli_debug, pcep_cli_debug_cmd, - "[no] debug pathd pcep [basic]$basic_str [path]$path_str [message]$message_str [pceplib]$pceplib_str", + "[no] debug pathd pcep [$debug_type]", NO_STR DEBUG_STR "pathd debugging\n" "pcep module debugging\n" @@ -1793,8 +2044,7 @@ DEFPY(pcep_cli_debug, "pcep message debugging\n" "pceplib debugging\n") { - return path_pcep_cli_debug(vty, no, basic_str, path_str, message_str, - pceplib_str); + return path_pcep_cli_debug(vty, debug_type, !no); } DEFPY(pcep_cli_show_srte_pcep_counters, @@ -1818,6 +2068,35 @@ DEFPY_NOSH( return CMD_SUCCESS; } +DEFPY( + pcep_cli_no_pcep, + pcep_cli_no_pcep_cmd, + "no pcep", + NO_STR + "PCEP configuration\n") +{ + /* Delete PCCs */ + path_pcep_cli_pcc_delete(vty); + + for (int i = 0; i < MAX_PCE; i++) { + /* Delete PCEs */ + if (pcep_g->pce_opts_cli[i] != NULL) { + XFREE(MTYPE_PCEP, pcep_g->pce_opts_cli[i]); + pcep_g->pce_opts_cli[i] = NULL; + pcep_g->num_pce_opts_cli--; + } + + /* Delete PCE-CONFIGs */ + if (pcep_g->config_group_opts[i] != NULL) { + XFREE(MTYPE_PCEP, pcep_g->config_group_opts[i]); + pcep_g->config_group_opts[i] = NULL; + pcep_g->num_config_group_opts--; + } + } + + return CMD_SUCCESS; +} + DEFPY_NOSH( pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd, @@ -2011,7 +2290,17 @@ DEFPY(pcep_cli_pcc_pcc_msd, "PCC maximum SID depth \n" "PCC maximum SID depth value\n") { - return path_pcep_cli_pcc_pcc_msd(vty, msd_str, msd); + return path_pcep_cli_pcc_pcc_msd(vty, msd_str, msd, false); +} + +DEFPY(no_pcep_cli_pcc_pcc_msd, + no_pcep_cli_pcc_pcc_msd_cmd, + "no msd [(1-32)]", + NO_STR + "PCC maximum SID depth \n" + "PCC maximum SID depth value\n") +{ + return path_pcep_cli_pcc_pcc_msd(vty, msd_str, msd, true); } DEFPY(pcep_cli_pcc_pcc_peer, @@ -2045,14 +2334,27 @@ DEFPY(pcep_cli_show_srte_pcc, DEFPY(pcep_cli_show_srte_pcep_session, pcep_cli_show_srte_pcep_session_cmd, - "show sr-te pcep session [WORD]$pce", + "show sr-te pcep session WORD$pce [json$uj]", SHOW_STR "SR-TE info\n" "PCEP info\n" "Show PCEP Session information\n" - "PCE name\n") + "PCE name\n" + JSON_STR) +{ + return path_pcep_cli_show_srte_pcep_session(vty, pce, !!uj); +} + +DEFPY(pcep_cli_show_srte_pcep_sessions, + pcep_cli_show_srte_pcep_sessions_cmd, + "show sr-te pcep session [json$uj]", + SHOW_STR + "SR-TE info\n" + "PCEP info\n" + "Show PCEP Session information\n" + JSON_STR) { - return path_pcep_cli_show_srte_pcep_session(vty, pce); + return path_pcep_cli_show_srte_pcep_session(vty, NULL, !!uj); } DEFPY(pcep_cli_clear_srte_pcep_session, @@ -2087,6 +2389,7 @@ void pcep_cli_init(void) install_default(PCEP_NODE); install_element(SR_TRAFFIC_ENG_NODE, &pcep_cli_pcep_cmd); + install_element(SR_TRAFFIC_ENG_NODE, &pcep_cli_no_pcep_cmd); /* PCEP configuration group related configuration commands */ install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd); @@ -2115,6 +2418,7 @@ void pcep_cli_init(void) install_element(PCEP_NODE, &pcep_cli_no_pcc_cmd); install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_peer_cmd); install_element(PCEP_PCC_NODE, &pcep_cli_pcc_pcc_msd_cmd); + install_element(PCEP_PCC_NODE, &no_pcep_cli_pcc_pcc_msd_cmd); /* Top commands */ install_element(CONFIG_NODE, &pcep_cli_debug_cmd); @@ -2124,5 +2428,6 @@ void pcep_cli_init(void) install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_config_cmd); install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_pce_cmd); install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_session_cmd); + install_element(ENABLE_NODE, &pcep_cli_show_srte_pcep_sessions_cmd); install_element(ENABLE_NODE, &pcep_cli_clear_srte_pcep_session_cmd); } diff --git a/pathd/path_zebra.c b/pathd/path_zebra.c index 826443f97906..ba03315c82f7 100644 --- a/pathd/path_zebra.c +++ b/pathd/path_zebra.c @@ -29,6 +29,17 @@ static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS); struct zclient *zclient; static struct zclient *zclient_sync; +/* Event to retry synch zapi setup for label-manager */ +static struct event *t_sync_connect; + +enum path_sync_level { + PATH_SYNC_NONE = 0, + PATH_SYNC_CONN, + PATH_SYNC_HELLO, + PATH_SYNC_DONE +}; +static enum path_sync_level path_sync_client_level; + /* Global Variables */ bool g_has_router_id_v4 = false; bool g_has_router_id_v6 = false; @@ -236,26 +247,48 @@ void path_zebra_release_label(mpls_label_t label) zlog_warn("%s: error releasing label range!", __func__); } -static void path_zebra_label_manager_connect(void) +/* + * Initialize and connect the synchronous zclient session for the + * label-manager. This is prepared to retry on error. + */ +static void path_zebra_label_manager_connect(struct event *event) { - /* Connect to label manager. */ - while (zclient_socket_connect(zclient_sync) < 0) { - zlog_warn("%s: error connecting synchronous zclient!", - __func__); - sleep(1); + if (path_sync_client_level == PATH_SYNC_NONE) { + /* Connect to label manager. */ + if (zclient_socket_connect(zclient_sync) < 0) { + zlog_warn("%s: error connecting synchronous zclient!", + __func__); + event_add_timer(master, path_zebra_label_manager_connect, + NULL, 1, &t_sync_connect); + return; + } + set_nonblocking(zclient_sync->sock); + + path_sync_client_level = PATH_SYNC_CONN; } - set_nonblocking(zclient_sync->sock); /* Send hello to notify zebra this is a synchronous client */ - while (zclient_send_hello(zclient_sync) < 0) { - zlog_warn("%s: Error sending hello for synchronous zclient!", - __func__); - sleep(1); + if (path_sync_client_level == PATH_SYNC_CONN) { + if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) { + zlog_warn("%s: Error sending hello for synchronous zclient!", + __func__); + event_add_timer(master, path_zebra_label_manager_connect, + NULL, 1, &t_sync_connect); + return; + } + + path_sync_client_level = PATH_SYNC_HELLO; } - while (lm_label_manager_connect(zclient_sync, 0) != 0) { - zlog_warn("%s: error connecting to label manager!", __func__); - sleep(1); + if (path_sync_client_level == PATH_SYNC_HELLO) { + if (lm_label_manager_connect(zclient_sync, 0) != 0) { + zlog_warn("%s: error connecting to label manager!", + __func__); + event_add_timer(master, path_zebra_label_manager_connect, + NULL, 1, &t_sync_connect); + return; + } + path_sync_client_level = PATH_SYNC_DONE; } } @@ -320,9 +353,6 @@ static zclient_handler *const path_handlers[] = { */ void path_zebra_init(struct event_loop *master) { - struct zclient_options options = zclient_options_default; - options.synchronous = true; - /* Initialize asynchronous zclient. */ zclient = zclient_new(master, &zclient_options_default, path_handlers, array_size(path_handlers)); @@ -330,20 +360,22 @@ void path_zebra_init(struct event_loop *master) zclient->zebra_connected = path_zebra_connected; /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_SRTE; zclient_sync->instance = 1; zclient_sync->privs = &pathd_privs; /* Connect to the LM. */ - path_zebra_label_manager_connect(); + t_sync_connect = NULL; + path_zebra_label_manager_connect(NULL); } void path_zebra_stop(void) { zclient_stop(zclient); zclient_free(zclient); + event_cancel(&t_sync_connect); zclient_stop(zclient_sync); zclient_free(zclient_sync); } diff --git a/pathd/pathd.c b/pathd/pathd.c index 6c13503c7dcc..9bb7dbae84a4 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -148,6 +148,16 @@ void srte_segment_list_del(struct srte_segment_list *segment_list) XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list); } +static void srte_segment_list_terminate(void) +{ + while (!RB_EMPTY(srte_segment_list_head, &srte_segment_lists)) { + struct srte_segment_list *sl = RB_ROOT(srte_segment_list_head, + &srte_segment_lists); + + srte_segment_list_del(sl); + } +} + /** * Search for a segment list by name. * @@ -1281,6 +1291,11 @@ void pathd_shutdown(void) { path_ted_teardown(); srte_clean_zebra(); + + srte_segment_list_terminate(); + + vrf_terminate(); + frr_fini(); } diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c index c4708d3f08fe..6695b537a80c 100644 --- a/pbrd/pbr_main.c +++ b/pbrd/pbr_main.c @@ -71,6 +71,8 @@ static void sigint(void) pbr_vrf_terminate(); + pbr_zebra_destroy(); + frr_fini(); exit(0); @@ -101,26 +103,26 @@ struct frr_signal_t pbr_signals[] = { }, }; -#define PBR_VTY_PORT 2615 - static const struct frr_yang_module_info *const pbrd_yang_modules[] = { &frr_filter_info, &frr_interface_info, &frr_vrf_info, }; -FRR_DAEMON_INFO(pbrd, PBR, .vty_port = PBR_VTY_PORT, - - .proghelp = "Implementation of PBR.", +/* clang-format off */ +FRR_DAEMON_INFO(pbrd, PBR, + .vty_port = PBR_VTY_PORT, + .proghelp = "Implementation of PBR.", - .signals = pbr_signals, - .n_signals = array_size(pbr_signals), + .signals = pbr_signals, + .n_signals = array_size(pbr_signals), - .privs = &pbr_privs, + .privs = &pbr_privs, - .yang_modules = pbrd_yang_modules, - .n_yang_modules = array_size(pbrd_yang_modules), + .yang_modules = pbrd_yang_modules, + .n_yang_modules = array_size(pbrd_yang_modules), ); +/* clang-format on */ int main(int argc, char **argv, char **envp) { @@ -158,8 +160,10 @@ int main(int argc, char **argv, char **envp) access_list_init(); pbr_nht_init(); pbr_map_init(); - if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up, - pbr_ifp_down, pbr_ifp_destroy); + hook_register_prio(if_real, 0, pbr_ifp_create); + hook_register_prio(if_up, 0, pbr_ifp_up); + hook_register_prio(if_down, 0, pbr_ifp_down); + hook_register_prio(if_unreal, 0, pbr_ifp_destroy); pbr_zebra_init(); pbr_vrf_init(); pbr_vty_init(); diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index 4f7882fb2213..ff252f850534 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -534,6 +534,7 @@ void pbr_nht_set_seq_nhg_data(struct pbr_map_sequence *pbrms, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: pbrms->family = AF_INET; + break; case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_BLACKHOLE: break; @@ -649,7 +650,15 @@ static void pbr_nht_release_individual_nexthop(struct pbr_map_sequence *pbrms) void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms) { - pbr_map_delete_nexthops(pbrms); + struct pbr_map *pbrm = pbrms->parent; + + /* The idea here is to send a delete command to zebra only once, + * and set 'valid' and 'installed' to false only when the last + * rule is being deleted. In other words, the pbr common should be + * updated only when the last rule is being updated or deleted. + */ + if (pbrm->seqnumbers->count == 1) + pbr_map_delete_nexthops(pbrms); pbr_nht_release_individual_nexthop(pbrms); } @@ -889,7 +898,7 @@ static void pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc, pbr_nht_individual_nexthop_interface_update(pnhc, pnhi); break; } - /* Intentional fall thru */ + fallthrough; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV6: diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index 9b67492fbc27..a702a57155fb 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -36,7 +36,7 @@ struct pbr_nexthop_cache { struct pbr_nexthop_group_cache *parent; char vrf_name[VRF_NAMSIZ + 1]; - char intf_name[INTERFACE_NAMSIZ + 1]; + char intf_name[IFNAMSIZ + 1]; struct nexthop nexthop; diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c index ef4a4c2c6310..d8adb91fef8b 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -123,4 +123,6 @@ void pbr_vrf_terminate(void) FOR_ALL_INTERFACES (vrf, ifp) pbr_if_del(ifp); } + + vrf_terminate(); } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 582ffac9b24b..64d88847c8a5 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -1667,8 +1667,7 @@ static void vty_json_pbrms(json_object *j, struct vty *vty, json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno); json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno); json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged); - json_object_boolean_add(jpbrm, "installed", - pbr_nht_get_installed(nhg_name)); + json_object_boolean_add(jpbrm, "installed", pbrms->installed); json_object_string_add(jpbrm, "installedReason", pbrms->reason ? rbuf : "Valid"); @@ -1818,7 +1817,7 @@ static void vty_json_pbr_map(json_object *j, struct vty *vty, DEFPY (show_pbr_map, show_pbr_map_cmd, - "show pbr map [NAME$name] [detail$detail|json$json]", + "show pbr map [NAME$name] [detail$detail] [json$json]", SHOW_STR PBR_STR "PBR Map\n" diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index ee17a193f46f..dd15beaff440 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -129,29 +129,6 @@ int pbr_ifp_down(struct interface *ifp) return 0; } -static int interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - - if (!ifp) { - DEBUGD(&pbr_dbg_zebra, "%s: VRF change interface not found", - __func__); - - return 0; - } - - DEBUGD(&pbr_dbg_zebra, "%s: %s VRF change %u -> %u", __func__, - ifp->name, vrf_id, new_vrf_id); - - if_update_to_new_vrf(ifp, new_vrf_id); - - return 0; -} - static int route_notify_owner(ZAPI_CALLBACK_ARGS) { struct prefix p; @@ -201,7 +178,7 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) enum zapi_rule_notify_owner note; struct pbr_map_sequence *pbrms; struct pbr_map_interface *pmi; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; uint64_t installed; if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique, @@ -245,6 +222,8 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) static void zebra_connected(struct zclient *zclient) { DEBUGD(&pbr_dbg_zebra, "%s: Registering for fun and profit", __func__); + + zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, true); zclient_send_reg_requests(zclient, VRF_DEFAULT); } @@ -387,38 +366,30 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi) } } -static int pbr_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) +static void pbr_zebra_nexthop_update(struct vrf *vrf, struct prefix *matched, + struct zapi_route *nhr) { - struct zapi_route nhr; - struct prefix matched; uint32_t i; - if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { - zlog_err("Failure to decode Nexthop update message"); - return 0; - } - if (DEBUG_MODE_CHECK(&pbr_dbg_zebra, DEBUG_MODE_ALL)) { - DEBUGD(&pbr_dbg_zebra, "%s: Received Nexthop update: %pFX against %pFX", - __func__, &matched, &nhr.prefix); + __func__, matched, &nhr->prefix); DEBUGD(&pbr_dbg_zebra, "%s: (Nexthops(%u)", __func__, - nhr.nexthop_num); + nhr->nexthop_num); - for (i = 0; i < nhr.nexthop_num; i++) { + for (i = 0; i < nhr->nexthop_num; i++) { DEBUGD(&pbr_dbg_zebra, "%s: Type: %d: vrf: %d, ifindex: %d gate: %pI4", - __func__, nhr.nexthops[i].type, - nhr.nexthops[i].vrf_id, nhr.nexthops[i].ifindex, - &nhr.nexthops[i].gate.ipv4); + __func__, nhr->nexthops[i].type, + nhr->nexthops[i].vrf_id, nhr->nexthops[i].ifindex, + &nhr->nexthops[i].gate.ipv4); } } - nhr.prefix = matched; - pbr_nht_nexthop_update(&nhr); - return 1; + nhr->prefix = *matched; + pbr_nht_nexthop_update(nhr); } extern struct zebra_privs_t pbr_privs; @@ -426,21 +397,28 @@ extern struct zebra_privs_t pbr_privs; static zclient_handler *const pbr_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = interface_vrf_update, [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, - [ZEBRA_NEXTHOP_UPDATE] = pbr_zebra_nexthop_update, }; void pbr_zebra_init(void) { - struct zclient_options opt = { .receive_notify = true }; - - zclient = zclient_new(master, &opt, pbr_handlers, + zclient = zclient_new(master, &zclient_options_default, pbr_handlers, array_size(pbr_handlers)); zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs); zclient->zebra_connected = zebra_connected; + zclient->nexthop_update = pbr_zebra_nexthop_update; +} + +void pbr_zebra_destroy(void) +{ + if (zclient == NULL) + return; + + zclient_stop(zclient); + zclient_free(zclient); + zclient = NULL; } void pbr_send_rnh(struct nexthop *nhop, bool reg) diff --git a/pbrd/pbr_zebra.h b/pbrd/pbr_zebra.h index ef844ef797ad..5cbb1fd682f7 100644 --- a/pbrd/pbr_zebra.h +++ b/pbrd/pbr_zebra.h @@ -14,6 +14,7 @@ struct pbr_interface { extern struct event_loop *master; extern void pbr_zebra_init(void); +extern void pbr_zebra_destroy(void); extern void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg, afi_t install_afi); diff --git a/pceplib/pcep_session_logic_counters.c b/pceplib/pcep_session_logic_counters.c index 6f6f2a0df465..b12b8ab0e072 100644 --- a/pceplib/pcep_session_logic_counters.c +++ b/pceplib/pcep_session_logic_counters.c @@ -36,30 +36,30 @@ void create_session_counters(pcep_session *session) struct counters_subgroup *rx_msg_subgroup = create_counters_subgroup( "RX Message counters", COUNTER_SUBGROUP_ID_RX_MSG, PCEP_TYPE_MAX + 1); - create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_OPEN, - "Message Open"); + create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_OPEN, "Message Open", + "messageOpen"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_KEEPALIVE, - "Message KeepAlive"); + "Message KeepAlive", "messageKeepalive"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREQ, - "Message PcReq"); + "Message PcReq", "messagePcReq"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREP, - "Message PcRep"); + "Message PcRep", "messagePcRep"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCNOTF, - "Message Notify"); + "Message Notify", "messageNotify"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_ERROR, - "Message Error"); + "Message Error", "messageError"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_CLOSE, - "Message Close"); + "Message Close", "messageClose"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_REPORT, - "Message Report"); + "Message Report", "messageReport"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_UPDATE, - "Message Update"); + "Message Update", "messageUpdate"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_INITIATE, - "Message Initiate"); + "Message Initiate", "messageInitiate"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_START_TLS, - "Message StartTls"); + "Message StartTls", "messageStartTls"); create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_MAX, - "Message Erroneous"); + "Message Erroneous", "messageErroneous"); struct counters_subgroup *tx_msg_subgroup = clone_counters_subgroup(rx_msg_subgroup, "TX Message counters", @@ -74,59 +74,61 @@ void create_session_counters(pcep_session *session) struct counters_subgroup *rx_obj_subgroup = create_counters_subgroup( "RX Object counters", COUNTER_SUBGROUP_ID_RX_OBJ, 100); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_OPEN, - "Object Open"); - create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RP, - "Object RP"); + "Object Open", "objectOpen"); + create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RP, "Object RP", + "objectRP"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOPATH, - "Object Nopath"); - create_subgroup_counter( - rx_obj_subgroup, - ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV4), - "Object Endpoint IPv4"); - create_subgroup_counter( - rx_obj_subgroup, - ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV6), - "Object Endpoint IPv6"); + "Object Nopath", "objectNopath"); + create_subgroup_counter(rx_obj_subgroup, + ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | + PCEP_OBJ_TYPE_ENDPOINT_IPV4), + "Object Endpoint IPv4", "objectEndpointIPv4"); + create_subgroup_counter(rx_obj_subgroup, + ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | + PCEP_OBJ_TYPE_ENDPOINT_IPV6), + "Object Endpoint IPv6", "objectEndpointIPv6"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_BANDWIDTH, - "Object Bandwidth"); + "Object Bandwidth", "objectBandwidth"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_METRIC, - "Object Metric"); + "Object Metric", "objectMetric"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERO, - "Object ERO"); + "Object ERO", "objectERO"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RRO, - "Object RRO"); + "Object RRO", "objectRRO"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSPA, - "Object LSPA"); + "Object LSPA", "objectLSPA"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_IRO, - "Object IRO"); + "Object IRO", "objectIRO"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SVEC, - "Object SVEC"); + "Object SVEC", "objectSVEC"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOTF, - "Object Notify"); + "Object Notify", "objectNotify"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERROR, - "Object Error"); + "Object Error", "objectError"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_CLOSE, - "Object Close"); + "Object Close", "objectClose"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSP, - "Object LSP"); + "Object LSP", "objectLSP"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SRP, - "Object SRP"); + "Object SRP", "objectSRP"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_VENDOR_INFO, - "Object Vendor Info"); + "Object Vendor Info", "objectVendorInfo"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_INTER_LAYER, - "Object Inter-Layer"); + "Object Inter-Layer", "objectInterLayer"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SWITCH_LAYER, - "Object Switch-Layer"); + "Object Switch-Layer", "objectSwitchLayer"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_REQ_ADAP_CAP, - "Object Requested Adap-Cap"); + "Object Requested Adap-Cap", + "objectRequestedAdapCap"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SERVER_IND, - "Object Server-Indication"); + "Object Server-Indication", + "objectServerIndication"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ASSOCIATION, - "Object Association"); + "Object Association", "objectAssociation"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX, - "Object Unknown"); + "Object Unknown", "objectUnknown"); create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX + 1, - "Object Erroneous"); + "Object Erroneous", "objectErroneous"); struct counters_subgroup *tx_obj_subgroup = clone_counters_subgroup(rx_obj_subgroup, "TX Object counters", @@ -139,21 +141,22 @@ void create_session_counters(pcep_session *session) "RX RO Sub-Object counters", COUNTER_SUBGROUP_ID_RX_SUBOBJ, RO_SUBOBJ_UNKNOWN + 2); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV4, - "RO Sub-Object IPv4"); + "RO Sub-Object IPv4", "ROSubObjectIPv4"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV6, - "RO Sub-Object IPv6"); + "RO Sub-Object IPv6", "ROSubObjectIPv6"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_LABEL, - "RO Sub-Object Label"); + "RO Sub-Object Label", "ROSubObjectLabel"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_UNNUM, - "RO Sub-Object Unnum"); + "RO Sub-Object Unnum", "ROSubObjectUnnum"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_ASN, - "RO Sub-Object ASN"); + "RO Sub-Object ASN", "ROSubObjectASN"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_SR, - "RO Sub-Object SR"); + "RO Sub-Object SR", "ROSubObjectSR"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN, - "RO Sub-Object Unknown"); + "RO Sub-Object Unknown", "ROSubObjectUnknown"); create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN + 1, - "RO Sub-Object Erroneous"); + "RO Sub-Object Erroneous", + "ROSubObjectErroneous"); struct counters_subgroup *tx_subobj_subgroup = clone_counters_subgroup( rx_subobj_subgroup, "TX RO Sub-Object counters", @@ -168,28 +171,36 @@ void create_session_counters(pcep_session *session) PCEP_SR_SUBOBJ_NAI_UNKNOWN + 1); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_ABSENT, - "RO Sub-Object SR NAI absent"); + "RO Sub-Object SR NAI absent", + "ROSubObjectSRNAIAbsent"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_IPV4_NODE, - "RO Sub-Object SR NAI IPv4 Node"); + "RO Sub-Object SR NAI IPv4 Node", + "ROSubObjectSRNAIIPv4Node"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_IPV6_NODE, - "RO Sub-Object SR NAI IPv6 Node"); + "RO Sub-Object SR NAI IPv6 Node", + "ROSubObjectSRNAIIPv6Node"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, - "RO Sub-Object SR NAI IPv4 Adj"); + "RO Sub-Object SR NAI IPv4 Adj", + "ROSubObjectSRNAIIPv4Adj"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, - "RO Sub-Object SR NAI IPv6 Adj"); + "RO Sub-Object SR NAI IPv6 Adj", + "ROSubObjectSRNAIIPv6Adj"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, - "RO Sub-Object SR NAI Unnumbered IPv4 Adj"); + "RO Sub-Object SR NAI Unnumbered IPv4 Adj", + "ROSubObjectSRNAIUnnumberedIPv4Adj"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, - "RO Sub-Object SR NAI Link Local IPv6 Adj"); + "RO Sub-Object SR NAI Link Local IPv6 Adj", + "ROSubObjectSRNAILinkLocalIPv6Adj"); create_subgroup_counter(rx_subobj_sr_nai_subgroup, PCEP_SR_SUBOBJ_NAI_UNKNOWN, - "RO Sub-Object SR NAI Unknown"); + "RO Sub-Object SR NAI Unknown", + "ROSubObjectSRNAIUnknown"); struct counters_subgroup *tx_subobj_sr_nai_subgroup = clone_counters_subgroup(rx_subobj_sr_nai_subgroup, @@ -204,56 +215,60 @@ void create_session_counters(pcep_session *session) PCEP_OBJ_TLV_TYPE_UNKNOWN + 1); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR, - "TLV No Path Vector"); + "TLV No Path Vector", "TLVNoPathVector"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_VENDOR_INFO, - "TLV Vendor Info"); + "TLV Vendor Info", "TLVVendorInfo"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY, - "TLV Stateful PCE Capability"); + "TLV Stateful PCE Capability", + "TLVStatefulPCCapability"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME, - "TLV Symbolic Path Name"); + "TLV Symbolic Path Name", "TLVSymbolicPathName"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS, - "TLV IPv4 LSP Identifier"); + "TLV IPv4 LSP Identifier", + "TLVIPv4LSPIdentifier"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS, - "TLV IPv6 LSP Identifier"); + "TLV IPv6 LSP Identifier", + "TLVIPv6LSPIdentifier"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE, - "TLV LSP Error Code"); + "TLV LSP Error Code", "TLVLSPErrorCode"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC, - "TLV RSVP Error Spec"); + "TLV RSVP Error Spec", "TLVRSVPErrorSpec"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION, - "TLV LSP DB Version"); + "TLV LSP DB Version", "TLVLSPDBVersion"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID, - "TLV Speaker Entity ID"); + "TLV Speaker Entity ID", "TLVSpeakerEntityId"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY, - "TLV SR PCE Capability"); + "TLV SR PCE Capability", "TLVSRPCECapability"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE, - "TLV Path Setup Type"); + "TLV Path Setup Type", "TLVPathSetupType"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY, - "TLV Path Setup Type Capability"); + "TLV Path Setup Type Capability", + "TLVPathSetupTypeCapability"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID, - "TLV SR Policy PolId"); + "TLV SR Policy PolId", "TLVSRPolicyPolId"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME, - "TLV SR Policy PolName"); + "TLV SR Policy PolName", "TLVSRPolicyPolName"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID, - "TLV SR Policy CpathId"); + "TLV SR Policy CpathId", "TLVSRPolicyCpathId"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE, - "TLV SR Policy CpathRef"); + "TLV SR Policy CpathRef", "TLVSRPolicyCpathRef"); create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_UNKNOWN, - "TLV Unknown"); + "TLV Unknown", "TLVUnknown"); struct counters_subgroup *tx_tlv_subgroup = clone_counters_subgroup( rx_tlv_subgroup, "TX TLV counters", COUNTER_SUBGROUP_ID_TX_TLV); @@ -265,28 +280,32 @@ void create_session_counters(pcep_session *session) "Events counters", COUNTER_SUBGROUP_ID_EVENT, MAX_COUNTERS); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_PCC_CONNECT, - "PCC connect"); + "PCC connect", "PCCConnect"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_PCE_CONNECT, - "PCE connect"); + "PCE connect", "PCEConnect"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT, - "PCC disconnect"); + "PCC disconnect", "PCCDisconnect"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT, - "PCE disconnect"); + "PCE disconnect", "PCEDisconnect"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE, - "Timer KeepAlive expired"); + "Timer KeepAlive expired", + "timerKeepAliveExpired"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER, - "Timer DeadTimer expired"); + "Timer DeadTimer expired", + "timerDeadTimerExpired"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT, - "Timer OpenKeepWait expired"); + "Timer OpenKeepWait expired", + "timerOpenKeepWaitExpired"); create_subgroup_counter(events_subgroup, PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE, - "Timer OpenKeepAlive expired"); + "Timer OpenKeepAlive expired", + "timerOpenKeepAliveExpired"); /* * Create the parent counters group diff --git a/pceplib/pcep_socket_comm_mock.c b/pceplib/pcep_socket_comm_mock.c index 24755efee940..bda9b1ffdca9 100644 --- a/pceplib/pcep_socket_comm_mock.c +++ b/pceplib/pcep_socket_comm_mock.c @@ -115,7 +115,7 @@ bool initialize_socket_comm_external_infra( return true; } -bool destroy_socket_comm_loop() +bool destroy_socket_comm_loop(void) { mock_socket_metadata.destroy_socket_comm_loop_times_called++; diff --git a/pceplib/pcep_utils_counters.c b/pceplib/pcep_utils_counters.c index badef9351a75..1ab341c69c51 100644 --- a/pceplib/pcep_utils_counters.c +++ b/pceplib/pcep_utils_counters.c @@ -139,7 +139,8 @@ clone_counters_subgroup(struct counters_subgroup *subgroup, if (counter != NULL) { create_subgroup_counter(cloned_subgroup, counter->counter_id, - counter->counter_name); + counter->counter_name, + counter->counter_name_json); } } @@ -180,7 +181,8 @@ bool add_counters_subgroup(struct counters_group *group, } bool create_subgroup_counter(struct counters_subgroup *subgroup, - uint32_t counter_id, const char *counter_name) + uint32_t counter_id, const char *counter_name, + const char *counter_name_json) { if (subgroup == NULL) { pcep_log( @@ -212,7 +214,9 @@ bool create_subgroup_counter(struct counters_subgroup *subgroup, counter->counter_id = counter_id; strlcpy(counter->counter_name, counter_name, sizeof(counter->counter_name)); - + if (counter_name_json) + strlcpy(counter->counter_name_json, counter_name_json, + sizeof(counter->counter_name_json)); subgroup->num_counters++; subgroup->counters[counter->counter_id] = counter; diff --git a/pceplib/pcep_utils_counters.h b/pceplib/pcep_utils_counters.h index 755c94eb0cd4..dfae02fb2ea1 100644 --- a/pceplib/pcep_utils_counters.h +++ b/pceplib/pcep_utils_counters.h @@ -55,18 +55,18 @@ extern "C" { * *events_subgroup = create_counters_subgroup("events counters", 4); * * Use message_id: PCEP_TYPE_OPEN=1 - * create_subgroup_counter(rx_subgroup, 1, "Message Open"); - * create_subgroup_counter(rx_subgroup, 2, "Message KeepAlive"); - * create_subgroup_counter(rx_subgroup, 3, "Message PcReq"); + * create_subgroup_counter(rx_subgroup, 1, "Message Open", "messageOpen"); + * create_subgroup_counter(rx_subgroup, 2, "Message KeepAlive", "messageKeepAlive"); + * create_subgroup_counter(rx_subgroup, 3, "Message PcReq", "messagePcReq"); * - * create_subgroup_counter(tx_subgroup, 1, "Message Open"); - * create_subgroup_counter(tx_subgroup, 2, "Message KeepAlive"); - * create_subgroup_counter(tx_subgroup, 3, "Message PcReq"); + * create_subgroup_counter(tx_subgroup, 1, "Message Open", "messageOpen"); + * create_subgroup_counter(tx_subgroup, 2, "Message KeepAlive", "messageKeepAlive"); + * create_subgroup_counter(tx_subgroup, 3, "Message PcReq", "messagePcReq"); * - * create_subgroup_counter(events_subgroup, 1, "PCC Connect"); - * create_subgroup_counter(events_subgroup, 2, "PCE Connect"); - * create_subgroup_counter(events_subgroup, 3, "PCC Disconnect"); - * create_subgroup_counter(events_subgroup, 4, "PCE Disconnect"); + * create_subgroup_counter(events_subgroup, 1, "PCC Connect", "PCConnect"); + * create_subgroup_counter(events_subgroup, 2, "PCE Connect", "PCEConnect"); + * create_subgroup_counter(events_subgroup, 3, "PCC Disconnect", "PCCDisconnect"); + * create_subgroup_counter(events_subgroup, 4, "PCE Disconnect", "PCEDisconnect"); * * struct counters_group *cntrs_group = create_counters_group("PCEP Counters", * 3); add_counters_subgroup(cntrs_group, rx_subgroup); @@ -81,6 +81,7 @@ extern "C" { struct counter { uint16_t counter_id; char counter_name[MAX_COUNTER_STR_LENGTH]; + char counter_name_json[MAX_COUNTER_STR_LENGTH]; uint32_t counter_value; }; @@ -142,13 +143,15 @@ clone_counters_subgroup(struct counters_subgroup *subgroup, const char *subgroup_name, uint16_t subgroup_id); /* - * Create a counter in a subgroup with the given counter_id and counter_name. + * Create a counter in a subgroup with the given counter_id and counter_name + * and counter_name_json. * The counter_id is 0-based. * Return true on success or false if subgroup is NULL, counter_id >= * MAX_COUNTERS, or if counter_name is NULL. */ bool create_subgroup_counter(struct counters_subgroup *subgroup, - uint32_t counter_id, const char *counter_name); + uint32_t counter_id, const char *counter_name, + const char *couter_name_json); /* * Delete the counters_group and recursively delete all subgroups and their diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c index c4eaeaab2449..e1f524921f2e 100644 --- a/pceplib/test/pcep_msg_messages_test.c +++ b/pceplib/test/pcep_msg_messages_test.c @@ -48,17 +48,17 @@ int pcep_messages_test_suite_teardown(void) return 0; } -void pcep_messages_test_setup() +void pcep_messages_test_setup(void) { versioning = create_default_pcep_versioning(); } -void pcep_messages_test_teardown() +void pcep_messages_test_teardown(void) { destroy_pcep_versioning(versioning); } -void test_pcep_msg_create_open() +void test_pcep_msg_create_open(void) { uint8_t keepalive = 30; uint8_t deadtimer = 60; @@ -96,8 +96,7 @@ void test_pcep_msg_create_open() pcep_msg_free_message(message); } - -void test_pcep_msg_create_request() +void test_pcep_msg_create_request(void) { /* First test with NULL objects */ struct pcep_message *message = @@ -185,13 +184,11 @@ void test_pcep_msg_create_request() pcep_msg_free_message(message); } - -void test_pcep_msg_create_request_svec() +void test_pcep_msg_create_request_svec(void) { } - -void test_pcep_msg_create_reply_nopath() +void test_pcep_msg_create_reply_nopath(void) { struct pcep_object_rp *rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); @@ -219,8 +216,7 @@ void test_pcep_msg_create_reply_nopath() pcep_msg_free_message(message); } - -void test_pcep_msg_create_reply() +void test_pcep_msg_create_reply(void) { /* First test with NULL ero and rp objects */ struct pcep_message *message = pcep_msg_create_reply(NULL, NULL); @@ -268,8 +264,7 @@ void test_pcep_msg_create_reply() pcep_msg_free_message(message); } - -void test_pcep_msg_create_close() +void test_pcep_msg_create_close(void) { uint8_t reason = PCEP_CLOSE_REASON_UNREC_MSG; @@ -301,8 +296,7 @@ void test_pcep_msg_create_close() pcep_msg_free_message(message); } - -void test_pcep_msg_create_error() +void test_pcep_msg_create_error(void) { uint8_t error_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT; uint8_t error_value = PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT; @@ -337,8 +331,7 @@ void test_pcep_msg_create_error() pcep_msg_free_message(message); } - -void test_pcep_msg_create_keepalive() +void test_pcep_msg_create_keepalive(void) { struct pcep_message *message = pcep_msg_create_keepalive(); CU_ASSERT_PTR_NOT_NULL(message); @@ -356,7 +349,7 @@ void test_pcep_msg_create_keepalive() pcep_msg_free_message(message); } -void test_pcep_msg_create_report() +void test_pcep_msg_create_report(void) { double_linked_list *obj_list = dll_initialize(); @@ -387,7 +380,7 @@ void test_pcep_msg_create_report() pcep_msg_free_message(message); } -void test_pcep_msg_create_update() +void test_pcep_msg_create_update(void) { double_linked_list *obj_list = dll_initialize(); double_linked_list *ero_subobj_list = dll_initialize(); @@ -398,10 +391,8 @@ void test_pcep_msg_create_update() /* Should return NULL if obj_list is empty */ message = pcep_msg_create_update(obj_list); CU_ASSERT_PTR_NULL(message); - if (message != NULL) { + if (message != NULL) pcep_msg_free_message(message); - message = NULL; - } struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL); struct pcep_object_lsp *lsp = @@ -417,10 +408,9 @@ void test_pcep_msg_create_update() CU_ASSERT_PTR_NULL(message); dll_append(obj_list, ero); - if (message != NULL) { + if (message != NULL) pcep_msg_free_message(message); - message = NULL; - } + message = pcep_msg_create_update(obj_list); CU_ASSERT_PTR_NOT_NULL(message); pcep_encode_message(message, versioning); @@ -442,7 +432,7 @@ void test_pcep_msg_create_update() pcep_msg_free_message(message); } -void test_pcep_msg_create_initiate() +void test_pcep_msg_create_initiate(void) { double_linked_list *obj_list = dll_initialize(); double_linked_list *ero_subobj_list = dll_initialize(); @@ -450,10 +440,8 @@ void test_pcep_msg_create_initiate() /* Should return NULL if obj_list is empty */ struct pcep_message *message = pcep_msg_create_initiate(NULL); CU_ASSERT_PTR_NULL(message); - if (message != NULL) { + if (message != NULL) pcep_msg_free_message(message); - message = NULL; - } struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL); struct pcep_object_lsp *lsp = @@ -466,10 +454,8 @@ void test_pcep_msg_create_initiate() dll_append(obj_list, srp); message = pcep_msg_create_initiate(obj_list); CU_ASSERT_PTR_NULL(message); - if (message != NULL) { + if (message != NULL) pcep_msg_free_message(message); - message = NULL; - } dll_append(obj_list, lsp); dll_append(obj_list, ero); diff --git a/pceplib/test/pcep_msg_object_error_types_test.c b/pceplib/test/pcep_msg_object_error_types_test.c index 3237fecb1f93..b7198fbe6906 100644 --- a/pceplib/test/pcep_msg_object_error_types_test.c +++ b/pceplib/test/pcep_msg_object_error_types_test.c @@ -44,7 +44,7 @@ void pcep_object_error_types_test_teardown(void) { } -void test_get_error_type_str() +void test_get_error_type_str(void) { const char *error_type_str; int i = 0; @@ -57,7 +57,7 @@ void test_get_error_type_str() CU_ASSERT_PTR_NULL(get_error_type_str(MAX_ERROR_TYPE)); } -void test_get_error_value_str() +void test_get_error_value_str(void) { const char *error_value_str; int i = 0, j = 0; diff --git a/pceplib/test/pcep_msg_objects_test.c b/pceplib/test/pcep_msg_objects_test.c index 1315fe3f34c2..0a1d34d55756 100644 --- a/pceplib/test/pcep_msg_objects_test.c +++ b/pceplib/test/pcep_msg_objects_test.c @@ -49,18 +49,18 @@ int pcep_objects_test_suite_teardown(void) return 0; } -void reset_objects_buffer() +void reset_objects_buffer(void) { memset(object_buf, 0, 2000); } -void pcep_objects_test_setup() +void pcep_objects_test_setup(void) { versioning = create_default_pcep_versioning(); reset_objects_buffer(); } -void pcep_objects_test_teardown() +void pcep_objects_test_teardown(void) { destroy_pcep_versioning(versioning); } @@ -123,7 +123,7 @@ static void verify_pcep_obj_header(uint8_t obj_class, uint8_t obj_type, obj_hdr->encoded_object); } -void test_pcep_obj_create_open() +void test_pcep_obj_create_open(void) { uint8_t deadtimer = 60; uint8_t keepalive = 30; @@ -147,7 +147,7 @@ void test_pcep_obj_create_open() pcep_obj_free_object((struct pcep_object_header *)open); } -void test_pcep_obj_create_open_with_tlvs() +void test_pcep_obj_create_open_with_tlvs(void) { uint8_t deadtimer = 60; uint8_t keepalive = 30; @@ -182,7 +182,7 @@ void test_pcep_obj_create_open_with_tlvs() pcep_obj_free_object((struct pcep_object_header *)open); } -void test_pcep_obj_create_rp() +void test_pcep_obj_create_rp(void) { uint32_t reqid = 15; uint8_t invalid_priority = 100; @@ -213,7 +213,7 @@ void test_pcep_obj_create_rp() pcep_obj_free_object((struct pcep_object_header *)rp); } -void test_pcep_obj_create_nopath() +void test_pcep_obj_create_nopath(void) { uint8_t ni = 8; uint32_t errorcode = 42; @@ -251,7 +251,8 @@ void test_pcep_obj_create_nopath() pcep_obj_free_object((struct pcep_object_header *)nopath); } -void test_pcep_obj_create_association_ipv4() + +void test_pcep_obj_create_association_ipv4(void) { uint16_t all_assoc_groups = 0xffff; @@ -275,7 +276,7 @@ void test_pcep_obj_create_association_ipv4() pcep_obj_free_object((struct pcep_object_header *)assoc); } -void test_pcep_obj_create_association_ipv6() +void test_pcep_obj_create_association_ipv6(void) { uint32_t all_assoc_groups = 0xffff; struct in6_addr src; @@ -305,7 +306,7 @@ void test_pcep_obj_create_association_ipv6() pcep_obj_free_object((struct pcep_object_header *)assoc); } -void test_pcep_obj_create_endpoint_ipv4() +void test_pcep_obj_create_endpoint_ipv4(void) { struct in_addr src_ipv4, dst_ipv4; inet_pton(AF_INET, "192.168.1.2", &src_ipv4); @@ -334,7 +335,7 @@ void test_pcep_obj_create_endpoint_ipv4() pcep_obj_free_object((struct pcep_object_header *)ipv4); } -void test_pcep_obj_create_endpoint_ipv6() +void test_pcep_obj_create_endpoint_ipv6(void) { struct in6_addr src_ipv6, dst_ipv6; inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src_ipv6); @@ -368,7 +369,7 @@ void test_pcep_obj_create_endpoint_ipv6() pcep_obj_free_object((struct pcep_object_header *)ipv6); } -void test_pcep_obj_create_bandwidth() +void test_pcep_obj_create_bandwidth(void) { /* 1.8 => binary 1.11001101 * exponent = 127 => 0111 1111 @@ -389,7 +390,7 @@ void test_pcep_obj_create_bandwidth() pcep_obj_free_object((struct pcep_object_header *)bw); } -void test_pcep_obj_create_metric() +void test_pcep_obj_create_metric(void) { uint8_t type = PCEP_METRIC_BORDER_NODE_COUNT; /* https://en.wikipedia.org/wiki/IEEE_754-1985 @@ -421,7 +422,7 @@ void test_pcep_obj_create_metric() pcep_obj_free_object((struct pcep_object_header *)metric); } -void test_pcep_obj_create_lspa() +void test_pcep_obj_create_lspa(void) { uint32_t exclude_any = 10; uint32_t include_any = 20; @@ -448,7 +449,7 @@ void test_pcep_obj_create_lspa() pcep_obj_free_object((struct pcep_object_header *)lspa); } -void test_pcep_obj_create_svec() +void test_pcep_obj_create_svec(void) { struct pcep_object_svec *svec = pcep_obj_create_svec(true, true, true, NULL); @@ -479,7 +480,7 @@ void test_pcep_obj_create_svec() pcep_obj_free_object((struct pcep_object_header *)svec); } -void test_pcep_obj_create_error() +void test_pcep_obj_create_error(void) { uint8_t error_type = PCEP_ERRT_SESSION_FAILURE; uint8_t error_value = PCEP_ERRV_RECVD_INVALID_OPEN_MSG; @@ -499,7 +500,7 @@ void test_pcep_obj_create_error() pcep_obj_free_object((struct pcep_object_header *)error); } -void test_pcep_obj_create_close() +void test_pcep_obj_create_close(void) { uint8_t reason = PCEP_CLOSE_REASON_DEADTIMER; @@ -517,7 +518,7 @@ void test_pcep_obj_create_close() pcep_obj_free_object((struct pcep_object_header *)close); } -void test_pcep_obj_create_srp() +void test_pcep_obj_create_srp(void) { bool lsp_remove = true; uint32_t srp_id_number = 0x89674523; @@ -538,7 +539,7 @@ void test_pcep_obj_create_srp() pcep_obj_free_object((struct pcep_object_header *)srp); } -void test_pcep_obj_create_lsp() +void test_pcep_obj_create_lsp(void) { uint32_t plsp_id = 0x000fffff; enum pcep_lsp_operational_status status = PCEP_LSP_OPERATIONAL_ACTIVE; @@ -579,7 +580,7 @@ void test_pcep_obj_create_lsp() pcep_obj_free_object((struct pcep_object_header *)lsp); } -void test_pcep_obj_create_vendor_info() +void test_pcep_obj_create_vendor_info(void) { uint32_t enterprise_number = 0x01020304; uint32_t enterprise_specific_info = 0x05060708; @@ -645,19 +646,19 @@ static void test_pcep_obj_create_object_common(ro_func func_to_test, pcep_obj_free_object((struct pcep_object_header *)ero); } -void test_pcep_obj_create_ero() +void test_pcep_obj_create_ero(void) { test_pcep_obj_create_object_common( pcep_obj_create_ero, PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO); } -void test_pcep_obj_create_rro() +void test_pcep_obj_create_rro(void) { test_pcep_obj_create_object_common( pcep_obj_create_rro, PCEP_OBJ_CLASS_RRO, PCEP_OBJ_TYPE_RRO); } -void test_pcep_obj_create_iro() +void test_pcep_obj_create_iro(void) { test_pcep_obj_create_object_common( pcep_obj_create_iro, PCEP_OBJ_CLASS_IRO, PCEP_OBJ_TYPE_IRO); @@ -731,7 +732,7 @@ verify_pcep_obj_ro_sr_header(struct pcep_object_ro *ro, } } -void test_pcep_obj_create_ro_subobj_ipv4() +void test_pcep_obj_create_ro_subobj_ipv4(void) { struct in_addr ro_ipv4; inet_pton(AF_INET, "192.168.1.2", &ro_ipv4); @@ -768,7 +769,7 @@ void test_pcep_obj_create_ro_subobj_ipv4() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_ipv6() +void test_pcep_obj_create_ro_subobj_ipv6(void) { struct in6_addr ro_ipv6; uint8_t prefix_len = 16; @@ -811,7 +812,7 @@ void test_pcep_obj_create_ro_subobj_ipv6() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_unnum() +void test_pcep_obj_create_ro_subobj_unnum(void) { struct in_addr router_id; uint32_t if_id = 123; @@ -836,7 +837,7 @@ void test_pcep_obj_create_ro_subobj_unnum() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_32label() +void test_pcep_obj_create_ro_subobj_32label(void) { uint8_t class_type = 1; uint32_t label = 0xeeffaabb; @@ -856,7 +857,7 @@ void test_pcep_obj_create_ro_subobj_32label() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_asn() +void test_pcep_obj_create_ro_subobj_asn(void) { uint16_t asn = 0x0102; @@ -871,7 +872,7 @@ void test_pcep_obj_create_ro_subobj_asn() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_sr_nonai() +void test_pcep_obj_create_ro_subobj_sr_nonai(void) { uint32_t sid = 0x01020304; @@ -902,7 +903,7 @@ void test_pcep_obj_create_ro_subobj_sr_nonai() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_sr_ipv4_node() +void test_pcep_obj_create_ro_subobj_sr_ipv4_node(void) { uint32_t sid = 0x01020304; struct in_addr ipv4_node_id; @@ -954,7 +955,7 @@ void test_pcep_obj_create_ro_subobj_sr_ipv4_node() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_sr_ipv6_node() +void test_pcep_obj_create_ro_subobj_sr_ipv6_node(void) { uint32_t sid = 0x01020304; struct in6_addr ipv6_node_id; @@ -1007,7 +1008,7 @@ void test_pcep_obj_create_ro_subobj_sr_ipv6_node() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_sr_ipv4_adj() +void test_pcep_obj_create_ro_subobj_sr_ipv4_adj(void) { struct in_addr local_ipv4; struct in_addr remote_ipv4; @@ -1072,7 +1073,7 @@ void test_pcep_obj_create_ro_subobj_sr_ipv4_adj() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_sr_ipv6_adj() +void test_pcep_obj_create_ro_subobj_sr_ipv6_adj(void) { uint32_t sid = 0x01020304; struct in6_addr local_ipv6; @@ -1147,7 +1148,7 @@ void test_pcep_obj_create_ro_subobj_sr_ipv6_adj() pcep_obj_free_object((struct pcep_object_header *)ro); } -void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj() +void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(void) { uint32_t sid = 0x01020304; uint32_t local_node_id = 0x11223344; @@ -1208,7 +1209,7 @@ void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj() /* TODO Test draft07 types */ } -void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj() +void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(void) { uint32_t sid = 0x01020304; uint32_t local_if_id = 0x11002200; diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c index 3ead269a6f6f..fc11205f2dfe 100644 --- a/pceplib/test/pcep_msg_tlvs_test.c +++ b/pceplib/test/pcep_msg_tlvs_test.c @@ -55,23 +55,23 @@ int pcep_tlvs_test_suite_teardown(void) return 0; } -void reset_tlv_buffer() +void reset_tlv_buffer(void) { memset(tlv_buf, 0, 2000); } -void pcep_tlvs_test_setup() +void pcep_tlvs_test_setup(void) { versioning = create_default_pcep_versioning(); reset_tlv_buffer(); } -void pcep_tlvs_test_teardown() +void pcep_tlvs_test_teardown(void) { destroy_pcep_versioning(versioning); } -void test_pcep_tlv_create_stateful_pce_capability() +void test_pcep_tlv_create_stateful_pce_capability(void) { struct pcep_object_tlv_stateful_pce_capability *tlv = pcep_tlv_create_stateful_pce_capability(true, true, true, true, @@ -96,7 +96,7 @@ void test_pcep_tlv_create_stateful_pce_capability() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_speaker_entity_id() +void test_pcep_tlv_create_speaker_entity_id(void) { struct pcep_object_tlv_speaker_entity_identifier *tlv = pcep_tlv_create_speaker_entity_id(NULL); @@ -105,10 +105,8 @@ void test_pcep_tlv_create_speaker_entity_id() double_linked_list *list = dll_initialize(); tlv = pcep_tlv_create_speaker_entity_id(list); CU_ASSERT_PTR_NULL(tlv); - if (tlv != NULL) { + if (tlv != NULL) pceplib_free(PCEPLIB_INFRA, tlv); - tlv = NULL; - } uint32_t *speaker_entity = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); @@ -130,7 +128,7 @@ void test_pcep_tlv_create_speaker_entity_id() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_lsp_db_version() +void test_pcep_tlv_create_lsp_db_version(void) { uint64_t lsp_db_version = 0xf005ba11ba5eba11; struct pcep_object_tlv_lsp_db_version *tlv = @@ -148,7 +146,7 @@ void test_pcep_tlv_create_lsp_db_version() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_path_setup_type() +void test_pcep_tlv_create_path_setup_type(void) { uint8_t pst = 0x89; @@ -166,7 +164,7 @@ void test_pcep_tlv_create_path_setup_type() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_path_setup_type_capability() +void test_pcep_tlv_create_path_setup_type_capability(void) { /* The sub_tlv list is optional */ @@ -179,28 +177,22 @@ void test_pcep_tlv_create_path_setup_type_capability() double_linked_list *pst_list = dll_initialize(); tlv = pcep_tlv_create_path_setup_type_capability(pst_list, NULL); CU_ASSERT_PTR_NULL(tlv); - if (tlv != NULL) { + if (tlv != NULL) pcep_obj_free_tlv(&tlv->header); - tlv = NULL; - } /* Should still return NULL if pst_list is NULL */ double_linked_list *sub_tlv_list = dll_initialize(); tlv = pcep_tlv_create_path_setup_type_capability(NULL, sub_tlv_list); CU_ASSERT_PTR_NULL(tlv); - if (tlv != NULL) { + if (tlv != NULL) pcep_obj_free_tlv(&tlv->header); - tlv = NULL; - } /* Should still return NULL if pst_list is empty */ tlv = pcep_tlv_create_path_setup_type_capability(pst_list, sub_tlv_list); CU_ASSERT_PTR_NULL(tlv); - if (tlv != NULL) { + if (tlv != NULL) pcep_obj_free_tlv(&tlv->header); - tlv = NULL; - } /* Test only populating the pst list */ uint8_t *pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1); @@ -274,7 +266,7 @@ void test_pcep_tlv_create_path_setup_type_capability() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_sr_pce_capability() +void test_pcep_tlv_create_sr_pce_capability(void) { struct pcep_object_tlv_sr_pce_capability *tlv = pcep_tlv_create_sr_pce_capability(true, true, 8); @@ -294,7 +286,7 @@ void test_pcep_tlv_create_sr_pce_capability() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_symbolic_path_name() +void test_pcep_tlv_create_symbolic_path_name(void) { /* char *symbolic_path_name, uint16_t symbolic_path_name_length); */ char path_name[16] = "Some Path Name"; @@ -336,7 +328,7 @@ void test_pcep_tlv_create_symbolic_path_name() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_ipv4_lsp_identifiers() +void test_pcep_tlv_create_ipv4_lsp_identifiers(void) { struct in_addr sender_ip, endpoint_ip; uint16_t lsp_id = 7; @@ -397,7 +389,7 @@ void test_pcep_tlv_create_ipv4_lsp_identifiers() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_ipv6_lsp_identifiers() +void test_pcep_tlv_create_ipv6_lsp_identifiers(void) { struct in6_addr sender_ip, endpoint_ip; uint16_t lsp_id = 3; @@ -444,7 +436,8 @@ void test_pcep_tlv_create_ipv6_lsp_identifiers() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_srpag_pol_id_ipv4() + +void test_pcep_tlv_create_srpag_pol_id_ipv4(void) { uint32_t color = 1; struct in_addr src; @@ -474,7 +467,8 @@ void test_pcep_tlv_create_srpag_pol_id_ipv4() pceplib_free(PCEPLIB_MESSAGES, dec_hdr); pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_srpag_pol_id_ipv6() + +void test_pcep_tlv_create_srpag_pol_id_ipv6(void) { uint32_t color = 1; @@ -504,7 +498,7 @@ void test_pcep_tlv_create_srpag_pol_id_ipv6() pceplib_free(PCEPLIB_MESSAGES, dec_hdr); pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_srpag_pol_name() +void test_pcep_tlv_create_srpag_pol_name(void) { const char *pol_name = "Some Pol Name"; @@ -524,7 +518,7 @@ void test_pcep_tlv_create_srpag_pol_name() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_srpag_cp_id() +void test_pcep_tlv_create_srpag_cp_id(void) { // draft-ietf-spring-segment-routing-policy-06.pdf#2.3 // 10 PCEP, 20 BGP SR Policy, 30 Via Configuration @@ -558,7 +552,7 @@ void test_pcep_tlv_create_srpag_cp_id() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_srpag_cp_pref() +void test_pcep_tlv_create_srpag_cp_pref(void) { uint32_t preference_default = 100; @@ -587,7 +581,8 @@ void test_pcep_tlv_create_srpag_cp_pref() pceplib_free(PCEPLIB_MESSAGES, dec_hdr); pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_lsp_error_code() + +void test_pcep_tlv_create_lsp_error_code(void) { struct pcep_object_tlv_lsp_error_code *tlv = pcep_tlv_create_lsp_error_code( @@ -605,7 +600,7 @@ void test_pcep_tlv_create_lsp_error_code() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_rsvp_ipv4_error_spec() +void test_pcep_tlv_create_rsvp_ipv4_error_spec(void) { struct in_addr error_node_ip; inet_pton(AF_INET, "192.168.1.1", &error_node_ip); @@ -629,7 +624,7 @@ void test_pcep_tlv_create_rsvp_ipv4_error_spec() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_rsvp_ipv6_error_spec() +void test_pcep_tlv_create_rsvp_ipv6_error_spec(void) { struct in6_addr error_node_ip; inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &error_node_ip); @@ -653,7 +648,7 @@ void test_pcep_tlv_create_rsvp_ipv6_error_spec() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_nopath_vector() +void test_pcep_tlv_create_nopath_vector(void) { uint32_t enterprise_number = 0x01020304; uint32_t enterprise_specific_info = 0x05060708; @@ -673,7 +668,7 @@ void test_pcep_tlv_create_nopath_vector() pcep_obj_free_tlv(&tlv->header); } -void test_pcep_tlv_create_arbitrary() +void test_pcep_tlv_create_arbitrary(void) { char data[16] = "Some Data"; uint16_t data_length = 9; diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c index 858650ec8f2d..440cccdadcee 100644 --- a/pceplib/test/pcep_msg_tools_test.c +++ b/pceplib/test/pcep_msg_tools_test.c @@ -199,7 +199,7 @@ static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr) return (obj_hdr->tlv_list->num_entries > 0); } -void test_pcep_msg_read_pcep_initiate() +void test_pcep_msg_read_pcep_initiate(void) { char filename[BASE_TMPFILE_SIZE]; @@ -303,7 +303,7 @@ void test_pcep_msg_read_pcep_initiate() } -void test_pcep_msg_read_pcep_initiate2() +void test_pcep_msg_read_pcep_initiate2(void) { char filename[BASE_TMPFILE_SIZE]; @@ -396,7 +396,7 @@ void test_pcep_msg_read_pcep_initiate2() unlink(filename); } -void test_pcep_msg_read_pcep_open() +void test_pcep_msg_read_pcep_open(void) { char filename[BASE_TMPFILE_SIZE]; @@ -444,7 +444,7 @@ void test_pcep_msg_read_pcep_open() unlink(filename); } -void test_pcep_msg_read_pcep_update() +void test_pcep_msg_read_pcep_update(void) { char filename[BASE_TMPFILE_SIZE]; @@ -530,7 +530,7 @@ void test_pcep_msg_read_pcep_update() unlink(filename); } -void test_pcep_msg_read_pcep_open_initiate() +void test_pcep_msg_read_pcep_open_initiate(void) { char filename[BASE_TMPFILE_SIZE]; @@ -563,7 +563,7 @@ void test_pcep_msg_read_pcep_open_initiate() unlink(filename); } -void test_pcep_msg_read_pcep_open_cisco_pce() +void test_pcep_msg_read_pcep_open_cisco_pce(void) { char filename[BASE_TMPFILE_SIZE]; @@ -630,7 +630,7 @@ void test_pcep_msg_read_pcep_open_cisco_pce() unlink(filename); } -void test_pcep_msg_read_pcep_update_cisco_pce() +void test_pcep_msg_read_pcep_update_cisco_pce(void) { char filename[BASE_TMPFILE_SIZE]; @@ -778,7 +778,7 @@ void test_pcep_msg_read_pcep_update_cisco_pce() unlink(filename); } -void test_pcep_msg_read_pcep_report_cisco_pcc() +void test_pcep_msg_read_pcep_report_cisco_pcc(void) { char filename[BASE_TMPFILE_SIZE]; @@ -943,7 +943,7 @@ void test_pcep_msg_read_pcep_report_cisco_pcc() unlink(filename); } -void test_pcep_msg_read_pcep_initiate_cisco_pcc() +void test_pcep_msg_read_pcep_initiate_cisco_pcc(void) { char filename[BASE_TMPFILE_SIZE]; @@ -1055,7 +1055,7 @@ void test_pcep_msg_read_pcep_initiate_cisco_pcc() unlink(filename); } -void test_validate_message_header() +void test_validate_message_header(void) { uint8_t pcep_message_invalid_version[] = {0x40, 0x01, 0x04, 0x00}; uint8_t pcep_message_invalid_flags[] = {0x22, 0x01, 0x04, 0x00}; @@ -1141,7 +1141,7 @@ struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class, return msg; } -void test_validate_message_objects() +void test_validate_message_objects(void) { /* Valid Open message */ struct pcep_message *msg = @@ -1203,7 +1203,7 @@ void test_validate_message_objects() pcep_msg_free_message(msg); } -void test_validate_message_objects_invalid() +void test_validate_message_objects_invalid(void) { /* unsupported message ID = 0 * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */ diff --git a/pceplib/test/pcep_pcc_api_test.c b/pceplib/test/pcep_pcc_api_test.c index 904308fdfd3a..768325a5a2e7 100644 --- a/pceplib/test/pcep_pcc_api_test.c +++ b/pceplib/test/pcep_pcc_api_test.c @@ -34,13 +34,13 @@ extern const char UNKNOWN_EVENT_STR[]; * Test suite setup and teardown called before AND after the test suite. */ -int pcep_pcc_api_test_suite_setup() +int pcep_pcc_api_test_suite_setup(void) { pceplib_memory_reset(); return 0; } -int pcep_pcc_api_test_suite_teardown() +int pcep_pcc_api_test_suite_teardown(void) { printf("\n"); pceplib_memory_dump(); @@ -51,13 +51,13 @@ int pcep_pcc_api_test_suite_teardown() * Test case setup and teardown called before AND after each test. */ -void pcep_pcc_api_test_setup() +void pcep_pcc_api_test_setup(void) { setup_mock_socket_comm_info(); } -void pcep_pcc_api_test_teardown() +void pcep_pcc_api_test_teardown(void) { teardown_mock_socket_comm_info(); } @@ -66,7 +66,7 @@ void pcep_pcc_api_test_teardown() * Unit test cases */ -void test_initialize_pcc() +void test_initialize_pcc(void) { CU_ASSERT_TRUE(initialize_pcc()); /* Give the PCC time to initialize */ @@ -74,7 +74,7 @@ void test_initialize_pcc() CU_ASSERT_TRUE(destroy_pcc()); } -void test_connect_pce() +void test_connect_pce(void) { pcep_configuration *config = create_default_pcep_configuration(); struct hostent *host_info = gethostbyname("localhost"); @@ -109,7 +109,7 @@ void test_connect_pce() destroy_pcc(); } -void test_connect_pce_ipv6() +void test_connect_pce_ipv6(void) { pcep_configuration *config = create_default_pcep_configuration(); struct in6_addr dest_address; @@ -147,7 +147,7 @@ void test_connect_pce_ipv6() destroy_pcc(); } -void test_connect_pce_with_src_ip() +void test_connect_pce_with_src_ip(void) { pcep_configuration *config = create_default_pcep_configuration(); struct hostent *host_info = gethostbyname("localhost"); @@ -180,7 +180,7 @@ void test_connect_pce_with_src_ip() destroy_pcc(); } -void test_disconnect_pce() +void test_disconnect_pce(void) { pcep_configuration *config = create_default_pcep_configuration(); struct hostent *host_info = gethostbyname("localhost"); @@ -225,7 +225,7 @@ void test_disconnect_pce() } -void test_send_message() +void test_send_message(void) { pcep_configuration *config = create_default_pcep_configuration(); struct hostent *host_info = gethostbyname("localhost"); @@ -249,7 +249,7 @@ void test_send_message() destroy_pcc(); } -void test_event_queue() +void test_event_queue(void) { /* This initializes the event_queue */ CU_ASSERT_TRUE(initialize_pcc()); @@ -278,7 +278,7 @@ void test_event_queue() CU_ASSERT_TRUE(destroy_pcc()); } -void test_get_event_type_str() +void test_get_event_type_str(void) { CU_ASSERT_EQUAL(strcmp(get_event_type_str(MESSAGE_RECEIVED), MESSAGE_RECEIVED_STR), diff --git a/pceplib/test/pcep_utils_counters_test.c b/pceplib/test/pcep_utils_counters_test.c index 2cad9a64438f..7fa2f3ce62fb 100644 --- a/pceplib/test/pcep_utils_counters_test.c +++ b/pceplib/test/pcep_utils_counters_test.c @@ -22,7 +22,7 @@ #include "pcep_utils_counters_test.h" -void test_create_counters_group() +void test_create_counters_group(void) { const char group_name[] = "group"; uint16_t num_subgroups = 10; @@ -45,7 +45,7 @@ void test_create_counters_group() delete_counters_group(group); } -void test_create_counters_subgroup() +void test_create_counters_subgroup(void) { const char subgroup_name[] = "subgroup"; uint16_t subgroup_id = 10; @@ -77,7 +77,7 @@ void test_create_counters_subgroup() delete_counters_subgroup(subgroup); } -void test_add_counters_subgroup() +void test_add_counters_subgroup(void) { struct counters_group *group = create_counters_group("group", 1); struct counters_subgroup *subgroup1 = @@ -102,27 +102,29 @@ void test_add_counters_subgroup() delete_counters_subgroup(subgroup2); } -void test_create_subgroup_counter() +void test_create_subgroup_counter(void) { uint16_t counter_id = 1; char counter_name[] = "my counter"; + char counter_name_json[] = "myCounter"; struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", 1, 2); - CU_ASSERT_FALSE( - create_subgroup_counter(NULL, counter_id, counter_name)); + CU_ASSERT_FALSE(create_subgroup_counter(NULL, counter_id, counter_name, + counter_name_json)); CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id + 1, - counter_name)); - CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id, NULL)); + counter_name, counter_name_json)); + CU_ASSERT_FALSE( + create_subgroup_counter(subgroup, counter_id, NULL, NULL)); CU_ASSERT_EQUAL(subgroup->num_counters, 0); - CU_ASSERT_TRUE( - create_subgroup_counter(subgroup, counter_id, counter_name)); + CU_ASSERT_TRUE(create_subgroup_counter(subgroup, counter_id, + counter_name, counter_name_json)); CU_ASSERT_EQUAL(subgroup->num_counters, 1); delete_counters_subgroup(subgroup); } -void test_delete_counters_group() +void test_delete_counters_group(void) { struct counters_group *group = create_counters_group("group", 1); @@ -130,7 +132,7 @@ void test_delete_counters_group() CU_ASSERT_TRUE(delete_counters_group(group)); } -void test_delete_counters_subgroup() +void test_delete_counters_subgroup(void) { struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", 1, 1); @@ -139,14 +141,14 @@ void test_delete_counters_subgroup() CU_ASSERT_TRUE(delete_counters_subgroup(subgroup)); } -void test_reset_group_counters() +void test_reset_group_counters(void) { uint16_t subgroup_id = 1; uint16_t counter_id = 1; struct counters_group *group = create_counters_group("group", 10); struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", subgroup_id, 10); - create_subgroup_counter(subgroup, counter_id, "counter"); + create_subgroup_counter(subgroup, counter_id, "counter", "counter"); add_counters_subgroup(group, subgroup); struct counter *counter = subgroup->counters[counter_id]; @@ -159,12 +161,12 @@ void test_reset_group_counters() delete_counters_group(group); } -void test_reset_subgroup_counters() +void test_reset_subgroup_counters(void) { uint16_t counter_id = 1; struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", 1, 10); - create_subgroup_counter(subgroup, counter_id, "counter"); + create_subgroup_counter(subgroup, counter_id, "counter", "counter"); struct counter *counter = subgroup->counters[counter_id]; counter->counter_value = 100; @@ -176,14 +178,14 @@ void test_reset_subgroup_counters() delete_counters_subgroup(subgroup); } -void test_increment_counter() +void test_increment_counter(void) { uint16_t subgroup_id = 1; uint16_t counter_id = 1; struct counters_group *group = create_counters_group("group", 10); struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", subgroup_id, 10); - create_subgroup_counter(subgroup, counter_id, "counter"); + create_subgroup_counter(subgroup, counter_id, "counter", "counter"); add_counters_subgroup(group, subgroup); struct counter *counter = subgroup->counters[counter_id]; @@ -199,13 +201,13 @@ void test_increment_counter() delete_counters_group(group); } -void test_increment_subgroup_counter() +void test_increment_subgroup_counter(void) { int counter_id = 1; uint32_t counter_value = 100; struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", 1, 10); - create_subgroup_counter(subgroup, counter_id, "counter"); + create_subgroup_counter(subgroup, counter_id, "counter", "counter"); struct counter *counter = subgroup->counters[counter_id]; counter->counter_value = counter_value; @@ -218,14 +220,14 @@ void test_increment_subgroup_counter() delete_counters_subgroup(subgroup); } -void test_dump_counters_group_to_log() +void test_dump_counters_group_to_log(void) { uint16_t subgroup_id = 1; uint16_t counter_id = 1; struct counters_group *group = create_counters_group("group", 10); struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", subgroup_id, 10); - create_subgroup_counter(subgroup, counter_id, "counter"); + create_subgroup_counter(subgroup, counter_id, "counter", "counter"); add_counters_subgroup(group, subgroup); CU_ASSERT_FALSE(dump_counters_group_to_log(NULL)); @@ -234,13 +236,13 @@ void test_dump_counters_group_to_log() delete_counters_group(group); } -void test_dump_counters_subgroup_to_log() +void test_dump_counters_subgroup_to_log(void) { uint16_t subgroup_id = 1; uint16_t counter_id = 1; struct counters_subgroup *subgroup = create_counters_subgroup("subgroup", subgroup_id, 10); - create_subgroup_counter(subgroup, counter_id, "counter"); + create_subgroup_counter(subgroup, counter_id, "counter", "counter"); CU_ASSERT_FALSE(dump_counters_subgroup_to_log(NULL)); CU_ASSERT_TRUE(dump_counters_subgroup_to_log(subgroup)); diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index 262ce86c291e..f7a4e0e48112 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -41,45 +41,207 @@ static struct cmd_node debug_node = { .config_write = pim_debug_config_write, }; -DEFPY (ipv6_pim_joinprune_time, - ipv6_pim_joinprune_time_cmd, - "ipv6 pim join-prune-interval (1-65535)$jpi", - IPV6_STR - PIM_STR +DEFPY_NOSH (router_pim6, + router_pim6_cmd, + "router pim6 [vrf NAME]", + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM6_NODE, xpath); + + return CMD_SUCCESS; +} + +DEFPY (no_router_pim6, + no_router_pim6_cmd, + "no router pim6 [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (pim6_joinprune_time, + pim6_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ipv6_joinprune_time, + ipv6_pim_joinprune_time_cmd, + "ipv6 pim join-prune-interval (1-65535)$jpi", + IPV6_STR PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } -DEFPY (no_ipv6_pim_joinprune_time, - no_ipv6_pim_joinprune_time_cmd, - "no ipv6 pim join-prune-interval [(1-65535)]", + return ret; +} + +DEFPY (no_pim6_joinprune_time, + no_pim6_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_joinprune_time, + no_ipv6_pim_joinprune_time_cmd, + "no ipv6 pim join-prune-interval [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_spt_switchover_infinity, - ipv6_pim_spt_switchover_infinity_cmd, - "ipv6 pim spt-switchover infinity-and-beyond", - IPV6_STR - PIM_STR +DEFPY (pim6_spt_switchover_infinity, + pim6_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ipv6_spt_switchover_infinity, + ipv6_pim_spt_switchover_infinity_cmd, + "ipv6 pim spt-switchover infinity-and-beyond", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_spt_switchover_infinity_plist, - ipv6_pim_spt_switchover_infinity_plist_cmd, - "ipv6 pim spt-switchover infinity-and-beyond prefix-list WORD$plist", - IPV6_STR - PIM_STR + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_spt_switchover_infinity_plist, + pim6_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -87,25 +249,104 @@ DEFPY (ipv6_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ipv6_spt_switchover_infinity_plist, + ipv6_pim_spt_switchover_infinity_plist_cmd, + "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity, - no_ipv6_pim_spt_switchover_infinity_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond", +DEFPY (no_pim6_spt_switchover_infinity, + no_pim6_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity, + no_ipv6_pim_spt_switchover_infinity_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, - no_ipv6_pim_spt_switchover_infinity_plist_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond prefix-list WORD", +DEFPY (no_pim6_spt_switchover_infinity_plist, + no_pim6_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -113,100 +354,453 @@ DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity_plist, + no_ipv6_pim_spt_switchover_infinity_plist_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_packets, - ipv6_pim_packets_cmd, - "ipv6 pim packets (1-255)", - IPV6_STR - PIM_STR + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_packets, + pim6_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ipv6_pim_packets, + ipv6_pim_packets_cmd, + "ipv6 pim packets (1-255)", + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_packets, - no_ipv6_pim_packets_cmd, - "no ipv6 pim packets [(1-255)]", +DEFPY (no_pim6_packets, + no_pim6_packets_cmd, + "no packets [(1-255)]", NO_STR - IPV6_STR - PIM_STR "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_packets, + no_ipv6_pim_packets_cmd, + "no ipv6 pim packets [(1-255)]", + NO_STR + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_keep_alive, - ipv6_pim_keep_alive_cmd, - "ipv6 pim keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_keep_alive, + pim6_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_keep_alive, + ipv6_pim_keep_alive_cmd, + "ipv6 pim keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); -DEFPY (no_ipv6_pim_keep_alive, - no_ipv6_pim_keep_alive_cmd, - "no ipv6 pim keep-alive-timer [(1-65535)]", + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim6_keep_alive, + no_pim6_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_keep_alive, + no_ipv6_pim_keep_alive_cmd, + "no ipv6 pim keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_rp_keep_alive, - ipv6_pim_rp_keep_alive_cmd, - "ipv6 pim rp keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_rp_keep_alive, + pim6_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_rp_keep_alive, + ipv6_pim_rp_keep_alive_cmd, + "ipv6 pim rp keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_keep_alive, - no_ipv6_pim_rp_keep_alive_cmd, - "no ipv6 pim rp keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_rp_keep_alive, + no_pim6_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_rp_keep_alive, + no_ipv6_pim_rp_keep_alive_cmd, + "no ipv6 pim rp keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_register_suppress, - ipv6_pim_register_suppress_cmd, - "ipv6 pim register-suppress-time (1-65535)$rst", - IPV6_STR - PIM_STR +DEFPY (pim6_register_suppress, + pim6_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ipv6_pim_register_suppress, + ipv6_pim_register_suppress_cmd, + "ipv6 pim register-suppress-time (1-65535)$rst", + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } -DEFPY (no_ipv6_pim_register_suppress, - no_ipv6_pim_register_suppress_cmd, - "no ipv6 pim register-suppress-time [(1-65535)]", + return ret; +} + +DEFPY (no_pim6_register_suppress, + no_pim6_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_register_suppress, + no_ipv6_pim_register_suppress_cmd, + "no ipv6 pim register-suppress-time [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (interface_ipv6_pim, interface_ipv6_pim_cmd, @@ -244,7 +838,7 @@ DEFPY (interface_no_ipv6_pim, DEFPY (interface_ipv6_pim_drprio, interface_ipv6_pim_drprio_cmd, - "ipv6 pim drpriority (1-4294967295)", + "ipv6 pim drpriority (0-4294967295)", IPV6_STR PIM_STR "Set the Designated Router Election Priority\n" @@ -255,7 +849,7 @@ DEFPY (interface_ipv6_pim_drprio, DEFPY (interface_no_ipv6_pim_drprio, interface_no_ipv6_pim_drprio_cmd, - "no ipv6 pim drpriority [(1-4294967295)]", + "no ipv6 pim drpriority [(0-4294967295)]", NO_STR IPV6_STR PIM_STR @@ -405,11 +999,9 @@ DEFPY (interface_no_ipv6_mroute, source_str); } -DEFPY (ipv6_pim_rp, - ipv6_pim_rp_cmd, - "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", - IPV6_STR - PIM_STR +DEFPY (pim6_rp, + pim6_rp_cmd, + "rp X:X::X:X$rp [X:X::X:X/M]$gp", "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -418,13 +1010,53 @@ DEFPY (ipv6_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ipv6_pim_rp, + ipv6_pim_rp_cmd, + "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp, - no_ipv6_pim_rp_cmd, - "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", +DEFPY (no_pim6_rp, + no_pim6_rp_cmd, + "no rp X:X::X:X$rp [X:X::X:X/M]$gp", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -433,12 +1065,53 @@ DEFPY (no_ipv6_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ipv6_pim_rp, + no_ipv6_pim_rp_cmd, + "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_rp_prefix_list, - ipv6_pim_rp_prefix_list_cmd, - "ipv6 pim rp X:X::X:X$rp prefix-list WORD$plist", - IPV6_STR - PIM_STR + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_rp_prefix_list, + pim6_rp_prefix_list_cmd, + "rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -446,13 +1119,53 @@ DEFPY (ipv6_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ipv6_pim_rp_prefix_list, + ipv6_pim_rp_prefix_list_cmd, + "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_prefix_list, - no_ipv6_pim_rp_prefix_list_cmd, - "no ipv6 pim rp X:X::X:X$rp prefix-list WORD$plist", +DEFPY (no_pim6_rp_prefix_list, + no_pim6_rp_prefix_list_cmd, + "no rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -460,6 +1173,49 @@ DEFPY (no_ipv6_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ipv6_pim_rp_prefix_list, + no_ipv6_pim_rp_prefix_list_cmd, + "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ipv6_pim_bsm, ipv6_pim_bsm_cmd, @@ -503,10 +1259,9 @@ DEFPY (no_ipv6_pim_ucast_bsm, return pim_process_no_unicast_bsm_cmd(vty); } -DEFPY (ipv6_ssmpingd, - ipv6_ssmpingd_cmd, - "ipv6 ssmpingd [X:X::X:X]$source", - IPV6_STR +DEFPY (pim6_ssmpingd, + pim6_ssmpingd_cmd, + "ssmpingd [X:X::X:X]$source", CONF_SSMPINGD_STR "Source address\n") { @@ -514,61 +1269,151 @@ DEFPY (ipv6_ssmpingd, return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); } +DEFPY_ATTR(ipv6_ssmpingd, + ipv6_ssmpingd_cmd, + "ipv6 ssmpingd [X:X::X:X]$source", + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); -DEFPY (no_ipv6_ssmpingd, - no_ipv6_ssmpingd_cmd, - "no ipv6 ssmpingd [X:X::X:X]$source", - NO_STR - IPV6_STR - CONF_SSMPINGD_STR - "Source address\n") + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim6_ssmpingd, + no_pim6_ssmpingd_cmd, + "no ssmpingd [X:X::X:X]$source", + NO_STR + CONF_SSMPINGD_STR + "Source address\n") { const char *src_str = (source_str) ? source_str : "::"; return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); } - -DEFPY (interface_ipv6_mld_join, - interface_ipv6_mld_join_cmd, - "ipv6 mld join X:X::X:X$group [X:X::X:X$source]", - IPV6_STR - IFACE_MLD_STR - "MLD join multicast group\n" - "Multicast group address\n" - "Source address\n") +DEFPY_ATTR(no_ipv6_ssmpingd, + no_ipv6_ssmpingd_cmd, + "no ipv6 ssmpingd [X:X::X:X]$source", + NO_STR + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; char xpath[XPATH_MAXLEN]; - - if (!IN6_IS_ADDR_MULTICAST(&group)) { - vty_out(vty, "Invalid Multicast Address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (source_str) { - if (IPV6_ADDR_SAME(&source, &in6addr_any)) { - vty_out(vty, "Bad source address %s\n", source_str); + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { return CMD_WARNING_CONFIG_FAILED; } - } else - source_str = "::"; + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } - snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6", - group_str, source_str); + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return nb_cli_apply_changes(vty, NULL); + return ret; } -DEFPY (interface_no_ipv6_mld_join, - interface_no_ipv6_mld_join_cmd, - "no ipv6 mld join X:X::X:X$group [X:X::X:X$source]", +DEFPY_YANG_HIDDEN (interface_ipv6_mld_join, + interface_ipv6_mld_join_cmd, + "[no] ipv6 mld join X:X::X:X$grp [X:X::X:X]$src", + NO_STR + IPV6_STR + IFACE_MLD_STR + "MLD join multicast group\n" + "Multicast group address\n" + "Source address\n") +{ + nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY), + NULL); + return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH, + "frr-routing:ipv6", grp_str, + (src_str ? src_str : "::")); +} +ALIAS (interface_ipv6_mld_join, + interface_ipv6_mld_join_group_cmd, + "[no] ipv6 mld join-group X:X::X:X$grp [X:X::X:X]$src", NO_STR IPV6_STR IFACE_MLD_STR "MLD join multicast group\n" "Multicast group address\n" + "Source address\n"); + +DEFPY_YANG (interface_ipv6_mld_static_group, + interface_ipv6_mld_static_group_cmd, + "[no] ipv6 mld static-group X:X::X:X$grp [X:X::X:X]$src", + NO_STR + IPV6_STR + IFACE_MLD_STR + "Static multicast group\n" + "Multicast group address\n" + "Source address\n") +{ + nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY), + NULL); + return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH, + "frr-routing:ipv6", grp_str, + (src_str ? src_str : "::")); +} + +DEFPY (interface_no_ipv6_mld_static_group, + interface_no_ipv6_mld_static_group_cmd, + "no ipv6 mld static-group X:X::X:X$group [X:X::X:X$source]", + NO_STR + IPV6_STR + IFACE_MLD_STR + "Static multicast group\n" + "Multicast group address\n" "Source address\n") { char xpath[XPATH_MAXLEN]; @@ -581,8 +1426,8 @@ DEFPY (interface_no_ipv6_mld_join, } else source_str = "::"; - snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6", - group_str, source_str); + snprintf(xpath, sizeof(xpath), FRR_GMP_STATIC_GROUP_XPATH, + "frr-routing:ipv6", group_str, source_str); nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -1733,12 +2578,16 @@ DEFPY (debug_pimv6_bsm, return CMD_SUCCESS; } -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); - - install_node(&debug_node); +struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", + .config_write = pim_router_config_write, +}; +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd); @@ -1753,6 +2602,60 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &ipv6_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + pim_install_deprecated(); + + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(CONFIG_NODE, &no_router_pim6_cmd); + + install_node(&pim6_node); + install_default(PIM6_NODE); + + install_element(PIM6_NODE, &pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &no_pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &pim6_packets_cmd); + install_element(PIM6_NODE, &no_pim6_packets_cmd); + install_element(PIM6_NODE, &pim6_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_register_suppress_cmd); + install_element(PIM6_NODE, &no_pim6_register_suppress_cmd); + install_element(PIM6_NODE, &pim6_rp_cmd); + install_element(PIM6_NODE, &no_pim6_rp_cmd); + install_element(PIM6_NODE, &pim6_rp_prefix_list_cmd); + install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd); + install_element(PIM6_NODE, &pim6_ssmpingd_cmd); + install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); @@ -1764,10 +2667,8 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); - install_element(INTERFACE_NODE, - &interface_ipv6_pim_boundary_oil_cmd); - install_element(INTERFACE_NODE, - &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); /* Install BSM command */ @@ -1775,31 +2676,17 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd); install_element(INTERFACE_NODE, &ipv6_pim_ucast_bsm_cmd); install_element(INTERFACE_NODE, &no_ipv6_pim_ucast_bsm_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &ipv6_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mld_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_join_cmd); - install_element(INTERFACE_NODE, &interface_no_ipv6_mld_join_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mld_join_group_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mld_static_group_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_version_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_version_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_query_interval_cmd); - install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_query_max_response_time_cmd); install_element(INTERFACE_NODE, diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index 1af4a17e5bd5..24443404eb5e 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -26,6 +26,7 @@ #include "pim_nb.h" #include "pim6_cmd.h" #include "pim6_mld.h" +#include "pim_zlookup.h" zebra_capabilities_t _caps_p[] = { ZCAP_SYS_ADMIN, @@ -93,6 +94,7 @@ struct frr_signal_t pim6d_signals[] = { }, }; +/* clang-format off */ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -104,7 +106,6 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pim6d, PIM6, .vty_port = PIM6D_VTY_PORT, .proghelp = "Protocol Independent Multicast (RFC7761) for IPv6", @@ -189,11 +190,20 @@ int main(int argc, char **argv, char **envp) static void pim6_terminate(void) { + struct zclient *zclient; + pim_vrf_terminate(); pim_router_terminate(); prefix_list_reset(); access_list_reset(); + zclient = pim_zebra_zclient_get(); + if (zclient) { + zclient_stop(zclient); + zclient_free(zclient); + } + + zclient_lookup_free(); frr_fini(); } diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index 20ef9216a9c9..a39d182990bf 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -13,6 +13,7 @@ */ #include +#include #include #include "lib/memory.h" diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index 94c63bbccc78..c1416e1dd0f6 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -14,16 +14,19 @@ #if PIM_IPV == 4 typedef struct in_addr pim_addr; +typedef struct prefix_ipv4 prefix_pim; #define PIM_ADDRSTRLEN INET_ADDRSTRLEN #define PIM_AF AF_INET #define PIM_AFI AFI_IP #define PIM_PROTO_REG IPPROTO_RAW +#define PIM_IANA_AFI IANA_AFI_IPV4 #define PIM_IPADDR IPADDR_V4 #define ipaddr_pim ipaddr_v4 #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" #define PIM_AF_DBG "pim" +#define PIM_AF_ROUTER "pim" #define GM_AF_DBG "igmp" #define PIM_MROUTE_DBG "mroute" #define PIMREG "pimreg" @@ -33,27 +36,30 @@ typedef struct in_addr pim_addr; #define PIM_ADDR_FUNCNAME(name) ipv4_##name union pimprefixptr { - prefixtype(pimprefixptr, struct prefix, p) - prefixtype(pimprefixptr, struct prefix_ipv4, p4) + uniontype(pimprefixptr, struct prefix, p) + uniontype(pimprefixptr, struct prefix_ipv4, p4) } TRANSPARENT_UNION; union pimprefixconstptr { - prefixtype(pimprefixconstptr, const struct prefix, p) - prefixtype(pimprefixconstptr, const struct prefix_ipv4, p4) + uniontype(pimprefixconstptr, const struct prefix, p) + uniontype(pimprefixconstptr, const struct prefix_ipv4, p4) } TRANSPARENT_UNION; #else typedef struct in6_addr pim_addr; +typedef struct prefix_ipv6 prefix_pim; #define PIM_ADDRSTRLEN INET6_ADDRSTRLEN #define PIM_AF AF_INET6 #define PIM_AFI AFI_IP6 #define PIM_PROTO_REG IPPROTO_PIM +#define PIM_IANA_AFI IANA_AFI_IPV6 #define PIM_IPADDR IPADDR_V6 #define ipaddr_pim ipaddr_v6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" #define PIM_AF_DBG "pimv6" +#define PIM_AF_ROUTER "pim6" #define GM_AF_DBG "mld" #define PIM_MROUTE_DBG "mroute6" #define PIMREG "pim6reg" @@ -63,13 +69,13 @@ typedef struct in6_addr pim_addr; #define PIM_ADDR_FUNCNAME(name) ipv6_##name union pimprefixptr { - prefixtype(pimprefixptr, struct prefix, p) - prefixtype(pimprefixptr, struct prefix_ipv6, p6) + uniontype(pimprefixptr, struct prefix, p) + uniontype(pimprefixptr, struct prefix_ipv6, p6) } TRANSPARENT_UNION; union pimprefixconstptr { - prefixtype(pimprefixconstptr, const struct prefix, p) - prefixtype(pimprefixconstptr, const struct prefix_ipv6, p6) + uniontype(pimprefixconstptr, const struct prefix, p) + uniontype(pimprefixconstptr, const struct prefix_ipv6, p6) } TRANSPARENT_UNION; #endif diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index df9161943d37..2d451718a983 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -1451,3 +1451,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return 0; } + +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc) +{ + /* stub for Candidate-RP */ +} diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 2e90cf905337..633c46966ead 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -78,7 +78,7 @@ static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], if (!vrf) { if (uj) - vty_json_empty(vty); + vty_json_empty(vty, NULL); else vty_out(vty, "Specified VRF: %s does not exist\n", argv[*idx]->arg); @@ -682,6 +682,91 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty, vty_json(vty, json); } +static void igmp_show_interface_static_group(struct pim_instance *pim, + struct vty *vty, bool uj) +{ + struct interface *ifp; + json_object *json = NULL; + json_object *json_iface = NULL; + json_object *json_grp = NULL; + json_object *json_grp_arr = NULL; + + if (uj) { + json = json_object_new_object(); + json_object_string_add(json, "vrf", + vrf_id_to_name(pim->vrf->vrf_id)); + } else { + vty_out(vty, + "Interface Address Source Group\n"); + } + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp; + struct listnode *node; + struct static_group *stgrp; + struct in_addr pri_addr; + char pri_addr_str[INET_ADDRSTRLEN]; + + pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (!pim_ifp->static_group_list) + continue; + + pri_addr = pim_find_primary_addr(ifp); + pim_inet4_dump("", pri_addr, pri_addr_str, + sizeof(pri_addr_str)); + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node, + stgrp)) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("", stgrp->group_addr, group_str, + sizeof(group_str)); + pim_inet4_dump("", stgrp->source_addr, source_str, + sizeof(source_str)); + + if (uj) { + json_object_object_get_ex(json, ifp->name, + &json_iface); + + if (!json_iface) { + json_iface = json_object_new_object(); + json_object_string_add(json_iface, + "name", + ifp->name); + json_object_object_add(json, ifp->name, + json_iface); + json_grp_arr = json_object_new_array(); + json_object_object_add(json_iface, + "groups", + json_grp_arr); + } + + json_grp = json_object_new_object(); + json_object_string_add(json_grp, "source", + source_str); + json_object_string_add(json_grp, "group", + group_str); + json_object_string_add(json_grp, "primaryAddr", + pri_addr_str); + json_object_array_add(json_grp_arr, json_grp); + } else { + vty_out(vty, "%-16s %-15s %-15s %-15s\n", + ifp->name, pri_addr_str, source_str, + group_str); + } + } /* for (pim_ifp->static_group_list) */ + + } /* for (iflist) */ + + if (uj) + vty_json(vty, json); +} + static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, const char *ifname, bool uj) { @@ -1457,19 +1542,13 @@ static void clear_interfaces(struct pim_instance *pim) static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, const char *gname) { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; const struct lyd_node *member_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); /* Group must exists, otherwise just quit. */ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return; @@ -1477,8 +1556,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* Group members check: */ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value)); strlcat(xpath_member_value, "/members", sizeof(xpath_member_value)); - if (yang_dnode_exists(vty->candidate_config->dnode, - xpath_member_value)) { + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value)) { member_dnode = yang_dnode_get(vty->candidate_config->dnode, xpath_member_value); if (!member_dnode || !yang_is_last_list_dnode(member_dnode)) @@ -1731,6 +1809,15 @@ DEFUN (show_ip_igmp_join, return CMD_SUCCESS; } +ALIAS (show_ip_igmp_join, + show_ip_igmp_join_group_cmd, + "show ip igmp [vrf NAME] join-group [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP static join information\n" + JSON_STR); DEFUN (show_ip_igmp_join_vrf_all, show_ip_igmp_join_vrf_all_cmd, @@ -1763,6 +1850,69 @@ DEFUN (show_ip_igmp_join_vrf_all, return CMD_SUCCESS; } +ALIAS (show_ip_igmp_join_vrf_all, + show_ip_igmp_join_group_vrf_all_cmd, + "show ip igmp vrf all join-group [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP static join information\n" + JSON_STR); + +DEFUN (show_ip_igmp_static_group, + show_ip_igmp_static_group_cmd, + "show ip igmp [vrf NAME] static-group [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "Static group information\n" + JSON_STR) +{ + int idx = 2; + bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); + + if (!vrf) + return CMD_WARNING; + + igmp_show_interface_static_group(vrf->info, vty, uj); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_static_group_vrf_all, + show_ip_igmp_static_group_vrf_all_cmd, + "show ip igmp vrf all static-group [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "Static group information\n" + JSON_STR) +{ + bool uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + igmp_show_interface_static_group(vrf->info, vty, uj); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_SUCCESS; +} DEFPY(show_ip_igmp_groups, show_ip_igmp_groups_cmd, @@ -1941,12 +2091,15 @@ DEFUN (show_ip_pim_mlag_summary, json_object *json_stat = NULL; json = json_object_new_object(); - if (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP) - json_object_boolean_true_add(json, "mlagConnUp"); - if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP) - json_object_boolean_true_add(json, "mlagPeerConnUp"); - if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP) - json_object_boolean_true_add(json, "mlagPeerZebraUp"); + json_object_boolean_add(json, "mlagConnUp", + CHECK_FLAG(router->mlag_flags, + PIM_MLAGF_LOCAL_CONN_UP)); + json_object_boolean_add(json, "mlagPeerConnUp", + CHECK_FLAG(router->mlag_flags, + PIM_MLAGF_PEER_CONN_UP)); + json_object_boolean_add(json, "mlagPeerZebraUp", + CHECK_FLAG(router->mlag_flags, + PIM_MLAGF_PEER_ZEBRA_UP)); json_object_string_add(json, "mlagRole", mlag_role2str(router->mlag_role, role_buf, sizeof(role_buf))); @@ -2827,6 +2980,40 @@ DEFPY (clear_ip_mroute_count, return clear_ip_mroute_count_command(vty, name); } +DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd, + "clear ip msdp peer A.B.C.D$peer [vrf WORD$vrfname]", + CLEAR_STR + IP_STR + MSDP_STR + "Restart MSDP peer\n" + "MSDP peer address\n" + VRF_CMD_HELP_STR) +{ + const struct pim_instance *pim; + const struct listnode *node; + const struct vrf *vrf; + struct pim_msdp_peer *mp; + + if (vrfname) + vrf = vrf_lookup_by_name(vrfname); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (vrf == NULL || vrf->info == NULL) + return CMD_WARNING; + + pim = vrf->info; + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) { + if (mp->peer.s_addr != peer.s_addr) + continue; + + pim_msdp_peer_restart(mp); + break; + } + + return CMD_SUCCESS; +} + DEFPY (show_ip_mroute_count, show_ip_mroute_count_cmd, "show ip mroute [vrf NAME] count [json$json]", @@ -2986,22 +3173,108 @@ DEFUN (show_ip_ssmpingd, return CMD_SUCCESS; } -DEFUN (ip_pim_spt_switchover_infinity, - ip_pim_spt_switchover_infinity_cmd, - "ip pim spt-switchover infinity-and-beyond", - IP_STR - PIM_STR +DEFPY_NOSH (router_pim, + router_pim_cmd, + "router pim [vrf NAME]", + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM_NODE, xpath); + return CMD_SUCCESS; +} + +DEFPY (no_router_pim, + no_router_pim_cmd, + "no router pim [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + + +DEFPY (pim_spt_switchover_infinity, + pim_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity, + ip_pim_spt_switchover_infinity_cmd, + "ip pim spt-switchover infinity-and-beyond", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_spt_switchover_infinity_plist, - ip_pim_spt_switchover_infinity_plist_cmd, - "ip pim spt-switchover infinity-and-beyond prefix-list WORD$plist", - IP_STR - PIM_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_spt_switchover_infinity_plist, + pim_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3009,25 +3282,104 @@ DEFPY (ip_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity_plist, + ip_pim_spt_switchover_infinity_plist_cmd, + "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity, - no_ip_pim_spt_switchover_infinity_cmd, - "no ip pim spt-switchover infinity-and-beyond", +DEFPY (no_pim_spt_switchover_infinity, + no_pim_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity, + no_ip_pim_spt_switchover_infinity_cmd, + "no ip pim spt-switchover infinity-and-beyond", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity_plist, - no_ip_pim_spt_switchover_infinity_plist_cmd, - "no ip pim spt-switchover infinity-and-beyond prefix-list WORD", +DEFPY (no_pim_spt_switchover_infinity_plist, + no_pim_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3035,28 +3387,61 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity_plist, + no_ip_pim_spt_switchover_infinity_plist_cmd, + "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (pim_register_accept_list, pim_register_accept_list_cmd, - "[no] ip pim register-accept-list WORD$word", + "[no] register-accept-list PREFIXLIST4_NAME$word", NO_STR - IP_STR - PIM_STR "Only accept registers from a specific source prefix list\n" "Prefix-List name\n") { - const char *vrfname; char reg_alist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(reg_alist_xpath, "/register-accept-list", - sizeof(reg_alist_xpath)); + "./register-accept-list"); if (no) nb_cli_enqueue_change(vty, reg_alist_xpath, @@ -3067,123 +3452,560 @@ DEFPY (pim_register_accept_list, return nb_cli_apply_changes(vty, NULL); } - -DEFPY (ip_pim_joinprune_time, - ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (1-65535)$jpi", - IP_STR - "pim multicast routing\n" - "Join Prune Send Interval\n" - "Seconds\n") +DEFPY_ATTR(ip_pim_register_accept_list, + ip_pim_register_accept_list_cmd, + "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + NO_STR + IP_STR + PIM_STR + "Only accept registers from a specific source prefix list\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - return pim_process_join_prune_cmd(vty, jpi_str); + char reg_alist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), + "./register-accept-list"); + + if (no) + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_MODIFY, word); + + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_joinprune_time, - no_ip_pim_joinprune_time_cmd, - "no ip pim join-prune-interval [(1-65535)]", +DEFPY (pim_joinprune_time, + pim_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", + "Join Prune Send Interval\n" + "Seconds\n") +{ + return pim_process_join_prune_cmd(vty, jpi_str); +} +DEFPY_ATTR(ip_pim_joinprune_time, + ip_pim_joinprune_time_cmd, + "ip pim join-prune-interval (1-65535)$jpi", + IP_STR + PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_joinprune_time, + no_pim_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ip_pim_joinprune_time, + no_ip_pim_joinprune_time_cmd, + "no ip pim join-prune-interval [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_register_suppress, - ip_pim_register_suppress_cmd, - "ip pim register-suppress-time (1-65535)$rst", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_register_suppress, + pim_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ip_pim_register_suppress, + ip_pim_register_suppress_cmd, + "ip pim register-suppress-time (1-65535)$rst", + IP_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_register_suppress, - no_ip_pim_register_suppress_cmd, - "no ip pim register-suppress-time [(1-65535)]", +DEFPY (no_pim_register_suppress, + no_pim_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ip_pim_register_suppress, + no_ip_pim_register_suppress_cmd, + "no ip pim register-suppress-time [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_rp_keep_alive, - ip_pim_rp_keep_alive_cmd, - "ip pim rp keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_rp_keep_alive, + pim_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ip_pim_rp_keep_alive, + ip_pim_rp_keep_alive_cmd, + "ip pim rp keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (no_ip_pim_rp_keep_alive, - no_ip_pim_rp_keep_alive_cmd, - "no ip pim rp keep-alive-timer [(1-65535)]", + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_rp_keep_alive, + no_pim_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ip_pim_rp_keep_alive, + no_ip_pim_rp_keep_alive_cmd, + "no ip pim rp keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_keep_alive, - ip_pim_keep_alive_cmd, - "ip pim keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_keep_alive, + pim_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } +DEFPY_ATTR(ip_pim_keep_alive, + ip_pim_keep_alive_cmd, + "ip pim keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (no_ip_pim_keep_alive, - no_ip_pim_keep_alive_cmd, - "no ip pim keep-alive-timer [(1-65535)]", + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_keep_alive, + no_pim_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ip_pim_keep_alive, + no_ip_pim_keep_alive_cmd, + "no ip pim keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_packets, - ip_pim_packets_cmd, - "ip pim packets (1-255)", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_packets, + pim_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ip_pim_packets, + ip_pim_packets_cmd, + "ip pim packets (1-255)", + IP_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_packets, - no_ip_pim_packets_cmd, - "no ip pim packets [(1-255)]", +DEFPY (no_pim_packets, + no_pim_packets_cmd, + "no packets [(1-255)]", NO_STR - IP_STR - "pim multicast routing\n" "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ip_pim_packets, + no_ip_pim_packets_cmd, + "no ip pim packets [(1-255)]", + NO_STR + IP_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ip_igmp_group_watermark, ip_igmp_group_watermark_cmd, @@ -3214,64 +4036,131 @@ DEFPY (no_ip_igmp_group_watermark, return CMD_SUCCESS; } -DEFUN (ip_pim_v6_secondary, - ip_pim_v6_secondary_cmd, - "ip pim send-v6-secondary", - IP_STR - "pim multicast routing\n" +DEFPY (pim_v6_secondary, + pim_v6_secondary_cmd, + "send-v6-secondary", "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_v6_secondary, + ip_pim_v6_secondary_cmd, + "ip pim send-v6-secondary", + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_v6_secondary, - no_ip_pim_v6_secondary_cmd, - "no ip pim send-v6-secondary", +DEFPY (no_pim_v6_secondary, + no_pim_v6_secondary_cmd, + "no send-v6-secondary", NO_STR - IP_STR - "pim multicast routing\n" "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_v6_secondary, + no_ip_pim_v6_secondary_cmd, + "no ip pim send-v6-secondary", + NO_STR + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY (ip_pim_rp, - ip_pim_rp_cmd, - "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_rp, + pim_rp_cmd, + "rp A.B.C.D$rp [A.B.C.D/M]$gp", "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3280,12 +4169,52 @@ DEFPY (ip_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ip_pim_rp, + ip_pim_rp_cmd, + "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_rp_prefix_list, - ip_pim_rp_prefix_list_cmd, - "ip pim rp A.B.C.D$rp prefix-list WORD$plist", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_rp_prefix_list, + pim_rp_prefix_list_cmd, + "rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3293,13 +4222,53 @@ DEFPY (ip_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ip_pim_rp_prefix_list, + ip_pim_rp_prefix_list_cmd, + "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ip_pim_rp, - no_ip_pim_rp_cmd, - "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", +DEFPY (no_pim_rp, + no_pim_rp_cmd, + "no rp A.B.C.D$rp [A.B.C.D/M]$gp", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3308,13 +4277,54 @@ DEFPY (no_ip_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ip_pim_rp, + no_ip_pim_rp_cmd, + "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ip_pim_rp_prefix_list, - no_ip_pim_rp_prefix_list_cmd, - "no ip pim rp A.B.C.D$rp prefix-list WORD$plist", +DEFPY (no_pim_rp_prefix_list, + no_pim_rp_prefix_list_cmd, + "no rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3322,103 +4332,263 @@ DEFPY (no_ip_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ip_pim_rp_prefix_list, + no_ip_pim_rp_prefix_list_cmd, + "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (ip_pim_ssm_prefix_list, - ip_pim_ssm_prefix_list_cmd, - "ip pim ssm prefix-list WORD", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ssm_prefix_list, + pim_ssm_prefix_list_cmd, + "ssm prefix-list PREFIXLIST4_NAME$plist", "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ssm_prefix_list, + ip_pim_ssm_prefix_list_cmd, + "ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return nb_cli_apply_changes(vty, NULL); + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list, - no_ip_pim_ssm_prefix_list_cmd, - "no ip pim ssm prefix-list", +DEFPY (no_pim_ssm_prefix_list, + no_pim_ssm_prefix_list_cmd, + "no ssm prefix-list", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ssm_prefix_list, + no_ip_pim_ssm_prefix_list_cmd, + "no ip pim ssm prefix-list", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); - + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list_name, - no_ip_pim_ssm_prefix_list_name_cmd, - "no ip pim ssm prefix-list WORD", +DEFPY (no_pim_ssm_prefix_list_name, + no_pim_ssm_prefix_list_name_cmd, + "no ssm prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; const struct lyd_node *ssm_plist_dnode; - char ssm_plist_xpath[XPATH_MAXLEN]; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; + const char *ssm_plist_name; + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); + ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, + ssm_plist_xpath); + + if (!ssm_plist_dnode) { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + return CMD_WARNING_CONFIG_FAILED; + } + + ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); + + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); + } + + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + + return CMD_WARNING_CONFIG_FAILED; +} +DEFPY_ATTR(no_ip_pim_ssm_prefix_list_name, + no_ip_pim_ssm_prefix_list_name_cmd, + "no ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const struct lyd_node *ssm_plist_dnode; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; const char *ssm_plist_name; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, ssm_plist_xpath); - - if (!ssm_plist_dnode) { - vty_out(vty, - "%% pim ssm prefix-list %s doesn't exist\n", - argv[5]->arg); - return CMD_WARNING_CONFIG_FAILED; + if (ssm_plist_dnode) { + ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", + plist); + } + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); } - ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); - - if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) { - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, - NULL); - - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; } - vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg); - - return CMD_WARNING_CONFIG_FAILED; + return ret; } DEFUN (show_ip_pim_ssm_range, @@ -3508,135 +4678,354 @@ DEFPY (show_ip_pim_bsr, return pim_show_bsr_helper(vrf, vty, !!json); } -DEFUN (ip_ssmpingd, - ip_ssmpingd_cmd, - "ip ssmpingd [A.B.C.D]", - IP_STR +DEFPY (pim_ssmpingd, + pim_ssmpingd_cmd, + "ssmpingd [A.B.C.D]$src", CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 2; - const char *src_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); +} +DEFPY_ATTR(ip_pim_ssmpingd, + ip_ssmpingd_cmd, + "ip ssmpingd [A.B.C.D]$src", + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_ssmpingd, - no_ip_ssmpingd_cmd, - "no ip ssmpingd [A.B.C.D]", +DEFPY (no_pim_ssmpingd, + no_pim_ssmpingd_cmd, + "no ssmpingd [A.B.C.D]$src", NO_STR - IP_STR CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 3; - const char *src_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); +} +DEFPY_ATTR(no_ip_pim_ssmpingd, + no_ip_ssmpingd_cmd, + "no ip ssmpingd [A.B.C.D]$src", + NO_STR + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + return ret; } -DEFUN (ip_pim_ecmp, - ip_pim_ecmp_cmd, - "ip pim ecmp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp, + pim_ecmp_cmd, + "ecmp", "Enable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp, + ip_pim_ecmp_cmd, + "ip pim ecmp", + IP_STR + PIM_STR + "Enable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp, - no_ip_pim_ecmp_cmd, - "no ip pim ecmp", +DEFPY (no_pim_ecmp, + no_pim_ecmp_cmd, + "no ecmp", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp, + no_ip_pim_ecmp_cmd, + "no ip pim ecmp", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (ip_pim_ecmp_rebalance, - ip_pim_ecmp_rebalance_cmd, - "ip pim ecmp rebalance", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp_rebalance, + pim_ecmp_rebalance_cmd, + "ecmp rebalance", "Enable PIM ECMP \n" "Enable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp_rebalance, + ip_pim_ecmp_rebalance_cmd, + "ip pim ecmp rebalance", + IP_STR + PIM_STR + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp_rebalance, - no_ip_pim_ecmp_rebalance_cmd, - "no ip pim ecmp rebalance", +DEFPY (no_pim_ecmp_rebalance, + no_pim_ecmp_rebalance_cmd, + "no ecmp rebalance", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n" "Disable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp_rebalance, + no_ip_pim_ecmp_rebalance_cmd, + "no ip pim ecmp rebalance", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } DEFUN (interface_ip_igmp, @@ -3692,71 +5081,47 @@ DEFUN (interface_no_ip_igmp, "frr-routing:ipv4"); } -DEFUN (interface_ip_igmp_join, - interface_ip_igmp_join_cmd, - "ip igmp join A.B.C.D [A.B.C.D]", - IP_STR - IFACE_IGMP_STR - "IGMP join multicast group\n" - "Multicast group address\n" - "Source address\n") +DEFPY_YANG_HIDDEN (interface_ip_igmp_join, + interface_ip_igmp_join_cmd, + "[no] ip igmp join A.B.C.D$grp [A.B.C.D]$src", + NO_STR + IP_STR + IFACE_IGMP_STR + "IGMP join multicast group\n" + "Multicast group address\n" + "Source address\n") { - int idx_group = 3; - int idx_source = 4; - const char *source_str; - char xpath[XPATH_MAXLEN]; - - if (argc == 5) { - source_str = argv[idx_source]->arg; - - if (strcmp(source_str, "0.0.0.0") == 0) { - vty_out(vty, "Bad source address %s\n", - argv[idx_source]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - } else - source_str = "0.0.0.0"; - - snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, - "frr-routing:ipv4", argv[idx_group]->arg, source_str); - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - - return nb_cli_apply_changes(vty, NULL); + nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY), + NULL); + return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH, + "frr-routing:ipv4", grp_str, + (src_str ? src_str : "0.0.0.0")); } - -DEFUN (interface_no_ip_igmp_join, - interface_no_ip_igmp_join_cmd, - "no ip igmp join A.B.C.D [A.B.C.D]", - NO_STR - IP_STR - IFACE_IGMP_STR - "IGMP join multicast group\n" - "Multicast group address\n" - "Source address\n") -{ - int idx_group = 4; - int idx_source = 5; - const char *source_str; - char xpath[XPATH_MAXLEN]; - - if (argc == 6) { - source_str = argv[idx_source]->arg; - - if (strcmp(source_str, "0.0.0.0") == 0) { - vty_out(vty, "Bad source address %s\n", - argv[idx_source]->arg); - return CMD_WARNING_CONFIG_FAILED; - } - } else - source_str = "0.0.0.0"; - - snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, - "frr-routing:ipv4", argv[idx_group]->arg, source_str); - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); +ALIAS(interface_ip_igmp_join, + interface_ip_igmp_join_group_cmd, + "[no] ip igmp join-group A.B.C.D$grp [A.B.C.D]$src", + NO_STR + IP_STR + IFACE_IGMP_STR + "IGMP join multicast group\n" + "Multicast group address\n" + "Source address\n"); + +DEFPY_YANG (interface_ip_igmp_static_group, + interface_ip_igmp_static_group_cmd, + "[no] ip igmp static-group A.B.C.D$grp [A.B.C.D]$src", + NO_STR + IP_STR + IFACE_IGMP_STR + "Static multicast group\n" + "Multicast group address\n" + "Source address\n") +{ + nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY), + NULL); + return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH, + "frr-routing:ipv4", grp_str, + (src_str ? src_str : "0.0.0.0")); } DEFUN (interface_ip_igmp_query_interval, @@ -3953,7 +5318,7 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval, DEFUN (interface_ip_pim_drprio, interface_ip_pim_drprio_cmd, - "ip pim drpriority (1-4294967295)", + "ip pim drpriority (0-4294967295)", IP_STR PIM_STR "Set the Designated Router Election Priority\n" @@ -3966,7 +5331,7 @@ DEFUN (interface_ip_pim_drprio, DEFUN (interface_no_ip_pim_drprio, interface_no_ip_pim_drprio_cmd, - "no ip pim drpriority [(1-4294967295)]", + "no ip pim drpriority [(0-4294967295)]", NO_STR IP_STR PIM_STR @@ -4645,15 +6010,24 @@ DEFPY (debug_pim_zebra, return CMD_SUCCESS; } -DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", - DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(debug_pim_mlag, + debug_pim_mlag_cmd, + "debug pim mlag", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DO_DEBUG_MLAG; return CMD_SUCCESS; } -DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", - NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(no_debug_pim_mlag, + no_debug_pim_mlag_cmd, + "no debug pim mlag", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DONT_DEBUG_MLAG; return CMD_SUCCESS; @@ -5013,145 +6387,447 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ -DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, - "ip msdp peer A.B.C.D$peer source A.B.C.D$source", - IP_STR +DEFPY(pim_msdp_peer, pim_msdp_peer_cmd, + "msdp peer A.B.C.D$peer source A.B.C.D$source", CFG_MSDP_STR "Configure MSDP peer\n" "Peer IP address\n" "Source address for TCP connection\n" "Local IP address\n") { - const char *vrfname; - char temp_xpath[XPATH_MAXLEN]; char msdp_peer_source_xpath[XPATH_MAXLEN]; + snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, + source_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_peer, + ip_msdp_peer_cmd, + "ip msdp peer A.B.C.D$peer source A.B.C.D$source", + IP_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "Peer IP address\n" + "Source address for TCP connection\n" + "Local IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_source_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']/source-ip", peer_str); - strlcat(msdp_peer_source_xpath, temp_xpath, - sizeof(msdp_peer_source_xpath)); - + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, source_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, - "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", - IP_STR +DEFPY(msdp_peer_md5, msdp_peer_md5_cmd, + "msdp peer A.B.C.D$peer password WORD$psk", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, "MD5"); + nb_cli_enqueue_change(vty, "./authentication-key", NB_OP_MODIFY, psk); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(no_msdp_peer_md5, no_msdp_peer_md5_cmd, + "no msdp peer A.B.C.D$peer password [WORD]", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, + "None"); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(pim_msdp_timers, pim_msdp_timers_cmd, + "msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", CFG_MSDP_STR "MSDP timers configuration\n" "Keep alive period (in seconds)\n" "Hold time period (in seconds)\n" "Connection retry period (in seconds)\n") { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); + if (connretry_str) + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); + else + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(ip_pim_msdp_timers, + ip_msdp_timers_cmd, + "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + "Keep alive period (in seconds)\n" + "Hold time period (in seconds)\n" + "Connection retry period (in seconds)\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_MODIFY, holdtime_str); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_MODIFY, keepalive_str); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); if (connretry_str) - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_MODIFY, - connretry_str); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); else - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, - NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); - return CMD_SUCCESS; + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd, - "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", +DEFPY(no_pim_msdp_timers, no_pim_msdp_timers_cmd, + "no msdp timers [(1-65535) (1-65535) [(1-65535)]]", NO_STR - IP_STR CFG_MSDP_STR "MSDP timers configuration\n" IGNORED_IN_NO_STR IGNORED_IN_NO_STR IGNORED_IN_NO_STR) { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(no_ip_pim_msdp_timers, + no_ip_msdp_timers_cmd, + "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", + NO_STR + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return CMD_SUCCESS; + return ret; } -DEFUN (no_ip_msdp_peer, - no_ip_msdp_peer_cmd, - "no ip msdp peer A.B.C.D", +DEFPY (no_pim_msdp_peer, + no_pim_msdp_peer_cmd, + "no msdp peer A.B.C.D", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP peer\n" "peer ip address\n") { - const char *vrfname; char msdp_peer_xpath[XPATH_MAXLEN]; - char temp_xpath[XPATH_MAXLEN]; + + snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_peer, + no_ip_msdp_peer_cmd, + "no ip msdp peer A.B.C.D", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP peer\n" + "peer ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']", - argv[4]->arg); + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath)); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + return ret; +} - return nb_cli_apply_changes(vty, NULL); +DEFPY(msdp_peer_sa_filter, msdp_peer_sa_filter_cmd, + "msdp peer A.B.C.D$peer sa-filter ACL_NAME$acl_name $dir", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_MODIFY, + acl_name); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_MODIFY, + acl_name); + + return nb_cli_apply_changes(vty, "%s", xpath); } -DEFPY(ip_msdp_mesh_group_member, - ip_msdp_mesh_group_member_cmd, - "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", - IP_STR +DEFPY(no_msdp_peer_sa_filter, no_ip_msdp_peer_sa_filter_cmd, + "no msdp peer A.B.C.D$peer sa-filter ACL_NAME $dir", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(pim_msdp_mesh_group_member, + pim_msdp_mesh_group_member_cmd, + "msdp mesh-group WORD$gname member A.B.C.D$maddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group member. */ + strlcat(xpath_value, "/members[address='", sizeof(xpath_value)); + strlcat(xpath_value, maddr_str, sizeof(xpath_value)); + strlcat(xpath_value, "']", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_member, + ip_msdp_mesh_group_member_cmd, + "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group member. */ @@ -5159,33 +6835,32 @@ DEFPY(ip_msdp_mesh_group_member, strlcat(xpath_value, maddr_str, sizeof(xpath_value)); strlcat(xpath_value, "']", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_member, - no_ip_msdp_mesh_group_member_cmd, - "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", +DEFPY(no_pim_msdp_mesh_group_member, + no_pim_msdp_mesh_group_member_cmd, + "no msdp mesh-group WORD$gname member A.B.C.D$maddr", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group member\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { vty_out(vty, "%% mesh-group does not exist\n"); @@ -5214,59 +6889,221 @@ DEFPY(no_ip_msdp_mesh_group_member, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_member, + no_ip_msdp_mesh_group_member_cmd, + "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group member\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN + 26]; + char xpath_member_value[XPATH_MAXLEN]; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY(ip_msdp_mesh_group_source, - ip_msdp_mesh_group_source_cmd, - "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", - IP_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + /* Remove mesh group member. */ + strlcpy(xpath_member_value, xpath_value, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "/members[address='", + sizeof(xpath_member_value)); + strlcat(xpath_member_value, maddr_str, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "']", sizeof(xpath_member_value)); + if (yang_dnode_exists(vty->candidate_config->dnode, + xpath_member_value)) { + nb_cli_enqueue_change(vty, xpath_member_value, + NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% mesh-group member does not exist\n"); + } + } else { + vty_out(vty, "%% mesh-group does not exist\n"); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY(pim_msdp_mesh_group_source, + pim_msdp_mesh_group_source_cmd, + "msdp mesh-group WORD$gname source A.B.C.D$saddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group local address\n" "Source IP address for the TCP connection\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_source, + ip_msdp_mesh_group_source_cmd, + "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group local address\n" + "Source IP address for the TCP connection\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); - /* Create mesh group source. */ strlcat(xpath_value, "/source", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_source, - no_ip_msdp_mesh_group_source_cmd, - "no ip msdp mesh-group WORD$gname source [A.B.C.D]", +DEFPY(no_pim_msdp_mesh_group_source, + no_pim_msdp_mesh_group_source_cmd, + "no msdp mesh-group WORD$gname source [A.B.C.D]", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group source\n" "Mesh group name\n" "Mesh group source\n" "Mesh group local address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_source, + no_ip_msdp_mesh_group_source_cmd, + "no ip msdp mesh-group WORD$gname source [A.B.C.D]", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group source\n" + "Mesh group name\n" + "Mesh group source\n" + "Mesh group local address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group source. */ @@ -5278,36 +7115,83 @@ DEFPY(no_ip_msdp_mesh_group_source, * to not break legacy CLI behaviour. */ pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group, - no_ip_msdp_mesh_group_cmd, - "no ip msdp mesh-group WORD$gname", +DEFPY(no_pim_msdp_mesh_group, + no_pim_msdp_mesh_group_cmd, + "no msdp mesh-group WORD$gname", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group\n" "Mesh group name\n") { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + char xpath_value[XPATH_MAXLEN + 26]; /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return CMD_SUCCESS; nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group, + no_ip_msdp_mesh_group_cmd, + "no ip msdp mesh-group WORD$gname", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group\n" + "Mesh group name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN + 26]; + int ret = CMD_SUCCESS; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) @@ -5326,7 +7210,8 @@ static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, if (json) { /* currently there is only one mesh group but we should still * make - * it a dict with mg-name as key */ + * it a dict with mg-name as key + */ json_mg_row = json_object_new_object(); json_object_string_add(json_mg_row, "name", mg->mesh_group_name); @@ -6308,119 +8193,224 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work, return CMD_SUCCESS; } -DEFUN_HIDDEN (no_ip_pim_mlag, - no_ip_pim_mlag_cmd, - "no ip pim mlag", +DEFPY_HIDDEN (no_pim_mlag, + no_pim_mlag_cmd, + "no mlag", NO_STR - IP_STR - PIM_STR "MLAG\n") { char mlag_xpath[XPATH_MAXLEN]; - snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); + nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_mlag, + no_ip_pim_mlag_cmd, + "no ip pim mlag", + NO_STR + IP_STR + PIM_STR + "MLAG\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char mlag_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY_HIDDEN (pim_mlag, + pim_mlag_cmd, + "mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n") +{ + char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; + char mlag_my_role_xpath[XPATH_MAXLEN]; + char mlag_peer_state_xpath[XPATH_MAXLEN]; + char mlag_reg_address_xpath[XPATH_MAXLEN]; + + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); + + snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), + "./mlag/my-role"); + if (!strcmp(role, "primary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_PRIMARY"); + } else if (!strcmp(role, "secondary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_SECONDARY"); + } else { + vty_out(vty, "unknown MLAG role %s\n", role); + return CMD_WARNING; + } + + snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), + "./mlag/peer-state"); + if (!strcmp(state, "up")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "true"); + } else if (strcmp(state, "down")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "false"); + } else { + vty_out(vty, "unknown MLAG state %s\n", state); + return CMD_WARNING; + } + snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), + "./mlag/reg-address"); + nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, + addr_str); return nb_cli_apply_changes(vty, NULL); } - -DEFUN_HIDDEN (ip_pim_mlag, - ip_pim_mlag_cmd, - "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D", - IP_STR - PIM_STR - "MLAG\n" - "peerlink sub interface\n" - "MLAG role\n" - "MLAG role primary\n" - "MLAG role secondary\n" - "peer session state\n" - "peer session state up\n" - "peer session state down\n" - "configure PIP\n" - "unique ip address\n") +DEFPY_ATTR(ip_pim_mlag, + ip_pim_mlag_cmd, + "ip pim mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + IP_STR + PIM_STR + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - int idx; char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; char mlag_my_role_xpath[XPATH_MAXLEN]; char mlag_peer_state_xpath[XPATH_MAXLEN]; char mlag_reg_address_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", - sizeof(mlag_peerlink_rif_xpath)); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } - idx = 3; - nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, - argv[idx]->arg); + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_my_role_xpath, "/mlag/my-role", - sizeof(mlag_my_role_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "primary")) { + "./mlag/my-role"); + if (!strcmp(role, "primary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_PRIMARY"); - - } else if (!strcmp(argv[idx]->arg, "secondary")) { + } else if (!strcmp(role, "secondary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_SECONDARY"); - } else { - vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG role %s\n", role); + ret = CMD_WARNING; + goto done; } snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peer_state_xpath, "/mlag/peer-state", - sizeof(mlag_peer_state_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "up")) { + "./mlag/peer-state"); + if (!strcmp(state, "up")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "true"); - - } else if (strcmp(argv[idx]->arg, "down")) { + } else if (strcmp(state, "down")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "false"); - } else { - vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG state %s\n", state); + ret = CMD_WARNING; + goto done; } snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_reg_address_xpath, "/mlag/reg-address", - sizeof(mlag_reg_address_xpath)); - - idx += 2; + "./mlag/reg-address"); nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, - argv[idx]->arg); + addr_str); - return nb_cli_apply_changes(vty, NULL); -} + ret = nb_cli_apply_changes(vty, NULL); -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); +done: + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - install_node(&debug_node); + return ret; +} - install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); +struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", + .config_write = pim_router_config_write, +}; +/* This function installs all of the deprecated PIM configuration commands that live in the global config and/or VRF nodes + * This configuration has been moved to the new 'router pim' config node instead like all the other routing protocols. + * No new commands should be added here. + */ +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); @@ -6446,8 +8436,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); - install_element(CONFIG_NODE, &pim_register_accept_list_cmd); - install_element(VRF_NODE, &pim_register_accept_list_cmd); + install_element(CONFIG_NODE, &ip_pim_register_accept_list_cmd); + install_element(VRF_NODE, &ip_pim_register_accept_list_cmd); install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd); @@ -6464,14 +8454,6 @@ void pim_cmd_init(void) install_element(VRF_NODE, &ip_pim_v6_secondary_cmd); install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd); - install_element(CONFIG_NODE, &ip_ssmpingd_cmd); - install_element(VRF_NODE, &ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); - install_element(VRF_NODE, &no_ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &ip_msdp_peer_cmd); - install_element(VRF_NODE, &ip_msdp_peer_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); - install_element(VRF_NODE, &no_ip_msdp_peer_cmd); install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); @@ -6482,15 +8464,97 @@ void pim_cmd_init(void) install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element(CONFIG_NODE, &ip_pim_mlag_cmd); install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd); - install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + install_element(CONFIG_NODE, &ip_ssmpingd_cmd); + install_element(VRF_NODE, &ip_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); + install_element(VRF_NODE, &no_ip_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ip_msdp_peer_cmd); + install_element(VRF_NODE, &ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element(VRF_NODE, &no_ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &ip_msdp_timers_cmd); + install_element(VRF_NODE, &ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); + install_element(VRF_NODE, &no_ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(CONFIG_NODE, &no_router_pim_cmd); + + install_node(&pim_node); + install_default(PIM_NODE); + + install_element(PIM_NODE, &pim_rp_cmd); + install_element(PIM_NODE, &no_pim_rp_cmd); + install_element(PIM_NODE, &pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd); + install_element(PIM_NODE, &pim_ssm_prefix_list_cmd); + install_element(PIM_NODE, &pim_register_suppress_cmd); + install_element(PIM_NODE, &no_pim_register_suppress_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &pim_register_accept_list_cmd); + install_element(PIM_NODE, &pim_joinprune_time_cmd); + install_element(PIM_NODE, &no_pim_joinprune_time_cmd); + install_element(PIM_NODE, &pim_keep_alive_cmd); + install_element(PIM_NODE, &pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &pim_packets_cmd); + install_element(PIM_NODE, &no_pim_packets_cmd); + install_element(PIM_NODE, &pim_v6_secondary_cmd); + install_element(PIM_NODE, &no_pim_v6_secondary_cmd); + install_element(PIM_NODE, &pim_ecmp_cmd); + install_element(PIM_NODE, &no_pim_ecmp_cmd); + install_element(PIM_NODE, &pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &no_pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &pim_mlag_cmd); + install_element(PIM_NODE, &no_pim_mlag_cmd); + + install_element(PIM_NODE, &pim_ssmpingd_cmd); + install_element(PIM_NODE, &no_pim_ssmpingd_cmd); + + install_element(PIM_NODE, &pim_msdp_peer_cmd); + install_element(PIM_NODE, &no_pim_msdp_peer_cmd); + install_element(PIM_NODE, &msdp_peer_md5_cmd); + install_element(PIM_NODE, &no_msdp_peer_md5_cmd); + install_element(PIM_NODE, &pim_msdp_timers_cmd); + install_element(PIM_NODE, &no_pim_msdp_timers_cmd); + install_element(PIM_NODE, &msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &no_ip_msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd); - install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_join_group_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_static_group_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_version_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_version_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd); @@ -6531,10 +8595,30 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_ip_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd); + install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); + install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); + /* Install BSM command */ + install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); + /* Install BFD command */ + install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); + install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); +#if HAVE_BFDD == 0 + install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); +#endif /* !HAVE_BFDD */ + install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_join_cmd); + install_element(VIEW_NODE, &show_ip_igmp_join_group_cmd); install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_igmp_join_group_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_igmp_static_group_cmd); + install_element(VIEW_NODE, &show_ip_igmp_static_group_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); @@ -6587,8 +8671,23 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd); install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd); install_element(VIEW_NODE, &show_ip_pim_statistics_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); + install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); + + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd); + install_element(ENABLE_NODE, &clear_ip_msdp_peer_cmd); install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_cmd); @@ -6601,134 +8700,98 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &show_debugging_pim_cmd); install_element(ENABLE_NODE, &debug_igmp_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_cmd); - install_element(ENABLE_NODE, &debug_igmp_events_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); - install_element(ENABLE_NODE, &debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_mroute_cmd); - install_element(ENABLE_NODE, &debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &debug_pim_static_cmd); - install_element(ENABLE_NODE, &no_debug_pim_static_cmd); - install_element(ENABLE_NODE, &debug_pim_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &debug_pim_events_cmd); - install_element(ENABLE_NODE, &debug_pim_packets_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &debug_pim_zebra_cmd); - install_element(ENABLE_NODE, &debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &debug_msdp_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_cmd); - install_element(ENABLE_NODE, &debug_msdp_events_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); - install_element(ENABLE_NODE, &debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &debug_mtrace_cmd); - install_element(ENABLE_NODE, &no_debug_mtrace_cmd); - install_element(ENABLE_NODE, &debug_bsm_cmd); - install_element(ENABLE_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &debug_igmp_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_cmd); install_element(CONFIG_NODE, &no_debug_igmp_cmd); + install_element(ENABLE_NODE, &debug_igmp_events_cmd); install_element(CONFIG_NODE, &debug_igmp_events_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); + install_element(ENABLE_NODE, &debug_igmp_packets_cmd); install_element(CONFIG_NODE, &debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_mroute_cmd); install_element(CONFIG_NODE, &debug_mroute_cmd); + install_element(ENABLE_NODE, &debug_mroute_detail_cmd); install_element(CONFIG_NODE, &debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_cmd); install_element(CONFIG_NODE, &no_debug_mroute_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &debug_pim_static_cmd); install_element(CONFIG_NODE, &debug_pim_static_cmd); + install_element(ENABLE_NODE, &no_debug_pim_static_cmd); install_element(CONFIG_NODE, &no_debug_pim_static_cmd); + install_element(ENABLE_NODE, &debug_pim_cmd); install_element(CONFIG_NODE, &debug_pim_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_cmd); install_element(CONFIG_NODE, &debug_pim_nht_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); install_element(CONFIG_NODE, &debug_pim_nht_det_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &debug_pim_events_cmd); install_element(CONFIG_NODE, &debug_pim_events_cmd); + install_element(ENABLE_NODE, &debug_pim_packets_cmd); install_element(CONFIG_NODE, &debug_pim_packets_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_cmd); install_element(CONFIG_NODE, &debug_pim_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_ssmpingd_cmd); install_element(CONFIG_NODE, &debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &debug_pim_zebra_cmd); install_element(CONFIG_NODE, &debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &debug_msdp_cmd); install_element(CONFIG_NODE, &debug_msdp_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_cmd); install_element(CONFIG_NODE, &no_debug_msdp_cmd); + install_element(ENABLE_NODE, &debug_msdp_events_cmd); install_element(CONFIG_NODE, &debug_msdp_events_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); + install_element(ENABLE_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &debug_mtrace_cmd); install_element(CONFIG_NODE, &debug_mtrace_cmd); + install_element(ENABLE_NODE, &no_debug_mtrace_cmd); install_element(CONFIG_NODE, &no_debug_mtrace_cmd); + install_element(ENABLE_NODE, &debug_bsm_cmd); install_element(CONFIG_NODE, &debug_bsm_cmd); + install_element(ENABLE_NODE, &no_debug_bsm_cmd); install_element(CONFIG_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &ip_msdp_timers_cmd); - install_element(VRF_NODE, &ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); - install_element(VRF_NODE, &no_ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); - install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); - install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); - install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); - /* Install BSM command */ - install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); - /* Install BFD command */ - install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); - install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); -#if HAVE_BFDD == 0 - install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); -#endif /* !HAVE_BFDD */ + install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + pim_install_deprecated(); } diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index c3eb49d5f31d..d1368ff1ffe4 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -6,6 +6,7 @@ */ #include +#include #include "lib/json.h" #include "command.h" @@ -68,7 +69,7 @@ const char *pim_cli_get_vrf_name(struct vty *vty) return NULL; } - return yang_dnode_get_string(vrf_node, "./name"); + return yang_dnode_get_string(vrf_node, "name"); } int pim_process_join_prune_cmd(struct vty *vty, const char *jpi_str) @@ -99,25 +100,13 @@ int pim_process_no_join_prune_cmd(struct vty *vty) int pim_process_spt_switchover_infinity_cmd(struct vty *vty) { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + char spt_plist_xpath[XPATH_MAXLEN + 40]; + char spt_action_xpath[XPATH_MAXLEN + 26]; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "%s/spt-switchover/spt-infinity-prefix-list", VTY_CURR_XPATH); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "%s/spt-switchover/spt-action", VTY_CURR_XPATH); if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, @@ -131,55 +120,30 @@ int pim_process_spt_switchover_infinity_cmd(struct vty *vty) int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, const char *plist) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, "PIM_SPT_INFINITY"); - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, - plist); + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, plist); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_spt_switchover_cmd(struct vty *vty) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, @@ -216,35 +180,20 @@ int pim_process_no_pim_packet_cmd(struct vty *vty) int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, - kat); + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, kat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_keepalivetimer_cmd(struct vty *vty) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); @@ -253,58 +202,47 @@ int pim_process_no_keepalivetimer_cmd(struct vty *vty) int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat) { - const char *vrfname; char rp_ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rpkat); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rpkat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_rp_kat_cmd(struct vty *vty) { - const char *vrfname; char rp_ka_timer[6]; char rp_ka_timer_xpath[XPATH_MAXLEN]; uint v; char rs_timer_xpath[XPATH_MAXLEN]; - snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), - FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL); + snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); strlcat(rs_timer_xpath, "/register-suppress-time", sizeof(rs_timer_xpath)); /* RFC4601 */ - v = yang_dnode_get_uint16(vty->candidate_config->dnode, "%s", - rs_timer_xpath); + /* Check if register suppress time is configured or assigned + * the default register suppress time. + */ + if (yang_dnode_exists(vty->candidate_config->dnode, rs_timer_xpath)) + v = yang_dnode_get_uint16(vty->candidate_config->dnode, "%s", + rs_timer_xpath); + else + v = PIM_REGISTER_SUPPRESSION_TIME_DEFAULT; + v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT; if (v > UINT16_MAX) v = UINT16_MAX; snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rp_ka_timer); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rp_ka_timer); return nb_cli_apply_changes(vty, NULL); } @@ -523,8 +461,8 @@ int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, int pim_process_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { - const char *vrfname; - char rp_group_xpath[XPATH_MAXLEN]; + char group_xpath[XPATH_MAXLEN]; + int printed; int result = 0; struct prefix group; pim_addr rp_addr; @@ -565,16 +503,17 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str, } #endif - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + printed = snprintf(group_xpath, sizeof(group_xpath), + "./" FRR_PIM_STATIC_RP_XPATH "/group-list[.='%s']", + rp_str, group_str); - snprintf(rp_group_xpath, sizeof(rp_group_xpath), - FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL, rp_str); - strlcat(rp_group_xpath, "/group-list", sizeof(rp_group_xpath)); + if (printed >= (int)(sizeof(group_xpath))) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); + return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, rp_group_xpath, NB_OP_CREATE, group_str); + nb_cli_enqueue_change(vty, group_xpath, NB_OP_CREATE, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -582,31 +521,15 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str, int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { - char group_list_xpath[XPATH_MAXLEN]; char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN + 47]; int printed; - const char *vrfname; const struct lyd_node *group_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); - - printed = snprintf(group_list_xpath, sizeof(group_list_xpath), - "%s/group-list", rp_xpath); - - if (printed >= (int)(sizeof(group_list_xpath))) { - vty_out(vty, "Xpath too long (%d > %u)", printed + 1, - XPATH_MAXLEN); - return CMD_WARNING_CONFIG_FAILED; - } - - printed = snprintf(group_xpath, sizeof(group_xpath), "%s[.='%s']", - group_list_xpath, group_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); + printed = snprintf(group_xpath, sizeof(group_xpath), + "%s/group-list[.='%s']", rp_xpath, group_str); if (printed >= (int)(sizeof(group_xpath))) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, @@ -623,8 +546,7 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, if (yang_is_last_list_dnode(group_dnode)) nb_cli_enqueue_change(vty, rp_xpath, NB_OP_DESTROY, NULL); else - nb_cli_enqueue_change(vty, group_list_xpath, NB_OP_DESTROY, - group_str); + nb_cli_enqueue_change(vty, group_xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -632,16 +554,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - const char *vrfname; char rp_plist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), - FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL, rp_str); + "./" FRR_PIM_STATIC_RP_XPATH, rp_str); strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); @@ -652,21 +568,14 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - char rp_xpath[XPATH_MAXLEN]; - char plist_xpath[XPATH_MAXLEN]; - const char *vrfname; + char rp_xpath[XPATH_MAXLEN + 47]; + char plist_xpath[XPATH_MAXLEN + 1070]; const struct lyd_node *plist_dnode; const char *plist; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); - - snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); + snprintf(plist_xpath, sizeof(plist_xpath), "%s", rp_xpath); strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); @@ -675,7 +584,7 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, return NB_OK; } - plist = yang_dnode_get_string(plist_dnode, "%s", plist_xpath); + plist = yang_dnode_get_string(plist_dnode, NULL); if (strcmp(prefix_list, plist)) { vty_out(vty, "%% Unable to find specified RP\n"); return NB_OK; @@ -1059,8 +968,8 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty, frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) { char src_str[PIM_ADDRSTRLEN]; char grp_str[PIM_ADDRSTRLEN]; - char in_ifname[INTERFACE_NAMSIZ + 1]; - char out_ifname[INTERFACE_NAMSIZ + 1]; + char in_ifname[IFNAMSIZ + 1]; + char out_ifname[IFNAMSIZ + 1]; int oif_vif_index; struct interface *ifp_in; bool isRpt; @@ -3404,20 +3313,18 @@ int gm_process_no_last_member_query_interval_cmd(struct vty *vty) int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation, const char *src_str) { - const char *vrfname; - char ssmpingd_ip_xpath[XPATH_MAXLEN]; + char ssmpingd_src_ip_xpath[XPATH_MAXLEN]; + int printed; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + printed = snprintf(ssmpingd_src_ip_xpath, sizeof(ssmpingd_src_ip_xpath), + "./ssm-pingd-source-ip[.='%s']", src_str); + if (printed >= (int)sizeof(ssmpingd_src_ip_xpath)) { + vty_out(vty, "Xpath too long (%d > %u)", printed + 1, + XPATH_MAXLEN); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip", - sizeof(ssmpingd_ip_xpath)); - - nb_cli_enqueue_change(vty, ssmpingd_ip_xpath, operation, src_str); + nb_cli_enqueue_change(vty, ssmpingd_src_ip_xpath, operation, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -3662,8 +3569,8 @@ void show_mroute(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg, int first; char grp_str[PIM_ADDRSTRLEN]; char src_str[PIM_ADDRSTRLEN]; - char in_ifname[INTERFACE_NAMSIZ + 1]; - char out_ifname[INTERFACE_NAMSIZ + 1]; + char in_ifname[IFNAMSIZ + 1]; + char out_ifname[IFNAMSIZ + 1]; int oif_vif_index; struct interface *ifp_in; char proto[100]; @@ -5693,3 +5600,34 @@ int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj) return CMD_SUCCESS; } + +int pim_router_config_write(struct vty *vty) +{ + struct vrf *vrf; + struct pim_instance *pim; + int writes = 0; + char framestr[64] = { 0 }; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + + if (!pim) + continue; + + snprintfrr(framestr, sizeof(framestr), "router %s", + PIM_AF_ROUTER); + if (vrf->vrf_id != VRF_DEFAULT) { + strlcat(framestr, " vrf ", sizeof(framestr)); + strlcat(framestr, vrf->name, sizeof(framestr)); + } + vty_frame(vty, "%s\n", framestr); + ++writes; + + writes += pim_global_config_write_worker(pim, vty); + + vty_endframe(vty, "exit\n"); + ++writes; + } + + return writes; +} diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index e30203fad75b..da2e44be585b 100644 --- a/pimd/pim_cmd_common.h +++ b/pimd/pim_cmd_common.h @@ -182,6 +182,8 @@ int pim_show_interface_traffic_helper(const char *vrf, const char *if_name, void clear_pim_interfaces(struct pim_instance *pim); void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj); int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj); +int pim_router_config_write(struct vty *vty); + /* * Special Macro to allow us to get the correct pim_instance; */ diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 978607d1479c..a0661ef36baf 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -440,7 +440,7 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf, } /* Secondary Address List */ - if (ifp->connected->count) { + if (if_connected_count(ifp->connected)) { curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp, PIM_AF); if (!curr) { diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 85e0fdf3afbe..45a2435ae550 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -37,10 +37,12 @@ #include "pim_jp_agg.h" #include "pim_igmp_join.h" #include "pim_vxlan.h" +#include "pim_tib.h" #include "pim6_mld.h" static void pim_if_gm_join_del_all(struct interface *ifp); +static void pim_if_static_group_del_all(struct interface *ifp); static int gm_join_sock(const char *ifname, ifindex_t ifindex, pim_addr group_addr, pim_addr source_addr, @@ -144,6 +146,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim, pim_ifp->gm_enable = gm; pim_ifp->gm_join_list = NULL; + pim_ifp->static_group_list = NULL; pim_ifp->pim_neighbor_list = NULL; pim_ifp->upstream_switch_list = NULL; pim_ifp->pim_generation_id = 0; @@ -188,9 +191,11 @@ void pim_if_delete(struct interface *ifp) assert(pim_ifp); pim_ifp->pim->mcast_if_count--; - if (pim_ifp->gm_join_list) { + if (pim_ifp->gm_join_list) pim_if_gm_join_del_all(ifp); - } + + if (pim_ifp->static_group_list) + pim_if_static_group_del_all(ifp); pim_ifchannel_delete_all(ifp); #if PIM_IPV == 4 @@ -379,7 +384,7 @@ static int pim_sec_addr_update(struct interface *ifp) sec_addr->flags |= PIM_SEC_ADDRF_STALE; } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { pim_addr addr = pim_addr_from_prefix(ifc->address); if (pim_addr_is_any(addr)) @@ -723,13 +728,12 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) if (pim_ifp && (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) || !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) { - struct listnode *cnode; struct connected *cc; memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest)); memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest)); - for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) { + frr_each (if_connected, ifc->ifp->connected, cc) { if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) && !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6)) continue; @@ -765,8 +769,6 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) void pim_if_addr_add_all(struct interface *ifp) { struct connected *ifc; - struct listnode *node; - struct listnode *nextnode; int v4_addrs = 0; int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; @@ -777,7 +779,7 @@ void pim_if_addr_add_all(struct interface *ifp) if (!pim_ifp) return; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { struct prefix *p = ifc->address; if (p->family != AF_INET) @@ -813,8 +815,6 @@ void pim_if_addr_add_all(struct interface *ifp) void pim_if_addr_del_all(struct interface *ifp) { struct connected *ifc; - struct listnode *node; - struct listnode *nextnode; struct pim_instance *pim; pim = ifp->vrf->info; @@ -825,7 +825,7 @@ void pim_if_addr_del_all(struct interface *ifp) if (!ifp->info) return; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + frr_each_safe (if_connected, ifp->connected, ifc) { struct prefix *p = ifc->address; if (p->family != PIM_AF) @@ -841,14 +841,12 @@ void pim_if_addr_del_all(struct interface *ifp) void pim_if_addr_del_all_igmp(struct interface *ifp) { struct connected *ifc; - struct listnode *node; - struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { + frr_each_safe (if_connected, ifp->connected, ifc) { struct prefix *p = ifc->address; if (p->family != AF_INET) @@ -861,7 +859,6 @@ void pim_if_addr_del_all_igmp(struct interface *ifp) pim_addr pim_find_primary_addr(struct interface *ifp) { struct connected *ifc; - struct listnode *node; struct pim_interface *pim_ifp = ifp->info; if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source)) @@ -873,7 +870,7 @@ pim_addr pim_find_primary_addr(struct interface *ifp) pim_addr best_addr = PIMADDR_ANY; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { pim_addr addr; if (ifc->address->family != AF_INET6) @@ -892,7 +889,7 @@ pim_addr pim_find_primary_addr(struct interface *ifp) int v6_addrs = 0; struct connected *promote_ifc = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { switch (ifc->address->family) { case AF_INET: v4_addrs++; @@ -1226,6 +1223,11 @@ static void gm_join_free(struct gm_join *ij) XFREE(MTYPE_PIM_IGMP_JOIN, ij); } +static void static_group_free(struct static_group *stgrp) +{ + XFREE(MTYPE_PIM_STATIC_GROUP, stgrp); +} + static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr, pim_addr source_addr) { @@ -1240,7 +1242,25 @@ static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr, return ij; } - return 0; + return NULL; +} + +static struct static_group *static_group_find(struct list *static_group_list, + pim_addr group_addr, + pim_addr source_addr) +{ + struct listnode *node; + struct static_group *stgrp; + + assert(static_group_list); + + for (ALL_LIST_ELEMENTS_RO(static_group_list, node, stgrp)) { + if ((!pim_addr_cmp(group_addr, stgrp->group_addr)) && + (!pim_addr_cmp(source_addr, stgrp->source_addr))) + return stgrp; + } + + return NULL; } static int gm_join_sock(const char *ifname, ifindex_t ifindex, @@ -1304,6 +1324,34 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr, return ij; } +static struct static_group *static_group_new(struct interface *ifp, + pim_addr group_addr, + pim_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct static_group *stgrp; + pim_sgaddr sg; + + pim_ifp = ifp->info; + assert(pim_ifp); + + stgrp = XCALLOC(MTYPE_PIM_STATIC_GROUP, sizeof(*stgrp)); + + stgrp->group_addr = group_addr; + stgrp->source_addr = source_addr; + stgrp->oilp = NULL; + + memset(&sg, 0, sizeof(sg)); + sg.src = source_addr; + sg.grp = group_addr; + + tib_sg_gm_join(pim_ifp->pim, sg, ifp, &(stgrp->oilp)); + + listnode_add(pim_ifp->static_group_list, stgrp); + + return stgrp; +} + ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, pim_addr source_addr) { @@ -1330,7 +1378,10 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, return ferr_ok(); } - (void)gm_join_new(ifp, group_addr, source_addr); + if (!gm_join_new(ifp, group_addr, source_addr)) { + return ferr_cfg_invalid("can't join (%pPA,%pPA) on interface %s", + &source_addr, &group_addr, ifp->name); + } if (PIM_DEBUG_GM_EVENTS) { zlog_debug( @@ -1387,7 +1438,6 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr, return 0; } -__attribute__((unused)) static void pim_if_gm_join_del_all(struct interface *ifp) { struct pim_interface *pim_ifp; @@ -1409,6 +1459,109 @@ static void pim_if_gm_join_del_all(struct interface *ifp) pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr); } +ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr, + pim_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct static_group *stgrp; + + pim_ifp = ifp->info; + if (!pim_ifp) { + return ferr_cfg_invalid("multicast not enabled on interface %s", + ifp->name); + } + + if (!pim_ifp->static_group_list) { + pim_ifp->static_group_list = list_new(); + pim_ifp->static_group_list->del = + (void (*)(void *))static_group_free; + } + + stgrp = static_group_find(pim_ifp->static_group_list, group_addr, + source_addr); + + /* This interface has already been configured with this static group + */ + if (stgrp) + return ferr_ok(); + + (void)static_group_new(ifp, group_addr, source_addr); + + if (PIM_DEBUG_GM_EVENTS) { + zlog_debug("%s: Added static group (S,G)=(%pPA,%pPA) on interface %s", + __func__, &source_addr, &group_addr, ifp->name); + } + + return ferr_ok(); +} + +int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr, + pim_addr source_addr) +{ + struct pim_interface *pim_ifp; + struct static_group *stgrp; + pim_sgaddr sg; + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", __func__, + ifp->name); + return -1; + } + + if (!pim_ifp->static_group_list) { + zlog_warn("%s: no static groups on interface %s", __func__, + ifp->name); + return -2; + } + + stgrp = static_group_find(pim_ifp->static_group_list, group_addr, + source_addr); + if (!stgrp) { + zlog_warn("%s: could not find static group %pPAs source %pPAs on interface %s", + __func__, &group_addr, &source_addr, ifp->name); + return -3; + } + + memset(&sg, 0, sizeof(sg)); + sg.src = source_addr; + sg.grp = group_addr; + + tib_sg_gm_prune(pim_ifp->pim, sg, ifp, &(stgrp->oilp)); + + listnode_delete(pim_ifp->static_group_list, stgrp); + static_group_free(stgrp); + if (listcount(pim_ifp->static_group_list) < 1) { + list_delete(&pim_ifp->static_group_list); + pim_ifp->static_group_list = 0; + } + + return 0; +} + +static void pim_if_static_group_del_all(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct listnode *node; + struct listnode *nextnode; + struct static_group *stgrp; + + pim_ifp = ifp->info; + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", __func__, + ifp->name); + return; + } + + if (!pim_ifp->static_group_list) + return; + + for (ALL_LIST_ELEMENTS(pim_ifp->static_group_list, node, nextnode, + stgrp)) + pim_if_static_group_del(ifp, stgrp->group_addr, + stgrp->source_addr); +} + /* RFC 4601 @@ -1487,7 +1640,7 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp) */ void pim_if_create_pimreg(struct pim_instance *pim) { - char pimreg_name[INTERFACE_NAMSIZ]; + char pimreg_name[IFNAMSIZ]; if (!pim->regiface) { if (pim->vrf->vrf_id == VRF_DEFAULT) @@ -1500,9 +1653,16 @@ void pim_if_create_pimreg(struct pim_instance *pim) pim->vrf->name); pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF; - if (!pim->regiface->info) - pim_if_new(pim->regiface, false, false, true, - false /*vxlan_term*/); + /* + * The pimreg interface might has been removed from + * kerenl with the VRF's deletion. It must be + * recreated, so delete the old one first. + */ + if (pim->regiface->info) + pim_if_delete(pim->regiface); + + pim_if_new(pim->regiface, false, false, true, + false /*vxlan_term*/); /* * On vrf moves we delete the interface if there @@ -1516,7 +1676,6 @@ void pim_if_create_pimreg(struct pim_instance *pim) struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src) { - struct listnode *cnode; struct connected *c; struct prefix p; @@ -1525,7 +1684,7 @@ struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src) pim_addr_to_prefix(&p, src); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (c->address->family != PIM_AF) continue; if (prefix_match(c->address, &p)) @@ -1679,7 +1838,9 @@ static int pim_ifp_up(struct interface *ifp) __func__, vrf->name); return 0; } + pim_zebra_interface_set_master(master, ifp); + break; } } } @@ -1764,8 +1925,10 @@ void pim_iface_init(void) hook_register_prio(if_add, 0, pim_if_new_hook); hook_register_prio(if_del, 0, pim_if_delete_hook); - if_zapi_callbacks(pim_ifp_create, pim_ifp_up, pim_ifp_down, - pim_ifp_destroy); + hook_register_prio(if_real, 0, pim_ifp_create); + hook_register_prio(if_up, 0, pim_ifp_up); + hook_register_prio(if_down, 0, pim_ifp_down); + hook_register_prio(if_unreal, 0, pim_ifp_destroy); } static void pim_if_membership_clear(struct interface *ifp) diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 0312f719d300..4d2037966598 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -98,6 +98,7 @@ struct pim_interface { */ struct list *gm_socket_list; /* list of struct IGMP or MLD sock */ struct list *gm_join_list; /* list of struct IGMP or MLD join */ + struct list *static_group_list; /* list of struct static group */ struct list *gm_group_list; /* list of struct IGMP or MLD group */ struct hash *gm_group_hash; @@ -222,6 +223,11 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr, pim_addr source_addr); +ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr, + pim_addr source_addr); +int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr, + pim_addr source_addr); + void pim_if_update_could_assert(struct interface *ifp); void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index da5518994193..8f9e41039ae6 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -342,6 +342,13 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, ch->sg_str, ch->interface->name); } + /* pim_upstream_update_join_desired looks at up->channel_oil, + * but that's updated from pim_forward_stop(). Need this here + * so we correctly determine join_desired right below. + */ + if (new_state == PIM_IFJOIN_NOINFO) + pim_forward_stop(ch); + /* Record uptime of state transition to/from NOINFO */ @@ -619,7 +626,6 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, static void ifjoin_to_noinfo(struct pim_ifchannel *ch) { pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO); - pim_forward_stop(ch); PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags); diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index a1f19b3c6e1c..de0ec01a655e 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -58,6 +58,12 @@ struct gm_join { time_t sock_creation; }; +struct static_group { + pim_addr group_addr; + pim_addr source_addr; + struct channel_oil *oilp; +}; + struct gm_sock { int fd; struct interface *interface; diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 4d3f6022a1d6..309da138d2b6 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -21,7 +21,6 @@ static struct in_addr mtrace_primary_address(struct interface *ifp) { struct connected *ifc; - struct listnode *node; struct in_addr any; struct pim_interface *pim_ifp; @@ -32,7 +31,7 @@ static struct in_addr mtrace_primary_address(struct interface *ifp) any.s_addr = INADDR_ANY; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { struct prefix *p = ifc->address; if (p->family != AF_INET) diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 18a9fb7c6c76..2c5ad4d44b1b 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -457,8 +457,6 @@ struct gm_source *igmp_get_source_by_addr(struct gm_group *group, listnode_add(group->group_source_list, src); - /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ - igmp_anysource_forward_stop(group); return src; } diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index b3410d15af72..a9eec9a9d25b 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -201,6 +201,7 @@ static int pim_vrf_config_write(struct vty *vty) { struct vrf *vrf; struct pim_instance *pim; + char spaces[10]; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; @@ -208,10 +209,24 @@ static int pim_vrf_config_write(struct vty *vty) if (!pim) continue; - if (vrf->vrf_id != VRF_DEFAULT) + if (vrf->vrf_id != VRF_DEFAULT) { vty_frame(vty, "vrf %s\n", vrf->name); - - pim_global_config_write_worker(pim, vty); + snprintf(spaces, sizeof(spaces), "%s", " "); + } else { + snprintf(spaces, sizeof(spaces), "%s", ""); + } + + /* Global IGMP/MLD configuration */ + if (pim->gm_watermark_limit != 0) { +#if PIM_IPV == 4 + vty_out(vty, + "%s" PIM_AF_NAME " igmp watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#else + vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#endif + } if (vrf->vrf_id != VRF_DEFAULT) vty_endframe(vty, "exit-vrf\n!\n"); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 11577ae46d01..ec331332cfca 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -97,7 +97,7 @@ struct pim_router { struct in_addr local_vtep_ip; struct pim_mlag_stats mlag_stats; enum pim_mlag_flags mlag_flags; - char peerlink_rif[INTERFACE_NAMSIZ]; + char peerlink_rif[IFNAMSIZ]; struct interface *peerlink_rif_p; }; diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 671f7a37a5a3..bfdb0f06b410 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -43,7 +43,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, { struct pim_interface *pim_ifp = NULL; - if (PIM_DEBUG_PIM_TRACE) + if (PIM_DEBUG_PIM_J_P) zlog_debug( "%s: join (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s", __func__, sg, !!(source_flags & PIM_RPT_BIT_MASK), @@ -115,7 +115,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, { struct pim_interface *pim_ifp = NULL; - if (PIM_DEBUG_PIM_TRACE) + if (PIM_DEBUG_PIM_J_P) zlog_debug( "%s: prune (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s", __func__, sg, source_flags & PIM_RPT_BIT_MASK, @@ -147,7 +147,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, * Received Prune(*,G) messages are processed even if the * RP in the message does not match RP(G). */ - if (PIM_DEBUG_PIM_TRACE) + if (PIM_DEBUG_PIM_J_P) zlog_debug("%s: Prune received with RP(%pPAs) for %pSG", __func__, &sg->src, sg); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 7db0a7676b2e..8f2ce0bed335 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -59,6 +59,7 @@ struct zebra_privs_t pimd_privs = { .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; +/* clang-format off */ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -70,17 +71,19 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_gmp_info, }; -FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, +FRR_DAEMON_INFO(pimd, PIM, + .vty_port = PIMD_VTY_PORT, + .proghelp = "Implementation of the PIM routing protocol.", - .proghelp = "Implementation of the PIM routing protocol.", + .signals = pimd_signals, + .n_signals = 4 /* XXX array_size(pimd_signals) XXX*/, - .signals = pimd_signals, - .n_signals = 4 /* XXX array_size(pimd_signals) XXX*/, + .privs = &pimd_privs, - .privs = &pimd_privs, .yang_modules = pimd_yang_modules, - .n_yang_modules = array_size(pimd_yang_modules), + .yang_modules = pimd_yang_modules, + .n_yang_modules = array_size(pimd_yang_modules), ); - +/* clang-format on */ int main(int argc, char **argv, char **envp) { diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 85780f013b32..2c35bc647368 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -14,6 +14,7 @@ DEFINE_MGROUP(PIMD, "pimd"); DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL"); DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface"); DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join"); +DEFINE_MTYPE(PIMD, PIM_STATIC_GROUP, "PIM interface IGMP static group"); DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket"); DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group"); DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source"); @@ -26,6 +27,7 @@ DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info"); DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info"); DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name"); +DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key"); DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr"); diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 41730e752284..b44d3e191a0b 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -13,6 +13,7 @@ DECLARE_MGROUP(PIMD); DECLARE_MTYPE(PIM_CHANNEL_OIL); DECLARE_MTYPE(PIM_INTERFACE); DECLARE_MTYPE(PIM_IGMP_JOIN); +DECLARE_MTYPE(PIM_STATIC_GROUP); DECLARE_MTYPE(PIM_IGMP_SOCKET); DECLARE_MTYPE(PIM_IGMP_GROUP); DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE); @@ -28,6 +29,7 @@ DECLARE_MTYPE(PIM_MSDP_MG_NAME); DECLARE_MTYPE(PIM_MSDP_SA); DECLARE_MTYPE(PIM_MSDP_MG); DECLARE_MTYPE(PIM_MSDP_MG_MBR); +DECLARE_MTYPE(PIM_MSDP_AUTH_KEY); DECLARE_MTYPE(PIM_SEC_ADDR); DECLARE_MTYPE(PIM_JP_AGG_GROUP); DECLARE_MTYPE(PIM_JP_AGG_SOURCE); diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c index 5d72eb65813c..dcef2d0d33ab 100644 --- a/pimd/pim_mlag.c +++ b/pimd/pim_mlag.c @@ -434,7 +434,7 @@ static void pim_mlag_up_local_add_send(struct pim_instance *pim, stream_putc(s, !(PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))); stream_putl(s, vrf->vrf_id); /* XXX - this field is a No-op for VXLAN*/ - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); stream_fifo_push_safe(router->mlag_fifo, s); pim_mlag_signal_zpthread(); @@ -467,7 +467,7 @@ static void pim_mlag_up_local_del_send(struct pim_instance *pim, stream_putl(s, MLAG_OWNER_VXLAN); stream_putl(s, vrf->vrf_id); /* XXX - this field is a No-op for VXLAN */ - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); /* XXX - is this the the most optimal way to do things */ stream_fifo_push_safe(router->mlag_fifo, s); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 7ea6ed9e1407..adc47e719d24 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -5,6 +5,9 @@ */ #include +#include +#include + #include "log.h" #include "privs.h" #include "if.h" @@ -53,10 +56,14 @@ int pim_mroute_set(struct pim_instance *pim, int enable) err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_TABLE, &data, data_len); if (err) { - zlog_warn( - "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s", - __FILE__, __func__, pim->mroute_socket, - data, errno, safe_strerror(errno)); + if (err == ENOPROTOOPT) + zlog_err("%s Kernel is not compiled with CONFIG_IP_MROUTE_MULTIPLE_TABLES and vrf's will not work", + __func__); + else + zlog_warn("%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s", + __FILE__, __func__, + pim->mroute_socket, data, + errno, safe_strerror(errno)); return -1; } } @@ -1216,7 +1223,7 @@ int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name) return pim_upstream_mroute_update(c_oil, name); } -/* Look for IIF changes and update the dateplane entry only if the IIF +/* Look for IIF changes and update the dataplane entry only if the IIF * has changed. */ int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name) diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index 8706f42206bd..fd4913ca429e 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -25,8 +25,19 @@ #include #if defined(HAVE_LINUX_MROUTE_H) #include -#else -#include "linux/mroute.h" +#endif + +#if defined(HAVE_NETINET_IP_MROUTE_H) +#include +/* + * MRT_TABLE of 155 is needed because it is not defined + * on FreeBSD. MRT_TABLE is for vrf's. There is no + * equivalent on BSD at this point in time. Let's + * just get it compiling + */ +#ifndef MRT_TABLE +#define MRT_TABLE 155 +#endif #endif typedef struct vifctl pim_vifctl; @@ -70,8 +81,17 @@ typedef struct sioc_sg_req pim_sioc_sg_req; #if defined(HAVE_LINUX_MROUTE6_H) #include -#else -#include "linux/mroute6.h" +#endif +#if defined(HAVE_NETINET_IP6_MROUTE_H) +#include +#include + +/* + * See the v4 discussion above + */ +#ifndef MRT_TABLE +#define MRT_TABLE 155 +#endif #endif #ifndef MRT_INIT diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index b1b6958fe166..215cc3c5029c 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -374,6 +374,8 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; + struct rp_info *rp_info; + struct prefix grp; sa = pim_msdp_sa_add(pim, sg, rp); if (!sa) { @@ -406,7 +408,13 @@ void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, sa->sg_str); } /* send an immediate SA update to peers */ - sa->rp = pim->msdp.originator_id; + pim_addr_to_prefix(&grp, sa->sg.grp); + rp_info = pim_rp_find_match_group(pim, &grp); + if (rp_info) { + sa->rp = rp_info->rp.rpf_addr; + } else { + sa->rp = pim->msdp.originator_id; + } pim_msdp_pkt_sa_tx_one(sa); } sa->flags &= ~PIM_MSDP_SAF_STALE; @@ -765,7 +773,10 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) * first listening peer is configured; but don't bother tearing it down * when * all the peers go down */ - pim_msdp_sock_listen(mp->pim); + if (mp->auth_type == MSDP_AUTH_NONE) + pim_msdp_sock_listen(mp->pim); + else + pim_msdp_sock_auth_listen(mp); } /* 11.2.A4 and 11.2.A5: transition active or passive peer to @@ -1037,6 +1048,7 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim, mp->state = PIM_MSDP_INACTIVE; mp->fd = -1; + mp->auth_listen_sock = -1; strlcpy(mp->last_reset, "-", sizeof(mp->last_reset)); /* higher IP address is listener */ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) { @@ -1092,6 +1104,12 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp) stream_fifo_free(mp->obuf); } + /* Free authentication data. */ + event_cancel(&mp->auth_listen_ev); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + if (mp->auth_listen_sock != -1) + close(mp->auth_listen_sock); + XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name); mp->pim = NULL; @@ -1120,19 +1138,32 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp) *mp = NULL; } -void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, - const struct in_addr *addr) +void pim_msdp_peer_restart(struct pim_msdp_peer *mp) { - pim_msdp_peer_stop_tcp_conn(mp, true); + /* Stop auth listening socket if any. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } - mp->local = *addr; + /* Stop previously running connection. */ + pim_msdp_peer_stop_tcp_conn(mp, true); + /* Start connection again. */ if (PIM_MSDP_PEER_IS_LISTENER(mp)) pim_msdp_peer_listen(mp); else pim_msdp_peer_connect(mp); } +void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, + const struct in_addr *addr) +{ + mp->local = *addr; + pim_msdp_peer_restart(mp); +} + /* peer hash and peer list helpers */ static unsigned int pim_msdp_peer_hash_key_make(const void *p) { @@ -1266,8 +1297,7 @@ static void pim_msdp_src_del(struct pim_msdp_mg *mg) } /*********************** MSDP feature APIs *********************************/ -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) { struct pim_msdp_mg *mg; struct listnode *mbrnode; @@ -1282,14 +1312,14 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, if (mg->src_ip.s_addr != INADDR_ANY) { pim_inet4_dump("", mg->src_ip, src_str, sizeof(src_str)); - vty_out(vty, "%sip msdp mesh-group %s source %s\n", - spaces, mg->mesh_group_name, src_str); + vty_out(vty, " msdp mesh-group %s source %s\n", + mg->mesh_group_name, src_str); ++count; } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { - vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", - spaces, mg->mesh_group_name, &mbr->mbr_ip); + vty_out(vty, " msdp mesh-group %s member %pI4\n", + mg->mesh_group_name, &mbr->mbr_ip); ++count; } } @@ -1297,8 +1327,7 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, return count; } -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces) +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) { struct pim_msdp_peer *mp; struct listnode *node; @@ -1309,8 +1338,21 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, if (mp->flags & PIM_MSDP_PEERF_IN_GROUP) continue; - vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces, - &mp->peer, &mp->local); + vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, + &mp->local); + + if (mp->auth_type == MSDP_AUTH_MD5) + vty_out(vty, " msdp peer %pI4 password %s\n", &mp->peer, + mp->auth_key); + + if (mp->acl_in) + vty_out(vty, " msdp peer %pI4 sa-filter %s in\n", + &mp->peer, mp->acl_in); + + if (mp->acl_out) + vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", + &mp->peer, mp->acl_out); + written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index ddc015f9b62b..f77b0e1a3afd 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -89,6 +89,11 @@ enum pim_msdp_peer_flags { PIM_MSDP_PEERF_IN_GROUP = (1 << 2), }; +enum msdp_auth_type { + MSDP_AUTH_NONE = 0, + MSDP_AUTH_MD5 = 1, +}; + struct pim_msdp_peer { struct pim_instance *pim; @@ -98,6 +103,13 @@ struct pim_msdp_peer { char *mesh_group_name; char key_str[INET_ADDRSTRLEN]; + /* Authentication data. */ + enum msdp_auth_type auth_type; + char *auth_key; + + int auth_listen_sock; + struct event *auth_listen_ev; + /* state */ enum pim_msdp_peer_state state; enum pim_msdp_peer_flags flags; @@ -138,6 +150,11 @@ struct pim_msdp_peer { /* timestamps */ int64_t uptime; + + /** SA input access list name. */ + char *acl_in; + /** SA output access list name. */ + char *acl_out; }; struct pim_msdp_mg_mbr { @@ -228,10 +245,8 @@ void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str); void pim_msdp_write(struct event *thread); -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces); +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty); +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp); @@ -306,6 +321,15 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp); void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, const struct in_addr *addr); +/** + * Restart peer's connection. + * + * This is used internally in MSDP and should be used by northbound + * when wanting to immediately apply connections settings such as + * authentication. + */ +void pim_msdp_peer_restart(struct pim_msdp_peer *mp); + #else /* PIM_IPV == 6 */ static inline void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) @@ -339,14 +363,13 @@ static inline void pim_msdp_sa_local_del(struct pim_instance *pim, } static inline int pim_msdp_config_write(struct pim_instance *pim, - struct vty *vty, const char *spaces) + struct vty *vty) { return 0; } static inline bool pim_msdp_peer_config_write(struct vty *vty, - struct pim_instance *pim, - const char *spaces) + struct pim_instance *pim) { return false; } diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index a414736cccf1..27f4966a1cc3 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include "frrevent.h" #include @@ -14,7 +16,9 @@ #include "pimd.h" #include "pim_instance.h" +#include "pim_rp.h" #include "pim_str.h" +#include "pim_util.h" #include "pim_errors.h" #include "pim_msdp.h" @@ -320,8 +324,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp) pim_msdp_pkt_send(mp, s); } -static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, - struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_push(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct stream *s; @@ -336,25 +340,6 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, } } -/* push the stream into the obuf fifo of all the peers */ -static void pim_msdp_pkt_sa_push(struct pim_instance *pim, - struct pim_msdp_peer *mp) -{ - struct listnode *mpnode; - - if (mp) { - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } else { - for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { - if (PIM_DEBUG_MSDP_INTERNAL) { - zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push", - mp->key_str); - } - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } - } -} - static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt, struct in_addr rp) { @@ -382,21 +367,115 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } +static bool msdp_cisco_match(const struct filter *filter, + const struct in_addr *source, + const struct in_addr *group) +{ + const struct filter_cisco *cfilter = &filter->u.cfilter; + uint32_t source_addr; + uint32_t group_addr; + + group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; + + if (cfilter->extended) { + source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; + if (group_addr == cfilter->mask.s_addr && + source_addr == cfilter->addr.s_addr) + return true; + } else if (group_addr == cfilter->addr.s_addr) + return true; + + return false; +} + +static enum filter_type msdp_access_list_apply(struct access_list *access, + const struct in_addr *source, + const struct in_addr *group) +{ + struct filter *filter; + struct prefix group_prefix; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) { + if (filter->cisco) { + if (msdp_cisco_match(filter, source, group)) + return filter->type; + } else { + group_prefix.family = AF_INET; + group_prefix.prefixlen = IPV4_MAX_BITLEN; + group_prefix.u.prefix4.s_addr = group->s_addr; + if (access_list_apply(access, &group_prefix)) + return filter->type; + } + } + + return FILTER_DENY; +} + +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa) +{ + struct access_list *acl; + + /* No output filter configured, just quit. */ + if (mp->acl_out == NULL) + return false; + + /* Find access list and test it. */ + acl = access_list_lookup(AFI_IP, mp->acl_out); + if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) + return true; + + return false; +} + +/** Count the number of SAs to be sent for a specific peer. */ +static size_t pim_msdp_peer_sa_count(const struct pim_instance *pim, + const struct pim_msdp_peer *peer) +{ + const struct pim_msdp_sa *sa; + const struct listnode *node; + size_t sa_count = 0; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, node, sa)) { + if (!CHECK_FLAG(sa->flags, PIM_MSDP_SAF_LOCAL)) + continue; + if (msdp_peer_sa_filter(peer, sa)) + continue; + + sa_count++; + } + + return sa_count; +} + static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct pim_msdp_peer *mp) { struct listnode *sanode; struct pim_msdp_sa *sa; + struct rp_info *rp_info; + struct prefix group_all; + struct in_addr rp; int sa_count; - int local_cnt = pim->msdp.local_cnt; + int local_cnt = pim_msdp_peer_sa_count(pim, mp); sa_count = 0; if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug(" sa gen %d", local_cnt); } - local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, - pim->msdp.originator_id); + rp = pim->msdp.originator_id; + if (pim_get_all_mcast_group(&group_all)) { + rp_info = pim_rp_find_match_group(pim, &group_all); + if (rp_info) { + rp = rp_info->rp.rpf_addr; + } + } + + local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt, rp); for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) { if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) { @@ -406,6 +485,15 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, * peers */ continue; } + + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + + continue; + } + /* add sa into scratch pad */ pim_msdp_pkt_sa_fill_one(sa); ++sa_count; @@ -418,7 +506,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, local_cnt); } local_cnt = pim_msdp_pkt_sa_fill_hdr( - pim, local_cnt, pim->msdp.originator_id); + pim, local_cnt, rp); } } @@ -445,15 +533,32 @@ static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim) void pim_msdp_pkt_sa_tx(struct pim_instance *pim) { - pim_msdp_pkt_sa_gen(pim, NULL /* mp */); + struct pim_msdp_peer *mp; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) + pim_msdp_pkt_sa_gen(pim, mp); + pim_msdp_pkt_sa_tx_done(pim); } void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa) { + struct pim_msdp_peer *mp; + struct listnode *node; + pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp); pim_msdp_pkt_sa_fill_one(sa); - pim_msdp_pkt_sa_push(sa->pim, NULL); + for (ALL_LIST_ELEMENTS_RO(sa->pim->msdp.peer_list, node, mp)) { + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + continue; + } + + pim_msdp_pkt_sa_push(sa->pim, mp); + } pim_msdp_pkt_sa_tx_done(sa->pim); } @@ -475,6 +580,15 @@ void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, /* Fills the message contents. */ sa.pim = mp->pim; sa.sg = sg; + + /* Don't push it if filtered. */ + if (msdp_peer_sa_filter(mp, &sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out (%pI4, %pI4)", + &mp->peer, &sa.sg.src, &sa.sg.grp); + return; + } + pim_msdp_pkt_sa_fill_one(&sa); /* Pushes the message. */ @@ -499,6 +613,7 @@ static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len) static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) { + struct access_list *acl; int prefix_len; pim_sgaddr sg; struct listnode *peer_node; @@ -522,6 +637,19 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) if (PIM_DEBUG_MSDP_PACKETS) { zlog_debug(" sg %pSG", &sg); } + + /* Filter incoming SA with configured access list. */ + if (mp->acl_in) { + acl = access_list_lookup(AFI_IP, mp->acl_in); + if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == + FILTER_DENY) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA in (%pI4, %pI4)", + &mp->peer, &sg.src, &sg.grp); + return; + } + } + pim_msdp_sa_ref(mp->pim, mp, &sg, rp); /* Forwards the SA to the peers that are not in the RPF to the RP nor in diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 1584a2453927..3af8d936852d 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -57,5 +57,7 @@ void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, struct in_addr rp, pim_sgaddr sg); +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa); #endif diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index fe8d5e934aca..2fb0bb87c789 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -49,6 +49,192 @@ static void pim_msdp_update_sock_send_buffer_size(int fd) } } +/** + * Helper function to reduce code duplication. + * + * \param vrf VRF pointer (`NULL` means default VRF) + * \param mp the MSDP session pointer. + * \returns valid file descriptor otherwise `-1`. + */ +static int _pim_msdp_sock_listen(const struct vrf *vrf, + const struct pim_msdp_peer *mp) +{ + const struct interface *ifp; + int sock; + int rv; + socklen_t socklen; + struct sockaddr_in sin = {}; + union sockunion su_peer = {}; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + zlog_warn("%s: socket: %s", __func__, strerror(errno)); + return -1; + } + + socklen = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(PIM_MSDP_TCP_PORT); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin.sin_len = socklen; +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + if (mp) + sin.sin_addr = mp->local; + + sockopt_reuseaddr(sock); + sockopt_reuseport(sock); + + /* Bind socket to VRF/address. */ + if (vrf && vrf->vrf_id != VRF_DEFAULT) { + ifp = if_lookup_by_name(vrf->name, vrf->vrf_id); + if (ifp == NULL) { + flog_err(EC_LIB_INTERFACE, + "%s: Unable to lookup vrf interface: %s", + __func__, vrf->name); + close(sock); + return -1; + } + + if (vrf_bind(vrf->vrf_id, sock, ifp->name) == -1) { + flog_err_sys(EC_LIB_SOCKET, + "%s: Unable to bind to socket: %s", + __func__, safe_strerror(errno)); + close(sock); + return -1; + } + } + + frr_with_privs (&pimd_privs) { + rv = bind(sock, (struct sockaddr *)&sin, socklen); + } + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, + "pim_msdp_socket bind to port %d: %s", + ntohs(sin.sin_port), safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set MD5 authentication. */ + if (mp && mp->auth_key) { + su_peer = mp->su_peer; + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(sock, &su_peer, mp->auth_key); + } + } + + + /* Start listening. */ + rv = listen(sock, SOMAXCONN); + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", + safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set socket DSCP byte */ + if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", + sock, safe_strerror(errno)); + } + + return sock; +} + +static void pim_msdp_sock_auth_accept(struct event *t) +{ + struct pim_msdp_peer *mp = EVENT_ARG(t); + int sock; + socklen_t sinlen; + struct sockaddr_in sin = {}; + + /* accept client connection. */ + sinlen = sizeof(sin); + sock = accept(mp->auth_listen_sock, (struct sockaddr *)&sin, &sinlen); + if (sock == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)", + safe_strerror(errno)); + + /* Accept failed, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* + * Previous connection still going. + * + * We must wait for the user to close the previous connection in order + * to establish the new one. User can manually force that by calling + * `clear ip msdp peer A.B.C.D`. + */ + if (mp->fd != -1) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4: old connection still running", + &sin.sin_addr); + } + close(sock); + + /* Unexpected connection, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* Unexpected client connected. */ + if (mp->peer.s_addr != sin.sin_addr.s_addr) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4", + &sin.sin_addr); + } + close(sock); + + /* Unexpected peer, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + if (PIM_DEBUG_MSDP_INTERNAL) + zlog_debug("MSDP peer %s accept success", mp->key_str); + + /* Configure socket. */ + mp->fd = sock; + set_nonblocking(mp->fd); + pim_msdp_update_sock_send_buffer_size(mp->fd); + pim_msdp_peer_established(mp); + + /* Stop listening. */ + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; +} + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp) +{ + /* Clear any listening connection if it exists. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } + + /* Start new listening socket. */ + mp->auth_listen_sock = _pim_msdp_sock_listen(mp->pim->vrf, mp); + if (mp->auth_listen_sock == -1) + return -1; + + /* Listen for connections and connected only with the expected end. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + + return 0; +} + /* passive peer socket accept */ static void pim_msdp_sock_accept(struct event *thread) { @@ -91,6 +277,21 @@ static void pim_msdp_sock_accept(struct event *thread) return; } + /* + * If authentication is configured then we can not accept + * unauthenticated connections. + */ + if (mp->auth_type != MSDP_AUTH_NONE) { + ++pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer unauthenticated connection refused from %pSU", + &su); + } + close(msdp_sock); + return; + } + if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd >= 0 ? "(dup)" : ""); @@ -116,9 +317,6 @@ static void pim_msdp_sock_accept(struct event *thread) int pim_msdp_sock_listen(struct pim_instance *pim) { int sock; - int socklen; - struct sockaddr_in sin; - int rc; struct pim_msdp_listener *listener = &pim->msdp.listener; if (pim->msdp.flags & PIM_MSDPF_LISTENER) { @@ -126,72 +324,20 @@ int pim_msdp_sock_listen(struct pim_instance *pim) return 0; } - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno)); - return sock; - } + sock = _pim_msdp_sock_listen(pim->vrf, NULL); + if (sock == -1) + return -1; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons(PIM_MSDP_TCP_PORT); - socklen = sizeof(struct sockaddr_in); + + memset(&listener->su.sin, 0, sizeof(listener->su.sin)); + listener->su.sin.sin_family = AF_INET; + listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = socklen; + listener->su.sin.sin_len = sizeof(listener->su.sin); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sockopt_reuseaddr(sock); - sockopt_reuseport(sock); - - if (pim->vrf->vrf_id != VRF_DEFAULT) { - struct interface *ifp = - if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id); - if (!ifp) { - flog_err(EC_LIB_INTERFACE, - "%s: Unable to lookup vrf interface: %s", - __func__, pim->vrf->name); - close(sock); - return -1; - } - if (pim_socket_bind(sock, ifp)) { - flog_err_sys(EC_LIB_SOCKET, - "%s: Unable to bind to socket: %s", - __func__, safe_strerror(errno)); - close(sock); - return -1; - } - } - - frr_with_privs(&pimd_privs) { - /* bind to well known TCP port */ - rc = bind(sock, (struct sockaddr *)&sin, socklen); - } - - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, - "pim_msdp_socket bind to port %d: %s", - ntohs(sin.sin_port), safe_strerror(errno)); - close(sock); - return rc; - } - - rc = listen(sock, 3 /* backlog */); - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", - safe_strerror(errno)); - close(sock); - return rc; - } - - /* Set socket DSCP byte */ - if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { - zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", - sock, safe_strerror(errno)); - } - /* add accept thread */ listener->fd = sock; - memcpy(&listener->su, &sin, socklen); event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock, &listener->thread); @@ -272,6 +418,14 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) mp->fd, safe_strerror(errno)); } + /* Set authentication (if configured). */ + if (mp->auth_key) { + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(mp->fd, &mp->su_peer, + mp->auth_key); + } + } + /* Connect to the remote mp. */ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0)); diff --git a/pimd/pim_msdp_socket.h b/pimd/pim_msdp_socket.h index ae31664f9ce6..d2c601409a5a 100644 --- a/pimd/pim_msdp_socket.h +++ b/pimd/pim_msdp_socket.h @@ -6,6 +6,9 @@ #ifndef PIM_MSDP_SOCKET_H #define PIM_MSDP_SOCKET_H +struct pim_msdp_peer; + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp); int pim_msdp_sock_listen(struct pim_instance *pim); int pim_msdp_sock_connect(struct pim_msdp_peer *mp); #endif diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c index 6814798bf5f3..7a86e6b46ee5 100644 --- a/pimd/pim_msg.c +++ b/pimd/pim_msg.c @@ -185,84 +185,78 @@ size_t pim_msg_get_jp_group_size(struct list *sources) size += sizeof(pim_encoded_source) * sources->count; js = listgetdata(listhead(sources)); - if (js && pim_addr_is_any(js->up->sg.src) && js->is_join) { - struct pim_upstream *child, *up; - struct listnode *up_node; - - up = js->up; - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "%s: Considering (%s) children for (S,G,rpt) prune", - __func__, up->sg_str); - - for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) { - /* - * PIM VXLAN is weird - * It auto creates the S,G and populates a bunch - * of flags that make it look like a SPT prune should - * be sent. But this regularly scheduled join - * for the *,G in the VXLAN setup can happen at - * scheduled times *before* the null register - * is received by the RP to cause it to initiate - * the S,G joins toward the source. Let's just - * assume that if this is a SRC VXLAN ORIG route - * and no actual ifchannels( joins ) have been - * created then do not send the embedded prune - * Why you may ask? Well if the prune is S,G - * RPT Prune is received *before* the join - * from the RP( if it flows to this routers - * upstream interface ) then we'll just wisely - * create a mroute with an empty oil on - * the upstream intermediate router preventing - * packets from flowing to the RP + if (!js || !pim_addr_is_any(js->up->sg.src) || !js->is_join) + return size; + + struct pim_upstream *child, *up; + struct listnode *up_node; + + up = js->up; + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("%s: Considering (%s) children for (S,G,rpt) prune", + __func__, up->sg_str); + + for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) { + /* + * PIM VXLAN is weird + * It auto creates the S,G and populates a bunch + * of flags that make it look like a SPT prune should + * be sent. But this regularly scheduled join + * for the *,G in the VXLAN setup can happen at + * scheduled times *before* the null register + * is received by the RP to cause it to initiate + * the S,G joins toward the source. Let's just + * assume that if this is a SRC VXLAN ORIG route + * and no actual ifchannels( joins ) have been + * created then do not send the embedded prune + * Why you may ask? Well if the prune is S,G + * RPT Prune is received *before* the join + * from the RP( if it flows to this routers + * upstream interface ) then we'll just wisely + * create a mroute with an empty oil on + * the upstream intermediate router preventing + * packets from flowing to the RP + */ + if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(child->flags) && + listcount(child->ifchannels) == 0) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("%s: %s Vxlan originated S,G route with no ifchannels, not adding prune to compound message", + __func__, child->sg_str); + } else if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) { + /* If we are using SPT and the SPT and RPT IIFs + * are different we can prune the source off + * of the RPT. + * If RPF_interface(S) is not resolved hold + * decision to prune as SPT may end up on the + * same IIF as RPF_interface(RP). */ - if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(child->flags) && - listcount(child->ifchannels) == 0) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug("%s: %s Vxlan originated S,G route with no ifchannels, not adding prune to compound message", - __func__, child->sg_str); - } else if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) { - /* If we are using SPT and the SPT and RPT IIFs - * are different we can prune the source off - * of the RPT. - * If RPF_interface(S) is not resolved hold - * decision to prune as SPT may end up on the - * same IIF as RPF_interface(RP). - */ - if (child->rpf.source_nexthop.interface && - !pim_rpf_is_same(&up->rpf, - &child->rpf)) { - size += sizeof(pim_encoded_source); - PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( - child->flags); - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message", - __func__, up->sg_str, - child->sg_str); - } else if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", - __func__, up->sg_str, - child->sg_str); - } else if (pim_upstream_empty_inherited_olist(child)) { - /* S is supposed to be forwarded along the RPT - * but it's inherited OIL is empty. So just - * prune it off. - */ + if (child->rpf.source_nexthop.interface && + !pim_rpf_is_same(&up->rpf, &child->rpf)) { size += sizeof(pim_encoded_source); PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE( - child->flags); + child->flags); if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", - __func__, child->sg_str); + zlog_debug("%s: SPT Bit and RPF'(%s) != RPF'(S,G): Add Prune (%s,rpt) to compound message", + __func__, up->sg_str, + child->sg_str); } else if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "%s: Do not add Prune %s to compound message %s", - __func__, child->sg_str, up->sg_str); - } + zlog_debug("%s: SPT Bit and RPF'(%s) == RPF'(S,G): Not adding Prune for (%s,rpt)", + __func__, up->sg_str, child->sg_str); + } else if (pim_upstream_empty_inherited_olist(child)) { + /* S is supposed to be forwarded along the RPT + * but it's inherited OIL is empty. So just + * prune it off. + */ + size += sizeof(pim_encoded_source); + PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(child->flags); + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("%s: inherited_olist(%s,rpt) is NULL, Add Prune to compound message", + __func__, child->sg_str); + } else if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("%s: Do not add Prune %s to compound message %s", + __func__, child->sg_str, up->sg_str); } + return size; } diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 339935f81a57..c154c18afa8f 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -163,6 +163,33 @@ const struct frr_yang_module_info frr_pim_info = { .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in", + .cbs = { + .modify = pim_msdp_peer_sa_filter_in_modify, + .destroy = pim_msdp_peer_sa_filter_in_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out", + .cbs = { + .modify = pim_msdp_peer_sa_filter_out_modify, + .destroy = pim_msdp_peer_sa_filter_out_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type", + .cbs = { + .modify = pim_msdp_peer_authentication_type_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key", + .cbs = { + .modify = pim_msdp_peer_authentication_key_modify, + .destroy = pim_msdp_peer_authentication_key_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { @@ -413,6 +440,13 @@ const struct frr_yang_module_info frr_gmp_info = { .modify = lib_interface_gmp_address_family_robustness_variable_modify, } }, + { + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group", + .cbs = { + .create = lib_interface_gmp_address_family_join_group_create, + .destroy = lib_interface_gmp_address_family_join_group_destroy, + } + }, { .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group", .cbs = { @@ -425,4 +459,3 @@ const struct frr_yang_module_info frr_gmp_info = { }, } }; - diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 0321d076f0da..fc4c11cea94d 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -65,6 +65,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( @@ -175,6 +182,10 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify( struct nb_cb_modify_args *args); int lib_interface_gmp_address_family_robustness_variable_modify( struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_join_group_create( + struct nb_cb_create_args *args); +int lib_interface_gmp_address_family_join_group_destroy( + struct nb_cb_destroy_args *args); int lib_interface_gmp_address_family_static_group_create( struct nb_cb_create_args *args); int lib_interface_gmp_address_family_static_group_destroy( @@ -207,17 +218,16 @@ int routing_control_plane_protocols_name_validate( "./frr-pim:pim/address-family[address-family='%s']/" \ "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ - "/frr-routing:routing/control-plane-protocols/" \ - "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ - "frr-pim:pim/address-family[address-family='%s']/" \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" #define FRR_GMP_INTERFACE_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']" #define FRR_GMP_ENABLE_XPATH \ "%s/frr-gmp:gmp/address-family[address-family='%s']/enable" -#define FRR_GMP_JOIN_XPATH \ - "./frr-gmp:gmp/address-family[address-family='%s']/" \ +#define FRR_GMP_JOIN_GROUP_XPATH \ + "./frr-gmp:gmp/address-family[address-family='%s']/" \ + "join-group[group-addr='%s'][source-addr='%s']" +#define FRR_GMP_STATIC_GROUP_XPATH \ + "./frr-gmp:gmp/address-family[address-family='%s']/" \ "static-group[group-addr='%s'][source-addr='%s']" -#define FRR_PIM_MSDP_XPATH FRR_PIM_VRF_XPATH "/msdp" #endif /* _FRR_PIM_NB_H_ */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index be05b69401e4..037bfea7861a 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -9,12 +9,14 @@ #include "pimd.h" #include "pim_nb.h" #include "lib/northbound_cli.h" +#include "lib/sockopt.h" #include "pim_igmpv3.h" #include "pim_neighbor.h" #include "pim_nht.h" #include "pim_pim.h" #include "pim_mlag.h" #include "pim_bfd.h" +#include "pim_msdp_socket.h" #include "pim_static.h" #include "pim_ssm.h" #include "pim_ssmpingd.h" @@ -485,7 +487,7 @@ int routing_control_plane_protocols_name_validate( { const char *name; - name = yang_dnode_get_string(args->dnode, "./name"); + name = yang_dnode_get_string(args->dnode, "name"); if (!strmatch(name, "pim")) { snprintf(args->errmsg, args->errmsg_len, "pim supports only one instance with name pimd"); @@ -779,7 +781,7 @@ void routing_control_plane_protocols_control_plane_protocol_pim_address_family_s vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - spt_switch_action = yang_dnode_get_enum(args->dnode, "./spt-action"); + spt_switch_action = yang_dnode_get_enum(args->dnode, "spt-action"); switch (spt_switch_action) { case PIM_SPT_INFINITY: @@ -922,8 +924,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_pimaddr(&source_addr, args->dnode, - "./source-addr"); + yang_dnode_get_pimaddr(&source_addr, args->dnode, NULL); result = pim_ssmpingd_start(pim, source_addr); if (result) { snprintf( @@ -953,8 +954,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_pimaddr(&source_addr, args->dnode, - "./source-addr"); + yang_dnode_get_pimaddr(&source_addr, args->dnode, NULL); result = pim_ssmpingd_stop(pim, source_addr); if (result) { snprintf( @@ -1055,6 +1055,9 @@ pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address nb_cb_destroy_args); pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); #if PIM_IPV != 6 /* @@ -1156,6 +1159,81 @@ int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type + */ +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + mp->auth_type = yang_dnode_get_enum(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key + */ +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + if (strlen(yang_dnode_get_string(args->dnode, NULL)) > + TCP_MD5SIG_MAXKEYLEN) { + snprintf(args->errmsg, args->errmsg_len, + "MD5 authentication key too long"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + mp->auth_key = XSTRDUP(MTYPE_PIM_MSDP_AUTH_KEY, + yang_dnode_get_string(args->dnode, NULL)); + + /* We must start listening the new authentication key now. */ + if (PIM_MSDP_PEER_IS_LISTENER(mp)) + pim_msdp_sock_auth_listen(mp); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + break; + } + + return NB_OK; +} /* * XPath: @@ -1233,8 +1311,8 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_ip(&peer_ip, args->dnode, "./peer-ip"); - yang_dnode_get_ip(&source_ip, args->dnode, "./source-ip"); + yang_dnode_get_ip(&peer_ip, args->dnode, "peer-ip"); + yang_dnode_get_ip(&source_ip, args->dnode, "source-ip"); mp = pim_msdp_peer_add(pim, &peer_ip.ipaddr_v4, &source_ip.ipaddr_v4, NULL); nb_running_set_entry(args->dnode, mp); @@ -1288,6 +1366,94 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms } #endif /* PIM_IPV != 6 */ +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in + */ +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + mp->acl_in = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out + */ +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + mp->acl_out = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + break; + } + + return NB_OK; +} + /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ @@ -1338,16 +1504,16 @@ void routing_control_plane_protocols_control_plane_protocol_pim_address_family_m struct interface *ifp; struct ipaddr reg_addr; - ifname = yang_dnode_get_string(args->dnode, "./peerlink-rif"); + ifname = yang_dnode_get_string(args->dnode, "peerlink-rif"); ifp = if_lookup_by_name(ifname, VRF_DEFAULT); if (!ifp) { snprintf(args->errmsg, args->errmsg_len, "No such interface name %s", ifname); return; } - role = yang_dnode_get_enum(args->dnode, "./my-role"); - peer_state = yang_dnode_get_bool(args->dnode, "./peer-state"); - yang_dnode_get_ip(®_addr, args->dnode, "./reg-address"); + role = yang_dnode_get_enum(args->dnode, "my-role"); + peer_state = yang_dnode_get_bool(args->dnode, "peer-state"); + yang_dnode_get_ip(®_addr, args->dnode, "reg-address"); pim_vxlan_mlag_update(true, peer_state, role, ifp, ®_addr.ip._v4_addr); @@ -1506,11 +1672,19 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_re */ int lib_interface_pim_address_family_create(struct nb_cb_create_args *args) { + struct interface *ifp; + switch (args->event) { case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: case NB_EV_APPLY: + case NB_EV_ABORT: + break; + case NB_EV_PREPARE: + ifp = nb_running_get_entry(args->dnode, NULL, true); + if (ifp->info) + return NB_OK; + + pim_if_new(ifp, false, false, false, false); break; } @@ -1759,11 +1933,11 @@ void lib_interface_pim_address_family_bfd_apply_finish( } pim_ifp->bfd_config.detection_multiplier = - yang_dnode_get_uint8(args->dnode, "./detect_mult"); + yang_dnode_get_uint8(args->dnode, "detect_mult"); pim_ifp->bfd_config.min_rx = - yang_dnode_get_uint16(args->dnode, "./min-rx-interval"); + yang_dnode_get_uint16(args->dnode, "min-rx-interval"); pim_ifp->bfd_config.min_tx = - yang_dnode_get_uint16(args->dnode, "./min-tx-interval"); + yang_dnode_get_uint16(args->dnode, "min-tx-interval"); pim_bfd_reg_dereg_all_nbr(ifp); } @@ -2191,7 +2365,7 @@ int lib_interface_pim_address_family_mroute_destroy( pim_iifp = iif->info; pim = pim_iifp->pim; - oifname = yang_dnode_get_string(args->dnode, "./oif"); + oifname = yang_dnode_get_string(args->dnode, "oif"); oif = if_lookup_by_name(oifname, pim->vrf->vrf_id); if (!oif) { @@ -2201,8 +2375,8 @@ int lib_interface_pim_address_family_mroute_destroy( return NB_ERR_INCONSISTENCY; } - yang_dnode_get_pimaddr(&source_addr, args->dnode, "./source-addr"); - yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); + yang_dnode_get_pimaddr(&source_addr, args->dnode, "source-addr"); + yang_dnode_get_pimaddr(&group_addr, args->dnode, "group-addr"); if (pim_static_del(pim, iif, oif, group_addr, source_addr)) { snprintf(args->errmsg, args->errmsg_len, @@ -2341,9 +2515,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp case NB_EV_APPLY: vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; - yang_dnode_get_pimaddr(&rp_addr, args->dnode, "./rp-address"); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "rp-address"); - if (yang_dnode_get(args->dnode, "./group-list")) { + if (yang_dnode_get(args->dnode, "group-list")) { yang_dnode_get_prefix(&group, args->dnode, "./group-list"); apply_mask(&group); @@ -2352,7 +2526,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp args->errmsg_len); } - else if (yang_dnode_get(args->dnode, "./prefix-list")) { + else if (yang_dnode_get(args->dnode, "prefix-list")) { plist = yang_dnode_get_string(args->dnode, "./prefix-list"); if (!pim_get_all_mcast_group(&group)) { @@ -2815,9 +2989,9 @@ int lib_interface_gmp_address_family_robustness_variable_modify( } /* - * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group */ -int lib_interface_gmp_address_family_static_group_create( +int lib_interface_gmp_address_family_join_group_create( struct nb_cb_create_args *args) { struct interface *ifp; @@ -2875,7 +3049,7 @@ int lib_interface_gmp_address_family_static_group_create( return NB_OK; } -int lib_interface_gmp_address_family_static_group_destroy( +int lib_interface_gmp_address_family_join_group_destroy( struct nb_cb_destroy_args *args) { struct interface *ifp; @@ -2910,3 +3084,94 @@ int lib_interface_gmp_address_family_static_group_destroy( return NB_OK; } + +/* + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group + */ +int lib_interface_gmp_address_family_static_group_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + pim_addr source_addr; + pim_addr group_addr; + int result; + const char *ifp_name; + const struct lyd_node *if_dnode; + + switch (args->event) { + case NB_EV_VALIDATE: + if_dnode = yang_dnode_get_parent(args->dnode, "interface"); + if (!is_pim_interface(if_dnode)) { + ifp_name = yang_dnode_get_string(if_dnode, "name"); + snprintf(args->errmsg, args->errmsg_len, + "multicast not enabled on interface %s", + ifp_name); + return NB_ERR_VALIDATION; + } + + yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); +#if PIM_IPV == 4 + if (pim_is_group_224_0_0_0_24(group_addr)) { + snprintf(args->errmsg, args->errmsg_len, + "Groups within 224.0.0.0/24 are reserved and cannot be joined"); + return NB_ERR_VALIDATION; + } +#else + if (ipv6_mcast_reserved(&group_addr)) { + snprintf(args->errmsg, args->errmsg_len, + "Groups within ffx2::/16 are reserved and cannot be joined"); + return NB_ERR_VALIDATION; + } +#endif + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_pimaddr(&source_addr, args->dnode, + "./source-addr"); + yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); + result = pim_if_static_group_add(ifp, group_addr, source_addr); + if (result) { + snprintf(args->errmsg, args->errmsg_len, + "Failure adding static group"); + return NB_ERR_INCONSISTENCY; + } + } + return NB_OK; +} + +int lib_interface_gmp_address_family_static_group_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + pim_addr source_addr; + pim_addr group_addr; + int result; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_pimaddr(&source_addr, args->dnode, + "./source-addr"); + yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); + result = pim_if_static_group_del(ifp, group_addr, source_addr); + + if (result) { + snprintf(args->errmsg, args->errmsg_len, + "%% Failure removing static group %pPAs %pPAs on interface %s: %d", + &source_addr, &group_addr, ifp->name, result); + + return NB_ERR_INCONSISTENCY; + } + + break; + } + + return NB_OK; +} diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 4e8e5f0df735..57dcff3b4710 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -161,18 +161,27 @@ void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr) pnc->bsr_count++; } +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc; + + pnc = pim_nht_get(pim, addr); + + pnc->candrp_count++; + return CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID); +} + static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) { if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u", - __func__, &pnc->rpf.rpf_addr, pim->vrf->name, - pnc->rp_list->count, pnc->upstream_hash->count, - pnc->bsr_count); + zlog_debug("%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u Cand-RP count:%u", + __func__, &pnc->rpf.rpf_addr, pim->vrf->name, + pnc->rp_list->count, pnc->upstream_hash->count, + pnc->bsr_count, pnc->candrp_count); - if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 - && pnc->bsr_count == 0) { + if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 && + pnc->bsr_count == 0 && pnc->candrp_count == 0) { struct zclient *zclient = pim_zebra_zclient_get(); pim_sendmsg_zebra_rnh(pim, zclient, pnc, @@ -258,6 +267,27 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr) pim_nht_drop_maybe(pim, pnc); } +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; + + lookup.rpf.rpf_addr = addr; + + pnc = hash_lookup(pim->rpf_hash, &lookup); + + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT C-RP entry %pPA", + &addr); + return; + } + + assertf(pnc->candrp_count > 0, "addr=%pPA", &addr); + pnc->candrp_count--; + + pim_nht_drop_maybe(pim, pnc); +} + bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip) { @@ -338,7 +368,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, if (nh->ifindex == IFINDEX_INTERNAL) continue; - /* fallthru */ + fallthrough; case NEXTHOP_TYPE_IPV4_IFINDEX: nhaddr = nh->gate.ipv4; break; @@ -350,7 +380,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, if (nh->ifindex == IFINDEX_INTERNAL) continue; - /* fallthru */ + fallthrough; case NEXTHOP_TYPE_IPV6_IFINDEX: nhaddr = nh->gate.ipv6; break; @@ -723,7 +753,8 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, /* This API is used to parse Registered address nexthop update coming from Zebra */ -int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) +void pim_nexthop_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr) { struct nexthop *nexthop; struct nexthop *nhlist_head = NULL; @@ -732,38 +763,27 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) struct pim_rpf rpf; struct pim_nexthop_cache *pnc = NULL; struct interface *ifp = NULL; - struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct pim_instance *pim; - struct zapi_route nhr; - struct prefix match; - if (!vrf) - return 0; pim = vrf->info; - if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) { - zlog_err("%s: Decode of nexthop update from zebra failed", - __func__); - return 0; - } - - rpf.rpf_addr = pim_addr_from_prefix(&match); + rpf.rpf_addr = pim_addr_from_prefix(match); pnc = pim_nexthop_cache_find(pim, &rpf); if (!pnc) { if (PIM_DEBUG_PIM_NHT) zlog_debug( "%s: Skipping NHT update, addr %pPA is not in local cached DB.", __func__, &rpf.rpf_addr); - return 0; + return; } pnc->last_update = pim_time_monotonic_usec(); - if (nhr.nexthop_num) { + if (nhr->nexthop_num) { pnc->nexthop_num = 0; - for (i = 0; i < nhr.nexthop_num; i++) { - nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]); + for (i = 0; i < nhr->nexthop_num; i++) { + nexthop = nexthop_from_zapi_nexthop(&nhr->nexthops[i]); switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: /* @@ -842,11 +862,11 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) #else pim_addr nhaddr = nexthop->gate.ipv6; #endif - zlog_debug( - "%s: NHT addr %pFX(%s) %d-nhop via %pPA(%s) type %d distance:%u metric:%u ", - __func__, &match, pim->vrf->name, i + 1, - &nhaddr, ifp->name, nexthop->type, - nhr.distance, nhr.metric); + zlog_debug("%s: NHT addr %pFX(%s) %d-nhop via %pPA(%s) type %d distance:%u metric:%u ", + __func__, match, pim->vrf->name, + i + 1, &nhaddr, ifp->name, + nexthop->type, nhr->distance, + nhr->metric); } if (!ifp->info) { @@ -887,23 +907,22 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) pnc->nexthop = nhlist_head; if (pnc->nexthop_num) { pnc->flags |= PIM_NEXTHOP_VALID; - pnc->distance = nhr.distance; - pnc->metric = nhr.metric; + pnc->distance = nhr->distance; + pnc->metric = nhr->metric; } } else { pnc->flags &= ~PIM_NEXTHOP_VALID; - pnc->nexthop_num = nhr.nexthop_num; + pnc->nexthop_num = nhr->nexthop_num; nexthops_free(pnc->nexthop); pnc->nexthop = NULL; } SET_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED); if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d", - __func__, &match, pim->vrf->name, nhr.nexthop_num, - pnc->nexthop_num, vrf_id, pnc->upstream_hash->count, - listcount(pnc->rp_list)); + zlog_debug("%s: NHT Update for %pFX(%s) num_nh %d num_pim_nh %d vrf:%u up %ld rp %d", + __func__, match, pim->vrf->name, nhr->nexthop_num, + pnc->nexthop_num, vrf->vrf_id, + pnc->upstream_hash->count, listcount(pnc->rp_list)); pim_rpf_set_refresh_time(pim); @@ -912,7 +931,8 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS) if (pnc->upstream_hash->count) pim_update_upstream_nh(pim, pnc); - return 0; + if (pnc->candrp_count) + pim_crp_nht_update(pim, pnc); } int pim_ecmp_nexthop_lookup(struct pim_instance *pim, diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 5a54e1c67ad3..e74b375dc6d2 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -38,6 +38,7 @@ struct pim_nexthop_cache { * same BSR */ uint32_t bsr_count; + uint32_t candrp_count; }; struct pnc_hash_walk_data { @@ -45,7 +46,8 @@ struct pnc_hash_walk_data { struct interface *ifp; }; -int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS); +void pim_nexthop_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr); int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr, struct pim_upstream *up, struct rp_info *rp, struct pim_nexthop_cache *out_pnc); @@ -70,4 +72,10 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr); bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip); void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp); + +/* wrappers for usage with Candidate RPs in BSMs */ +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr); +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr); +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc); + #endif diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index a4c9178bb9fc..6a7e8924f2f6 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -636,17 +636,15 @@ static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp) { - struct pim_interface *pim_ifp; - - - pim_ifp = ifp->info; + if (ifp) { + struct pim_interface *pim_ifp = ifp->info; - if (pim_ifp->pim_passive_enable) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "skip sending PIM message on passive interface %s", - ifp->name); - return 0; + if (pim_ifp->pim_passive_enable) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("skip sending PIM message on passive interface %s", + ifp->name); + return 0; + } } #if PIM_IPV == 4 @@ -710,7 +708,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x", - __func__, &dst, ifp->name, pim_msg_size, + __func__, &dst, ifp ? ifp->name : "*", pim_msg_size, header->checksum); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { @@ -718,7 +716,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, } pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, - tolen, ifp->name); + tolen, ifp ? ifp->name : "*"); return 0; #else @@ -727,7 +725,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, iovector[0].iov_base = pim_msg; iovector[0].iov_len = pim_msg_size; - pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); + pim_msg_send_frame(src, dst, ifp ? ifp->ifindex : 0, &iovector[0], fd); return 0; #endif @@ -743,14 +741,13 @@ static int hello_send(struct interface *ifp, uint16_t holdtime) pim_ifp = ifp->info; if (PIM_DEBUG_PIM_HELLO) - zlog_debug( - "%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", - __func__, &qpim_all_pim_routers_addr, ifp->name, - holdtime, pim_ifp->pim_propagation_delay_msec, - pim_ifp->pim_override_interval_msec, - pim_ifp->pim_can_disable_join_suppression, - pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, - listcount(ifp->connected)); + zlog_debug("%s: to %pPA on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%zu", + __func__, &qpim_all_pim_routers_addr, ifp->name, + holdtime, pim_ifp->pim_propagation_delay_msec, + pim_ifp->pim_override_interval_msec, + pim_ifp->pim_can_disable_join_suppression, + pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, + if_connected_count(ifp->connected)); pim_tlv_size = pim_hello_build_tlv( ifp, pim_msg + PIM_PIM_MIN_LEN, diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 1f69175829a4..b149b5a2a97c 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -109,12 +109,12 @@ static void pim_reg_stop_upstream(struct pim_instance *pim, up->reg_state = PIM_REG_PRUNE; pim_channel_del_oif(up->channel_oil, pim->regiface, PIM_OIF_FLAG_PROTO_PIM, __func__); - pim_upstream_start_register_stop_timer(up, 0); + pim_upstream_start_register_probe_timer(up); pim_vxlan_update_sg_reg_state(pim, up, false); break; case PIM_REG_JOIN_PENDING: up->reg_state = PIM_REG_PRUNE; - pim_upstream_start_register_stop_timer(up, 0); + pim_upstream_start_register_probe_timer(up); return; } } @@ -416,11 +416,8 @@ void pim_null_register_send(struct pim_upstream *up) memset(buffer, 0, (sizeof(ip6_hdr) + sizeof(pim_msg_header))); memcpy(buffer, &ip6_hdr, sizeof(ip6_hdr)); - pim_msg_header.ver = 0; - pim_msg_header.type = 0; - pim_msg_header.reserved = 0; - - pim_msg_header.checksum = 0; + memset(&pim_msg_header, 0, sizeof(pim_msg_header)); + memset(&ph, 0, sizeof(ph)); ph.src = up->sg.src; ph.dst = up->sg.grp; diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index c7516242f5ca..0f8940bb16d7 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -248,7 +248,7 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, } rp_info = rn->info; - if (PIM_DEBUG_PIM_TRACE) { + if (PIM_DEBUG_PIM_TRACE_DETAIL) { if (best) zlog_debug( "Lookedup(%pFX): prefix_list match %s, rn %p found: %pFX", @@ -543,6 +543,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_all); + if (rp_all->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_all->rp.rpf_addr, &rp_all->group); pim_rp_refresh_group_to_rp_mapping(pim); pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all, NULL); @@ -634,6 +637,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_info); + if (rp_info->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_info->rp.rpf_addr, &rp_info->group); pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ @@ -1101,16 +1107,17 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, pim_addr source, pim_addr group) { struct rp_info *rp_info; - struct prefix g; + struct prefix g = {}; - memset(&g, 0, sizeof(g)); + if (!pim_addr_is_any(source)) { + *up = source; + return 1; + } pim_addr_to_prefix(&g, group); - rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && - (pim_addr_is_any(source)))) { + if (!rp_info || pim_rpf_addr_is_inaddr_any(&rp_info->rp)) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); @@ -1118,16 +1125,11 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, return 0; } - if (pim_addr_is_any(source)) - *up = rp_info->rp.rpf_addr; - else - *up = source; - + *up = rp_info->rp.rpf_addr; return 1; } -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct rp_info *rp_info; @@ -1143,13 +1145,11 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, rp_addr = rp_info->rp.rpf_addr; if (rp_info->plist) - vty_out(vty, - "%s" PIM_AF_NAME - " pim rp %pPA prefix-list %s\n", - spaces, &rp_addr, rp_info->plist); + vty_out(vty, " rp %pPA prefix-list %s\n", &rp_addr, + rp_info->plist); else - vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", - spaces, &rp_addr, &rp_info->group); + vty_out(vty, " rp %pPA %pFX\n", &rp_addr, + &rp_info->group); count++; } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 9416a9a8a87e..32c6306740d6 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -46,8 +46,7 @@ int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, void pim_rp_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty); void pim_rp_setup(struct pim_instance *pim); diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index b17ae3131f02..d18ec4943a94 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -32,7 +32,7 @@ static pim_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); void pim_rpf_set_refresh_time(struct pim_instance *pim) { pim->last_route_change_time = pim_time_monotonic_usec(); - if (PIM_DEBUG_PIM_TRACE) + if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug("%s: vrf(%s) New last route change time: %" PRId64, __func__, pim->vrf->name, pim->last_route_change_time); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 6c65c5d3e967..3476c177b74c 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -5,6 +5,7 @@ */ #include +#include #include #include diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 80d60b862833..c463fa227c4c 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -217,18 +217,17 @@ int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct interface *ifp, int family) { - struct listnode *node; uint16_t option_len = 0; uint8_t *curr; size_t uel; - struct list *ifconnected = ifp->connected; + struct connected *ifc; struct pim_interface *pim_ifp = ifp->info; pim_addr addr; - node = listhead(ifconnected); + ifc = if_connected_first(ifp->connected); /* Empty address list ? */ - if (!node) { + if (!ifc) { return buf; } @@ -239,8 +238,7 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, /* Scan secondary address list */ curr = buf + 4; /* skip T and L */ - for (; node; node = listnextnode(node)) { - struct connected *ifc = listgetdata(node); + for (; ifc; ifc = if_connected_next(ifp->connected, ifc)) { struct prefix *p = ifc->address; int l_encode; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 743a047b0acb..7417f311377f 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -17,6 +17,7 @@ #include "jhash.h" #include "wheel.h" #include "network.h" +#include "frrdistance.h" #include "pimd.h" #include "pim_pim.h" @@ -662,10 +663,9 @@ void pim_upstream_update_use_rpt(struct pim_upstream *up, new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags); if (old_use_rpt != new_use_rpt) { if (PIM_DEBUG_PIM_EVENTS) - zlog_debug("%s switched from %s to %s", - up->sg_str, - old_use_rpt?"RPT":"SPT", - new_use_rpt?"RPT":"SPT"); + zlog_debug("%s switched from %s to %s", up->sg_str, + old_use_rpt ? "RPT" : "SPT", + new_use_rpt ? "RPT" : "SPT"); if (update_mroute) pim_upstream_mroute_add(up->channel_oil, __func__); } @@ -904,9 +904,15 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, false /*update_mroute*/); pim_upstream_mroute_iif_update(up->channel_oil, __func__); - if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) + if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) { + /* + * Set the right RPF so that future changes will + * be right + */ + (void)pim_rpf_update(pim, up, NULL, __func__); pim_upstream_keep_alive_timer_start( up, pim->keep_alive_time); + } } else if (!pim_addr_is_any(up->upstream_addr)) { pim_upstream_update_use_rpt(up, false /*update_mroute*/); @@ -1681,6 +1687,8 @@ const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str, return state_str; } +static void pim_upstream_start_register_stop_timer(struct pim_upstream *up); + static void pim_upstream_register_stop_timer(struct event *t) { struct pim_interface *pim_ifp; @@ -1728,7 +1736,7 @@ static void pim_upstream_register_stop_timer(struct event *t) return; } up->reg_state = PIM_REG_JOIN_PENDING; - pim_upstream_start_register_stop_timer(up, 1); + pim_upstream_start_register_stop_timer(up); if (((up->channel_oil->cc.lastused / 100) > pim->keep_alive_time) @@ -1746,34 +1754,59 @@ static void pim_upstream_register_stop_timer(struct event *t) } } -void pim_upstream_start_register_stop_timer(struct pim_upstream *up, - int null_register) +static void pim_upstream_start_register_stop_timer(struct pim_upstream *up) { uint32_t time; EVENT_OFF(up->t_rs_timer); - if (!null_register) { - uint32_t lower = (0.5 * router->register_suppress_time); - uint32_t upper = (1.5 * router->register_suppress_time); - time = lower + (frr_weak_random() % (upper - lower + 1)); - /* Make sure we don't wrap around */ - if (time >= router->register_probe_time) - time -= router->register_probe_time; - else - time = 0; - } else - time = router->register_probe_time; + time = router->register_probe_time; - if (PIM_DEBUG_PIM_TRACE) { - zlog_debug( - "%s: (S,G)=%s Starting upstream register stop timer %d", - __func__, up->sg_str, time); - } + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: (S,G)=%s Starting upstream register stop timer %d", + __func__, up->sg_str, time); event_add_timer(router->master, pim_upstream_register_stop_timer, up, time, &up->t_rs_timer); } +static void pim_upstream_register_probe_timer(struct event *t) +{ + struct pim_upstream *up = EVENT_ARG(t); + + if (!up->rpf.source_nexthop.interface || + !up->rpf.source_nexthop.interface->info) { + if (PIM_DEBUG_PIM_REG) + zlog_debug("cannot send Null register for %pSG, no path to RP", + &up->sg); + } else + pim_null_register_send(up); + + pim_upstream_start_register_stop_timer(up); +} + +void pim_upstream_start_register_probe_timer(struct pim_upstream *up) +{ + uint32_t time; + + EVENT_OFF(up->t_rs_timer); + + uint32_t lower = (0.5 * router->register_suppress_time); + uint32_t upper = (1.5 * router->register_suppress_time); + time = lower + (frr_weak_random() % (upper - lower + 1)); + /* Make sure we don't wrap around */ + if (time >= router->register_probe_time) + time -= router->register_probe_time; + else + time = 0; + + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: (S,G)=%s Starting upstream register stop null probe timer %d", + __func__, up->sg_str, time); + + event_add_timer(router->master, pim_upstream_register_probe_timer, up, + time, &up->t_rs_timer); +} + int pim_upstream_inherited_olist_decide(struct pim_instance *pim, struct pim_upstream *up) { @@ -1938,6 +1971,40 @@ void pim_upstream_terminate(struct pim_instance *pim) wheel_delete(pim->upstream_sg_wheel); pim->upstream_sg_wheel = NULL; } +bool pim_sg_is_reevaluate_oil_req(struct pim_instance *pim, + struct pim_upstream *up) +{ + struct pim_interface *pim_ifp = NULL; + + /* + * Attempt to retrieve the PIM interface information if the RPF + * interface is present + */ + if (up->rpf.source_nexthop.interface) { + pim_ifp = up->rpf.source_nexthop.interface->info; + } else { + if (PIM_DEBUG_PIM_TRACE) { + zlog_debug("%s: up %s RPF is not present", __func__, + up->sg_str); + } + } + + /* + * Determine if a reevaluation of the outgoing interface list (OIL) is + * required. This may be necessary in scenarios such as MSDP where the + * RP role for a group changes from secondary to primary. In such cases, + * SGRpt may receive a prune, resulting in an S,G entry with a NULL OIL. + * The S,G upstream should then inherit the OIL from *,G, which is + * particularly important for VXLAN setups. + */ + if (up->channel_oil->oil_inherited_rescan || + (pim_ifp && I_am_RP(pim_ifp->pim, up->sg.grp)) || + pim_upstream_empty_inherited_olist(up)) { + return true; + } + + return false; +} bool pim_upstream_equal(const void *arg1, const void *arg2) { @@ -2073,7 +2140,7 @@ static void pim_upstream_sg_running(void *arg) * only doing this at this point in time * to get us up and working for the moment */ - if (up->channel_oil->oil_inherited_rescan) { + if (pim_sg_is_reevaluate_oil_req(pim, up)) { if (PIM_DEBUG_TRACE) zlog_debug( "%s: Handling unscanned inherited_olist for %s[%s]", diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 4e0926e29483..8b4a35be398c 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -331,8 +331,7 @@ int pim_upstream_is_sg_rpt(struct pim_upstream *up); void pim_upstream_set_sptbit(struct pim_upstream *up, struct interface *incoming); -void pim_upstream_start_register_stop_timer(struct pim_upstream *up, - int null_register); +void pim_upstream_start_register_probe_timer(struct pim_upstream *up); void pim_upstream_send_join(struct pim_upstream *up); @@ -383,4 +382,6 @@ uint32_t pim_up_mlag_local_cost(struct pim_upstream *up); uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up); void pim_upstream_reeval_use_rpt(struct pim_instance *pim); int pim_upstream_could_register(struct pim_upstream *up); +bool pim_sg_is_reevaluate_oil_req(struct pim_instance *pim, + struct pim_upstream *up); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 0f6547ee2e9a..9cf4bb3e874a 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -172,89 +172,66 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) { int writes = 0; struct pim_ssm *ssm = pim->ssm_info; - char spaces[10]; - if (pim->vrf->vrf_id == VRF_DEFAULT) - snprintf(spaces, sizeof(spaces), "%s", ""); - else - snprintf(spaces, sizeof(spaces), "%s", " "); - - writes += pim_msdp_peer_config_write(vty, pim, spaces); - writes += pim_msdp_config_write(pim, vty, spaces); + writes += pim_msdp_peer_config_write(vty, pim); + writes += pim_msdp_config_write(pim, vty); if (!pim->send_v6_secondary) { - vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces); + vty_out(vty, " no send-v6-secondary\n"); ++writes; } - writes += pim_rp_config_write(pim, vty, spaces); + writes += pim_rp_config_write(pim, vty); if (pim->vrf->vrf_id == VRF_DEFAULT) { if (router->register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { - vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n", - spaces, router->register_suppress_time); + vty_out(vty, " register-suppress-time %d\n", + router->register_suppress_time); ++writes; } if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) { - vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n", - spaces, router->t_periodic); + vty_out(vty, " join-prune-interval %d\n", + router->t_periodic); ++writes; } if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) { - vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces, - router->packet_process); + vty_out(vty, " packets %d\n", router->packet_process); ++writes; } } if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n", - spaces, pim->keep_alive_time); + vty_out(vty, " keep-alive-timer %d\n", pim->keep_alive_time); ++writes; } if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n", - spaces, pim->rp_keep_alive_time); + vty_out(vty, " rp keep-alive-timer %d\n", + pim->rp_keep_alive_time); ++writes; } if (ssm->plist_name) { - vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces, - ssm->plist_name); + vty_out(vty, " ssm prefix-list %s\n", ssm->plist_name); ++writes; } if (pim->register_plist) { - vty_out(vty, "%sip pim register-accept-list %s\n", spaces, - pim->register_plist); + vty_out(vty, " register-accept-list %s\n", pim->register_plist); ++writes; } if (pim->spt.switchover == PIM_SPT_INFINITY) { if (pim->spt.plist) vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n", - spaces, pim->spt.plist); + " spt-switchover infinity-and-beyond prefix-list %s\n", + pim->spt.plist); else - vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n", - spaces); + vty_out(vty, " spt-switchover infinity-and-beyond\n"); ++writes; } if (pim->ecmp_rebalance_enable) { - vty_out(vty, "%sip pim ecmp rebalance\n", spaces); + vty_out(vty, " ecmp rebalance\n"); ++writes; } else if (pim->ecmp_enable) { - vty_out(vty, "%sip pim ecmp\n", spaces); - ++writes; - } - - if (pim->gm_watermark_limit != 0) { -#if PIM_IPV == 4 - vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#else - vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#endif + vty_out(vty, " ecmp\n"); ++writes; } @@ -263,8 +240,7 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) struct ssmpingd_sock *ss; ++writes; for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { - vty_out(vty, "%s" PIM_AF_NAME " ssmpingd %pPA\n", - spaces, &ss->source_addr); + vty_out(vty, " ssmpingd %pPA\n", &ss->source_addr); ++writes; } } @@ -272,8 +248,8 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { - vty_out(vty, "%sip msdp timers %u %u", spaces, - pim->msdp.hold_time, pim->msdp.keep_alive); + vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, + pim->msdp.keep_alive); if (pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) vty_out(vty, " %u", pim->msdp.connection_retry); @@ -330,21 +306,38 @@ static int gm_config_write(struct vty *vty, int writes, ++writes; } - /* IF ip igmp join */ + /* IF ip igmp join-group */ if (pim_ifp->gm_join_list) { struct listnode *node; struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { if (pim_addr_is_any(ij->source_addr)) - vty_out(vty, " ip igmp join %pPAs\n", + vty_out(vty, " ip igmp join-group %pPAs\n", &ij->group_addr); else - vty_out(vty, " ip igmp join %pPAs %pPAs\n", + vty_out(vty, " ip igmp join-group %pPAs %pPAs\n", &ij->group_addr, &ij->source_addr); ++writes; } } + /* IF ip igmp static-group */ + if (pim_ifp->static_group_list) { + struct listnode *node; + struct static_group *stgrp; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node, + stgrp)) { + if (pim_addr_is_any(stgrp->source_addr)) + vty_out(vty, " ip igmp static-group %pPAs\n", + &stgrp->group_addr); + else + vty_out(vty, + " ip igmp static-group %pPAs %pPAs\n", + &stgrp->group_addr, &stgrp->source_addr); + ++writes; + } + } + return writes; } #else @@ -382,21 +375,41 @@ static int gm_config_write(struct vty *vty, int writes, vty_out(vty, " ipv6 mld last-member-query-interval %d\n", pim_ifp->gm_specific_query_max_response_time_dsec); - /* IF ipv6 mld join */ + /* IF ipv6 mld join-group */ if (pim_ifp->gm_join_list) { struct listnode *node; struct gm_join *ij; + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) { if (pim_addr_is_any(ij->source_addr)) - vty_out(vty, " ipv6 mld join %pPAs\n", + vty_out(vty, " ipv6 mld join-group %pPAs\n", &ij->group_addr); else - vty_out(vty, " ipv6 mld join %pPAs %pPAs\n", + vty_out(vty, + " ipv6 mld join-group %pPAs %pPAs\n", &ij->group_addr, &ij->source_addr); ++writes; } } + /* IF ipv6 mld static-group */ + if (pim_ifp->static_group_list) { + struct listnode *node; + struct static_group *stgrp; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node, + stgrp)) { + if (pim_addr_is_any(stgrp->source_addr)) + vty_out(vty, " ipv6 mld static-group %pPAs\n", + &stgrp->group_addr); + else + vty_out(vty, + " ipv6 mld static-group %pPAs %pPAs\n", + &stgrp->group_addr, &stgrp->source_addr); + ++writes; + } + } + return writes; } #endif diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 9650da89a8ab..f1f315cc9810 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -32,6 +32,30 @@ static void pim_vxlan_work_timer_setup(bool start); static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim, struct interface *ifp); +#define PIM_VXLAN_STARTUP_NULL_REGISTERS 10 + +static void pim_vxlan_rp_send_null_register_startup(struct event *e) +{ + struct pim_vxlan_sg *vxlan_sg = EVENT_ARG(e); + + vxlan_sg->null_register_sent++; + + if (vxlan_sg->null_register_sent > PIM_VXLAN_STARTUP_NULL_REGISTERS) { + if (PIM_DEBUG_VXLAN) + zlog_debug("Null registering stopping for %s", + vxlan_sg->sg_str); + return; + } + + pim_null_register_send(vxlan_sg->up); + + if (PIM_DEBUG_VXLAN) + zlog_debug("Sent null register for %s", vxlan_sg->sg_str); + + event_add_timer(router->master, pim_vxlan_rp_send_null_register_startup, + vxlan_sg, PIM_VXLAN_WORK_TIME, &vxlan_sg->null_register); +} + /* * The rp info has gone from no path to having a * path. Let's immediately send out the null pim register @@ -61,8 +85,13 @@ void pim_vxlan_rp_info_is_alive(struct pim_instance *pim, * If the rp is the same we should send */ if (rpg == rpg_changed) { - zlog_debug("VXLAN RP INFO is alive sending"); - pim_null_register_send(vxlan_sg->up); + if (PIM_DEBUG_VXLAN) + zlog_debug("VXLAN RP info for %s alive sending", + vxlan_sg->sg_str); + vxlan_sg->null_register_sent = 0; + event_add_event(router->master, + pim_vxlan_rp_send_null_register_startup, + vxlan_sg, 0, &vxlan_sg->null_register); } } } @@ -201,8 +230,18 @@ void pim_vxlan_update_sg_reg_state(struct pim_instance *pim, */ if (reg_join) pim_vxlan_add_work(vxlan_sg); - else + else { + /* + * Stop the event that is sending NULL Registers on startup + * there is no need to keep spamming it + */ + if (PIM_DEBUG_VXLAN) + zlog_debug("Received Register stop for %s", + vxlan_sg->sg_str); + + EVENT_OFF(vxlan_sg->null_register); pim_vxlan_del_work(vxlan_sg); + } } static void pim_vxlan_work_timer_cb(struct event *t) @@ -804,6 +843,7 @@ static void pim_vxlan_sg_del_item(struct pim_vxlan_sg *vxlan_sg) { vxlan_sg->flags |= PIM_VXLAN_SGF_DEL_IN_PROG; + EVENT_OFF(vxlan_sg->null_register); pim_vxlan_del_work(vxlan_sg); if (pim_vxlan_is_orig_mroute(vxlan_sg)) @@ -1210,6 +1250,9 @@ void pim_vxlan_exit(struct pim_instance *pim) { hash_clean_and_free(&pim->vxlan.sg_hash, (void (*)(void *))pim_vxlan_sg_del_item); + + if (vxlan_info.work_list) + list_delete(&vxlan_info.work_list); } void pim_vxlan_terminate(void) diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h index 5039bf654097..fe3d6254fab7 100644 --- a/pimd/pim_vxlan.h +++ b/pimd/pim_vxlan.h @@ -49,6 +49,9 @@ struct pim_vxlan_sg { struct interface *iif; /* on a MLAG setup the peerlink is added as a static OIF */ struct interface *orig_oif; + + struct event *null_register; + uint32_t null_register_sent; }; enum pim_vxlan_mlag_flags { diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 92dcbf9d1d5b..04cd087e6a07 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -51,49 +51,15 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS) return 0; } -static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - struct pim_instance *pim; - struct pim_interface *pim_ifp; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (PIM_DEBUG_ZEBRA) - zlog_debug("%s: %s updating from %u to %u", __func__, ifp->name, - vrf_id, new_vrf_id); - - pim = pim_get_pim_instance(new_vrf_id); - if (!pim) - return 0; - - if_update_to_new_vrf(ifp, new_vrf_id); - - pim_ifp = ifp->info; - if (!pim_ifp) - return 0; - - pim_ifp->pim->mcast_if_count--; - pim_ifp->pim = pim; - pim_ifp->pim->mcast_if_count++; - - return 0; -} - #ifdef PIM_DEBUG_IFADDR_DUMP static void dump_if_address(struct interface *ifp) { struct connected *ifc; - struct listnode *node; zlog_debug("%s %s: interface %s addresses:", __FILE__, __func__, ifp->name); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { struct prefix *p = ifc->address; if (p->family != AF_INET) @@ -130,8 +96,8 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) p = c->address; if (PIM_DEBUG_ZEBRA) { - zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s", - __func__, c->ifp->name, vrf_id, p, c->flags, + zlog_debug("%s: %s(%s) connected IP address %pFX flags %u %s", + __func__, c->ifp->name, VRF_LOGNAME(pim_ifp->pim->vrf), p, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); @@ -216,8 +182,8 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS) if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s(%u) disconnected IP address %pFX flags %u %s", - __func__, c->ifp->name, vrf_id, p, c->flags, + "%s: %s(%s) disconnected IP address %pFX flags %u %s", + __func__, c->ifp->name, VRF_LOGNAME(vrf), p, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); @@ -359,7 +325,7 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) stream_get(&sg.grp, s, prefixlen); if (PIM_DEBUG_ZEBRA) - zlog_debug("%u:recv SG %s %pSG", vrf_id, + zlog_debug("%s:recv SG %s %pSG", VRF_LOGNAME(pim->vrf), (cmd == ZEBRA_VXLAN_SG_ADD) ? "add" : "del", &sg); if (cmd == ZEBRA_VXLAN_SG_ADD) @@ -461,9 +427,7 @@ static zclient_handler *const pim_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del, - [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update, [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra, - [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update, #if PIM_IPV == 4 [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc, @@ -483,6 +447,7 @@ void pim_zebra_init(void) zclient->zebra_capabilities = pim_zebra_capabilities; zclient->zebra_connected = pim_zebra_connected; + zclient->nexthop_update = pim_nexthop_update; zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs); if (PIM_DEBUG_PIM_TRACE) { diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 6a026f994767..c19119fa4788 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -122,10 +122,7 @@ void zclient_lookup_free(void) void zclient_lookup_new(void) { - struct zclient_options options = zclient_options_default; - options.synchronous = true; - - zlookup = zclient_new(router->master, &options, NULL, 0); + zlookup = zclient_new(router->master, &zclient_options_sync, NULL, 0); if (!zlookup) { flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_new() failure", __func__); diff --git a/pimd/pimd.h b/pimd/pimd.h index 9ec84fc0a685..3d9318953bb7 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -19,9 +19,6 @@ #include "pim_memory.h" #include "pim_assert.h" -#define PIMD_VTY_PORT 2611 -#define PIM6D_VTY_PORT 2622 - #define PIM_IP_PROTO_IGMP (2) #define PIM_IP_PROTO_PIM (103) #define PIM_IGMP_MIN_LEN (8) diff --git a/pkgsrc/bgpd.sh.in b/pkgsrc/bgpd.sh.in index d234b5435c33..a8ba7c68f095 100644 --- a/pkgsrc/bgpd.sh.in +++ b/pkgsrc/bgpd.sh.in @@ -16,7 +16,7 @@ fi name="bgpd" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/eigrpd.sh.in b/pkgsrc/eigrpd.sh.in index b28b81eeda98..dd8caf87faa3 100644 --- a/pkgsrc/eigrpd.sh.in +++ b/pkgsrc/eigrpd.sh.in @@ -16,7 +16,7 @@ fi name="eigrpd" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/mgmtd.sh.in b/pkgsrc/mgmtd.sh.in index fb57c0a2fbda..313633a7823d 100644 --- a/pkgsrc/mgmtd.sh.in +++ b/pkgsrc/mgmtd.sh.in @@ -16,7 +16,7 @@ fi name="mgmtd" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/ospf6d.sh.in b/pkgsrc/ospf6d.sh.in index 3fbdb81b7fd7..c9854ed793ab 100644 --- a/pkgsrc/ospf6d.sh.in +++ b/pkgsrc/ospf6d.sh.in @@ -16,7 +16,7 @@ fi name="ospf6d" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/ospfd.sh.in b/pkgsrc/ospfd.sh.in index daa2252091b8..07dee55574d2 100644 --- a/pkgsrc/ospfd.sh.in +++ b/pkgsrc/ospfd.sh.in @@ -16,7 +16,7 @@ fi name="ospfd" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/ripd.sh.in b/pkgsrc/ripd.sh.in index 31575419fc61..6c9b580a31af 100644 --- a/pkgsrc/ripd.sh.in +++ b/pkgsrc/ripd.sh.in @@ -16,7 +16,7 @@ fi name="ripd" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/ripngd.sh.in b/pkgsrc/ripngd.sh.in index d06ac90b02d4..d316d460140b 100644 --- a/pkgsrc/ripngd.sh.in +++ b/pkgsrc/ripngd.sh.in @@ -16,7 +16,7 @@ fi name="ripngd" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/pkgsrc/zebra.sh.in b/pkgsrc/zebra.sh.in index c2f12a78335b..7a241067825f 100644 --- a/pkgsrc/zebra.sh.in +++ b/pkgsrc/zebra.sh.in @@ -16,7 +16,7 @@ fi name="zebra" rcvar=$name -required_files="@sysconfdir@/${name}.conf" +required_files="@e_sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" diff --git a/python/clippy/__init__.py b/python/clippy/__init__.py index 60119fbac097..668724ab2ab8 100644 --- a/python/clippy/__init__.py +++ b/python/clippy/__init__.py @@ -20,6 +20,7 @@ CMD_ATTR_HIDDEN, CMD_ATTR_DEPRECATED, CMD_ATTR_NOSH, + elf_notes, ) diff --git a/python/clippy/elf.py b/python/clippy/elf.py index cc442eeda9aa..fd348428f0ad 100644 --- a/python/clippy/elf.py +++ b/python/clippy/elf.py @@ -458,7 +458,16 @@ def __getitem__(self, k): - `this[123:str]` - extract until null byte. The slice stop value is the `str` type (or, technically, `unicode`.) """ - return self._obj[k] + if k.start < getattr(self._obj, "len", float("+Inf")): + return self._obj[k] + + real_sect = self._elffile.get_section_addr(self._obj.sh_addr + k.start) + offs = self._obj.sh_addr - real_sect.sh_addr + if k.stop is str: + new_k = slice(k.start + offs, str) + else: + new_k = slice(k.start + offs, k.stop + offs) + return real_sect[new_k] def getreloc(self, offset): """ diff --git a/python/firstheader.py b/python/firstheader.py index 06e28958452e..1a3cadfd5e89 100644 --- a/python/firstheader.py +++ b/python/firstheader.py @@ -15,7 +15,7 @@ argp.add_argument("--warn-empty", action="store_const", const=True) argp.add_argument("--pipe", action="store_const", const=True) -include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M) +include_re = re.compile(r'^#\s*include\s+["<]([^ ">]+)[">]', re.M) ignore = [ lambda fn: fn.startswith("tools/"), diff --git a/python/makefile.py b/python/makefile.py index 573871fb68c7..45f032296f3b 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -91,7 +91,7 @@ autoderp = "#AUTODERP# " out_lines = [] bcdeps = [] -make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)") +make_rule_re = re.compile(r"^([^:\s]+):\s*([^:\s]+)\s*($|\n)") while lines: line = lines.pop(0) diff --git a/python/tsexpand.py b/python/tsexpand.py new file mode 100644 index 000000000000..5d6099750fb9 --- /dev/null +++ b/python/tsexpand.py @@ -0,0 +1,131 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: MIT +# +# 2024 by David Lamparter +# +# this tool edits an FRR source .c file to expand the typesafe DECLARE_DLIST +# et al. definitions. This can be helpful to get better warnings/errors from +# GCC when something re. a typesafe container is involved. You can also use +# it on .h files. +# The actual expansions created by this tool are written to separate files +# called something like "lib/cspf__visited_tsexpand.h" (for a container named +# "visited") +# +# THIS TOOL EDITS THE FILE IN PLACE. MAKE A BACKUP IF YOU HAVE UNSAVED WORK +# IN PROGRESS (which is likely because you're debugging a typesafe container +# problem!) +# +# The PREDECL_XYZ is irrelevant for this tool, it needs to be run on the file +# that has the DECLARE_XYZ (can be .c or .h) +# +# the lines added by this tool all have /* $ts_expand: remove$ */ at the end +# you can undo the effects of this tool by calling sed: +# +# sed -e '/\$ts_expand: remove\$/ d' -i.orig filename.c + +import os +import sys +import re +import subprocess +import shlex + +decl_re = re.compile( + r"""(?<=\n)[ \t]*DECLARE_(LIST|ATOMLIST|DLIST|HEAP|HASH|(SORTLIST|SKIPLIST|RBTREE|ATOMSORT)_(NON)?UNIQ)\(\s*(?P[^, \t\n]+)\s*,[^)]+\)\s*;[ \t]*\n""" +) +kill_re = re.compile(r"""(?<=\n)[^\n]*/\* \$ts_expand: remove\$ \*/\n""") + +src_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# some files may be compiled with different CPPFLAGS, that's not supported +# here... +cpp = subprocess.check_output( + ["make", "var-CPP", "var-AM_CPPFLAGS", "var-DEFS"], cwd=src_root +) +cpp = shlex.split(cpp.decode("UTF-8")) + + +def process_file(filename): + with open(filename, "r") as ifd: + data = ifd.read() + + data = kill_re.sub("", data) + + before = 0 + + dirname = os.path.dirname(filename) + basename = os.path.basename(filename).removesuffix(".c").removesuffix(".h") + + xname = filename + ".exp" + with open(filename + ".exp", "w") as ofd: + for m in decl_re.finditer(data): + s = m.start() + e = m.end() + ofd.write(data[before:s]) + + # start gcc/clang with some "magic" options to make it expand the + # typesafe macros, but nothing else. + # -P removes the "#line" markers (which are useless because + # everything ends up on one line anyway) + # -D_TYPESAFE_EXPAND_MACROS prevents the system header files + # (stddef.h, stdint.h, etc.) from being included and expanded + # -imacros loads the macro definitions from typesafe.h, but + # doesn't include any of the "plain text" (i.e. prototypes + # and outside-macro struct definitions) from it + # atomlist.h is sufficient because it includes typesafe.h which + # includes typerb.h, that's all of them + p_expand = subprocess.Popen( + cpp + + [ + "-P", + "-D_TYPESAFE_EXPAND_MACROS", + "-imacros", + "lib/atomlist.h", + "-", + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + cwd=src_root, + ) + # the output will look like shit, all on one line. format it. + p_format = subprocess.Popen( + ["clang-format", "-"], + stdin=p_expand.stdout, + stdout=subprocess.PIPE, + cwd=src_root, + ) + # pipe between cpp & clang-format needs to be closed + p_expand.stdout.close() + + # ... and finally, write the DECLARE_XYZ statement, and ONLY that + # statements. No headers, no other definitions. + p_expand.stdin.write(data[s:e].encode("UTF-8")) + p_expand.stdin.close() + + odata = b"" + while rd := p_format.stdout.read(): + odata = odata + rd + + p_expand.wait() + p_format.wait() + + # and now that we have the expanded text, write it out, put an + # #include in the .c file, and put "#if 0" around the original + # DECLARE_XYZ statement (otherwise it'll be duplicate...) + newname = os.path.join(dirname, f"{basename}__{m.group('name')}_tsexpand.h") + with open(newname, "wb") as nfd: + nfd.write(odata) + + ofd.write(f'#include "{newname}" /* $ts_expand: remove$ */\n') + ofd.write("#if 0 /* $ts_expand: remove$ */\n") + ofd.write(data[s:e]) + ofd.write("#endif /* $ts_expand: remove$ */\n") + before = e + + ofd.write(data[before:]) + + os.rename(xname, filename) + + +if __name__ == "__main__": + for filename in sys.argv[1:]: + process_file(filename) diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py index 0a7e28ec7ac1..0cfb11e72111 100644 --- a/python/xref2vtysh.py +++ b/python/xref2vtysh.py @@ -26,25 +26,27 @@ except ImportError: pass +import _clippy + frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # vtysh needs to know which daemon(s) to send commands to. For lib/, this is # not quite obvious... daemon_flags = { - "lib/agentx.c": "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA", - "lib/filter.c": "VTYSH_ACL", - "lib/filter_cli.c": "VTYSH_ACL", + "lib/libagentx.c": "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA", + "lib/filter.c": "VTYSH_ACL_SHOW", + "lib/filter_cli.c": "VTYSH_ACL_CONFIG", "lib/if.c": "VTYSH_INTERFACE", - "lib/keychain.c": "VTYSH_KEYS", - "lib/mgmt_be_client.c": "VTYSH_STATICD", - "lib/mgmt_fe_client.c": "VTYSH_MGMTD", + "lib/keychain_cli.c": "VTYSH_KEYS", + "lib/mgmt_be_client.c": "VTYSH_MGMT_BACKEND", + "lib/mgmt_fe_client.c": "VTYSH_MGMT_FRONTEND", "lib/lib_vty.c": "VTYSH_ALL", "lib/log_vty.c": "VTYSH_ALL", "lib/nexthop_group.c": "VTYSH_NH_GROUP", "lib/resolver.c": "VTYSH_NHRPD|VTYSH_BGPD", - "lib/routemap.c": "VTYSH_RMAP", - "lib/routemap_cli.c": "VTYSH_RMAP", + "lib/routemap.c": "VTYSH_RMAP_SHOW", + "lib/routemap_cli.c": "VTYSH_RMAP_CONFIG", "lib/spf_backoff.c": "VTYSH_ISISD", "lib/event.c": "VTYSH_ALL", "lib/vrf.c": "VTYSH_VRF", @@ -58,6 +60,16 @@ #include "linklist.h" #include "vtysh/vtysh.h" + +#pragma GCC visibility push(internal) + +#define MAKE_VECTOR(name, len, ...) \\ + static void * name ## _vitems[] = { __VA_ARGS__ }; \\ + static struct _vector name = { \\ + .active = len, \\ + .count = len, \\ + .index = name ## _vitems, \\ + } """ if sys.stderr.isatty(): @@ -206,10 +218,7 @@ def _get_daemons(self): } if defun_file == "lib/if_rmap.c": - if v6_cmd: - return {"VTYSH_RIPNGD"} - else: - return {"VTYSH_RIPD"} + return {"VTYSH_MGMTD"} return {} @@ -327,17 +336,7 @@ def process(cls, nodes, name, origin, spec): def load(cls, xref): nodes = NodeDict() - mgmtname = "mgmtd/libmgmt_be_nb.la" for cmd_name, origins in xref.get("cli", {}).items(): - # If mgmtd has a yang version of a CLI command, make it the only daemon - # to handle it. For now, daemons can still be compiling their cmds into the - # binaries to allow for running standalone with CLI config files. When they - # do this they will also be present in the xref file, but we want to ignore - # those in vtysh. - if "yang" in origins.get(mgmtname, {}).get("attrs", []): - CommandEntry.process(nodes, cmd_name, mgmtname, origins[mgmtname]) - continue - for origin, spec in origins.items(): CommandEntry.process(nodes, cmd_name, origin, spec) return nodes @@ -348,23 +347,159 @@ def output_defs(cls, ofd): ofd.write(entry.get_def()) @classmethod - def output_install(cls, ofd, nodes): - ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + def output_node_graph(cls, ofd, node, cmds, splitfile): + graph = _clippy.Graph(None) + + for _, cmd in sorted(cmds.items()): + cg = _clippy.Graph(cmd.cmd, cmd._spec["doc"], cmd.name) + graph.merge(cg) + + if len(graph) <= 2: + return [] + + ofd.write("\n") + ofd.write(f"static struct cmd_token ctkn_{node}[];\n") + ofd.write(f"static struct graph_node gn_{node}[];\n") + ofd.write("\n") + + vectors = [] + cmdels = set() + + ofd.write(f"static struct cmd_token ctkn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + vectors.append( + ( + list(i.idx for i in token.next()), + list(i.idx for i in token.prev()), + ) + ) - for name, items in sorted(nodes.items_named()): - for item in sorted(items.values(), key=lambda i: i.name): - ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name)) + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t{'{'} /* [{i}] = {token.text} */ {'}'},\n") + cmdels.add(token.text) + continue - ofd.write("}\n") + ofd.write(f"\t{'{'} /* [{i}] */\n\t\t.type = {token.type},\n") + if token.attr: + ofd.write(f"\t\t.attr = {token.attr},\n") + if token.allowrepeat: + ofd.write(f"\t\t.allowrepeat = true,\n") + if token.varname_src: + ofd.write(f"\t\t.varname_src = {token.varname_src},\n") + if token.text: + ofd.write(f'\t\t.text = (char *)"{c_escape(token.text)}",\n') + if token.desc: + ofd.write(f'\t\t.desc = (char *)"{c_escape(token.desc)}",\n') + if token.min: + ofd.write(f"\t\t.min = {token.min},\n") + if token.max: + ofd.write(f"\t\t.max = {token.max},\n") + if token.varname: + ofd.write(f'\t\t.varname = (char *)"{c_escape(token.varname)}",\n') + + if token.type == "FORK_TKN": + fj = token.join() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + if token.type == "JOIN_TKN": + fj = token.fork() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + + ofd.write(f"\t{'}'},\n") + + ofd.write("};\n\n") + + if splitfile: + for cmdel in sorted(cmdels): + ofd.write(f"extern struct cmd_element {cmdel}_vtysh;\n") + ofd.write("\n") + + for i, next_prev in enumerate(vectors): + n, p = next_prev + items = ", ".join(f"&gn_{node}[{i}]" for i in n) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_next, {len(n)}, {items});\n") + items = ", ".join(f"&gn_{node}[{i}]" for i in p) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_prev, {len(p)}, {items});\n") + + ofd.write(f"\nstatic struct graph_node gn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + ofd.write("\t{\n") + ofd.write(f"\t\t.from = &gn_{node}_{i}_prev,\n") + ofd.write(f"\t\t.to = &gn_{node}_{i}_next,\n") + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t\t.data = (void *)&{token.text}_vtysh,\n") + else: + ofd.write(f"\t\t.data = &ctkn_{node}[{i}],\n") + ofd.write("\t},\n") + ofd.write("};\n") + + items = ", ".join(f"&gn_{node}[{i}]" for i in range(0, len(graph))) + ofd.write(f"MAKE_VECTOR(gvec_{node}, {len(graph)}, {items});\n") + + ofd.write( + f""" +{"extern " if splitfile else "static "}void install_{node}(void);\n +{"" if splitfile else "static "}void install_{node}(void)\n +{'{'} + unsigned node_id = {node}; + struct cmd_node *node; + + assert(node_id < vector_active(cmdvec)); + node = vector_slot(cmdvec, node_id); + assert(node); + assert(vector_active(node->cmdgraph->nodes) == 1); + graph_delete_node(node->cmdgraph, vector_slot(node->cmdgraph->nodes, 0)); + vector_free(node->cmdgraph->nodes); + node->cmdgraph->nodes = &gvec_{node}; +{'}'} +""" + ) + + return [node] @classmethod - def run(cls, xref, ofd): - ofd.write(vtysh_cmd_head) + def run(cls, xref, ofds): + for ofd in ofds: + ofd.write(vtysh_cmd_head) + + ofd = ofds.pop(0) NodeDict.load_nodenames() nodes = cls.load(xref) cls.output_defs(ofd) - cls.output_install(ofd, nodes) + + out_nodes = [] + for nodeid, cmds in nodes.items(): + node = nodes.nodename(nodeid) + + if ofds: + gfd, splitfile = ofds[nodeid % len(ofds)], True + else: + gfd, splitfile = ofd, False + + # install_element(VIEW_NODE, x) implies install_element(ENABLE_NODE, x) + # this needs to be handled here. + if node == "ENABLE_NODE": + nodeid_view = list( + k for k, v in nodes.nodenames.items() if v == "VIEW_NODE" + ) + assert len(nodeid_view) == 1 + cmds.update(nodes[nodeid_view[0]]) + + out_nodes.extend(cls.output_node_graph(gfd, node, cmds, splitfile)) + + out_nodes.sort() + + if ofds: + ofd.write("\n") + for name in out_nodes: + ofd.write(f"extern void install_{name}(void);\n") + + ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + + for name in out_nodes: + ofd.write(f"\tinstall_{name}();\n") + + ofd.write("}\n") def main(): diff --git a/python/xrelfo.py b/python/xrelfo.py index a40b19e5fb52..5f7616f25093 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -22,7 +22,7 @@ from clippy.uidhash import uidhash from clippy.elf import * -from clippy import frr_top_src, CmdAttr +from clippy import frr_top_src, CmdAttr, elf_notes from tiabwarfo import FieldApplicator from xref2vtysh import CommandEntry @@ -327,6 +327,7 @@ def __init__(self): } ) self._xrefs = [] + self.note_warn = False def load_file(self, filename): orig_filename = filename @@ -395,6 +396,15 @@ def load_elf(self, filename, orig_filename): ptrs = edf.iter_data(XrefPtr, slice(start, end)) else: + if elf_notes: + self.note_warn = True + sys.stderr.write( + """%s: warning: binary has no FRRouting.XREF note +%s- one of FRR_MODULE_SETUP, FRR_DAEMON_INFO or XREF_SETUP must be used +""" + % (orig_filename, orig_filename) + ) + xrefarray = edf.get_section("xref_array") if xrefarray is None: raise ValueError("file has neither xref note nor xref_array section") @@ -437,7 +447,9 @@ def main(): argp = argparse.ArgumentParser(description="FRR xref ELF extractor") argp.add_argument("-o", dest="output", type=str, help="write JSON output") argp.add_argument("--out-by-file", type=str, help="write by-file JSON output") - argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c") + argp.add_argument( + "-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c", nargs="*" + ) argp.add_argument("-Wlog-format", action="store_const", const=True) argp.add_argument("-Wlog-args", action="store_const", const=True) argp.add_argument("-Werror", action="store_const", const=True) @@ -471,6 +483,9 @@ def _main(args): sys.stderr.write("while processing %s:\n" % (fn)) traceback.print_exc() + if xrelfo.note_warn and args.Werror: + errors += 1 + for option in dir(args): if option.startswith("W") and option != "Werror": checks = sorted(xrelfo.check(args)) @@ -515,9 +530,17 @@ def _main(args): os.rename(args.out_by_file + ".tmp", args.out_by_file) if args.vtysh_cmds: - with open(args.vtysh_cmds + ".tmp", "w") as fd: - CommandEntry.run(out, fd) - os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds) + fds = [] + for filename in args.vtysh_cmds: + fds.append(open(filename + ".tmp", "w")) + + CommandEntry.run(out, fds) + + while fds: + fds.pop(0).close() + for filename in args.vtysh_cmds: + os.rename(filename + ".tmp", filename) + if args.Werror and CommandEntry.warn_counter: sys.exit(1) diff --git a/qpb/qpb.c b/qpb/qpb.c index 63454f115666..625817857819 100644 --- a/qpb/qpb.c +++ b/qpb/qpb.c @@ -10,3 +10,8 @@ /* * Main file for the qpb library. */ + +#include "config.h" +#include "xref.h" + +XREF_SETUP(); diff --git a/qpb/qpb.h b/qpb/qpb.h index d52528f41b83..280461447f09 100644 --- a/qpb/qpb.h +++ b/qpb/qpb.h @@ -14,6 +14,7 @@ #ifndef _QPB_H #define _QPB_H +#include "nexthop.h" #include "prefix.h" #include "qpb/qpb.pb-c.h" diff --git a/redhat/frr.pam b/redhat/frr.pam index 17a62f1999c8..a574c5e57569 100644 --- a/redhat/frr.pam +++ b/redhat/frr.pam @@ -4,8 +4,8 @@ ##### if running frr as root: # Only allow root (and possibly wheel) to use this because enable access # is unrestricted. -auth sufficient pam_rootok.so -account sufficient pam_rootok.so +auth sufficient pam_permit.so +account sufficient pam_permit.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient pam_wheel.so trust use_uid diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index c7fd7e625a73..d6775e6e9cae 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -16,6 +16,7 @@ %{!?with_cumulus: %global with_cumulus 0 } %{!?with_eigrpd: %global with_eigrpd 1 } %{!?with_fpm: %global with_fpm 1 } +%{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 } %{!?with_ldpd: %global with_ldpd 1 } %{!?with_multipath: %global with_multipath 256 } %{!?with_nhrpd: %global with_nhrpd 1 } @@ -29,6 +30,7 @@ %{!?with_rtadv: %global with_rtadv 1 } %{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_pathd: %global with_pathd 1 } +%{!?with_grpc: %global with_grpc 0 } # user and group %{!?frr_user: %global frr_user frr } @@ -42,8 +44,9 @@ %define zeb_docs %{zeb_src}/doc %define frr_tools %{zeb_src}/tools -# defines for configure -%define rundir %{_localstatedir}/run/%{name} +%if 0%{!?_runstatedir:1} +%define _runstatedir %{_localstatedir}/run +%endif ############################################################################ @@ -180,11 +183,12 @@ BuildRequires: flex BuildRequires: gcc BuildRequires: json-c-devel BuildRequires: libcap-devel +BuildRequires: protobuf-c-devel BuildRequires: make BuildRequires: ncurses-devel BuildRequires: readline-devel BuildRequires: texinfo -BuildRequires: libyang-devel >= 2.1.80 +BuildRequires: libyang-devel >= 2.1.128 %if 0%{?rhel} && 0%{?rhel} < 7 #python27-devel is available from ius community repo for RedHat/CentOS 6 BuildRequires: python27-devel @@ -198,6 +202,12 @@ BuildRequires: python3-devel BuildRequires: python3-sphinx %endif %endif +%if %{with_grpc} +BuildRequires: grpc-devel >= 1.16.1 +BuildRequires: protobuf-devel >= 3.6.1 +BuildRequires: protobuf-compiler >= 3.6.1 +BuildRequires: protobuf-c-devel +%endif %if 0%{?rhel} > 7 #platform-python-devel is needed for /usr/bin/pathfix.py BuildRequires: platform-python-devel @@ -298,6 +308,17 @@ through the AgentX protocol. Provides read-only access to current routing state through standard SNMP MIBs. +%if %{with_grpc} +%package grpc +Summary: GRPC support for FRR daemons +Group: System Environment/Daemons +License: GPLv3+ +Requires: %{name} = %{version}-%{release} + +%description grpc +Adds GRPC support to the individual FRR daemons. +%endif + %prep %setup -q -n frr-%{frrversion} @@ -316,11 +337,13 @@ routing state through standard SNMP MIBs. %configure \ --sbindir=%{_sbindir} \ - --sysconfdir=%{configdir} \ - --localstatedir=%{rundir} \ + --sysconfdir=%{_sysconfdir} \ + --localstatedir=%{_localstatedir} \ --disable-static \ --disable-werror \ - --enable-irdp \ +%if %{with_mgmtd_test_be_client} + --enable-mgmtd-test-be-client \ +%endif %if %{with_multipath} --enable-multipath=%{with_multipath} \ %endif @@ -419,6 +442,11 @@ routing state through standard SNMP MIBs. --enable-pathd \ %else --disable-pathd \ +%endif +%if %{with_grpc} + --enable-grpc \ +%else + --disable-grpc \ %endif --enable-snmp # end @@ -470,7 +498,7 @@ install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr install %{zeb_src}/tools/etc/frr/frr.conf %{buildroot}%{_sysconfdir}/frr/frr.conf.template install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr install -m644 %{zeb_src}/tools/etc/logrotate.d/frr %{buildroot}%{_sysconfdir}/logrotate.d/frr -install -d -m750 %{buildroot}%{rundir} +install -d -m750 %{buildroot}%{_runstatedir}/frr %if 0%{?rhel} > 7 || 0%{?fedora} > 29 # avoid `ERROR: ambiguous python shebang in` errors @@ -494,7 +522,7 @@ rm -f %{buildroot}%{_sbindir}/ospfclient.py getent passwd %{frr_user} >/dev/null || \ useradd -r -u %{frr_uid} -g %{frr_user} \ -s /sbin/nologin -c "FRRouting suite" \ - -d %{rundir} %{frr_user} + -d %{_runstatedir}/frr %{frr_user} %if 0%{?vty_group:1} usermod -a -G %{vty_group} %{frr_user} @@ -654,11 +682,11 @@ fi %if 0%{?frr_user:1} %dir %attr(751,%{frr_user},%{frr_user}) %{configdir} %dir %attr(755,%{frr_user},%{frr_user}) %{_localstatedir}/log/frr - %dir %attr(751,%{frr_user},%{frr_user}) %{rundir} + %dir %attr(751,%{frr_user},%{frr_user}) %{_runstatedir}/frr %else %dir %attr(750,root,root) %{configdir} %dir %attr(755,root,root) %{_localstatedir}/log/frr - %dir %attr(750,root,root) %{rundir} + %dir %attr(750,root,root) %{_runstatedir}/frr %endif %{_infodir}/frr.info.gz %{_mandir}/man*/* @@ -668,7 +696,11 @@ fi %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/mgmtd +%if %{with_mgmtd_test_be_client} + %{_sbindir}/mgmtd_testc +%endif %exclude %{_sbindir}/ssd +%exclude %{_sbindir}/fpm_listener %if %{with_watchfrr} %{_sbindir}/watchfrr %endif @@ -715,7 +747,6 @@ fi %endif %{_libdir}/frr/modules/zebra_cumulus_mlag.so %{_libdir}/frr/modules/dplane_fpm_nl.so -%{_libdir}/frr/modules/zebra_irdp.so %{_libdir}/frr/modules/bgpd_bmp.so %{_libdir}/libfrr_pb.so* %{_libdir}/libfrrfpm_pb.so* @@ -775,12 +806,16 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %{_libdir}/frr/modules/*snmp.so +%if %{with_grpc} +%files grpc +%{_libdir}/libfrrgrpc_pb.* +%{_libdir}/frr/modules/grpc.so +%endif + %files devel %{_libdir}/lib*.so %dir %{_includedir}/%{name} %{_includedir}/%{name}/*.h -%dir %{_includedir}/%{name}/mgmtd -%{_includedir}/%{name}/mgmtd/*.h %dir %{_includedir}/%{name}/ospfd %{_includedir}/%{name}/ospfd/*.h %if %{with_bfdd} @@ -799,9 +834,56 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog -* Tue Jun 06 2023 Martin Winter - %{version} +* Mon Mar 25 2024 Jafar Al-Gharaibeh - %{version} + +* Mon Mar 25 2024 Jafar Al-Gharaibeh - 10.0 +- Major highlights: +- Introduce local host routes +- Require libyang 2.1.128 +- Add suport to configire a log file per daemon +- BGP BMP Loc-RIB (RFC9069) support +- eBGP-OAD (One Administrative Domain) support +- BGP RPKI VRF support +- BGP SNMP traps for BGP4-MIBV2 +- Management (mgmtd) daemon "replace" operation support +- BGP dynamic capabilities for addpath, fqdn, orf capabilities +- SRv6 encapsulation source address feature +- OSPFv3 Point-To-Multipoint mode + +* Mon Oct 09 2023 Donatas Abraitis - 9.1 +- Major highlights: +- OSPFv2 HMAC-SHA Cryptographic Authentication +- BGP MAC-VRF Site-Of-Origin support +- BGP Dynamic capability support +- IS-IS SRv6 uSID support (RFC 9352) +- Change next-hop resolution via the default route for a traditional profile +- Add support for VLAN, ECN, DSCP mangling/filtering +- Zebra support for route replace semantics in FPM +- New command for BGP `neighbor x addpath-tx-best-selected` +- New command for BGP `mpls bgp l3vpn-multi-domain-switching` +- A couple more new BGP route-map commands for as-path, communities manipulation * Tue Jun 06 2023 Jafar Al-Gharaibeh - 9.0 +- Major highlights: +- Centralized Management Daemon (mgmtd) +- Switched to libyang minimum version 2.1.80 +- Memory footprint for BGP reduced drastically +- Add BGP `neighbor path-attribute treat-as-withdraw` command +- Add BGP ASN dot notation support (RFC 5396) +- Add BGP Software Version capability +- Allow BGP peering via 127.0.0.0/8 +- Deprecate BGP `internet` community - this is the Cisco-specific community, which is never been RFC-defined and confusing +- Implement `match source-protocol` for BGP route maps +- Implement BGP Node Target extended communities (draft-ietf-idr-node-target-ext-comm) +- Implement Flex-Algo for SR-MPLS (RFC 9350) +- Add support for IS-IS `advertise-passive-only` +- Add IS-IS `affinity-map` support +- Add the `graceful-restart hello-delay` OSPFv2/OSPFv3 command +- Add the `ipv6 mld join` PIMv6 command +- Add `allow-ecmp x` RIP/RIPng command +- Add BFD support for RIP +- For a full list of new features and bug fixes, please refer to: +- https://frrouting.org/release/ * Fri Mar 10 2023 Jafar Al-Gharaibeh - 8.5 - Major Highlights: diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 097c708ab1c7..5712a0b825b9 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -8,6 +8,7 @@ #include #include "if.h" +#include "if_rmap.h" #include "vrf.h" #include "log.h" #include "prefix.h" @@ -73,7 +74,7 @@ void cli_show_router_rip(struct vty *vty, const struct lyd_node *dnode, { const char *vrf_name; - vrf_name = yang_dnode_get_string(dnode, "./vrf"); + vrf_name = yang_dnode_get_string(dnode, "vrf"); vty_out(vty, "!\n"); vty_out(vty, "router rip"); @@ -82,6 +83,11 @@ void cli_show_router_rip(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, "\n"); } +void cli_show_end_router_rip(struct vty *vty, const struct lyd_node *dnode) +{ + vty_out(vty, "exit\n"); +} + /* * XPath: /frr-ripd:ripd/instance/allow-ecmp */ @@ -255,11 +261,11 @@ void cli_show_rip_distance_source(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " distance %s %s", - yang_dnode_get_string(dnode, "./distance"), - yang_dnode_get_string(dnode, "./prefix")); - if (yang_dnode_exists(dnode, "./access-list")) + yang_dnode_get_string(dnode, "distance"), + yang_dnode_get_string(dnode, "prefix")); + if (yang_dnode_exists(dnode, "access-list")) vty_out(vty, " %s", - yang_dnode_get_string(dnode, "./access-list")); + yang_dnode_get_string(dnode, "access-list")); vty_out(vty, "\n"); } @@ -273,8 +279,13 @@ DEFPY_YANG (rip_neighbor, "Specify a neighbor router\n" "Neighbor address\n") { - nb_cli_enqueue_change(vty, "./explicit-neighbor", - no ? NB_OP_DESTROY : NB_OP_CREATE, neighbor_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./explicit-neighbor[.='%s']", + neighbor_str); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -295,8 +306,12 @@ DEFPY_YANG (rip_network_prefix, "Enable routing on an IP network\n" "IP prefix /, e.g., 35.0.0.0/8\n") { - nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./network[.='%s']", network_str); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -317,8 +332,12 @@ DEFPY_YANG (rip_network_if, "Enable routing on an IP network\n" "Interface name\n") { - nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DESTROY : NB_OP_CREATE, network); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./interface[.='%s']", network); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -362,12 +381,12 @@ void cli_show_rip_offset_list(struct vty *vty, const struct lyd_node *dnode, { const char *interface; - interface = yang_dnode_get_string(dnode, "./interface"); + interface = yang_dnode_get_string(dnode, "interface"); vty_out(vty, " offset-list %s %s %s", - yang_dnode_get_string(dnode, "./access-list"), - yang_dnode_get_string(dnode, "./direction"), - yang_dnode_get_string(dnode, "./metric")); + yang_dnode_get_string(dnode, "access-list"), + yang_dnode_get_string(dnode, "direction"), + yang_dnode_get_string(dnode, "metric")); if (!strmatch(interface, "*")) vty_out(vty, " %s", interface); vty_out(vty, "\n"); @@ -412,17 +431,21 @@ DEFPY_YANG (rip_passive_interface, bool passive_default = yang_dnode_get_bool(vty->candidate_config->dnode, "%s%s", VTY_CURR_XPATH, "/passive-default"); + char xpath[XPATH_MAXLEN]; + enum nb_operation op; if (passive_default) { - nb_cli_enqueue_change(vty, "./non-passive-interface", - no ? NB_OP_CREATE : NB_OP_DESTROY, - ifname); + snprintf(xpath, sizeof(xpath), + "./non-passive-interface[.='%s']", ifname); + op = no ? NB_OP_CREATE : NB_OP_DESTROY; } else { - nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DESTROY : NB_OP_CREATE, - ifname); + snprintf(xpath, sizeof(xpath), "./passive-interface[.='%s']", + ifname); + op = no ? NB_OP_DESTROY : NB_OP_CREATE; } + nb_cli_enqueue_change(vty, xpath, op, NULL); + return nb_cli_apply_changes(vty, NULL); } @@ -475,13 +498,13 @@ void cli_show_rip_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " redistribute %s", - yang_dnode_get_string(dnode, "./protocol")); - if (yang_dnode_exists(dnode, "./metric")) + yang_dnode_get_string(dnode, "protocol")); + if (yang_dnode_exists(dnode, "metric")) vty_out(vty, " metric %s", - yang_dnode_get_string(dnode, "./metric")); - if (yang_dnode_exists(dnode, "./route-map")) + yang_dnode_get_string(dnode, "metric")); + if (yang_dnode_exists(dnode, "route-map")) vty_out(vty, " route-map %s", - yang_dnode_get_string(dnode, "./route-map")); + yang_dnode_get_string(dnode, "route-map")); vty_out(vty, "\n"); } @@ -495,8 +518,12 @@ DEFPY_YANG (rip_route, "RIP static route configuration\n" "IP prefix /\n") { - nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./static-route[.='%s']", route_str); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -550,9 +577,9 @@ void cli_show_rip_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " timers basic %s %s %s\n", - yang_dnode_get_string(dnode, "./update-interval"), - yang_dnode_get_string(dnode, "./holddown-interval"), - yang_dnode_get_string(dnode, "./flush-interval")); + yang_dnode_get_string(dnode, "update-interval"), + yang_dnode_get_string(dnode, "holddown-interval"), + yang_dnode_get_string(dnode, "flush-interval")); } /* @@ -591,7 +618,7 @@ void cli_show_rip_version(struct vty *vty, const struct lyd_node *dnode, * We have only one "version" command and three possible combinations of * send/receive values. */ - switch (yang_dnode_get_enum(dnode, "./receive")) { + switch (yang_dnode_get_enum(dnode, "receive")) { case RI_RIP_VERSION_1: vty_out(vty, " version 1\n"); break; @@ -912,7 +939,7 @@ void cli_show_ip_rip_authentication_scheme(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - switch (yang_dnode_get_enum(dnode, "./mode")) { + switch (yang_dnode_get_enum(dnode, "mode")) { case RIP_NO_AUTH: vty_out(vty, " no ip rip authentication mode\n"); break; @@ -922,8 +949,8 @@ void cli_show_ip_rip_authentication_scheme(struct vty *vty, case RIP_AUTH_MD5: vty_out(vty, " ip rip authentication mode md5"); if (show_defaults - || !yang_dnode_is_default(dnode, "./md5-auth-length")) { - if (yang_dnode_get_enum(dnode, "./md5-auth-length") + || !yang_dnode_is_default(dnode, "md5-auth-length")) { + if (yang_dnode_get_enum(dnode, "md5-auth-length") == RIP_AUTH_MD5_SIZE) vty_out(vty, " auth-length rfc"); else @@ -1098,85 +1125,151 @@ void cli_show_ip_rip_bfd_profile(struct vty *vty, const struct lyd_node *dnode, yang_dnode_get_string(dnode, NULL)); } -/* - * XPath: /frr-ripd:clear-rip-route - */ -DEFPY_YANG (clear_ip_rip, - clear_ip_rip_cmd, - "clear ip rip [vrf WORD]", - CLEAR_STR - IP_STR - "Clear IP RIP database\n" - VRF_CMD_HELP_STR) +DEFPY_YANG( + rip_distribute_list, rip_distribute_list_cmd, + "distribute-list ACCESSLIST4_NAME$name $dir [WORD$ifname]", + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") { - struct list *input; - int ret; - - input = list_new(); - if (vrf) { - struct yang_data *yang_vrf; - - yang_vrf = yang_data_new("/frr-ripd:clear-rip-route/input/vrf", - vrf); - listnode_add(input, yang_vrf); - } + char xpath[XPATH_MAXLEN]; - ret = nb_cli_rpc(vty, "/frr-ripd:clear-rip-route", input, NULL); + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/access-list", + ifname ? ifname : "", dir); + /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */ + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name); + return nb_cli_apply_changes(vty, NULL); +} - list_delete(&input); +DEFPY_YANG( + rip_distribute_list_prefix, rip_distribute_list_prefix_cmd, + "distribute-list prefix PREFIXLIST4_NAME$name $dir [WORD$ifname]", + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + char xpath[XPATH_MAXLEN]; - return ret; + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/prefix-list", + ifname ? ifname : "", dir); + /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */ + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (rip_distribute_list, - rip_distribute_list_cmd, - "distribute-list [prefix] ACCESSLIST4_NAME [WORD]", - "Filter networks in routing updates\n" - "Specify a prefix\n" - "Access-list name\n" - "Filter incoming routing updates\n" - "Filter outgoing routing updates\n" - "Interface name\n") +DEFPY_YANG(no_rip_distribute_list, + no_rip_distribute_list_cmd, + "no distribute-list [ACCESSLIST4_NAME$name] $dir [WORD$ifname]", + NO_STR + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") { - const char *ifname = NULL; - int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0; + const struct lyd_node *value_node; + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/access-list", + ifname ? ifname : "", dir); + /* + * See if the user has specified specific list so check it exists. + * + * NOTE: Other FRR CLI commands do not do this sort of verification and + * there may be an official decision not to. + */ + if (name) { + value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s", + VTY_CURR_XPATH, xpath); + if (!value_node || strcmp(name, lyd_get_value(value_node))) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} - if (argv[argc - 1]->type == VARIABLE_TKN) - ifname = argv[argc - 1]->arg; +DEFPY_YANG(no_rip_distribute_list_prefix, + no_rip_distribute_list_prefix_cmd, + "no distribute-list prefix [PREFIXLIST4_NAME$name] $dir [WORD$ifname]", + NO_STR + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + const struct lyd_node *value_node; + char xpath[XPATH_MAXLEN]; - return distribute_list_parser(prefix, true, argv[2 + prefix]->text, - argv[1 + prefix]->arg, ifname); + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/prefix-list", + ifname ? ifname : "", dir); + /* + * See if the user has specified specific list so check it exists. + * + * NOTE: Other FRR CLI commands do not do this sort of verification and + * there may be an official decision not to. + */ + if (name) { + value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s", + VTY_CURR_XPATH, xpath); + if (!value_node || strcmp(name, lyd_get_value(value_node))) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (rip_no_distribute_list, - rip_no_distribute_list_cmd, - "no distribute-list [prefix] ACCESSLIST4_NAME [WORD]", - NO_STR - "Filter networks in routing updates\n" - "Specify a prefix\n" - "Access-list name\n" - "Filter incoming routing updates\n" - "Filter outgoing routing updates\n" - "Interface name\n") +/* + * XPath: /frr-ripd:clear-rip-route + */ +DEFPY_YANG (clear_ip_rip, + clear_ip_rip_cmd, + "clear ip rip [vrf WORD]", + CLEAR_STR + IP_STR + "Clear IP RIP database\n" + VRF_CMD_HELP_STR) { - const char *ifname = NULL; - int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; - - if (argv[argc - 1]->type == VARIABLE_TKN) - ifname = argv[argc - 1]->arg; + if (vrf) + nb_cli_rpc_enqueue(vty, "vrf", vrf); - return distribute_list_no_parser(vty, prefix, true, - argv[3 + prefix]->text, - argv[2 + prefix]->arg, ifname); + return nb_cli_rpc(vty, "/frr-ripd:clear-rip-route", NULL); } +/* RIP node structure. */ +static struct cmd_node rip_node = { + .name = "rip", + .node = RIP_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", + // .config_write = config_write_rip, +}; + void rip_cli_init(void) { + install_node(&rip_node); + install_element(CONFIG_NODE, &router_rip_cmd); install_element(CONFIG_NODE, &no_router_rip_cmd); install_element(RIP_NODE, &rip_distribute_list_cmd); - install_element(RIP_NODE, &rip_no_distribute_list_cmd); + install_element(RIP_NODE, &rip_distribute_list_prefix_cmd); + install_element(RIP_NODE, &no_rip_distribute_list_cmd); + install_element(RIP_NODE, &no_rip_distribute_list_prefix_cmd); install_element(RIP_NODE, &rip_allow_ecmp_cmd); install_element(RIP_NODE, &no_rip_allow_ecmp_cmd); @@ -1200,6 +1293,7 @@ void rip_cli_init(void) install_element(RIP_NODE, &no_rip_version_cmd); install_element(RIP_NODE, &rip_bfd_default_profile_cmd); install_element(RIP_NODE, &no_rip_bfd_default_profile_cmd); + install_default(RIP_NODE); install_element(INTERFACE_NODE, &ip_rip_split_horizon_cmd); install_element(INTERFACE_NODE, &ip_rip_v2_broadcast_cmd); @@ -1219,4 +1313,145 @@ void rip_cli_init(void) install_element(INTERFACE_NODE, &no_ip_rip_bfd_profile_cmd); install_element(ENABLE_NODE, &clear_ip_rip_cmd); -} + + if_rmap_init(RIP_NODE); +} +/* clang-format off */ +const struct frr_yang_module_info frr_ripd_cli_info = { + .name = "frr-ripd", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-ripd:ripd/instance", + .cbs.cli_show = cli_show_router_rip, + .cbs.cli_show_end = cli_show_end_router_rip, + }, + { + .xpath = "/frr-ripd:ripd/instance/allow-ecmp", + .cbs.cli_show = cli_show_rip_allow_ecmp, + }, + { + .xpath = "/frr-ripd:ripd/instance/default-information-originate", + .cbs.cli_show = cli_show_rip_default_information_originate, + }, + { + .xpath = "/frr-ripd:ripd/instance/default-metric", + .cbs.cli_show = cli_show_rip_default_metric, + }, + { + .xpath = "/frr-ripd:ripd/instance/distance/default", + .cbs.cli_show = cli_show_rip_distance, + }, + { + .xpath = "/frr-ripd:ripd/instance/distance/source", + .cbs.cli_show = cli_show_rip_distance_source, + }, + { + .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", + .cbs.cli_show = cli_show_rip_neighbor, + }, + { + .xpath = "/frr-ripd:ripd/instance/network", + .cbs.cli_show = cli_show_rip_network_prefix, + }, + { + .xpath = "/frr-ripd:ripd/instance/interface", + .cbs.cli_show = cli_show_rip_network_interface, + }, + { + .xpath = "/frr-ripd:ripd/instance/offset-list", + .cbs.cli_show = cli_show_rip_offset_list, + }, + { + .xpath = "/frr-ripd:ripd/instance/passive-default", + .cbs.cli_show = cli_show_rip_passive_default, + }, + { + .xpath = "/frr-ripd:ripd/instance/passive-interface", + .cbs.cli_show = cli_show_rip_passive_interface, + }, + { + .xpath = "/frr-ripd:ripd/instance/non-passive-interface", + .cbs.cli_show = cli_show_rip_non_passive_interface, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/in/access-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/out/access-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/in/prefix-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/out/prefix-list", + .cbs.cli_show = group_distribute_list_ipv4_cli_show, + }, + { + .xpath = "/frr-ripd:ripd/instance/redistribute", + .cbs.cli_show = cli_show_rip_redistribute, + }, + { + .xpath = "/frr-ripd:ripd/instance/if-route-maps/if-route-map", + .cbs.cli_show = cli_show_if_route_map, + }, + { + .xpath = "/frr-ripd:ripd/instance/static-route", + .cbs.cli_show = cli_show_rip_route, + }, + { + .xpath = "/frr-ripd:ripd/instance/timers", + .cbs.cli_show = cli_show_rip_timers, + }, + { + .xpath = "/frr-ripd:ripd/instance/version", + .cbs.cli_show = cli_show_rip_version, + }, + { + .xpath = "/frr-ripd:ripd/instance/default-bfd-profile", + .cbs.cli_show = cli_show_ripd_instance_default_bfd_profile, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon", + .cbs.cli_show = cli_show_ip_rip_split_horizon, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/v2-broadcast", + .cbs.cli_show = cli_show_ip_rip_v2_broadcast, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-receive", + .cbs.cli_show = cli_show_ip_rip_receive_version, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-send", + .cbs.cli_show = cli_show_ip_rip_send_version, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme", + .cbs.cli_show = cli_show_ip_rip_authentication_scheme, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", + .cbs.cli_show = cli_show_ip_rip_authentication_string, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", + .cbs.cli_show = cli_show_ip_rip_authentication_key_chain, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/enable", + .cbs.cli_show = cli_show_ip_rip_bfd_enable, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/profile", + .cbs.cli_show = cli_show_ip_rip_bfd_profile, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index b58015a67d89..486d7b05c208 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -128,14 +128,12 @@ static void rip_request_interface_send(struct interface *ifp, uint8_t version) /* RIPv1 and non multicast interface. */ if (if_is_pointopoint(ifp) || if_is_broadcast(ifp)) { - struct listnode *cnode, *cnnode; struct connected *connected; if (IS_RIP_DEBUG_EVENT) zlog_debug("broadcast request to %s", ifp->name); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, - connected)) { + frr_each (if_connected, ifp->connected, connected) { if (connected->address->family != AF_INET) continue; @@ -197,14 +195,13 @@ static void rip_request_interface(struct interface *ifp) /* Multicast packet receive socket. */ static int rip_multicast_join(struct interface *ifp, int sock) { - struct listnode *cnode; struct connected *ifc; if (if_is_operative(ifp) && if_is_multicast(ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug("multicast join at %s", ifp->name); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { struct prefix_ipv4 *p; struct in_addr group; @@ -228,14 +225,13 @@ static int rip_multicast_join(struct interface *ifp, int sock) /* Leave from multicast group. */ static void rip_multicast_leave(struct interface *ifp, int sock) { - struct listnode *cnode; struct connected *connected; if (if_is_up(ifp) && if_is_multicast(ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug("multicast leave from %s", ifp->name); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix_ipv4 *p; struct in_addr group; @@ -256,11 +252,10 @@ static void rip_multicast_leave(struct interface *ifp, int sock) /* Is there and address on interface that I could use ? */ static int rip_if_ipv4_address_check(struct interface *ifp) { - struct listnode *nn; struct connected *connected; int count = 0; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix *p; p = connected->address; @@ -279,10 +274,9 @@ int if_check_address(struct rip *rip, struct in_addr addr) struct interface *ifp; FOR_ALL_INTERFACES (rip->vrf, ifp) { - struct listnode *cnode; struct connected *connected; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)connected->address; @@ -383,31 +377,6 @@ static int rip_ifp_destroy(struct interface *ifp) return 0; } -/* VRF update for an interface. */ -int rip_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (IS_RIP_DEBUG_ZEBRA) { - struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); - - zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", - ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf), - new_vrf_id); - } - - if_update_to_new_vrf(ifp, new_vrf_id); - rip_interface_sync(ifp); - - return 0; -} - static void rip_interface_clean(struct rip_interface *ri) { ri->enable_network = 0; @@ -621,14 +590,13 @@ static int rip_enable_network_lookup_if(struct interface *ifp) { struct rip_interface *ri = ifp->info; struct rip *rip = ri->rip; - struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv4 address; if (!rip) return -1; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix *p; struct route_node *n; @@ -805,14 +773,13 @@ static void rip_connect_set(struct interface *ifp, int set) { struct rip_interface *ri = ifp->info; struct rip *rip = ri->rip; - struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv4 address; struct nexthop nh; memset(&nh, 0, sizeof(nh)); - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix *p; p = connected->address; @@ -1142,7 +1109,8 @@ void rip_if_init(void) hook_register_prio(if_del, 0, rip_interface_delete_hook); /* Install interface node. */ - if_cmd_init_default(); - if_zapi_callbacks(rip_ifp_create, rip_ifp_up, - rip_ifp_down, rip_ifp_destroy); + hook_register_prio(if_real, 0, rip_ifp_create); + hook_register_prio(if_up, 0, rip_ifp_up); + hook_register_prio(if_down, 0, rip_ifp_down); + hook_register_prio(if_unreal, 0, rip_ifp_destroy); } diff --git a/ripd/rip_main.c b/ripd/rip_main.c index ac358ebbaf58..67469f5fe52c 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -22,6 +22,8 @@ #include "libfrr.h" #include "routemap.h" #include "bfd.h" +#include "mgmt_be_client.h" +#include "libagentx.h" #include "ripd/ripd.h" #include "ripd/rip_bfd.h" @@ -53,6 +55,8 @@ struct zebra_privs_t ripd_privs = { /* Master of threads. */ struct event_loop *master; +struct mgmt_be_client *mgmt_be_client; + static struct frr_daemon_info ripd_di; /* SIGHUP handler. */ @@ -67,12 +71,31 @@ static void sighup(void) /* SIGINT handler. */ static void sigint(void) { + struct vrf *vrf; + zlog_notice("Terminating on signal"); bfd_protocol_integration_set_shutdown(true); + + + nb_oper_cancel_all_walks(); + mgmt_be_client_destroy(mgmt_be_client); + mgmt_be_client = NULL; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (!vrf->info) + continue; + + rip_clean(vrf->info); + } + rip_vrf_terminate(); if_rmap_terminate(); rip_zclient_stop(); + + route_map_finish(); + + keychain_terminate(); frr_fini(); exit(0); @@ -109,17 +132,27 @@ static const struct frr_yang_module_info *const ripd_yang_modules[] = { &frr_ripd_info, &frr_route_map_info, &frr_vrf_info, + &ietf_key_chain_info, + &ietf_key_chain_deviation_info, }; -FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(ripd, RIP, + .vty_port = RIP_VTY_PORT, + .proghelp = "Implementation of the RIP routing protocol.", - .proghelp = "Implementation of the RIP routing protocol.", + .signals = ripd_signals, + .n_signals = array_size(ripd_signals), - .signals = ripd_signals, .n_signals = array_size(ripd_signals), + .privs = &ripd_privs, - .privs = &ripd_privs, .yang_modules = ripd_yang_modules, - .n_yang_modules = array_size(ripd_yang_modules), + .yang_modules = ripd_yang_modules, + .n_yang_modules = array_size(ripd_yang_modules), + + /* mgmtd will load the per-daemon config file now */ + .flags = FRR_NO_SPLIT_CONFIG, ); +/* clang-format on */ #define DEPRECATED_OPTIONS "" @@ -158,14 +191,17 @@ int main(int argc, char **argv) master = frr_init(); /* Library initialization. */ + libagentx_init(); rip_error_init(); - keychain_init(); + keychain_init_new(true); rip_vrf_init(); /* RIP related initialization. */ rip_init(); rip_if_init(); - rip_cli_init(); + + mgmt_be_client = mgmt_be_client_create("ripd", NULL, 0, master); + rip_zclient_init(master); rip_bfd_init(master); diff --git a/ripd/rip_nb.c b/ripd/rip_nb.c index d11f1e1d34fe..231099d3ac41 100644 --- a/ripd/rip_nb.c +++ b/ripd/rip_nb.c @@ -6,11 +6,12 @@ #include -#include "northbound.h" +#include "distribute.h" +#include "if_rmap.h" #include "libfrr.h" +#include "northbound.h" #include "ripd/rip_nb.h" -#include "lib/if_rmap.h" /* clang-format off */ const struct frr_yang_module_info frr_ripd_info = { @@ -19,7 +20,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance", .cbs = { - .cli_show = cli_show_router_rip, .create = ripd_instance_create, .destroy = ripd_instance_destroy, .get_keys = ripd_instance_get_keys, @@ -30,35 +30,30 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/allow-ecmp", .cbs = { - .cli_show = cli_show_rip_allow_ecmp, .modify = ripd_instance_allow_ecmp_modify, }, }, { .xpath = "/frr-ripd:ripd/instance/default-information-originate", .cbs = { - .cli_show = cli_show_rip_default_information_originate, .modify = ripd_instance_default_information_originate_modify, }, }, { .xpath = "/frr-ripd:ripd/instance/default-metric", .cbs = { - .cli_show = cli_show_rip_default_metric, .modify = ripd_instance_default_metric_modify, }, }, { .xpath = "/frr-ripd:ripd/instance/distance/default", .cbs = { - .cli_show = cli_show_rip_distance, .modify = ripd_instance_distance_default_modify, }, }, { .xpath = "/frr-ripd:ripd/instance/distance/source", .cbs = { - .cli_show = cli_show_rip_distance_source, .create = ripd_instance_distance_source_create, .destroy = ripd_instance_distance_source_destroy, }, @@ -79,7 +74,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", .cbs = { - .cli_show = cli_show_rip_neighbor, .create = ripd_instance_explicit_neighbor_create, .destroy = ripd_instance_explicit_neighbor_destroy, }, @@ -87,7 +81,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/network", .cbs = { - .cli_show = cli_show_rip_network_prefix, .create = ripd_instance_network_create, .destroy = ripd_instance_network_destroy, }, @@ -95,7 +88,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/interface", .cbs = { - .cli_show = cli_show_rip_network_interface, .create = ripd_instance_interface_create, .destroy = ripd_instance_interface_destroy, }, @@ -103,7 +95,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/offset-list", .cbs = { - .cli_show = cli_show_rip_offset_list, .create = ripd_instance_offset_list_create, .destroy = ripd_instance_offset_list_destroy, }, @@ -123,14 +114,12 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/passive-default", .cbs = { - .cli_show = cli_show_rip_passive_default, .modify = ripd_instance_passive_default_modify, }, }, { .xpath = "/frr-ripd:ripd/instance/passive-interface", .cbs = { - .cli_show = cli_show_rip_passive_interface, .create = ripd_instance_passive_interface_create, .destroy = ripd_instance_passive_interface_destroy, }, @@ -138,16 +127,49 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/non-passive-interface", .cbs = { - .cli_show = cli_show_rip_non_passive_interface, .create = ripd_instance_non_passive_interface_create, .destroy = ripd_instance_non_passive_interface_destroy, }, }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list", + .cbs = { + .create = ripd_instance_distribute_list_create, + .destroy = group_distribute_list_destroy, + } + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/in/access-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + } + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/out/access-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + } + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/in/prefix-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + } + }, + { + .xpath = "/frr-ripd:ripd/instance/distribute-list/out/prefix-list", + .cbs = { + .modify = group_distribute_list_ipv4_modify, + .destroy = group_distribute_list_ipv4_destroy, + } + }, { .xpath = "/frr-ripd:ripd/instance/redistribute", .cbs = { .apply_finish = ripd_instance_redistribute_apply_finish, - .cli_show = cli_show_rip_redistribute, .create = ripd_instance_redistribute_create, .destroy = ripd_instance_redistribute_destroy, }, @@ -171,7 +193,6 @@ const struct frr_yang_module_info frr_ripd_info = { .cbs = { .create = ripd_instance_if_route_maps_if_route_map_create, .destroy = ripd_instance_if_route_maps_if_route_map_destroy, - .cli_show = cli_show_if_route_map, } }, { @@ -191,7 +212,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/static-route", .cbs = { - .cli_show = cli_show_rip_route, .create = ripd_instance_static_route_create, .destroy = ripd_instance_static_route_destroy, }, @@ -200,7 +220,6 @@ const struct frr_yang_module_info frr_ripd_info = { .xpath = "/frr-ripd:ripd/instance/timers", .cbs = { .apply_finish = ripd_instance_timers_apply_finish, - .cli_show = cli_show_rip_timers, }, }, { @@ -221,12 +240,6 @@ const struct frr_yang_module_info frr_ripd_info = { .modify = ripd_instance_timers_update_interval_modify, }, }, - { - .xpath = "/frr-ripd:ripd/instance/version", - .cbs = { - .cli_show = cli_show_rip_version, - }, - }, { .xpath = "/frr-ripd:ripd/instance/version/receive", .cbs = { @@ -244,43 +257,32 @@ const struct frr_yang_module_info frr_ripd_info = { .cbs = { .modify = ripd_instance_default_bfd_profile_modify, .destroy = ripd_instance_default_bfd_profile_destroy, - .cli_show = cli_show_ripd_instance_default_bfd_profile, }, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon", .cbs = { - .cli_show = cli_show_ip_rip_split_horizon, .modify = lib_interface_rip_split_horizon_modify, }, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/v2-broadcast", .cbs = { - .cli_show = cli_show_ip_rip_v2_broadcast, .modify = lib_interface_rip_v2_broadcast_modify, }, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-receive", .cbs = { - .cli_show = cli_show_ip_rip_receive_version, .modify = lib_interface_rip_version_receive_modify, }, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-send", .cbs = { - .cli_show = cli_show_ip_rip_send_version, .modify = lib_interface_rip_version_send_modify, }, }, - { - .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme", - .cbs = { - .cli_show = cli_show_ip_rip_authentication_scheme, - }, - }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode", .cbs = { @@ -297,7 +299,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", .cbs = { - .cli_show = cli_show_ip_rip_authentication_string, .destroy = lib_interface_rip_authentication_password_destroy, .modify = lib_interface_rip_authentication_password_modify, }, @@ -305,7 +306,6 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", .cbs = { - .cli_show = cli_show_ip_rip_authentication_key_chain, .destroy = lib_interface_rip_authentication_key_chain_destroy, .modify = lib_interface_rip_authentication_key_chain_modify, }, @@ -320,14 +320,12 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/enable", .cbs = { - .cli_show = cli_show_ip_rip_bfd_enable, .modify = lib_interface_rip_bfd_enable_modify, }, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/bfd-monitoring/profile", .cbs = { - .cli_show = cli_show_ip_rip_bfd_profile, .modify = lib_interface_rip_bfd_profile_modify, .destroy = lib_interface_rip_bfd_profile_destroy, }, diff --git a/ripd/rip_nb.h b/ripd/rip_nb.h index 9929e0952b6f..ee592daf81a1 100644 --- a/ripd/rip_nb.h +++ b/ripd/rip_nb.h @@ -7,7 +7,10 @@ #ifndef _FRR_RIP_NB_H_ #define _FRR_RIP_NB_H_ +#include "northbound.h" + extern const struct frr_yang_module_info frr_ripd_info; +extern const struct frr_yang_module_info frr_ripd_cli_info; /* Mandatory callbacks. */ int ripd_instance_create(struct nb_cb_create_args *args); @@ -45,6 +48,8 @@ int ripd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args); int ripd_instance_non_passive_interface_create(struct nb_cb_create_args *args); int ripd_instance_non_passive_interface_destroy( struct nb_cb_destroy_args *args); +int ripd_instance_distribute_list_create(struct nb_cb_create_args *args); +int ripd_instance_distribute_list_destroy(struct nb_cb_destroy_args *args); int ripd_instance_redistribute_create(struct nb_cb_create_args *args); int ripd_instance_redistribute_destroy(struct nb_cb_destroy_args *args); int ripd_instance_redistribute_route_map_modify(struct nb_cb_modify_args *args); @@ -168,6 +173,7 @@ void ripd_instance_timers_apply_finish(struct nb_cb_apply_finish_args *args); /* Optional 'cli_show' callbacks. */ void cli_show_router_rip(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_end_router_rip(struct vty *vty, const struct lyd_node *dnode); void cli_show_rip_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_rip_default_information_originate(struct vty *vty, @@ -235,4 +241,6 @@ void cli_show_ip_rip_bfd_profile(struct vty *vty, const struct lyd_node *dnode, extern void ripd_notif_send_auth_type_failure(const char *ifname); extern void ripd_notif_send_auth_failure(const char *ifname); +extern void rip_cli_init(void); + #endif /* _FRR_RIP_NB_H_ */ diff --git a/ripd/rip_nb_config.c b/ripd/rip_nb_config.c index 8d3b6705968a..fb7533789b5f 100644 --- a/ripd/rip_nb_config.c +++ b/ripd/rip_nb_config.c @@ -35,7 +35,7 @@ int ripd_instance_create(struct nb_cb_create_args *args) const char *vrf_name; int socket; - vrf_name = yang_dnode_get_string(args->dnode, "./vrf"); + vrf_name = yang_dnode_get_string(args->dnode, "vrf"); vrf = vrf_lookup_by_name(vrf_name); /* @@ -189,7 +189,7 @@ int ripd_instance_distance_source_create(struct nb_cb_create_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - yang_dnode_get_ipv4p(&prefix, args->dnode, "./prefix"); + yang_dnode_get_ipv4p(&prefix, args->dnode, "prefix"); apply_mask_ipv4(&prefix); /* Get RIP distance node. */ @@ -395,7 +395,7 @@ int ripd_instance_offset_list_create(struct nb_cb_create_args *args) return NB_OK; rip = nb_running_get_entry(args->dnode, NULL, true); - ifname = yang_dnode_get_string(args->dnode, "./interface"); + ifname = yang_dnode_get_string(args->dnode, "interface"); offset = rip_offset_list_new(rip, ifname); nb_running_set_entry(args->dnode, offset); @@ -411,7 +411,7 @@ int ripd_instance_offset_list_destroy(struct nb_cb_destroy_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - direct = yang_dnode_get_enum(args->dnode, "./direction"); + direct = yang_dnode_get_enum(args->dnode, "direction"); offset = nb_running_unset_entry(args->dnode); if (offset->direct[direct].alist_name) { @@ -548,6 +548,23 @@ int ripd_instance_non_passive_interface_destroy(struct nb_cb_destroy_args *args) return rip_passive_nondefault_unset(rip, ifname); } + +/* + * XPath: /frr-ripd:ripd/instance/distribute-list + */ +int ripd_instance_distribute_list_create(struct nb_cb_create_args *args) +{ + struct rip *rip; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + rip = nb_running_get_entry(args->dnode, NULL, true); + group_distribute_list_create_helper(args, rip->distribute_ctx); + + return NB_OK; +} + /* * XPath: /frr-ripd:ripd/instance/redistribute */ @@ -560,7 +577,7 @@ int ripd_instance_redistribute_create(struct nb_cb_create_args *args) return NB_OK; rip = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + type = yang_dnode_get_enum(args->dnode, "protocol"); rip->redist[type].enabled = true; @@ -576,7 +593,7 @@ int ripd_instance_redistribute_destroy(struct nb_cb_destroy_args *args) return NB_OK; rip = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + type = yang_dnode_get_enum(args->dnode, "protocol"); rip->redist[type].enabled = false; if (rip->redist[type].route_map.name) { @@ -600,7 +617,7 @@ void ripd_instance_redistribute_apply_finish( int type; rip = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + type = yang_dnode_get_enum(args->dnode, "protocol"); if (rip->enabled) rip_redistribute_conf_update(rip, type); @@ -1123,12 +1140,12 @@ int lib_interface_rip_bfd_create(struct nb_cb_create_args *args) ifp = nb_running_get_entry(args->dnode, NULL, true); ri = ifp->info; - ri->bfd.enabled = yang_dnode_get_bool(args->dnode, "./enable"); + ri->bfd.enabled = yang_dnode_get_bool(args->dnode, "enable"); XFREE(MTYPE_RIP_BFD_PROFILE, ri->bfd.profile); - if (yang_dnode_exists(args->dnode, "./profile")) + if (yang_dnode_exists(args->dnode, "profile")) ri->bfd.profile = XSTRDUP( MTYPE_RIP_BFD_PROFILE, - yang_dnode_get_string(args->dnode, "./profile")); + yang_dnode_get_string(args->dnode, "profile")); rip_bfd_interface_update(ri); diff --git a/ripd/rip_nb_rpcs.c b/ripd/rip_nb_rpcs.c index bbe3d0f0f834..5d3d7145b1d4 100644 --- a/ripd/rip_nb_rpcs.c +++ b/ripd/rip_nb_rpcs.c @@ -68,12 +68,11 @@ static void clear_rip_route(struct rip *rip) int clear_rip_route_rpc(struct nb_cb_rpc_args *args) { struct rip *rip; - struct yang_data *yang_vrf; - yang_vrf = yang_data_list_find(args->input, "%s/%s", args->xpath, - "input/vrf"); - if (yang_vrf) { - rip = rip_lookup_by_vrf_name(yang_vrf->value); + if (args->input && yang_dnode_exists(args->input, "vrf")) { + const char *name = yang_dnode_get_string(args->input, "vrf"); + + rip = rip_lookup_by_vrf_name(name); if (rip) clear_rip_route(rip); } else { diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 3e8ddeccf267..7e848bee4745 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -12,6 +12,7 @@ #include "frrevent.h" #include "memory.h" #include "table.h" +#include "frrdistance.h" #include "ripd/ripd.h" #include "ripd/rip_bfd.h" diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c index 2ae8857e3f12..be172774490a 100644 --- a/ripd/rip_routemap.c +++ b/ripd/rip_routemap.c @@ -531,7 +531,7 @@ static const struct route_map_rule_cmd route_set_tag_cmd = { /* Route-map init */ void rip_route_map_init(void) { - route_map_init(); + route_map_init_new(true); route_map_match_interface_hook(generic_match_add); route_map_no_match_interface_hook(generic_match_delete); diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 0e5d4d54c97a..f6a7a8283101 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -195,7 +195,7 @@ static int rip_snmp_ifaddr_del(struct connected *ifc) if (!rn) return 0; i = rn->info; - if (!strncmp(i->name, ifp->name, INTERFACE_NAMSIZ)) { + if (!strncmp(i->name, ifp->name, IFNAMSIZ)) { rn->info = NULL; route_unlock_node(rn); route_unlock_node(rn); diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 5bf51c2f1528..ce94e8e7545f 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -14,6 +14,8 @@ #include "log.h" #include "vrf.h" #include "bfd.h" +#include "frrdistance.h" + #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" @@ -222,7 +224,6 @@ static void rip_zebra_connected(struct zclient *zclient) zclient_handler *const rip_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = rip_interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = rip_interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = rip_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = rip_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = rip_zebra_read_route, }; diff --git a/ripd/ripd.c b/ripd/ripd.c index 7bfcaadc74cc..8768819fe26c 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -6,6 +6,11 @@ #include +#ifdef CRYPTO_OPENSSL +#include +#include +#endif + #include "vrf.h" #include "if.h" #include "command.h" @@ -29,8 +34,10 @@ #include "privs.h" #include "lib_errors.h" #include "northbound_cli.h" +#include "mgmt_be_client.h" #include "network.h" #include "lib/printfrr.h" +#include "frrdistance.h" #include "ripd/ripd.h" #include "ripd/rip_nb.h" @@ -403,7 +410,6 @@ static int rip_filter(int rip_distribute, struct prefix_ipv4 *p, static int rip_nexthop_check(struct rip *rip, struct in_addr *addr) { struct interface *ifp; - struct listnode *cnode; struct connected *ifc; struct prefix *p; @@ -411,7 +417,7 @@ static int rip_nexthop_check(struct rip *rip, struct in_addr *addr) invalid nexthop. */ FOR_ALL_INTERFACES (rip->vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { p = ifc->address; if (p->family == AF_INET @@ -1045,7 +1051,7 @@ static size_t rip_auth_md5_ah_write(struct stream *s, struct rip_interface *ri, /* RFC2080: The value used in the sequence number is arbitrary, but two suggestions are the time of the message's creation or a simple message counter. */ - stream_putl(s, ++seq); + stream_putl(s, seq++); /* Reserved field must be zero. */ stream_putl(s, 0); @@ -2212,8 +2218,8 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to, } if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT) { - for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, - listnode, tmp_ifc)) + frr_each (if_connected, ifc->ifp->connected, + tmp_ifc) if (prefix_match((struct prefix *)p, tmp_ifc->address)) { suppress = 1; @@ -2322,8 +2328,8 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to, if (rinfo->metric_out != RIP_METRIC_INFINITY && rinfo->type == ZEBRA_ROUTE_CONNECT) { - for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, - listnode, tmp_ifc)) + frr_each (if_connected, ifc->ifp->connected, + tmp_ifc) if (prefix_match((struct prefix *)p, tmp_ifc->address)) { rinfo->metric_out = @@ -2436,7 +2442,6 @@ static void rip_update_interface(struct connected *ifc, uint8_t version, /* Update send to all interface and neighbor. */ static void rip_update_process(struct rip *rip, int route_type) { - struct listnode *ifnode, *ifnnode; struct connected *connected; struct interface *ifp; struct rip_interface *ri; @@ -2475,8 +2480,7 @@ static void rip_update_process(struct rip *rip, int route_type) ifp->ifindex); /* send update on each connected network */ - for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode, - connected)) { + frr_each (if_connected, ifp->connected, connected) { if (connected->address->family == AF_INET) { if (vsend & RIPv1) rip_update_interface(connected, RIPv1, @@ -2767,7 +2771,6 @@ int rip_request_send(struct sockaddr_in *to, struct interface *ifp, { struct rte *rte; struct rip_packet rip_packet; - struct listnode *node, *nnode; memset(&rip_packet, 0, sizeof(rip_packet)); @@ -2791,7 +2794,7 @@ int rip_request_send(struct sockaddr_in *to, struct interface *ifp, } /* send request on each connected network */ - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)connected->address; @@ -3051,7 +3054,10 @@ DEFUN (show_ip_rip, } vty_out(vty, - "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface\n\n" @@ -3251,45 +3257,6 @@ DEFUN (show_ip_rip_status, return CMD_SUCCESS; } -/* RIP configuration write function. */ -static int config_write_rip(struct vty *vty) -{ - struct rip *rip; - int write = 0; - - RB_FOREACH(rip, rip_instance_head, &rip_instances) { - char xpath[XPATH_MAXLEN]; - struct lyd_node *dnode; - - snprintf(xpath, sizeof(xpath), - "/frr-ripd:ripd/instance[vrf='%s']", rip->vrf_name); - - dnode = yang_dnode_get(running_config->dnode, xpath); - assert(dnode); - - nb_cli_show_dnode_cmds(vty, dnode, false); - - /* Distribute configuration. */ - config_write_distribute(vty, rip->distribute_ctx); - - vty_out(vty, "exit\n"); - - write = 1; - } - - return write; -} - -static int config_write_rip(struct vty *vty); -/* RIP node structure. */ -static struct cmd_node rip_node = { - .name = "rip", - .node = RIP_NODE, - .parent_node = CONFIG_NODE, - .prompt = "%s(config-router)# ", - .config_write = config_write_rip, -}; - /* Distribute-list update functions. */ static void rip_distribute_update(struct distribute_ctx *ctx, struct distribute *dist) @@ -3651,8 +3618,6 @@ static int rip_vrf_disable(struct vrf *vrf) void rip_vrf_init(void) { vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete); - - vrf_cmd_init(NULL); } void rip_vrf_terminate(void) @@ -3663,20 +3628,17 @@ void rip_vrf_terminate(void) /* Allocate new rip structure and set default value. */ void rip_init(void) { - /* Install top nodes. */ - install_node(&rip_node); - /* Install rip commands. */ install_element(VIEW_NODE, &show_ip_rip_cmd); install_element(VIEW_NODE, &show_ip_rip_status_cmd); - install_default(RIP_NODE); - /* Debug related init. */ rip_debug_init(); + /* Enable mgmt be debug */ + mgmt_be_client_lib_vty_init(); /* Access list install. */ - access_list_init(); + access_list_init_new(true); access_list_add_hook(rip_distribute_update_all_wrapper); access_list_delete_hook(rip_distribute_update_all_wrapper); @@ -3690,6 +3652,4 @@ void rip_init(void) route_map_add_hook(rip_routemap_update); route_map_delete_hook(rip_routemap_update); - - if_rmap_init(RIP_NODE); } diff --git a/ripd/ripd.h b/ripd/ripd.h index ac4a51f586fd..08f7a2442d08 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -51,7 +51,6 @@ /* RIP port number. */ #define RIP_PORT_DEFAULT 520 -#define RIP_VTY_PORT 2602 /* Default configuration file name. */ #define RIPD_DEFAULT_CONFIG "ripd.conf" @@ -526,7 +525,6 @@ extern int offset_list_cmp(struct rip_offset_list *o1, extern void rip_vrf_init(void); extern void rip_vrf_terminate(void); -extern void rip_cli_init(void); extern struct zebra_privs_t ripd_privs; extern struct rip_instance_head rip_instances; diff --git a/ripd/subdir.am b/ripd/subdir.am index c793a6d68538..aed8d249fea2 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -14,7 +14,6 @@ endif ripd_ripd_SOURCES = \ ripd/rip_bfd.c \ - ripd/rip_cli.c \ ripd/rip_debug.c \ ripd/rip_errors.c \ ripd/rip_interface.c \ diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index 9a96e29313d6..99cb68ea3296 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -8,6 +8,7 @@ #include #include "if.h" +#include "if_rmap.h" #include "vrf.h" #include "log.h" #include "prefix.h" @@ -73,7 +74,7 @@ void cli_show_router_ripng(struct vty *vty, const struct lyd_node *dnode, { const char *vrf_name; - vrf_name = yang_dnode_get_string(dnode, "./vrf"); + vrf_name = yang_dnode_get_string(dnode, "vrf"); vty_out(vty, "!\n"); vty_out(vty, "router ripng"); @@ -82,6 +83,11 @@ void cli_show_router_ripng(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, "\n"); } +void cli_show_end_router_ripng(struct vty *vty, const struct lyd_node *dnode) +{ + vty_out(vty, "exit\n"); +} + /* * XPath: /frr-ripngd:ripngd/instance/allow-ecmp */ @@ -199,8 +205,12 @@ DEFPY_YANG (ripng_network_prefix, "RIPng enable on specified interface or network.\n" "IPv6 network\n") { - nb_cli_enqueue_change(vty, "./network", - no ? NB_OP_DESTROY : NB_OP_CREATE, network_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./network[.='%s']", network_str); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -222,8 +232,12 @@ DEFPY_YANG (ripng_network_if, "RIPng enable on specified interface or network.\n" "Interface name\n") { - nb_cli_enqueue_change(vty, "./interface", - no ? NB_OP_DESTROY : NB_OP_CREATE, network); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./interface[.='%s']", network); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -267,12 +281,12 @@ void cli_show_ripng_offset_list(struct vty *vty, const struct lyd_node *dnode, { const char *interface; - interface = yang_dnode_get_string(dnode, "./interface"); + interface = yang_dnode_get_string(dnode, "interface"); vty_out(vty, " offset-list %s %s %s", - yang_dnode_get_string(dnode, "./access-list"), - yang_dnode_get_string(dnode, "./direction"), - yang_dnode_get_string(dnode, "./metric")); + yang_dnode_get_string(dnode, "access-list"), + yang_dnode_get_string(dnode, "direction"), + yang_dnode_get_string(dnode, "metric")); if (!strmatch(interface, "*")) vty_out(vty, " %s", interface); vty_out(vty, "\n"); @@ -288,8 +302,12 @@ DEFPY_YANG (ripng_passive_interface, "Suppress routing updates on an interface\n" "Interface name\n") { - nb_cli_enqueue_change(vty, "./passive-interface", - no ? NB_OP_DESTROY : NB_OP_CREATE, ifname); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./passive-interface[.='%s']", ifname); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + ifname); return nb_cli_apply_changes(vty, NULL); } @@ -335,13 +353,13 @@ void cli_show_ripng_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " redistribute %s", - yang_dnode_get_string(dnode, "./protocol")); - if (yang_dnode_exists(dnode, "./metric")) + yang_dnode_get_string(dnode, "protocol")); + if (yang_dnode_exists(dnode, "metric")) vty_out(vty, " metric %s", - yang_dnode_get_string(dnode, "./metric")); - if (yang_dnode_exists(dnode, "./route-map")) + yang_dnode_get_string(dnode, "metric")); + if (yang_dnode_exists(dnode, "route-map")) vty_out(vty, " route-map %s", - yang_dnode_get_string(dnode, "./route-map")); + yang_dnode_get_string(dnode, "route-map")); vty_out(vty, "\n"); } @@ -355,8 +373,12 @@ DEFPY_YANG (ripng_route, "Static route setup\n" "Set static RIPng route announcement\n") { - nb_cli_enqueue_change(vty, "./static-route", - no ? NB_OP_DESTROY : NB_OP_CREATE, route_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./static-route[.='%s']", route_str); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -377,9 +399,13 @@ DEFPY_YANG (ripng_aggregate_address, "Set aggregate RIPng route announcement\n" "Aggregate network\n") { - nb_cli_enqueue_change(vty, "./aggregate-address", - no ? NB_OP_DESTROY : NB_OP_CREATE, - aggregate_address_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./aggregate-address[.='%s']", + aggregate_address_str); + + nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, + NULL); return nb_cli_apply_changes(vty, NULL); } @@ -435,9 +461,9 @@ void cli_show_ripng_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " timers basic %s %s %s\n", - yang_dnode_get_string(dnode, "./update-interval"), - yang_dnode_get_string(dnode, "./holddown-interval"), - yang_dnode_get_string(dnode, "./flush-interval")); + yang_dnode_get_string(dnode, "update-interval"), + yang_dnode_get_string(dnode, "holddown-interval"), + yang_dnode_get_string(dnode, "flush-interval")); } /* @@ -486,87 +512,156 @@ void cli_show_ipv6_ripng_split_horizon(struct vty *vty, } } -/* - * XPath: /frr-ripngd:clear-ripng-route - */ -DEFPY_YANG (clear_ipv6_rip, - clear_ipv6_rip_cmd, - "clear ipv6 ripng [vrf WORD]", - CLEAR_STR - IPV6_STR - "Clear IPv6 RIP database\n" - VRF_CMD_HELP_STR) +DEFPY_YANG( + ripng_ipv6_distribute_list, ripng_ipv6_distribute_list_cmd, + "ipv6 distribute-list ACCESSLIST6_NAME$name $dir [WORD$ifname]", + "IPv6\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") { - struct list *input; - int ret; + char xpath[XPATH_MAXLEN]; - input = list_new(); - if (vrf) { - struct yang_data *yang_vrf; + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/access-list", + ifname ? ifname : "", dir); + /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */ + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name); + return nb_cli_apply_changes(vty, NULL); +} - yang_vrf = yang_data_new( - "/frr-ripngd:clear-ripng-route/input/vrf", vrf); - listnode_add(input, yang_vrf); - } +DEFPY_YANG( + ripng_ipv6_distribute_list_prefix, ripng_ipv6_distribute_list_prefix_cmd, + "ipv6 distribute-list prefix PREFIXLIST6_NAME$name $dir [WORD$ifname]", + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + char xpath[XPATH_MAXLEN]; - ret = nb_cli_rpc(vty, "/frr-ripngd:clear-ripng-route", input, NULL); + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/prefix-list", + ifname ? ifname : "", dir); + /* nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); */ + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, name); + return nb_cli_apply_changes(vty, NULL); +} - list_delete(&input); +DEFPY_YANG(no_ripng_ipv6_distribute_list, + no_ripng_ipv6_distribute_list_cmd, + "no ipv6 distribute-list [ACCESSLIST6_NAME$name] $dir [WORD$ifname]", + NO_STR + "IPv6\n" + "Filter networks in routing updates\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + const struct lyd_node *value_node; + char xpath[XPATH_MAXLEN]; - return ret; + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/access-list", + ifname ? ifname : "", dir); + /* + * See if the user has specified specific list so check it exists. + * + * NOTE: Other FRR CLI commands do not do this sort of verification and + * there may be an official decision not to. + */ + if (name) { + value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s", + VTY_CURR_XPATH, xpath); + if (!value_node || strcmp(name, lyd_get_value(value_node))) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (ripng_ipv6_distribute_list, - ripng_ipv6_distribute_list_cmd, - "ipv6 distribute-list [prefix] ACCESSLIST6_NAME [WORD]", - "IPv6\n" - "Filter networks in routing updates\n" - "Specify a prefix\n" - "Access-list name\n" - "Filter incoming routing updates\n" - "Filter outgoing routing updates\n" - "Interface name\n") +DEFPY_YANG(no_ripng_ipv6_distribute_list_prefix, + no_ripng_ipv6_distribute_list_prefix_cmd, + "no ipv6 distribute-list prefix [PREFIXLIST6_NAME$name] $dir [WORD$ifname]", + NO_STR + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix list\n" + "Prefix-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") { - const char *ifname = NULL; - int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; - - if (argv[argc - 1]->type == VARIABLE_TKN) - ifname = argv[argc - 1]->arg; + const struct lyd_node *value_node; + char xpath[XPATH_MAXLEN]; - return distribute_list_parser(prefix, false, argv[3 + prefix]->text, - argv[2 + prefix]->arg, ifname); + snprintf(xpath, sizeof(xpath), + "./distribute-list[interface='%s']/%s/prefix-list", + ifname ? ifname : "", dir); + /* + * See if the user has specified specific list so check it exists. + * + * NOTE: Other FRR CLI commands do not do this sort of verification and + * there may be an official decision not to. + */ + if (name) { + value_node = yang_dnode_getf(vty->candidate_config->dnode, "%s/%s", + VTY_CURR_XPATH, xpath); + if (!value_node || strcmp(name, lyd_get_value(value_node))) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (ripng_no_ipv6_distribute_list, - ripng_no_ipv6_distribute_list_cmd, - "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME [WORD]", - NO_STR - "IPv6\n" - "Filter networks in routing updates\n" - "Specify a prefix\n" - "Access-list name\n" - "Filter incoming routing updates\n" - "Filter outgoing routing updates\n" - "Interface name\n") +/* + * XPath: /frr-ripngd:clear-ripng-route + */ +DEFPY_YANG (clear_ipv6_rip, + clear_ipv6_rip_cmd, + "clear ipv6 ripng [vrf WORD]", + CLEAR_STR + IPV6_STR + "Clear IPv6 RIP database\n" + VRF_CMD_HELP_STR) { - const char *ifname = NULL; - int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0; + if (vrf) + nb_cli_rpc_enqueue(vty, "vrf", vrf); - if (argv[argc - 1]->type == VARIABLE_TKN) - ifname = argv[argc - 1]->arg; - - return distribute_list_no_parser(vty, prefix, false, - argv[4 + prefix]->text, - argv[3 + prefix]->arg, ifname); + return nb_cli_rpc(vty, "/frr-ripngd:clear-ripng-route", NULL); } +/* RIPng node structure. */ +static struct cmd_node cmd_ripng_node = { + .name = "ripng", + .node = RIPNG_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-router)# ", +}; + void ripng_cli_init(void) { + /* Install RIPNG_NODE. */ + install_node(&cmd_ripng_node); + install_default(RIPNG_NODE); + install_element(CONFIG_NODE, &router_ripng_cmd); install_element(CONFIG_NODE, &no_router_ripng_cmd); install_element(RIPNG_NODE, &ripng_ipv6_distribute_list_cmd); - install_element(RIPNG_NODE, &ripng_no_ipv6_distribute_list_cmd); + install_element(RIPNG_NODE, &ripng_ipv6_distribute_list_prefix_cmd); + install_element(RIPNG_NODE, &no_ripng_ipv6_distribute_list_cmd); + install_element(RIPNG_NODE, &no_ripng_ipv6_distribute_list_prefix_cmd); install_element(RIPNG_NODE, &ripng_allow_ecmp_cmd); install_element(RIPNG_NODE, &no_ripng_allow_ecmp_cmd); @@ -586,4 +681,92 @@ void ripng_cli_init(void) install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); install_element(ENABLE_NODE, &clear_ipv6_rip_cmd); -} + + if_rmap_init(RIPNG_NODE); +} + +/* clang-format off */ +const struct frr_yang_module_info frr_ripngd_cli_info = { + .name = "frr-ripngd", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-ripngd:ripngd/instance", + .cbs.cli_show = cli_show_router_ripng, + .cbs.cli_show_end = cli_show_end_router_ripng, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/allow-ecmp", + .cbs.cli_show = cli_show_ripng_allow_ecmp, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/default-information-originate", + .cbs.cli_show = cli_show_ripng_default_information_originate, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/default-metric", + .cbs.cli_show = cli_show_ripng_default_metric, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/network", + .cbs.cli_show = cli_show_ripng_network_prefix, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/interface", + .cbs.cli_show = cli_show_ripng_network_interface, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/offset-list", + .cbs.cli_show = cli_show_ripng_offset_list, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/passive-interface", + .cbs.cli_show = cli_show_ripng_passive_interface, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/in/access-list", + .cbs.cli_show = group_distribute_list_ipv6_cli_show, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/out/access-list", + .cbs.cli_show = group_distribute_list_ipv6_cli_show, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/in/prefix-list", + .cbs.cli_show = group_distribute_list_ipv6_cli_show, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/out/prefix-list", + .cbs.cli_show = group_distribute_list_ipv6_cli_show, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/redistribute", + .cbs.cli_show = cli_show_ripng_redistribute, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/if-route-maps/if-route-map", + .cbs.cli_show = cli_show_if_route_map, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/static-route", + .cbs.cli_show = cli_show_ripng_route, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", + .cbs.cli_show = cli_show_ripng_aggregate_address, + }, + { + .xpath = "/frr-ripngd:ripngd/instance/timers", + .cbs.cli_show = cli_show_ripng_timers, + }, + { + .xpath = "/frr-interface:lib/interface/frr-ripngd:ripng/split-horizon", + .cbs = { + .cli_show = cli_show_ipv6_ripng_split_horizon, + }, + }, + { + .xpath = NULL, + }, + } +}; diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index a37cb7d092a5..9ef9f89005ec 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -128,11 +128,10 @@ static int ripng_multicast_leave(struct interface *ifp, int sock) /* How many link local IPv6 address could be used on the interface ? */ static int ripng_if_ipv6_lladdress_check(struct interface *ifp) { - struct listnode *nn; struct connected *connected; int count = 0; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix *p; p = connected->address; @@ -264,31 +263,6 @@ static int ripng_ifp_destroy(struct interface *ifp) return 0; } -/* VRF update for an interface. */ -int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS) -{ - struct interface *ifp; - vrf_id_t new_vrf_id; - - ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, - &new_vrf_id); - if (!ifp) - return 0; - - if (IS_RIPNG_DEBUG_ZEBRA) { - struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); - - zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", - ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf), - new_vrf_id); - } - - if_update_to_new_vrf(ifp, new_vrf_id); - ripng_interface_sync(ifp); - - return 0; -} - void ripng_interface_clean(struct ripng *ripng) { struct interface *ifp; @@ -433,14 +407,13 @@ static int ripng_enable_network_lookup_if(struct interface *ifp) { struct ripng_interface *ri = ifp->info; struct ripng *ripng = ri->ripng; - struct listnode *node; struct connected *connected; struct prefix_ipv6 address; if (!ripng) return -1; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix *p; struct agg_node *n; @@ -615,11 +588,10 @@ static void ripng_connect_set(struct interface *ifp, int set) { struct ripng_interface *ri = ifp->info; struct ripng *ripng = ri->ripng; - struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv6 address; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { struct prefix *p; p = connected->address; @@ -901,7 +873,8 @@ void ripng_if_init(void) hook_register_prio(if_del, 0, ripng_if_delete_hook); /* Install interface node. */ - if_cmd_init_default(); - if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up, - ripng_ifp_down, ripng_ifp_destroy); + hook_register_prio(if_real, 0, ripng_ifp_create); + hook_register_prio(if_up, 0, ripng_ifp_up); + hook_register_prio(if_down, 0, ripng_ifp_down); + hook_register_prio(if_unreal, 0, ripng_ifp_destroy); } diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 9933dae5cd76..ada9ad4e78b9 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -22,6 +22,7 @@ #include "if_rmap.h" #include "libfrr.h" #include "routemap.h" +#include "mgmt_be_client.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_nb.h" @@ -52,6 +53,8 @@ struct zebra_privs_t ripngd_privs = { /* Master of threads. */ struct event_loop *master; +struct mgmt_be_client *mgmt_be_client; + static struct frr_daemon_info ripngd_di; /* SIGHUP handler. */ @@ -66,11 +69,27 @@ static void sighup(void) /* SIGINT handler. */ static void sigint(void) { + struct vrf *vrf; + zlog_notice("Terminating on signal"); + nb_oper_cancel_all_walks(); + mgmt_be_client_destroy(mgmt_be_client); + mgmt_be_client = NULL; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (!vrf->info) + continue; + + ripng_clean(vrf->info); + } + ripng_vrf_terminate(); if_rmap_terminate(); ripng_zebra_stop(); + + route_map_finish(); + frr_fini(); exit(0); } @@ -108,18 +127,23 @@ static const struct frr_yang_module_info *const ripngd_yang_modules[] = { &frr_vrf_info, }; -FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(ripngd, RIPNG, + .vty_port = RIPNG_VTY_PORT, + .proghelp = "Implementation of the RIPng routing protocol.", - .proghelp = "Implementation of the RIPng routing protocol.", + .signals = ripng_signals, + .n_signals = array_size(ripng_signals), - .signals = ripng_signals, - .n_signals = array_size(ripng_signals), + .privs = &ripngd_privs, - .privs = &ripngd_privs, + .yang_modules = ripngd_yang_modules, + .n_yang_modules = array_size(ripngd_yang_modules), - .yang_modules = ripngd_yang_modules, - .n_yang_modules = array_size(ripngd_yang_modules), + /* mgmtd will load the per-daemon config file now */ + .flags = FRR_NO_SPLIT_CONFIG, ); +/* clang-format on */ #define DEPRECATED_OPTIONS "" @@ -160,7 +184,9 @@ int main(int argc, char **argv) /* RIPngd inits. */ ripng_init(); - ripng_cli_init(); + + mgmt_be_client = mgmt_be_client_create("ripngd", NULL, 0, master); + zebra_init(master); frr_config_fork(); diff --git a/ripngd/ripng_nb.c b/ripngd/ripng_nb.c index 1c6d7191a3a8..8e2054173380 100644 --- a/ripngd/ripng_nb.c +++ b/ripngd/ripng_nb.c @@ -6,11 +6,12 @@ #include -#include "northbound.h" +#include "distribute.h" +#include "if_rmap.h" #include "libfrr.h" +#include "northbound.h" #include "ripngd/ripng_nb.h" -#include "lib/if_rmap.h" /* clang-format off */ const struct frr_yang_module_info frr_ripngd_info = { @@ -19,7 +20,6 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance", .cbs = { - .cli_show = cli_show_router_ripng, .create = ripngd_instance_create, .destroy = ripngd_instance_destroy, .get_keys = ripngd_instance_get_keys, @@ -30,28 +30,24 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/allow-ecmp", .cbs = { - .cli_show = cli_show_ripng_allow_ecmp, .modify = ripngd_instance_allow_ecmp_modify, }, }, { .xpath = "/frr-ripngd:ripngd/instance/default-information-originate", .cbs = { - .cli_show = cli_show_ripng_default_information_originate, .modify = ripngd_instance_default_information_originate_modify, }, }, { .xpath = "/frr-ripngd:ripngd/instance/default-metric", .cbs = { - .cli_show = cli_show_ripng_default_metric, .modify = ripngd_instance_default_metric_modify, }, }, { .xpath = "/frr-ripngd:ripngd/instance/network", .cbs = { - .cli_show = cli_show_ripng_network_prefix, .create = ripngd_instance_network_create, .destroy = ripngd_instance_network_destroy, }, @@ -59,7 +55,6 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/interface", .cbs = { - .cli_show = cli_show_ripng_network_interface, .create = ripngd_instance_interface_create, .destroy = ripngd_instance_interface_destroy, }, @@ -67,7 +62,6 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/offset-list", .cbs = { - .cli_show = cli_show_ripng_offset_list, .create = ripngd_instance_offset_list_create, .destroy = ripngd_instance_offset_list_destroy, }, @@ -87,16 +81,49 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/passive-interface", .cbs = { - .cli_show = cli_show_ripng_passive_interface, .create = ripngd_instance_passive_interface_create, .destroy = ripngd_instance_passive_interface_destroy, }, }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list", + .cbs = { + .create = ripngd_instance_distribute_list_create, + .destroy = group_distribute_list_destroy, + } + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/in/access-list", + .cbs = { + .modify = group_distribute_list_ipv6_modify, + .destroy = group_distribute_list_ipv6_destroy, + } + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/out/access-list", + .cbs = { + .modify = group_distribute_list_ipv6_modify, + .destroy = group_distribute_list_ipv6_destroy, + } + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/in/prefix-list", + .cbs = { + .modify = group_distribute_list_ipv6_modify, + .destroy = group_distribute_list_ipv6_destroy, + } + }, + { + .xpath = "/frr-ripngd:ripngd/instance/distribute-list/out/prefix-list", + .cbs = { + .modify = group_distribute_list_ipv6_modify, + .destroy = group_distribute_list_ipv6_destroy, + } + }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute", .cbs = { .apply_finish = ripngd_instance_redistribute_apply_finish, - .cli_show = cli_show_ripng_redistribute, .create = ripngd_instance_redistribute_create, .destroy = ripngd_instance_redistribute_destroy, }, @@ -120,7 +147,6 @@ const struct frr_yang_module_info frr_ripngd_info = { .cbs = { .create = ripngd_instance_if_route_maps_if_route_map_create, .destroy = ripngd_instance_if_route_maps_if_route_map_destroy, - .cli_show = cli_show_if_route_map, } }, { @@ -140,7 +166,6 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/static-route", .cbs = { - .cli_show = cli_show_ripng_route, .create = ripngd_instance_static_route_create, .destroy = ripngd_instance_static_route_destroy, }, @@ -148,7 +173,6 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", .cbs = { - .cli_show = cli_show_ripng_aggregate_address, .create = ripngd_instance_aggregate_address_create, .destroy = ripngd_instance_aggregate_address_destroy, }, @@ -157,7 +181,6 @@ const struct frr_yang_module_info frr_ripngd_info = { .xpath = "/frr-ripngd:ripngd/instance/timers", .cbs = { .apply_finish = ripngd_instance_timers_apply_finish, - .cli_show = cli_show_ripng_timers, }, }, { @@ -251,7 +274,6 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripngd:ripng/split-horizon", .cbs = { - .cli_show = cli_show_ipv6_ripng_split_horizon, .modify = lib_interface_ripng_split_horizon_modify, }, }, diff --git a/ripngd/ripng_nb.h b/ripngd/ripng_nb.h index 1c0e63c24197..790a50f62893 100644 --- a/ripngd/ripng_nb.h +++ b/ripngd/ripng_nb.h @@ -7,7 +7,10 @@ #ifndef _FRR_RIPNG_NB_H_ #define _FRR_RIPNG_NB_H_ +#include "northbound.h" + extern const struct frr_yang_module_info frr_ripngd_info; +extern const struct frr_yang_module_info frr_ripngd_cli_info; /* Mandatory callbacks. */ int ripngd_instance_create(struct nb_cb_create_args *args); @@ -30,6 +33,8 @@ int ripngd_instance_offset_list_access_list_modify( int ripngd_instance_offset_list_metric_modify(struct nb_cb_modify_args *args); int ripngd_instance_passive_interface_create(struct nb_cb_create_args *args); int ripngd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args); +int ripngd_instance_distribute_list_create(struct nb_cb_create_args *args); +int ripngd_instance_distribute_list_destroy(struct nb_cb_destroy_args *args); int ripngd_instance_redistribute_create(struct nb_cb_create_args *args); int ripngd_instance_redistribute_destroy(struct nb_cb_destroy_args *args); int ripngd_instance_redistribute_route_map_modify( @@ -102,6 +107,7 @@ void ripngd_instance_timers_apply_finish(struct nb_cb_apply_finish_args *args); /* Optional 'cli_show' callbacks. */ void cli_show_router_ripng(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_end_router_ripng(struct vty *vty, const struct lyd_node *dnode); void cli_show_ripng_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_ripng_default_information_originate(struct vty *vty, @@ -134,4 +140,6 @@ void cli_show_ipv6_ripng_split_horizon(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +extern void ripng_cli_init(void); + #endif /* _FRR_RIPNG_NB_H_ */ diff --git a/ripngd/ripng_nb_config.c b/ripngd/ripng_nb_config.c index 0b1bd68eca20..d05d91cfc7fd 100644 --- a/ripngd/ripng_nb_config.c +++ b/ripngd/ripng_nb_config.c @@ -35,7 +35,7 @@ int ripngd_instance_create(struct nb_cb_create_args *args) const char *vrf_name; int socket; - vrf_name = yang_dnode_get_string(args->dnode, "./vrf"); + vrf_name = yang_dnode_get_string(args->dnode, "vrf"); vrf = vrf_lookup_by_name(vrf_name); /* @@ -262,7 +262,7 @@ int ripngd_instance_offset_list_create(struct nb_cb_create_args *args) return NB_OK; ripng = nb_running_get_entry(args->dnode, NULL, true); - ifname = yang_dnode_get_string(args->dnode, "./interface"); + ifname = yang_dnode_get_string(args->dnode, "interface"); offset = ripng_offset_list_new(ripng, ifname); nb_running_set_entry(args->dnode, offset); @@ -278,7 +278,7 @@ int ripngd_instance_offset_list_destroy(struct nb_cb_destroy_args *args) if (args->event != NB_EV_APPLY) return NB_OK; - direct = yang_dnode_get_enum(args->dnode, "./direction"); + direct = yang_dnode_get_enum(args->dnode, "direction"); offset = nb_running_unset_entry(args->dnode); if (offset->direct[direct].alist_name) { @@ -368,6 +368,22 @@ int ripngd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args) return ripng_passive_interface_unset(ripng, ifname); } +/* + * XPath: /frr-ripng:ripng/instance/distribute-list + */ +int ripngd_instance_distribute_list_create(struct nb_cb_create_args *args) +{ + struct ripng *ripng; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ripng = nb_running_get_entry(args->dnode, NULL, true); + group_distribute_list_create_helper(args, ripng->distribute_ctx); + + return NB_OK; +} + /* * XPath: /frr-ripngd:ripngd/instance/redistribute */ @@ -380,7 +396,7 @@ int ripngd_instance_redistribute_create(struct nb_cb_create_args *args) return NB_OK; ripng = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + type = yang_dnode_get_enum(args->dnode, "protocol"); ripng->redist[type].enabled = true; @@ -396,7 +412,7 @@ int ripngd_instance_redistribute_destroy(struct nb_cb_destroy_args *args) return NB_OK; ripng = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + type = yang_dnode_get_enum(args->dnode, "protocol"); ripng->redist[type].enabled = false; if (ripng->redist[type].route_map.name) { @@ -420,7 +436,7 @@ void ripngd_instance_redistribute_apply_finish( int type; ripng = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_enum(args->dnode, "./protocol"); + type = yang_dnode_get_enum(args->dnode, "protocol"); if (ripng->enabled) ripng_redistribute_conf_update(ripng, type); diff --git a/ripngd/ripng_nb_rpcs.c b/ripngd/ripng_nb_rpcs.c index b23572d49282..5498bbfc8e38 100644 --- a/ripngd/ripng_nb_rpcs.c +++ b/ripngd/ripng_nb_rpcs.c @@ -70,12 +70,11 @@ static void clear_ripng_route(struct ripng *ripng) int clear_ripng_route_rpc(struct nb_cb_rpc_args *args) { struct ripng *ripng; - struct yang_data *yang_vrf; - yang_vrf = yang_data_list_find(args->input, "%s/%s", args->xpath, - "input/vrf"); - if (yang_vrf) { - ripng = ripng_lookup_by_vrf_name(yang_vrf->value); + if (args->input && yang_dnode_exists(args->input, "vrf")) { + const char *name = yang_dnode_get_string(args->input, "vrf"); + + ripng = ripng_lookup_by_vrf_name(name); if (ripng) clear_ripng_route(ripng); } else { diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 901b548a42a1..247bac46971b 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -15,6 +15,7 @@ #include "linklist.h" #include "frrevent.h" #include "memory.h" +#include "frrdistance.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_nexthop.h" diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c index b5f74be3f613..3370546d5ca6 100644 --- a/ripngd/ripng_routemap.c +++ b/ripngd/ripng_routemap.c @@ -386,7 +386,7 @@ static const struct route_map_rule_cmd route_set_tag_cmd = { void ripng_route_map_init(void) { - route_map_init(); + route_map_init_new(true); route_map_match_interface_hook(generic_match_add); route_map_no_match_interface_hook(generic_match_delete); diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 49b8a197add1..bb5a880c0214 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -222,7 +222,6 @@ static void ripng_zebra_connected(struct zclient *zclient) static zclient_handler *const ripng_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = ripng_interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = ripng_interface_address_delete, - [ZEBRA_INTERFACE_VRF_UPDATE] = ripng_interface_vrf_update, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ripng_zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ripng_zebra_read_route, }; diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 465b40bd3f61..0aa2a9e486fb 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -23,6 +23,7 @@ #include "lib_errors.h" #include "northbound_cli.h" #include "network.h" +#include "mgmt_be_client.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" @@ -392,11 +393,10 @@ static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from, /* If ifp has same link-local address then return 1. */ static int ripng_lladdr_check(struct interface *ifp, struct in6_addr *addr) { - struct listnode *node; struct connected *connected; struct prefix *p; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family == AF_INET6 @@ -2070,7 +2070,10 @@ DEFUN (show_ipv6_ripng, /* Header of display. */ vty_out(vty, - "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface, (a/S) - aggregated/Suppressed\n\n" @@ -2268,45 +2271,6 @@ void ripng_ecmp_disable(struct ripng *ripng) } } -/* RIPng configuration write function. */ -static int ripng_config_write(struct vty *vty) -{ - struct ripng *ripng; - int write = 0; - - RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) { - char xpath[XPATH_MAXLEN]; - struct lyd_node *dnode; - - snprintf(xpath, sizeof(xpath), - "/frr-ripngd:ripngd/instance[vrf='%s']", - ripng->vrf_name); - - dnode = yang_dnode_get(running_config->dnode, xpath); - assert(dnode); - - nb_cli_show_dnode_cmds(vty, dnode, false); - - config_write_distribute(vty, ripng->distribute_ctx); - - vty_out(vty, "exit\n"); - - write = 1; - } - - return write; -} - -static int ripng_config_write(struct vty *vty); -/* RIPng node structure. */ -static struct cmd_node cmd_ripng_node = { - .name = "ripng", - .node = RIPNG_NODE, - .parent_node = CONFIG_NODE, - .prompt = "%s(config-router)# ", - .config_write = ripng_config_write, -}; - static void ripng_distribute_update(struct distribute_ctx *ctx, struct distribute *dist) { @@ -2674,8 +2638,6 @@ void ripng_vrf_init(void) { vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable, ripng_vrf_delete); - - vrf_cmd_init(NULL); } void ripng_vrf_terminate(void) @@ -2686,20 +2648,18 @@ void ripng_vrf_terminate(void) /* Initialize ripng structure and set commands. */ void ripng_init(void) { - /* Install RIPNG_NODE. */ - install_node(&cmd_ripng_node); - /* Install ripng commands. */ install_element(VIEW_NODE, &show_ipv6_ripng_cmd); install_element(VIEW_NODE, &show_ipv6_ripng_status_cmd); - install_default(RIPNG_NODE); - ripng_if_init(); ripng_debug_init(); + /* Enable mgmt be debug */ + mgmt_be_client_lib_vty_init(); + /* Access list install. */ - access_list_init(); + access_list_init_new(true); access_list_add_hook(ripng_distribute_update_all_wrapper); access_list_delete_hook(ripng_distribute_update_all_wrapper); @@ -2713,6 +2673,4 @@ void ripng_init(void) route_map_add_hook(ripng_routemap_update); route_map_delete_hook(ripng_routemap_update); - - if_rmap_init(RIPNG_NODE); } diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index c7468b6317c5..a316f2b4b5eb 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -16,7 +16,6 @@ /* RIPng version and port number. */ #define RIPNG_V1 1 #define RIPNG_PORT_DEFAULT 521 -#define RIPNG_VTY_PORT 2603 #define RIPNG_MAX_PACKET_SIZE 1500 #define RIPNG_PRIORITY_DEFAULT 0 @@ -413,7 +412,6 @@ extern int ripng_interface_add(ZAPI_CALLBACK_ARGS); extern int ripng_interface_delete(ZAPI_CALLBACK_ARGS); extern int ripng_interface_address_add(ZAPI_CALLBACK_ARGS); extern int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS); -extern int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS); extern void ripng_interface_sync(struct interface *ifp); extern struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id); @@ -433,7 +431,6 @@ extern void ripng_ecmp_change(struct ripng *ripng); extern void ripng_vrf_init(void); extern void ripng_vrf_terminate(void); -extern void ripng_cli_init(void); extern uint32_t zebra_ecmp_count; diff --git a/ripngd/subdir.am b/ripngd/subdir.am index 162426c58ca8..83e376b55530 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -9,7 +9,6 @@ man8 += $(MANBUILD)/frr-ripngd.8 endif ripngd_ripngd_SOURCES = \ - ripngd/ripng_cli.c \ ripngd/ripng_debug.c \ ripngd/ripng_interface.c \ ripngd/ripng_nexthop.c \ diff --git a/sharpd/sharp_logpump.c b/sharpd/sharp_logpump.c index 5474e80b116a..d02921f28724 100644 --- a/sharpd/sharp_logpump.c +++ b/sharpd/sharp_logpump.c @@ -5,6 +5,7 @@ */ #include +#include #include "vty.h" #include "command.h" diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index fa85c2b44839..2e72a4b99095 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -54,6 +54,32 @@ struct zebra_privs_t sharp_privs = { struct option longopts[] = {{0}}; +struct sharp_global sg; + +static void sharp_global_init(void) +{ + memset(&sg, 0, sizeof(sg)); + sg.nhs = list_new(); + sg.nhs->del = (void (*)(void *))sharp_nh_tracker_free; + sg.ted = NULL; + sg.srv6_locators = list_new(); +} + +static void sharp_srv6_locators_list_delete(void *item) +{ + struct sharp_srv6_locator *loc = item; + + list_delete(&loc->chunks); +} + +static void sharp_global_destroy(void) +{ + list_delete(&sg.nhs); + + sg.srv6_locators->del = sharp_srv6_locators_list_delete; + list_delete(&sg.srv6_locators); +} + /* Master of threads. */ struct event_loop *master; @@ -68,6 +94,11 @@ static void sigint(void) { zlog_notice("Terminating on signal"); + vrf_terminate(); + sharp_zebra_terminate(); + + sharp_global_destroy(); + frr_fini(); exit(0); @@ -98,8 +129,6 @@ struct frr_signal_t sharp_signals[] = { }, }; -#define SHARP_VTY_PORT 2614 - static const struct frr_yang_module_info *const sharpd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -107,26 +136,20 @@ static const struct frr_yang_module_info *const sharpd_yang_modules[] = { &frr_vrf_info, }; -FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(sharpd, SHARP, + .vty_port = SHARP_VTY_PORT, + .proghelp = "Implementation of a Sharp of routes daemon.", - .proghelp = "Implementation of a Sharp of routes daemon.", + .signals = sharp_signals, + .n_signals = array_size(sharp_signals), - .signals = sharp_signals, - .n_signals = array_size(sharp_signals), + .privs = &sharp_privs, - .privs = &sharp_privs, .yang_modules = sharpd_yang_modules, - .n_yang_modules = array_size(sharpd_yang_modules), + .yang_modules = sharpd_yang_modules, + .n_yang_modules = array_size(sharpd_yang_modules), ); - -struct sharp_global sg; - -static void sharp_global_init(void) -{ - memset(&sg, 0, sizeof(sg)); - sg.nhs = list_new(); - sg.ted = NULL; - sg.srv6_locators = list_new(); -} +/* clang-format on */ static void sharp_start_configuration(void) { diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c index fa7880572d9d..6d64fcfb259b 100644 --- a/sharpd/sharp_nht.c +++ b/sharpd/sharp_nht.c @@ -40,6 +40,11 @@ struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p) return nht; } +void sharp_nh_tracker_free(struct sharp_nh_tracker *nht) +{ + XFREE(MTYPE_NH_TRACKER, nht); +} + void sharp_nh_tracker_dump(struct vty *vty) { struct listnode *node; @@ -169,7 +174,8 @@ static void sharp_nhgroup_delete_cb(const char *name) if (!snhg) return; - nhg_del(snhg->id); + if (sharp_nhgroup_id_is_installed(snhg->id)) + nhg_del(snhg->id); sharp_nhg_rb_del(&nhg_head, snhg); XFREE(MTYPE_NHG, snhg); } diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h index 5523f2807975..b27952ac511c 100644 --- a/sharpd/sharp_nht.h +++ b/sharpd/sharp_nht.h @@ -18,6 +18,7 @@ struct sharp_nh_tracker { }; extern struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p); +extern void sharp_nh_tracker_free(struct sharp_nh_tracker *nht); extern void sharp_nh_tracker_dump(struct vty *vty); diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index e891c1b6be6a..21c596bf7124 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -27,8 +27,35 @@ DEFINE_MTYPE_STATIC(SHARPD, SRV6_LOCATOR, "SRv6 Locator"); +DEFPY(watch_neighbor, watch_neighbor_cmd, + "sharp watch [vrf NAME$vrf_name] neighbor", + "Sharp routing Protocol\n" + "Watch for changes\n" + "The vrf we would like to watch if non-default\n" + "The NAME of the vrf\n" + "Neighbor events\n") +{ + struct vrf *vrf; + + if (!vrf_name) + vrf_name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(vrf_name); + + if (!vrf) { + vty_out(vty, "The vrf NAME specified: %s does not exist\n", + vrf_name); + return CMD_WARNING; + } + + sharp_zebra_register_neigh(vrf->vrf_id, AFI_IP, true); + + return CMD_SUCCESS; +} + + DEFPY(watch_redistribute, watch_redistribute_cmd, - "sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD, + "[no] sharp watch [vrf NAME$vrf_name] redistribute " FRR_REDIST_STR_SHARPD, + NO_STR "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" @@ -49,7 +76,7 @@ DEFPY(watch_redistribute, watch_redistribute_cmd, } source = proto_redistnum(AFI_IP, argv[argc-1]->text); - sharp_redistribute_vrf(vrf, source); + sharp_redistribute_vrf(vrf, source, !no); return CMD_SUCCESS; } @@ -421,6 +448,7 @@ DEFPY (install_seg6local_routes, End_X$seg6l_endx X:X::X:X$seg6l_endx_nh6|\ End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\ End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\ + End_DX6$seg6l_enddx6 X:X::X:X$seg6l_enddx6_nh6|\ End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\ End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table|\ End_DT46$seg6l_enddt46 (1-4294967295)$seg6l_enddt46_table>\ @@ -440,6 +468,8 @@ DEFPY (install_seg6local_routes, "Redirect table id to use\n" "SRv6 End.DX4 function to use\n" "V4 Nexthop address to use\n" + "SRv6 End.DX6 function to use\n" + "V6 Nexthop address to use\n" "SRv6 End.DT6 function to use\n" "Redirect table id to use\n" "SRv6 End.DT4 function to use\n" @@ -489,6 +519,9 @@ DEFPY (install_seg6local_routes, if (seg6l_enddx4) { action = ZEBRA_SEG6_LOCAL_ACTION_END_DX4; ctx.nh4 = seg6l_enddx4_nh4; + } else if (seg6l_enddx6) { + action = ZEBRA_SEG6_LOCAL_ACTION_END_DX6; + ctx.nh6 = seg6l_enddx6_nh6; } else if (seg6l_endx) { action = ZEBRA_SEG6_LOCAL_ACTION_END_X; ctx.nh6 = seg6l_endx_nh6; @@ -948,7 +981,7 @@ DEFPY (import_te, static void sharp_srv6_locator_chunk_free(struct prefix_ipv6 *chunk) { - prefix_ipv6_free((struct prefix_ipv6 **)&chunk); + prefix_ipv6_free(&chunk); } DEFPY (sharp_srv6_manager_get_locator_chunk, @@ -1419,6 +1452,7 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &remove_routes_cmd); install_element(ENABLE_NODE, &vrf_label_cmd); install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd); + install_element(ENABLE_NODE, &watch_neighbor_cmd); install_element(ENABLE_NODE, &watch_redistribute_cmd); install_element(ENABLE_NODE, &watch_nexthop_v6_cmd); install_element(ENABLE_NODE, &watch_nexthop_v4_cmd); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index c095fec17b20..1048436b4313 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -247,13 +247,12 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, memcpy(&api.prefix, p, sizeof(*p)); api.flags = flags; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* Only send via ID if nhgroup has been successfully installed */ if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { - SET_FLAG(api.message, ZAPI_MESSAGE_NHG); - api.nhgid = nhgid; + zapi_route_set_nhg_id(&api, &nhgid); } else { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_NEXTHOPS_PTR(nhg, nh)) { /* Check if we set a VNI label */ if (nh->nh_label && @@ -512,6 +511,7 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) static void zebra_connected(struct zclient *zclient) { + zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, true); zclient_send_reg_requests(zclient, VRF_DEFAULT); /* @@ -562,6 +562,12 @@ void nhg_add(uint32_t id, const struct nexthop_group *nhg, } if (api_nhg.nexthop_num == 0) { + if (sharp_nhgroup_id_is_installed(id)) { + zlog_debug("%s: nhg %u: no nexthops, deleting nexthop group", __func__, + id); + zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg); + return; + } zlog_debug("%s: nhg %u not sent: no valid nexthops", __func__, id); is_valid = false; @@ -666,27 +672,20 @@ static int sharp_debug_nexthops(struct zapi_route *api) return i; } -static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) + +static void sharp_nexthop_update(struct vrf *vrf, struct prefix *matched, + struct zapi_route *nhr) { struct sharp_nh_tracker *nht; - struct zapi_route nhr; - struct prefix matched; - - if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { - zlog_err("%s: Decode of update failed", __func__); - return 0; - } zlog_debug("Received update for %pFX actual match: %pFX metric: %u", - &matched, &nhr.prefix, nhr.metric); + matched, &nhr->prefix, nhr->metric); - nht = sharp_nh_tracker_get(&matched); - nht->nhop_num = nhr.nexthop_num; + nht = sharp_nh_tracker_get(matched); + nht->nhop_num = nhr->nexthop_num; nht->updates++; - sharp_debug_nexthops(&nhr); - - return 0; + sharp_debug_nexthops(nhr); } static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) @@ -705,10 +704,11 @@ static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) return 0; } -void sharp_redistribute_vrf(struct vrf *vrf, int type) +void sharp_redistribute_vrf(struct vrf *vrf, int type, bool turn_on) { - zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, - 0, vrf->vrf_id); + zebra_redistribute_send(turn_on ? ZEBRA_REDISTRIBUTE_ADD + : ZEBRA_REDISTRIBUTE_DELETE, + zclient, AFI_IP, type, 0, vrf->vrf_id); } static zclient_handler *const sharp_opaque_handlers[] = { @@ -934,6 +934,7 @@ static int nhg_notify_owner(ZAPI_CALLBACK_ARGS) zlog_debug("Failed install of nhg %u", id); break; case ZAPI_NHG_REMOVED: + sharp_nhgroup_id_set_installed(id, false); zlog_debug("Removed nhg %u", id); break; case ZAPI_NHG_REMOVE_FAIL: @@ -989,6 +990,41 @@ static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) return 0; } +static int sharp_zebra_process_neigh(ZAPI_CALLBACK_ARGS) +{ + union sockunion addr = {}, lladdr = {}; + struct zapi_neigh_ip api = {}; + struct interface *ifp; + + zlog_debug("Received a neighbor event"); + zclient_neigh_ip_decode(zclient->ibuf, &api); + + if (api.ip_in.ipa_type == AF_UNSPEC) + return 0; + + sockunion_family(&addr) = api.ip_in.ipa_type; + memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr, + family2addrsize(api.ip_in.ipa_type)); + + sockunion_family(&lladdr) = api.ip_out.ipa_type; + if (api.ip_out.ipa_type != AF_UNSPEC) + memcpy((uint8_t *)sockunion_get_addr(&lladdr), + &api.ip_out.ip.addr, + family2addrsize(api.ip_out.ipa_type)); + ifp = if_lookup_by_index(api.index, vrf_id); + if (!ifp) { + zlog_debug("Failed to lookup interface for neighbor entry: %u for %u", + api.index, vrf_id); + return 0; + } + + zlog_debug("Received: %s %pSU dev %s lladr %pSU", + (cmd == ZEBRA_NEIGH_ADDED) ? "NEW" : "DEL", &addr, ifp->name, + &lladdr); + + return 0; +} + int sharp_zebra_send_interface_protodown(struct interface *ifp, bool down) { zlog_debug("Sending zebra to set %s protodown %s", ifp->name, @@ -1059,11 +1095,16 @@ int sharp_zebra_send_tc_filter_rate(struct interface *ifp, return 0; } +void sharp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg) +{ + zclient_register_neigh(zclient, vrf_id, afi, reg); +} + + static zclient_handler *const sharp_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, - [ZEBRA_NEXTHOP_UPDATE] = sharp_nexthop_update, [ZEBRA_NHG_NOTIFY_OWNER] = nhg_notify_owner, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = sharp_redistribute_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = sharp_redistribute_route, @@ -1071,19 +1112,36 @@ static zclient_handler *const sharp_handlers[] = { [ZEBRA_OPAQUE_NOTIFY] = sharp_opq_notify_handler, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = sharp_zebra_process_srv6_locator_chunk, + [ZEBRA_NEIGH_ADDED] = sharp_zebra_process_neigh, + [ZEBRA_NEIGH_REMOVED] = sharp_zebra_process_neigh, }; void sharp_zebra_init(void) { - struct zclient_options opt = {.receive_notify = true}; + hook_register_prio(if_real, 0, sharp_ifp_create); + hook_register_prio(if_up, 0, sharp_ifp_up); + hook_register_prio(if_down, 0, sharp_ifp_down); + hook_register_prio(if_unreal, 0, sharp_ifp_destroy); - if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, sharp_ifp_down, - sharp_ifp_destroy); - - zclient = zclient_new(master, &opt, sharp_handlers, + zclient = zclient_new(master, &zclient_options_default, sharp_handlers, array_size(sharp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); zclient->zebra_connected = zebra_connected; zclient->zebra_buffer_write_ready = sharp_zclient_buffer_ready; + zclient->nexthop_update = sharp_nexthop_update; +} + +void sharp_zebra_terminate(void) +{ + struct sharp_zclient *node = sharp_clients_head; + + while (node) { + sharp_zclient_delete(node->client->session_id); + + node = sharp_clients_head; + } + + zclient_stop(zclient); + zclient_free(zclient); } diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 025b4d8f8257..5cbcc146654c 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -8,6 +8,7 @@ #define __SHARP_ZEBRA_H__ extern void sharp_zebra_init(void); +extern void sharp_zebra_terminate(void); /* Add and delete extra zapi client sessions, for testing */ int sharp_zclient_create(uint32_t session_id); @@ -54,7 +55,7 @@ extern void sharp_zebra_send_arp(const struct interface *ifp, /* Register Link State Opaque messages */ extern void sharp_zebra_register_te(void); -extern void sharp_redistribute_vrf(struct vrf *vrf, int source); +extern void sharp_redistribute_vrf(struct vrf *vrf, int source, bool turn_on); extern int sharp_zebra_srv6_manager_get_locator_chunk(const char *lname); extern int sharp_zebra_srv6_manager_release_locator_chunk(const char *lname); @@ -70,4 +71,6 @@ extern int sharp_zebra_send_tc_filter_rate(struct interface *ifp, const struct prefix *destination, uint8_t ip_proto, uint16_t src_port, uint16_t dst_port, uint64_t rate); + +extern void sharp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg); #endif diff --git a/snapcraft/scripts/bfdd-service b/snapcraft/scripts/bfdd-service index f94a7abb4bd9..5e41d1ae6d1a 100644 --- a/snapcraft/scripts/bfdd-service +++ b/snapcraft/scripts/bfdd-service @@ -9,6 +9,5 @@ exec $SNAP/sbin/bfdd \ -f $SNAP_DATA/bfdd.conf \ --pid_file $SNAP_DATA/bfdd.pid \ --socket $SNAP_DATA/zsock \ - --vty_socket $SNAP_DATA \ - --bfdctl $SNAP_DATA/bfdd.sock + --vty_socket $SNAP_DATA diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index 607cbc7fe3c2..eea9bfc0ee66 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -249,7 +249,7 @@ apps: - network-bind - network-control bfdd-debug: - command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA --bfdctl $SNAP_DATA/bfdd.sock + command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA plugs: - network - network-bind @@ -302,7 +302,7 @@ parts: - libpcre2-8-0 source: https://github.com/CESNET/libyang.git source-type: git - source-tag: v2.1.80 + source-tag: v2.1.128 plugin: cmake configflags: - -DCMAKE_INSTALL_PREFIX:PATH=/usr @@ -369,7 +369,6 @@ parts: - --enable-ospfapi=yes - --enable-multipath=64 - --enable-rtadv - - --enable-irdp - --enable-user=root - --enable-group=root - --enable-pimd @@ -381,10 +380,10 @@ parts: - --enable-vrrpd - --enable-configfile-mask=0640 - --enable-logfile-mask=0640 - - --localstatedir=/var/run + - --sysconfdir=/etc + - --localstatedir=/var - --sbindir=/sbin - --bindir=/bin - - --sysconfdir=/etc/frr - --with-pkg-extra-version=@PACKAGE_EXTRAVERSION@ frr-defaults: plugin: dump diff --git a/staticd/static_bfd.c b/staticd/static_bfd.c index 507c64e6a4c9..c35751f3972b 100644 --- a/staticd/static_bfd.c +++ b/staticd/static_bfd.c @@ -91,11 +91,11 @@ void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn, struct vrf *vrf = NULL; use_interface = false; - use_source = yang_dnode_exists(dnode, "./source"); - use_profile = yang_dnode_exists(dnode, "./profile"); + use_source = yang_dnode_exists(dnode, "source"); + use_profile = yang_dnode_exists(dnode, "profile"); onlink = yang_dnode_exists(dnode, "../onlink") && yang_dnode_get_bool(dnode, "../onlink"); - mhop = yang_dnode_get_bool(dnode, "./multi-hop"); + mhop = yang_dnode_get_bool(dnode, "multi-hop"); vrf = vrf_lookup_by_name(yang_dnode_get_string(dnode, "../vrf")); family = static_next_hop_type_to_family(sn); @@ -112,7 +112,7 @@ void static_next_hop_bfd_monitor_enable(struct static_nexthop *sn, /* Configure the session. */ if (use_source) - yang_dnode_get_ip(&source, dnode, "./source"); + yang_dnode_get_ip(&source, dnode, "source"); if (onlink || mhop == false) bfd_sess_set_auto_source(sn->bsp, false); @@ -263,14 +263,13 @@ static void static_bfd_show_path_json(struct vty *vty, struct json_object *jo, static void static_bfd_show_json(struct vty *vty) { struct json_object *jo, *jo_path, *jo_afi_safi; - struct vrf *vrf; + struct static_vrf *svrf; jo = json_object_new_object(); jo_path = json_object_new_object(); json_object_object_add(jo, "path-list", jo_path); - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - const struct static_vrf *svrf = vrf->info; + RB_FOREACH (svrf, svrf_name_head, &svrfs) { struct route_table *rt; jo_afi_safi = json_object_new_array(); @@ -346,7 +345,7 @@ static void static_bfd_show_path(struct vty *vty, struct route_table *rt) void static_bfd_show(struct vty *vty, bool json) { - struct vrf *vrf; + struct static_vrf *svrf; if (json) { static_bfd_show_json(vty); @@ -355,21 +354,20 @@ void static_bfd_show(struct vty *vty, bool json) vty_out(vty, "Showing BFD monitored static routes:\n"); vty_out(vty, "\n Next hops:\n"); - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - const struct static_vrf *svrf = vrf->info; + RB_FOREACH (svrf, svrf_name_head, &svrfs) { struct route_table *rt; - vty_out(vty, " VRF %s IPv4 Unicast:\n", vrf->name); + vty_out(vty, " VRF %s IPv4 Unicast:\n", svrf->name); rt = svrf->stable[AFI_IP][SAFI_UNICAST]; if (rt) static_bfd_show_path(vty, rt); - vty_out(vty, "\n VRF %s IPv4 Multicast:\n", vrf->name); + vty_out(vty, "\n VRF %s IPv4 Multicast:\n", svrf->name); rt = svrf->stable[AFI_IP][SAFI_MULTICAST]; if (rt) static_bfd_show_path(vty, rt); - vty_out(vty, "\n VRF %s IPv6 Unicast:\n", vrf->name); + vty_out(vty, "\n VRF %s IPv6 Unicast:\n", svrf->name); rt = svrf->stable[AFI_IP6][SAFI_UNICAST]; if (rt) static_bfd_show_path(vty, rt); diff --git a/staticd/static_main.c b/staticd/static_main.c index 165fb4d65204..9468a98b833e 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -53,7 +53,7 @@ struct option longopts[] = { { 0 } }; /* Master of threads. */ struct event_loop *master; -struct mgmt_be_client *mgmt_be_client; +static struct mgmt_be_client *mgmt_be_client; static struct frr_daemon_info staticd_di; @@ -113,23 +113,26 @@ static const struct frr_yang_module_info *const staticd_yang_modules[] = { &frr_staticd_info, }; -#define STATIC_VTY_PORT 2616 - /* * NOTE: .flags == FRR_NO_SPLIT_CONFIG to avoid reading split config, mgmtd will * do this for us now */ -FRR_DAEMON_INFO(staticd, STATIC, .vty_port = STATIC_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(staticd, STATIC, + .vty_port = STATIC_VTY_PORT, + .proghelp = "Implementation of STATIC.", - .proghelp = "Implementation of STATIC.", + .signals = static_signals, + .n_signals = array_size(static_signals), - .signals = static_signals, - .n_signals = array_size(static_signals), + .privs = &static_privs, - .privs = &static_privs, .yang_modules = staticd_yang_modules, - .n_yang_modules = array_size(staticd_yang_modules), + .yang_modules = staticd_yang_modules, + .n_yang_modules = array_size(staticd_yang_modules), - .flags = FRR_NO_SPLIT_CONFIG); + .flags = FRR_NO_SPLIT_CONFIG, +); +/* clang-format on */ int main(int argc, char **argv, char **envp) { @@ -165,8 +168,10 @@ int main(int argc, char **argv, char **envp) hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); - - routing_control_plane_protocols_register_vrf_dependency(); + hook_register(routing_create, + routing_control_plane_protocols_staticd_create); + hook_register(routing_destroy, + routing_control_plane_protocols_staticd_destroy); /* * We set FRR_NO_SPLIT_CONFIG flag to avoid reading our config, but we diff --git a/staticd/static_nb.c b/staticd/static_nb.c index 1c69a58035b9..e6aa71a77b48 100644 --- a/staticd/static_nb.c +++ b/staticd/static_nb.c @@ -15,19 +15,11 @@ const struct frr_yang_module_info frr_staticd_info = { .name = "frr-staticd", .nodes = { - { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd", - .cbs = { - .cli_show = static_cli_show, - .cli_show_end = static_cli_show_end, - } - }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list", .cbs = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create, .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_destroy, - .cli_cmp = static_route_list_cli_cmp, } }, { @@ -35,7 +27,6 @@ const struct frr_yang_module_info frr_staticd_info = { .cbs = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_create, .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_destroy, - .cli_cmp = static_path_list_cli_cmp, } }, { @@ -51,8 +42,6 @@ const struct frr_yang_module_info frr_staticd_info = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create, .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy, .pre_validate = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate, - .cli_show = static_nexthop_cli_show, - .cli_cmp = static_nexthop_cli_cmp, } }, { @@ -150,7 +139,6 @@ const struct frr_yang_module_info frr_staticd_info = { .cbs = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create, .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy, - .cli_cmp = static_src_list_cli_cmp, } }, { @@ -158,7 +146,6 @@ const struct frr_yang_module_info frr_staticd_info = { .cbs = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_create, .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_destroy, - .cli_cmp = static_path_list_cli_cmp, } }, { @@ -174,8 +161,6 @@ const struct frr_yang_module_info frr_staticd_info = { .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create, .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy, .pre_validate = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate, - .cli_show = static_src_nexthop_cli_show, - .cli_cmp = static_nexthop_cli_cmp, } }, { diff --git a/staticd/static_nb.h b/staticd/static_nb.h index 9f80653b762d..be75d9d38ce3 100644 --- a/staticd/static_nb.h +++ b/staticd/static_nb.h @@ -11,6 +11,12 @@ extern "C" { #endif extern const struct frr_yang_module_info frr_staticd_info; +extern const struct frr_yang_module_info frr_staticd_cli_info; + +int routing_control_plane_protocols_staticd_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_staticd_destroy( + struct nb_cb_destroy_args *args); /* Mandatory callbacks. */ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create( diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c index ede2e387544c..7de5f0474aad 100644 --- a/staticd/static_nb_config.c +++ b/staticd/static_nb_config.c @@ -18,6 +18,7 @@ #include "static_vrf.h" #include "static_routes.h" #include "static_nb.h" +#include "static_zebra.h" static int static_path_list_create(struct nb_cb_create_args *args) @@ -33,8 +34,8 @@ static int static_path_list_create(struct nb_cb_create_args *args) case NB_EV_VALIDATE: vrf_dnode = yang_dnode_get_parent(args->dnode, "control-plane-protocol"); - vrf = yang_dnode_get_string(vrf_dnode, "./vrf"); - table_id = yang_dnode_get_uint32(args->dnode, "./table-id"); + vrf = yang_dnode_get_string(vrf_dnode, "vrf"); + table_id = yang_dnode_get_uint32(args->dnode, "table-id"); /* * TableId is not applicable for VRF. Consider the case of @@ -55,8 +56,8 @@ static int static_path_list_create(struct nb_cb_create_args *args) break; case NB_EV_APPLY: rn = nb_running_get_entry(args->dnode, NULL, true); - distance = yang_dnode_get_uint8(args->dnode, "./distance"); - table_id = yang_dnode_get_uint32(args->dnode, "./table-id"); + distance = yang_dnode_get_uint8(args->dnode, "distance"); + table_id = yang_dnode_get_uint32(args->dnode, "table-id"); pn = static_add_path(rn, table_id, distance); nb_running_set_entry(args->dnode, pn); } @@ -111,7 +112,7 @@ static int nexthop_iter_cb(const struct lyd_node *dnode, void *arg) struct nexthop_iter *iter = arg; enum static_nh_type nh_type; - nh_type = yang_dnode_get_enum(dnode, "./nh-type"); + nh_type = yang_dnode_get_enum(dnode, "nh-type"); if (nh_type == STATIC_BLACKHOLE) iter->blackhole = true; @@ -134,9 +135,8 @@ static bool static_nexthop_create(struct nb_cb_create_args *args) switch (args->event) { case NB_EV_VALIDATE: - ifname = yang_dnode_get_string(args->dnode, "./interface"); - nh_type = yang_dnode_get_enum(args->dnode, "./nh-type"); - if (ifname != NULL && nh_type != STATIC_BLACKHOLE) { + ifname = yang_dnode_get_string(args->dnode, "interface"); + if (ifname != NULL) { if (strcasecmp(ifname, "Null0") == 0 || strcasecmp(ifname, "reject") == 0 || strcasecmp(ifname, "blackhole") == 0) { @@ -170,12 +170,15 @@ static bool static_nexthop_create(struct nb_cb_create_args *args) case NB_EV_ABORT: break; case NB_EV_APPLY: - yang_dnode_get_ip(&ipaddr, args->dnode, "./gateway"); - nh_type = yang_dnode_get_enum(args->dnode, "./nh-type"); - ifname = yang_dnode_get_string(args->dnode, "./interface"); - nh_vrf = yang_dnode_get_string(args->dnode, "./vrf"); + yang_dnode_get_ip(&ipaddr, args->dnode, "gateway"); + nh_type = yang_dnode_get_enum(args->dnode, "nh-type"); + ifname = yang_dnode_get_string(args->dnode, "interface"); + nh_vrf = yang_dnode_get_string(args->dnode, "vrf"); pn = nb_running_get_entry(args->dnode, NULL, true); + if (strmatch(ifname, "(null)")) + ifname = ""; + if (!static_add_nexthop_validate(nh_vrf, nh_type, &ipaddr)) flog_warn( EC_LIB_NB_CB_CONFIG_VALIDATE, @@ -464,33 +467,10 @@ static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args) { struct static_nexthop *nh; enum static_nh_type nh_type; - const char *nh_ifname; - const char *nh_vrf; switch (args->event) { case NB_EV_VALIDATE: nh_type = yang_dnode_get_enum(args->dnode, "../nh-type"); - nh_ifname = yang_dnode_get_string(args->dnode, "../interface"); - nh_vrf = yang_dnode_get_string(args->dnode, "../vrf"); - if (nh_ifname && nh_vrf) { - struct vrf *vrf = vrf_lookup_by_name(nh_vrf); - - if (!vrf) { - snprintf(args->errmsg, args->errmsg_len, - "nexthop vrf %s not found", nh_vrf); - return NB_ERR_VALIDATION; - } - - struct interface *ifp = if_lookup_by_name(nh_ifname, - vrf->vrf_id); - - if (ifp && (!strmatch(nh_ifname, "blackhole") || - !strmatch(nh_ifname, "reject"))) { - snprintf(args->errmsg, args->errmsg_len, - "nexthop interface name must be (reject, blackhole)"); - return NB_ERR_VALIDATION; - } - } if (nh_type != STATIC_BLACKHOLE) { snprintf(args->errmsg, args->errmsg_len, "nexthop type is not the blackhole type"); @@ -535,7 +515,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa const struct lyd_node *mls_dnode; uint32_t count; - mls_dnode = yang_dnode_get(args->dnode, "./mpls-label-stack"); + mls_dnode = yang_dnode_get(args->dnode, "mpls-label-stack"); count = yang_get_list_elements_count(lyd_child(mls_dnode)); if (count > MPLS_MAX_LABELS) { @@ -552,7 +532,7 @@ int routing_control_plane_protocols_name_validate( { const char *name; - name = yang_dnode_get_string(args->dnode, "./name"); + name = yang_dnode_get_string(args->dnode, "name"); if (!strmatch(name, "staticd")) { snprintf(args->errmsg, args->errmsg_len, "static routing supports only one instance with name staticd"); @@ -560,6 +540,48 @@ int routing_control_plane_protocols_name_validate( } return NB_OK; } + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol + */ +int routing_control_plane_protocols_staticd_create(struct nb_cb_create_args *args) +{ + struct static_vrf *svrf; + const char *vrf; + + vrf = yang_dnode_get_string(args->dnode, "vrf"); + svrf = static_vrf_alloc(vrf); + nb_running_set_entry(args->dnode, svrf); + + return NB_OK; +} + +int routing_control_plane_protocols_staticd_destroy( + struct nb_cb_destroy_args *args) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct route_node *rn; + afi_t afi; + safi_t safi; + + svrf = nb_running_unset_entry(args->dnode); + + FOREACH_AFI_SAFI (afi, safi) { + stable = svrf->stable[afi][safi]; + if (!stable) + continue; + + for (rn = route_top(stable); rn; rn = route_next(rn)) + static_del_route(rn); + } + + static_vrf_free(svrf); + + return NB_OK; +} + /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list @@ -567,8 +589,7 @@ int routing_control_plane_protocols_name_validate( int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create( struct nb_cb_create_args *args) { - struct vrf *vrf; - struct static_vrf *s_vrf; + struct static_vrf *svrf; struct route_node *rn; const struct lyd_node *vrf_dnode; struct prefix prefix; @@ -579,15 +600,15 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_cr switch (args->event) { case NB_EV_VALIDATE: - yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); - afi_safi = yang_dnode_get_string(args->dnode, "./afi-safi"); + yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); + afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); yang_afi_safi_identity2value(afi_safi, &afi, &safi); prefix_afi = family2afi(prefix.family); if (afi != prefix_afi) { flog_warn( EC_LIB_NB_CB_CONFIG_VALIDATE, "route node %s creation failed", - yang_dnode_get_string(args->dnode, "./prefix")); + yang_dnode_get_string(args->dnode, "prefix")); return NB_ERR_VALIDATION; } break; @@ -597,19 +618,18 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_cr case NB_EV_APPLY: vrf_dnode = yang_dnode_get_parent(args->dnode, "control-plane-protocol"); - vrf = nb_running_get_entry(vrf_dnode, NULL, true); - s_vrf = vrf->info; + svrf = nb_running_get_entry(vrf_dnode, NULL, true); - yang_dnode_get_prefix(&prefix, args->dnode, "./prefix"); - afi_safi = yang_dnode_get_string(args->dnode, "./afi-safi"); + yang_dnode_get_prefix(&prefix, args->dnode, "prefix"); + afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); yang_afi_safi_identity2value(afi_safi, &afi, &safi); - rn = static_add_route(afi, safi, &prefix, NULL, s_vrf); - if (vrf->vrf_id == VRF_UNKNOWN) + rn = static_add_route(afi, safi, &prefix, NULL, svrf); + if (!svrf->vrf || svrf->vrf->vrf_id == VRF_UNKNOWN) snprintf( args->errmsg, args->errmsg_len, "Static Route to %s not installed currently because dependent config not fully available", - yang_dnode_get_string(args->dnode, "./prefix")); + yang_dnode_get_string(args->dnode, "prefix")); nb_running_set_entry(args->dnode, rn); break; } @@ -960,6 +980,17 @@ int route_next_hop_bfd_source_destroy(struct nb_cb_destroy_args *args) sn = nb_running_get_entry(args->dnode, NULL, true); static_next_hop_bfd_auto_source(sn); + + /* NHT information are needed by BFD to automatically find the source + * + * Force zebra to resend the information to BFD by unregistering and + * registering again NHT. The (...)/frr-nexthops/nexthop northbound + * apply_finish function will trigger a call to static_install_nexthop() + * that does a call to static_zebra_nht_register(nh, true); + * static_zebra_nht_register(sn, false); + */ + static_zebra_nht_register(sn, false); + return NB_OK; } @@ -1036,7 +1067,7 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr rn = nb_running_get_entry(args->dnode, NULL, true); info = route_table_get_info(rn->table); s_vrf = info->svrf; - yang_dnode_get_ipv6p(&src_prefix, args->dnode, "./src-prefix"); + yang_dnode_get_ipv6p(&src_prefix, args->dnode, "src-prefix"); afi = family2afi(src_prefix.family); src_rn = static_add_route(afi, safi, &rn->p, &src_prefix, s_vrf); diff --git a/staticd/static_nht.c b/staticd/static_nht.c index ebc5ea16ccc0..6be598434d42 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -18,8 +18,7 @@ #include "static_nht.h" static void static_nht_update_path(struct static_path *pn, struct prefix *nhp, - uint32_t nh_num, vrf_id_t nh_vrf_id, - struct vrf *vrf) + uint32_t nh_num, vrf_id_t nh_vrf_id) { struct static_nexthop *nh; @@ -49,18 +48,13 @@ static void static_nht_update_path(struct static_path *pn, struct prefix *nhp, static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, uint32_t nh_num, afi_t afi, safi_t safi, - struct vrf *vrf, vrf_id_t nh_vrf_id) + struct static_vrf *svrf, vrf_id_t nh_vrf_id) { struct route_table *stable; - struct static_vrf *svrf; struct route_node *rn; struct static_path *pn; struct static_route_info *si; - svrf = vrf->info; - if (!svrf) - return; - stable = static_vrf_static_table(afi, safi, svrf); if (!stable) return; @@ -71,7 +65,7 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, si = static_route_info_from_rnode(rn); frr_each(static_path_list, &si->path_list, pn) { static_nht_update_path(pn, nhp, nh_num, - nh_vrf_id, vrf); + nh_vrf_id); } route_unlock_node(rn); } @@ -83,7 +77,7 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, if (!si) continue; frr_each(static_path_list, &si->path_list, pn) { - static_nht_update_path(pn, nhp, nh_num, nh_vrf_id, vrf); + static_nht_update_path(pn, nhp, nh_num, nh_vrf_id); } } } @@ -91,29 +85,23 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, void static_nht_update(struct prefix *sp, struct prefix *nhp, uint32_t nh_num, afi_t afi, safi_t safi, vrf_id_t nh_vrf_id) { + struct static_vrf *svrf; - struct vrf *vrf; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - static_nht_update_safi(sp, nhp, nh_num, afi, safi, vrf, + RB_FOREACH (svrf, svrf_name_head, &svrfs) + static_nht_update_safi(sp, nhp, nh_num, afi, safi, svrf, nh_vrf_id); } static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi, - safi_t safi, struct vrf *vrf, + safi_t safi, struct static_vrf *svrf, vrf_id_t nh_vrf_id) { - struct static_vrf *svrf; struct route_table *stable; struct static_nexthop *nh; struct static_path *pn; struct route_node *rn; struct static_route_info *si; - svrf = vrf->info; - if (!svrf) - return; - stable = static_vrf_static_table(afi, safi, svrf); if (!stable) return; @@ -153,10 +141,10 @@ static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi, void static_nht_reset_start(struct prefix *nhp, afi_t afi, safi_t safi, vrf_id_t nh_vrf_id) { - struct vrf *vrf; + struct static_vrf *svrf; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - static_nht_reset_start_safi(nhp, afi, safi, vrf, nh_vrf_id); + RB_FOREACH (svrf, svrf_name_head, &svrfs) + static_nht_reset_start_safi(nhp, afi, safi, svrf, nh_vrf_id); } static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi, diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 1fbbf7e99d34..cba38183bbf0 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -87,11 +87,6 @@ void zebra_stable_node_cleanup(struct route_table *table, /* Install static path into rib. */ void static_install_path(struct static_path *pn) { - struct static_nexthop *nh; - - frr_each(static_nexthop_list, &pn->nexthop_list, nh) - static_zebra_nht_register(nh, true); - if (static_nexthop_list_count(&pn->nexthop_list)) static_zebra_route_add(pn, true); } @@ -245,21 +240,20 @@ void static_del_path(struct static_path *pn) XFREE(MTYPE_STATIC_PATH, pn); } -struct static_nexthop *static_add_nexthop(struct static_path *pn, - enum static_nh_type type, - struct ipaddr *ipaddr, - const char *ifname, - const char *nh_vrf, uint32_t color) +struct static_nexthop * +static_add_nexthop(struct static_path *pn, enum static_nh_type type, + struct ipaddr *ipaddr, const char *ifname, + const char *nh_vrfname, uint32_t color) { struct route_node *rn = pn->rn; struct static_nexthop *nh; - struct static_vrf *nh_svrf; + struct vrf *nh_vrf; struct interface *ifp; struct static_nexthop *cp; route_lock_node(rn); - nh_svrf = static_vrf_lookup_by_name(nh_vrf); + nh_vrf = vrf_lookup_by_name(nh_vrfname); /* Make new static route structure. */ nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop)); @@ -274,8 +268,8 @@ struct static_nexthop *static_add_nexthop(struct static_path *pn, if (nh->type == STATIC_BLACKHOLE) nh->bh_type = STATIC_BLACKHOLE_NULL; - nh->nh_vrf_id = nh_svrf ? nh_svrf->vrf->vrf_id : VRF_UNKNOWN; - strlcpy(nh->nh_vrfname, nh_vrf, sizeof(nh->nh_vrfname)); + nh->nh_vrf_id = nh_vrf ? nh_vrf->vrf_id : VRF_UNKNOWN; + strlcpy(nh->nh_vrfname, nh_vrfname, sizeof(nh->nh_vrfname)); if (ifname) strlcpy(nh->ifname, ifname, sizeof(nh->ifname)); @@ -378,6 +372,17 @@ void static_install_nexthop(struct static_nexthop *nh) } } +void static_uninstall_nexthop(struct static_nexthop *nh) +{ + struct static_path *pn = nh->pn; + + if (nh->nh_vrf_id == VRF_UNKNOWN) + return; + + static_zebra_nht_register(nh, false); + static_uninstall_path(pn); +} + void static_delete_nexthop(struct static_nexthop *nh) { struct static_path *pn = nh->pn; @@ -387,17 +392,8 @@ void static_delete_nexthop(struct static_nexthop *nh) /* Remove BFD session/configuration if any. */ bfd_sess_free(&nh->bsp); - if (nh->nh_vrf_id == VRF_UNKNOWN) - goto EXIT; - - static_zebra_nht_register(nh, false); - /* - * If we have other si nodes then route replace - * else delete the route - */ - static_uninstall_path(pn); + static_uninstall_nexthop(nh); -EXIT: route_unlock_node(rn); /* Free static route configuration. */ XFREE(MTYPE_STATIC_NEXTHOP, nh); @@ -437,14 +433,10 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, struct route_node *rn; struct static_nexthop *nh; struct static_path *pn; - struct vrf *vrf; + struct static_vrf *svrf; struct static_route_info *si; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct static_vrf *svrf; - - svrf = vrf->info; - + RB_FOREACH (svrf, svrf_name_head, &svrfs) { stable = static_vrf_static_table(afi, safi, svrf); if (!stable) continue; @@ -476,8 +468,8 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi, * afi -> The afi to look at * safi -> the safi to look at */ -static void static_fixup_vrf(struct static_vrf *svrf, - struct route_table *stable, afi_t afi, safi_t safi) +static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable, + afi_t afi, safi_t safi) { struct route_node *rn; struct static_nexthop *nh; @@ -491,13 +483,11 @@ static void static_fixup_vrf(struct static_vrf *svrf, continue; frr_each(static_path_list, &si->path_list, pn) { frr_each(static_nexthop_list, &pn->nexthop_list, nh) { - if (strcmp(svrf->vrf->name, nh->nh_vrfname) - != 0) + if (strcmp(vrf->name, nh->nh_vrfname) != 0) continue; - nh->nh_vrf_id = svrf->vrf->vrf_id; - nh->nh_registered = false; - if (nh->ifindex) { + nh->nh_vrf_id = vrf->vrf_id; + if (nh->ifname[0]) { ifp = if_lookup_by_name(nh->ifname, nh->nh_vrf_id); if (ifp) @@ -506,7 +496,7 @@ static void static_fixup_vrf(struct static_vrf *svrf, continue; } - static_install_path(pn); + static_install_nexthop(nh); } } } @@ -521,13 +511,9 @@ static void static_fixup_vrf(struct static_vrf *svrf, * afi -> the afi in question * safi -> the safi in question */ -static void static_enable_vrf(struct static_vrf *svrf, - struct route_table *stable, afi_t afi, - safi_t safi) +static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi) { struct route_node *rn; - struct static_nexthop *nh; - struct interface *ifp; struct static_path *pn; struct static_route_info *si; @@ -535,21 +521,8 @@ static void static_enable_vrf(struct static_vrf *svrf, si = static_route_info_from_rnode(rn); if (!si) continue; - frr_each(static_path_list, &si->path_list, pn) { - frr_each(static_nexthop_list, &pn->nexthop_list, nh) { - if (nh->ifindex) { - ifp = if_lookup_by_name(nh->ifname, - nh->nh_vrf_id); - if (ifp) - nh->ifindex = ifp->ifindex; - else - continue; - } - if (nh->nh_vrf_id == VRF_UNKNOWN) - continue; - static_install_path(pn); - } - } + frr_each(static_path_list, &si->path_list, pn) + static_install_path(pn); } } @@ -560,27 +533,26 @@ static void static_enable_vrf(struct static_vrf *svrf, * * enable_svrf -> the vrf being enabled */ -void static_fixup_vrf_ids(struct static_vrf *enable_svrf) +void static_fixup_vrf_ids(struct vrf *vrf) { struct route_table *stable; - struct vrf *vrf; + struct static_vrf *svrf, *enable_svrf; afi_t afi; safi_t safi; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct static_vrf *svrf; + enable_svrf = vrf->info; - svrf = vrf->info; + RB_FOREACH (svrf, svrf_name_head, &svrfs) { /* Install any static routes configured for this VRF. */ FOREACH_AFI_SAFI (afi, safi) { stable = svrf->stable[afi][safi]; if (!stable) continue; - static_fixup_vrf(enable_svrf, stable, afi, safi); + static_fixup_vrf(vrf, stable, afi, safi); if (enable_svrf == svrf) - static_enable_vrf(svrf, stable, afi, safi); + static_enable_vrf(stable, afi, safi); } } } @@ -595,8 +567,7 @@ void static_fixup_vrf_ids(struct static_vrf *enable_svrf) * afi -> the afi in question * safi -> the safi in question */ -static void static_cleanup_vrf(struct static_vrf *svrf, - struct route_table *stable, +static void static_cleanup_vrf(struct vrf *vrf, struct route_table *stable, afi_t afi, safi_t safi) { struct route_node *rn; @@ -610,11 +581,13 @@ static void static_cleanup_vrf(struct static_vrf *svrf, continue; frr_each(static_path_list, &si->path_list, pn) { frr_each(static_nexthop_list, &pn->nexthop_list, nh) { - if (strcmp(svrf->vrf->name, nh->nh_vrfname) - != 0) + if (strcmp(vrf->name, nh->nh_vrfname) != 0) continue; - static_uninstall_path(pn); + static_uninstall_nexthop(nh); + + nh->nh_vrf_id = VRF_UNKNOWN; + nh->ifindex = IFINDEX_INTERNAL; } } } @@ -632,7 +605,6 @@ static void static_disable_vrf(struct route_table *stable, afi_t afi, safi_t safi) { struct route_node *rn; - struct static_nexthop *nh; struct static_path *pn; struct static_route_info *si; @@ -640,11 +612,8 @@ static void static_disable_vrf(struct route_table *stable, si = static_route_info_from_rnode(rn); if (!si) continue; - frr_each(static_path_list, &si->path_list, pn) { - frr_each(static_nexthop_list, &pn->nexthop_list, nh) { - static_uninstall_path(pn); - } - } + frr_each(static_path_list, &si->path_list, pn) + static_uninstall_path(pn); } } @@ -656,26 +625,23 @@ static void static_disable_vrf(struct route_table *stable, * * disable_svrf - The vrf being disabled */ -void static_cleanup_vrf_ids(struct static_vrf *disable_svrf) +void static_cleanup_vrf_ids(struct vrf *vrf) { - struct vrf *vrf; + struct route_table *stable; + struct static_vrf *svrf, *disable_svrf; afi_t afi; safi_t safi; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct static_vrf *svrf; - - svrf = vrf->info; + disable_svrf = vrf->info; + RB_FOREACH (svrf, svrf_name_head, &svrfs) { /* Uninstall any static routes configured for this VRF. */ FOREACH_AFI_SAFI (afi, safi) { - struct route_table *stable; - stable = svrf->stable[afi][safi]; if (!stable) continue; - static_cleanup_vrf(disable_svrf, stable, afi, safi); + static_cleanup_vrf(vrf, stable, afi, safi); if (disable_svrf == svrf) static_disable_vrf(stable, afi, safi); @@ -683,71 +649,6 @@ void static_cleanup_vrf_ids(struct static_vrf *disable_svrf) } } -/* - * This function enables static routes when an interface it relies - * on in a different vrf is coming up. - * - * stable -> The stable we are looking at. - * ifp -> interface coming up - * afi -> the afi in question - * safi -> the safi in question - */ -static void static_fixup_intf_nh(struct route_table *stable, - struct interface *ifp, - afi_t afi, safi_t safi) -{ - struct route_node *rn; - struct static_nexthop *nh; - struct static_path *pn; - struct static_route_info *si; - - for (rn = route_top(stable); rn; rn = route_next(rn)) { - si = static_route_info_from_rnode(rn); - if (!si) - continue; - frr_each(static_path_list, &si->path_list, pn) { - frr_each(static_nexthop_list, &pn->nexthop_list, nh) { - if (nh->nh_vrf_id != ifp->vrf->vrf_id) - continue; - - if (nh->ifindex != ifp->ifindex) - continue; - - static_install_path(pn); - } - } - } -} - -/* - * This function enables static routes that rely on an interface in - * a different vrf when that interface comes up. - */ -void static_install_intf_nh(struct interface *ifp) -{ - struct route_table *stable; - struct vrf *vrf; - afi_t afi; - safi_t safi; - - RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { - struct static_vrf *svrf = vrf->info; - - /* Not needed if same vrf since happens naturally */ - if (vrf->vrf_id == ifp->vrf->vrf_id) - continue; - - /* Install any static routes configured for this interface. */ - FOREACH_AFI_SAFI (afi, safi) { - stable = svrf->stable[afi][safi]; - if (!stable) - continue; - - static_fixup_intf_nh(stable, ifp, afi, safi); - } - } -} - /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ void static_ifindex_update(struct interface *ifp, bool up) { diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 548148b187f5..2e2e4986c348 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -131,7 +131,7 @@ struct static_nexthop { bool nh_registered; bool nh_valid; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; /* Label information */ struct static_nh_label snh_label; @@ -199,20 +199,18 @@ extern uint32_t zebra_ecmp_count; extern struct zebra_privs_t static_privs; -void static_fixup_vrf_ids(struct static_vrf *svrf); +extern void static_fixup_vrf_ids(struct vrf *vrf); +extern void static_cleanup_vrf_ids(struct vrf *vrf); extern struct static_nexthop * static_add_nexthop(struct static_path *pn, enum static_nh_type type, struct ipaddr *ipaddr, const char *ifname, const char *nh_vrf, uint32_t color); extern void static_install_nexthop(struct static_nexthop *nh); +extern void static_uninstall_nexthop(struct static_nexthop *nh); extern void static_delete_nexthop(struct static_nexthop *nh); -extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf); - -extern void static_install_intf_nh(struct interface *ifp); - extern void static_ifindex_update(struct interface *ifp, bool up); extern void static_install_path(struct static_path *pn); @@ -239,7 +237,7 @@ extern void zebra_stable_node_cleanup(struct route_table *table, * Max string return via API static_get_nh_str in size_t */ -#define NEXTHOP_STR (INET6_ADDRSTRLEN + INTERFACE_NAMSIZ + 25) +#define NEXTHOP_STR (INET6_ADDRSTRLEN + IFNAMSIZ + 25) /* * For the given nexthop, returns the string * nexthop : returns the formatted string in nexthop diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index a67dce200fcf..710827a9ff49 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -18,16 +18,37 @@ DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info"); -static struct static_vrf *static_vrf_alloc(void) +static int svrf_name_compare(const struct static_vrf *a, + const struct static_vrf *b) +{ + return strcmp(a->name, b->name); +} + +RB_GENERATE(svrf_name_head, static_vrf, entry, svrf_name_compare); + +struct svrf_name_head svrfs = RB_INITIALIZER(&svrfs); + +static struct static_vrf *static_vrf_lookup_by_name(const char *name) +{ + struct static_vrf svrf; + + strlcpy(svrf.name, name, sizeof(svrf.name)); + return RB_FIND(svrf_name_head, &svrfs, &svrf); +} + +struct static_vrf *static_vrf_alloc(const char *name) { struct route_table *table; struct static_vrf *svrf; struct stable_info *info; + struct vrf *vrf; safi_t safi; afi_t afi; svrf = XCALLOC(MTYPE_STATIC_RTABLE_INFO, sizeof(struct static_vrf)); + strlcpy(svrf->name, name, sizeof(svrf->name)); + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { if (afi == AFI_IP6) @@ -46,16 +67,56 @@ static struct static_vrf *static_vrf_alloc(void) svrf->stable[afi][safi] = table; } } + + RB_INSERT(svrf_name_head, &svrfs, svrf); + + vrf = vrf_lookup_by_name(name); + if (vrf) { + svrf->vrf = vrf; + vrf->info = svrf; + } + return svrf; } +void static_vrf_free(struct static_vrf *svrf) +{ + struct route_table *table; + struct vrf *vrf; + safi_t safi; + afi_t afi; + void *info; + + vrf = svrf->vrf; + if (vrf) { + vrf->info = NULL; + svrf->vrf = NULL; + } + + RB_REMOVE(svrf_name_head, &svrfs, svrf); + + for (afi = AFI_IP; afi <= AFI_IP6; afi++) { + for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { + table = svrf->stable[afi][safi]; + info = route_table_get_info(table); + route_table_finish(table); + XFREE(MTYPE_STATIC_RTABLE_INFO, info); + svrf->stable[afi][safi] = NULL; + } + } + + XFREE(MTYPE_STATIC_RTABLE_INFO, svrf); +} + static int static_vrf_new(struct vrf *vrf) { struct static_vrf *svrf; - svrf = static_vrf_alloc(); - vrf->info = svrf; - svrf->vrf = vrf; + svrf = static_vrf_lookup_by_name(vrf->name); + if (svrf) { + vrf->info = svrf; + svrf->vrf = vrf; + } return 0; } @@ -63,37 +124,27 @@ static int static_vrf_new(struct vrf *vrf) static int static_vrf_enable(struct vrf *vrf) { static_zebra_vrf_register(vrf); - - static_fixup_vrf_ids(vrf->info); - + static_fixup_vrf_ids(vrf); return 0; } static int static_vrf_disable(struct vrf *vrf) { + static_cleanup_vrf_ids(vrf); static_zebra_vrf_unregister(vrf); return 0; } static int static_vrf_delete(struct vrf *vrf) { - struct route_table *table; struct static_vrf *svrf; - safi_t safi; - afi_t afi; - void *info; svrf = vrf->info; - for (afi = AFI_IP; afi <= AFI_IP6; afi++) { - for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) { - table = svrf->stable[afi][safi]; - info = route_table_get_info(table); - route_table_finish(table); - XFREE(MTYPE_STATIC_RTABLE_INFO, info); - svrf->stable[afi][safi] = NULL; - } + if (svrf) { + svrf->vrf = NULL; + vrf->info = NULL; } - XFREE(MTYPE_STATIC_RTABLE_INFO, svrf); + return 0; } @@ -110,43 +161,20 @@ struct route_table *static_vrf_static_table(afi_t afi, safi_t safi, return svrf->stable[afi][safi]; } -struct static_vrf *static_vrf_lookup_by_name(const char *name) -{ - struct vrf *vrf; - - if (!name) - name = VRF_DEFAULT_NAME; - - vrf = vrf_lookup_by_name(name); - if (vrf) - return ((struct static_vrf *)vrf->info); - - return NULL; -} - -static int static_vrf_config_write(struct vty *vty) -{ - struct lyd_node *dnode; - int written = 0; - - dnode = yang_dnode_get(running_config->dnode, "/frr-routing:routing"); - if (dnode) { - nb_cli_show_dnode_cmds(vty, dnode, false); - written = 1; - } - - return written; -} - void static_vrf_init(void) { vrf_init(static_vrf_new, static_vrf_enable, static_vrf_disable, static_vrf_delete); - vrf_cmd_init(static_vrf_config_write); + vrf_cmd_init(NULL); } void static_vrf_terminate(void) { + struct static_vrf *svrf, *svrf_next; + + RB_FOREACH_SAFE (svrf, svrf_name_head, &svrfs, svrf_next) + static_vrf_free(svrf); + vrf_terminate(); } diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h index 8f55775d3eec..26ee28fd816d 100644 --- a/staticd/static_vrf.h +++ b/staticd/static_vrf.h @@ -7,15 +7,27 @@ #ifndef __STATIC_VRF_H__ #define __STATIC_VRF_H__ +#include "openbsd-tree.h" + #ifdef __cplusplus extern "C" { #endif struct static_vrf { + RB_ENTRY(static_vrf) entry; + + char name[VRF_NAMSIZ + 1]; struct vrf *vrf; struct route_table *stable[AFI_MAX][SAFI_MAX]; }; +RB_HEAD(svrf_name_head, static_vrf); +RB_PROTOTYPE(svrf_name_head, static_vrf, entry, svrf_name_compare) + +extern struct svrf_name_head svrfs; + +struct static_vrf *static_vrf_alloc(const char *name); +void static_vrf_free(struct static_vrf *svrf); struct stable_info { struct static_vrf *svrf; @@ -25,8 +37,6 @@ struct stable_info { #define GET_STABLE_VRF_ID(info) info->svrf->vrf->vrf_id -struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name); - void static_vrf_init(void); struct route_table *static_vrf_static_table(afi_t afi, safi_t safi, diff --git a/staticd/static_vty.c b/staticd/static_vty.c index b07878f063e1..a18028ed087c 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -19,6 +19,7 @@ #include "libfrr.h" #include "routing_nb.h" #include "northbound_cli.h" +#include "frrdistance.h" #include "static_vrf.h" #include "static_vty.h" @@ -59,8 +60,6 @@ struct static_route_args { bool bfd_multi_hop; const char *bfd_source; const char *bfd_profile; - - const char *input; }; static int static_route_nb_run(struct vty *vty, struct static_route_args *args) @@ -83,7 +82,7 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) char buf_tag[PREFIX_STRLEN]; uint8_t label_stack_id = 0; uint8_t segs_stack_id = 0; - + char *orig_label = NULL, *orig_seg = NULL; const char *buf_gate_str; uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT; route_tag_t tag = 0; @@ -100,7 +99,7 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) return CMD_WARNING_CONFIG_FAILED; } - args->vrf = yang_dnode_get_string(vrf_dnode, "./name"); + args->vrf = yang_dnode_get_string(vrf_dnode, "name"); } else { if (args->vrf == NULL) args->vrf = VRF_DEFAULT_NAME; @@ -152,20 +151,9 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) else buf_gate_str = ""; - if (args->gateway == NULL && args->interface_name == NULL) { + if (args->gateway == NULL && args->interface_name == NULL) type = STATIC_BLACKHOLE; - /* If this is blackhole/reject flagged route, then - * specify interface_name with the value of what was really - * entered. - * interface_name will be validated later in NB functions - * to check if we don't create blackhole/reject routes that - * match the real interface names. - * E.g.: `ip route 10.0.0.1/32 bla` will create a blackhole - * route despite the real interface named `bla` exists. - */ - if (args->input) - args->interface_name = args->input; - } else if (args->gateway && args->interface_name) { + else if (args->gateway && args->interface_name) { if (args->afi == AFI_IP) type = STATIC_IPV4_GATEWAY_IFNAME; else @@ -329,7 +317,7 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY, NULL); - ostr = XSTRDUP(MTYPE_TMP, args->label); + orig_label = ostr = XSTRDUP(MTYPE_TMP, args->label); while ((nump = strsep(&ostr, "/")) != NULL) { snprintf(ab_xpath, sizeof(ab_xpath), FRR_STATIC_ROUTE_NHLB_KEY_XPATH, @@ -342,7 +330,6 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) NB_OP_MODIFY, nump); label_stack_id++; } - XFREE(MTYPE_TMP, ostr); } else { strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls)); strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH, @@ -363,7 +350,7 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) nb_cli_enqueue_change(vty, xpath_segs, NB_OP_DESTROY, NULL); - ostr = XSTRDUP(MTYPE_TMP, args->segs); + orig_seg = ostr = XSTRDUP(MTYPE_TMP, args->segs); while ((nump = strsep(&ostr, "/")) != NULL) { snprintf(ab_xpath, sizeof(ab_xpath), FRR_STATIC_ROUTE_NH_SRV6_KEY_SEG_XPATH, @@ -375,7 +362,6 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) NB_OP_MODIFY, nump); segs_stack_id++; } - XFREE(MTYPE_TMP, ostr); } else { strlcpy(xpath_segs, xpath_nexthop, sizeof(xpath_segs)); strlcat(xpath_segs, FRR_STATIC_ROUTE_NH_SRV6_SEGS_XPATH, @@ -418,6 +404,11 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args) } ret = nb_cli_apply_changes(vty, "%s", xpath_prefix); + + if (orig_label) + XFREE(MTYPE_TMP, orig_label); + if (orig_seg) + XFREE(MTYPE_TMP, orig_seg); } else { if (args->source) { if (args->distance) @@ -549,8 +540,6 @@ DEFPY_YANG(ip_route_blackhole, "Table to configure\n" "The table number to configure\n") { - int idx_flag = 0; - struct static_route_args args = { .delete = !!no, .afi = AFI_IP, @@ -565,9 +554,6 @@ DEFPY_YANG(ip_route_blackhole, .vrf = vrf, }; - if (flag && argv_find(argv, argc, flag, &idx_flag)) - args.input = argv[idx_flag]->arg; - return static_route_nb_run(vty, &args); } @@ -596,8 +582,6 @@ DEFPY_YANG(ip_route_blackhole_vrf, "Table to configure\n" "The table number to configure\n") { - int idx_flag = 0; - struct static_route_args args = { .delete = !!no, .afi = AFI_IP, @@ -619,9 +603,6 @@ DEFPY_YANG(ip_route_blackhole_vrf, */ assert(args.prefix); - if (flag && argv_find(argv, argc, flag, &idx_flag)) - args.input = argv[idx_flag]->arg; - return static_route_nb_run(vty, &args); } @@ -912,8 +893,6 @@ DEFPY_YANG(ipv6_route_blackhole, "Table to configure\n" "The table number to configure\n") { - int idx_flag = 0; - struct static_route_args args = { .delete = !!no, .afi = AFI_IP6, @@ -928,9 +907,6 @@ DEFPY_YANG(ipv6_route_blackhole, .vrf = vrf, }; - if (flag && argv_find(argv, argc, flag, &idx_flag)) - args.input = argv[idx_flag]->arg; - return static_route_nb_run(vty, &args); } @@ -959,8 +935,6 @@ DEFPY_YANG(ipv6_route_blackhole_vrf, "Table to configure\n" "The table number to configure\n") { - int idx_flag = 0; - struct static_route_args args = { .delete = !!no, .afi = AFI_IP6, @@ -982,9 +956,6 @@ DEFPY_YANG(ipv6_route_blackhole_vrf, */ assert(args.prefix); - if (flag && argv_find(argv, argc, flag, &idx_flag)) - args.input = argv[idx_flag]->arg; - return static_route_nb_run(vty, &args); } @@ -1230,8 +1201,10 @@ DEFPY_YANG(ipv6_route_vrf, ipv6_route_vrf_cmd, return static_route_nb_run(vty, &args); } -void static_cli_show(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) +#ifdef INCLUDE_MGMTD_CMDDEFS_ONLY + +static void static_cli_show(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) { const char *vrf; @@ -1240,7 +1213,7 @@ void static_cli_show(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, "vrf %s\n", vrf); } -void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode) +static void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode) { const char *vrf; @@ -1258,13 +1231,13 @@ static int mpls_label_iter_cb(const struct lyd_node *dnode, void *arg) { struct mpls_label_iter *iter = arg; - if (yang_dnode_exists(dnode, "./label")) { + if (yang_dnode_exists(dnode, "label")) { if (iter->first) vty_out(iter->vty, " label %s", - yang_dnode_get_string(dnode, "./label")); + yang_dnode_get_string(dnode, "label")); else vty_out(iter->vty, "/%s", - yang_dnode_get_string(dnode, "./label")); + yang_dnode_get_string(dnode, "label")); iter->first = false; } @@ -1282,16 +1255,16 @@ static int srv6_seg_iter_cb(const struct lyd_node *dnode, void *arg) char buffer[INET6_ADDRSTRLEN]; struct in6_addr cli_seg; - if (yang_dnode_exists(dnode, "./seg")) { + if (yang_dnode_exists(dnode, "seg")) { if (iter->first) { - yang_dnode_get_ipv6(&cli_seg, dnode, "./seg"); + yang_dnode_get_ipv6(&cli_seg, dnode, "seg"); if (inet_ntop(AF_INET6, &cli_seg, buffer, INET6_ADDRSTRLEN) == NULL) { return 1; } vty_out(iter->vty, " segments %s", buffer); } else { - yang_dnode_get_ipv6(&cli_seg, dnode, "./seg"); + yang_dnode_get_ipv6(&cli_seg, dnode, "seg"); if (inet_ntop(AF_INET6, &cli_seg, buffer, INET6_ADDRSTRLEN) == NULL) { return 1; @@ -1325,7 +1298,7 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, vrf = yang_dnode_get_string(route, "../../vrf"); - afi_safi = yang_dnode_get_string(route, "./afi-safi"); + afi_safi = yang_dnode_get_string(route, "afi-safi"); yang_afi_safi_identity2value(afi_safi, &afi, &safi); if (afi == AFI_IP) @@ -1340,32 +1313,32 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, else vty_out(vty, " mroute"); - vty_out(vty, " %s", yang_dnode_get_string(route, "./prefix")); + vty_out(vty, " %s", yang_dnode_get_string(route, "prefix")); if (src) vty_out(vty, " from %s", - yang_dnode_get_string(src, "./src-prefix")); + yang_dnode_get_string(src, "src-prefix")); - nh_type = yang_dnode_get_enum(nexthop, "./nh-type"); + nh_type = yang_dnode_get_enum(nexthop, "nh-type"); switch (nh_type) { case STATIC_IFNAME: vty_out(vty, " %s", - yang_dnode_get_string(nexthop, "./interface")); + yang_dnode_get_string(nexthop, "interface")); break; case STATIC_IPV4_GATEWAY: case STATIC_IPV6_GATEWAY: vty_out(vty, " %s", - yang_dnode_get_string(nexthop, "./gateway")); + yang_dnode_get_string(nexthop, "gateway")); break; case STATIC_IPV4_GATEWAY_IFNAME: case STATIC_IPV6_GATEWAY_IFNAME: vty_out(vty, " %s", - yang_dnode_get_string(nexthop, "./gateway")); + yang_dnode_get_string(nexthop, "gateway")); vty_out(vty, " %s", - yang_dnode_get_string(nexthop, "./interface")); + yang_dnode_get_string(nexthop, "interface")); break; case STATIC_BLACKHOLE: - bh_type = yang_dnode_get_enum(nexthop, "./bh-type"); + bh_type = yang_dnode_get_enum(nexthop, "bh-type"); switch (bh_type) { case STATIC_BLACKHOLE_DROP: vty_out(vty, " blackhole"); @@ -1380,13 +1353,13 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, break; } - if (yang_dnode_exists(path, "./tag")) { - tag = yang_dnode_get_uint32(path, "./tag"); + if (yang_dnode_exists(path, "tag")) { + tag = yang_dnode_get_uint32(path, "tag"); if (tag != 0 || show_defaults) vty_out(vty, " tag %" PRIu32, tag); } - distance = yang_dnode_get_uint8(path, "./distance"); + distance = yang_dnode_get_uint8(path, "distance"); if (distance != ZEBRA_STATIC_DISTANCE_DEFAULT || show_defaults) vty_out(vty, " %" PRIu8, distance); @@ -1400,48 +1373,49 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, yang_dnode_iterate(srv6_seg_iter_cb, &seg_iter, nexthop, "./srv6-segs-stack/entry"); - nexthop_vrf = yang_dnode_get_string(nexthop, "./vrf"); + nexthop_vrf = yang_dnode_get_string(nexthop, "vrf"); if (strcmp(vrf, nexthop_vrf)) vty_out(vty, " nexthop-vrf %s", nexthop_vrf); - table_id = yang_dnode_get_uint32(path, "./table-id"); + table_id = yang_dnode_get_uint32(path, "table-id"); if (table_id || show_defaults) vty_out(vty, " table %" PRIu32, table_id); - if (yang_dnode_exists(nexthop, "./onlink")) { - onlink = yang_dnode_get_bool(nexthop, "./onlink"); + if (yang_dnode_exists(nexthop, "onlink")) { + onlink = yang_dnode_get_bool(nexthop, "onlink"); if (onlink) vty_out(vty, " onlink"); } - if (yang_dnode_exists(nexthop, "./srte-color")) + if (yang_dnode_exists(nexthop, "srte-color")) vty_out(vty, " color %s", - yang_dnode_get_string(nexthop, "./srte-color")); + yang_dnode_get_string(nexthop, "srte-color")); - if (yang_dnode_exists(nexthop, "./bfd-monitoring")) { + if (yang_dnode_exists(nexthop, "bfd-monitoring")) { const struct lyd_node *bfd_dnode = - yang_dnode_get(nexthop, "./bfd-monitoring"); + yang_dnode_get(nexthop, "bfd-monitoring"); - if (yang_dnode_get_bool(bfd_dnode, "./multi-hop")) { + if (yang_dnode_get_bool(bfd_dnode, "multi-hop")) { vty_out(vty, " bfd multi-hop"); - if (yang_dnode_exists(bfd_dnode, "./source")) + if (yang_dnode_exists(bfd_dnode, "source")) vty_out(vty, " source %s", yang_dnode_get_string(bfd_dnode, "./source")); } else vty_out(vty, " bfd"); - if (yang_dnode_exists(bfd_dnode, "./profile")) + if (yang_dnode_exists(bfd_dnode, "profile")) vty_out(vty, " profile %s", - yang_dnode_get_string(bfd_dnode, "./profile")); + yang_dnode_get_string(bfd_dnode, "profile")); } vty_out(vty, "\n"); } -void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) +static void static_nexthop_cli_show(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) { const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list"); const struct lyd_node *route = @@ -1450,8 +1424,9 @@ void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, nexthop_cli_show(vty, route, NULL, path, dnode, show_defaults); } -void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) +static void static_src_nexthop_cli_show(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) { const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list"); const struct lyd_node *src = yang_dnode_get_parent(path, "src-list"); @@ -1460,16 +1435,16 @@ void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, nexthop_cli_show(vty, route, src, path, dnode, show_defaults); } -int static_nexthop_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2) +static int static_nexthop_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { enum static_nh_type nh_type1, nh_type2; struct prefix prefix1, prefix2; const char *vrf1, *vrf2; int ret = 0; - nh_type1 = yang_dnode_get_enum(dnode1, "./nh-type"); - nh_type2 = yang_dnode_get_enum(dnode2, "./nh-type"); + nh_type1 = yang_dnode_get_enum(dnode1, "nh-type"); + nh_type2 = yang_dnode_get_enum(dnode2, "nh-type"); if (nh_type1 != nh_type2) return (int)nh_type1 - (int)nh_type2; @@ -1477,24 +1452,24 @@ int static_nexthop_cli_cmp(const struct lyd_node *dnode1, switch (nh_type1) { case STATIC_IFNAME: ret = if_cmp_name_func( - yang_dnode_get_string(dnode1, "./interface"), - yang_dnode_get_string(dnode2, "./interface")); + yang_dnode_get_string(dnode1, "interface"), + yang_dnode_get_string(dnode2, "interface")); break; case STATIC_IPV4_GATEWAY: case STATIC_IPV6_GATEWAY: - yang_dnode_get_prefix(&prefix1, dnode1, "./gateway"); - yang_dnode_get_prefix(&prefix2, dnode2, "./gateway"); + yang_dnode_get_prefix(&prefix1, dnode1, "gateway"); + yang_dnode_get_prefix(&prefix2, dnode2, "gateway"); ret = prefix_cmp(&prefix1, &prefix2); break; case STATIC_IPV4_GATEWAY_IFNAME: case STATIC_IPV6_GATEWAY_IFNAME: - yang_dnode_get_prefix(&prefix1, dnode1, "./gateway"); - yang_dnode_get_prefix(&prefix2, dnode2, "./gateway"); + yang_dnode_get_prefix(&prefix1, dnode1, "gateway"); + yang_dnode_get_prefix(&prefix2, dnode2, "gateway"); ret = prefix_cmp(&prefix1, &prefix2); if (!ret) ret = if_cmp_name_func( - yang_dnode_get_string(dnode1, "./interface"), - yang_dnode_get_string(dnode2, "./interface")); + yang_dnode_get_string(dnode1, "interface"), + yang_dnode_get_string(dnode2, "interface")); break; case STATIC_BLACKHOLE: /* There's only one blackhole nexthop per route */ @@ -1505,28 +1480,28 @@ int static_nexthop_cli_cmp(const struct lyd_node *dnode1, if (ret) return ret; - vrf1 = yang_dnode_get_string(dnode1, "./vrf"); + vrf1 = yang_dnode_get_string(dnode1, "vrf"); if (strmatch(vrf1, "default")) vrf1 = ""; - vrf2 = yang_dnode_get_string(dnode2, "./vrf"); + vrf2 = yang_dnode_get_string(dnode2, "vrf"); if (strmatch(vrf2, "default")) vrf2 = ""; return if_cmp_name_func(vrf1, vrf2); } -int static_route_list_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2) +static int static_route_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { const char *afi_safi1, *afi_safi2; afi_t afi1, afi2; safi_t safi1, safi2; struct prefix prefix1, prefix2; - afi_safi1 = yang_dnode_get_string(dnode1, "./afi-safi"); + afi_safi1 = yang_dnode_get_string(dnode1, "afi-safi"); yang_afi_safi_identity2value(afi_safi1, &afi1, &safi1); - afi_safi2 = yang_dnode_get_string(dnode2, "./afi-safi"); + afi_safi2 = yang_dnode_get_string(dnode2, "afi-safi"); yang_afi_safi_identity2value(afi_safi2, &afi2, &safi2); if (afi1 != afi2) @@ -1535,41 +1510,98 @@ int static_route_list_cli_cmp(const struct lyd_node *dnode1, if (safi1 != safi2) return (int)safi1 - (int)safi2; - yang_dnode_get_prefix(&prefix1, dnode1, "./prefix"); - yang_dnode_get_prefix(&prefix2, dnode2, "./prefix"); + yang_dnode_get_prefix(&prefix1, dnode1, "prefix"); + yang_dnode_get_prefix(&prefix2, dnode2, "prefix"); return prefix_cmp(&prefix1, &prefix2); } -int static_src_list_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2) +static int static_src_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { struct prefix prefix1, prefix2; - yang_dnode_get_prefix(&prefix1, dnode1, "./src-prefix"); - yang_dnode_get_prefix(&prefix2, dnode2, "./src-prefix"); + yang_dnode_get_prefix(&prefix1, dnode1, "src-prefix"); + yang_dnode_get_prefix(&prefix2, dnode2, "src-prefix"); return prefix_cmp(&prefix1, &prefix2); } -int static_path_list_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2) +static int static_path_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { uint32_t table_id1, table_id2; uint8_t distance1, distance2; - table_id1 = yang_dnode_get_uint32(dnode1, "./table-id"); - table_id2 = yang_dnode_get_uint32(dnode2, "./table-id"); + table_id1 = yang_dnode_get_uint32(dnode1, "table-id"); + table_id2 = yang_dnode_get_uint32(dnode2, "table-id"); if (table_id1 != table_id2) return (int)table_id1 - (int)table_id2; - distance1 = yang_dnode_get_uint8(dnode1, "./distance"); - distance2 = yang_dnode_get_uint8(dnode2, "./distance"); + distance1 = yang_dnode_get_uint8(dnode1, "distance"); + distance2 = yang_dnode_get_uint8(dnode2, "distance"); return (int)distance1 - (int)distance2; } +const struct frr_yang_module_info frr_staticd_cli_info = { + .name = "frr-staticd", + .ignore_cfg_cbs = true, + .nodes = { + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd", + .cbs = { + .cli_show = static_cli_show, + .cli_show_end = static_cli_show_end, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list", + .cbs = { + .cli_cmp = static_route_list_cli_cmp, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list", + .cbs = { + .cli_cmp = static_path_list_cli_cmp, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop", + .cbs = { + .cli_show = static_nexthop_cli_show, + .cli_cmp = static_nexthop_cli_cmp, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list", + .cbs = { + .cli_cmp = static_src_list_cli_cmp, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list", + .cbs = { + .cli_cmp = static_path_list_cli_cmp, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop", + .cbs = { + .cli_show = static_src_nexthop_cli_show, + .cli_cmp = static_nexthop_cli_cmp, + } + }, + { + .xpath = NULL, + }, + } +}; + +#else /* ifdef INCLUDE_MGMTD_CMDDEFS_ONLY */ + DEFPY_YANG(debug_staticd, debug_staticd_cmd, "[no] debug static [{events$events|route$route|bfd$bfd}]", NO_STR DEBUG_STR STATICD_STR @@ -1577,18 +1609,15 @@ DEFPY_YANG(debug_staticd, debug_staticd_cmd, "Debug route\n" "Debug bfd\n") { -#ifndef INCLUDE_MGMTD_CMDDEFS_ONLY /* If no specific category, change all */ if (strmatch(argv[argc - 1]->text, "static")) static_debug_set(vty->node, !no, true, true, true); else static_debug_set(vty->node, !no, !!events, !!route, !!bfd); -#endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */ return CMD_SUCCESS; } -#ifndef INCLUDE_MGMTD_CMDDEFS_ONLY DEFPY(staticd_show_bfd_routes, staticd_show_bfd_routes_cmd, "show bfd static route [json]$isjson", SHOW_STR @@ -1630,10 +1659,11 @@ void static_vty_init(void) { #ifndef INCLUDE_MGMTD_CMDDEFS_ONLY install_node(&debug_node); + install_element(ENABLE_NODE, &debug_staticd_cmd); + install_element(CONFIG_NODE, &debug_staticd_cmd); install_element(ENABLE_NODE, &show_debugging_static_cmd); install_element(ENABLE_NODE, &staticd_show_bfd_routes_cmd); -#endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */ - +#else /* else INCLUDE_MGMTD_CMDDEFS_ONLY */ install_element(CONFIG_NODE, &ip_mroute_dist_cmd); install_element(CONFIG_NODE, &ip_route_blackhole_cmd); @@ -1649,9 +1679,9 @@ void static_vty_init(void) install_element(VRF_NODE, &ipv6_route_address_interface_vrf_cmd); install_element(CONFIG_NODE, &ipv6_route_cmd); install_element(VRF_NODE, &ipv6_route_vrf_cmd); +#endif /* ifndef INCLUDE_MGMTD_CMDDEFS_ONLY */ - install_element(ENABLE_NODE, &debug_staticd_cmd); - install_element(CONFIG_NODE, &debug_staticd_cmd); - +#ifndef INCLUDE_MGMTD_CMDDEFS_ONLY mgmt_be_client_lib_vty_init(); +#endif } diff --git a/staticd/static_vty.h b/staticd/static_vty.h index 77e52b5bdf86..4b4cc1c3bf39 100644 --- a/staticd/static_vty.h +++ b/staticd/static_vty.h @@ -11,22 +11,6 @@ extern "C" { #endif -void static_cli_show(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults); -void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode); -void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults); -void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults); -int static_nexthop_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2); -int static_route_list_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2); -int static_src_list_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2); -int static_path_list_cli_cmp(const struct lyd_node *dnode1, - const struct lyd_node *dnode2); - void static_vty_init(void); #ifdef __cplusplus diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 6abbdadc085d..420ed7903bbc 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -111,8 +111,6 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) static int static_ifp_up(struct interface *ifp) { - /* Install any static reliant on this interface coming up */ - static_install_intf_nh(ifp); static_ifindex_update(ifp, true); return 0; @@ -166,9 +164,14 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) static void zebra_connected(struct zclient *zclient) { + struct vrf *vrf; + + zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, true); zclient_send_reg_requests(zclient, VRF_DEFAULT); - static_fixup_vrf_ids(vrf_info_lookup(VRF_DEFAULT)); + vrf = vrf_lookup_by_id(VRF_DEFAULT); + assert(vrf); + static_fixup_vrf_ids(vrf); } /* API to check whether the configured nexthop address is @@ -186,48 +189,40 @@ static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family) } return false; } -static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) + +static void static_zebra_nexthop_update(struct vrf *vrf, struct prefix *matched, + struct zapi_route *nhr) { struct static_nht_data *nhtd, lookup; - struct zapi_route nhr; - struct prefix matched; afi_t afi = AFI_IP; - if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) { - zlog_err("Failure to decode nexthop update message"); - return 1; - } - if (zclient->bfd_integration) - bfd_nht_update(&matched, &nhr); + bfd_nht_update(matched, nhr); - if (matched.family == AF_INET6) + if (matched->family == AF_INET6) afi = AFI_IP6; - if (nhr.type == ZEBRA_ROUTE_CONNECT) { - if (static_nexthop_is_local(vrf_id, &matched, - nhr.prefix.family)) - nhr.nexthop_num = 0; + if (nhr->type == ZEBRA_ROUTE_CONNECT) { + if (static_nexthop_is_local(vrf->vrf_id, matched, + nhr->prefix.family)) + nhr->nexthop_num = 0; } memset(&lookup, 0, sizeof(lookup)); - lookup.nh = matched; - lookup.nh_vrf_id = vrf_id; - lookup.safi = nhr.safi; + lookup.nh = *matched; + lookup.nh_vrf_id = vrf->vrf_id; + lookup.safi = nhr->safi; nhtd = static_nht_hash_find(static_nht_hash, &lookup); if (nhtd) { - nhtd->nh_num = nhr.nexthop_num; + nhtd->nh_num = nhr->nexthop_num; - static_nht_reset_start(&matched, afi, nhr.safi, - nhtd->nh_vrf_id); - static_nht_update(NULL, &matched, nhr.nexthop_num, afi, - nhr.safi, nhtd->nh_vrf_id); + static_nht_reset_start(matched, afi, nhr->safi, nhtd->nh_vrf_id); + static_nht_update(NULL, matched, nhr->nexthop_num, afi, + nhr->safi, nhtd->nh_vrf_id); } else zlog_err("No nhtd?"); - - return 1; } static void static_zebra_capabilities(struct zclient_capabilities *cap) @@ -346,7 +341,8 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) /* refresh with existing data */ afi_t afi = prefix_afi(&lookup.nh); - if (nh->state == STATIC_NOT_INSTALLED) + if (nh->state == STATIC_NOT_INSTALLED || + nh->state == STATIC_SENT_TO_ZEBRA) nh->state = STATIC_START; static_nht_update(&rn->p, &nhtd->nh, nhtd->nh_num, afi, si->safi, nh->nh_vrf_id); @@ -395,6 +391,9 @@ extern void static_zebra_route_add(struct static_path *pn, bool install) struct zapi_route api; uint32_t nh_num = 0; + if (!si->svrf->vrf || si->svrf->vrf->vrf_id == VRF_UNKNOWN) + return; + p = src_pp = NULL; srcdest_rnode_prefixes(rn, &p, &src_pp); @@ -535,22 +534,22 @@ static zclient_handler *const static_handlers[] = { [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, - [ZEBRA_NEXTHOP_UPDATE] = static_zebra_nexthop_update, }; void static_zebra_init(void) { - struct zclient_options opt = { .receive_notify = true }; - - if_zapi_callbacks(static_ifp_create, static_ifp_up, - static_ifp_down, static_ifp_destroy); + hook_register_prio(if_real, 0, static_ifp_create); + hook_register_prio(if_up, 0, static_ifp_up); + hook_register_prio(if_down, 0, static_ifp_down); + hook_register_prio(if_unreal, 0, static_ifp_destroy); - zclient = zclient_new(master, &opt, static_handlers, + zclient = zclient_new(master, &zclient_options_default, static_handlers, array_size(static_handlers)); zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs); zclient->zebra_capabilities = static_zebra_capabilities; zclient->zebra_connected = zebra_connected; + zclient->nexthop_update = static_zebra_nexthop_update; static_nht_hash_init(static_nht_hash); static_bfd_initialize(zclient, master); diff --git a/staticd/subdir.am b/staticd/subdir.am index 022428281f60..07ebe3c02c27 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -36,7 +36,7 @@ clippy_scan += \ # end staticd_staticd_SOURCES = staticd/static_main.c -staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP) +staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP) $(LIBYANG_LIBS) nodist_staticd_staticd_SOURCES = \ yang/frr-bfdd.yang.c \ diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c index 799733b7b53c..29d2e4cf6e29 100644 --- a/tests/bgpd/test_aspath.c +++ b/tests/bgpd/test_aspath.c @@ -653,7 +653,7 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, - PEER_CAP_AS4_RCV, + 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, @@ -685,7 +685,7 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, - PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, + 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, @@ -701,7 +701,7 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, - PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, + 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, @@ -717,7 +717,7 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, - PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, + 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, @@ -733,7 +733,7 @@ static struct aspath_tests { "8466 3 52737 4096", AS4_DATA, -1, - PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV, + 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 9d3d0ecbc128..1ee47a38e457 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -617,6 +617,7 @@ static struct test_segment misc_segments[] = }, 2, SHOULD_ERR, + -1, }, { "dyn-empty", @@ -835,7 +836,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type) switch (type) { case CAPABILITY: len += 2; /* to cover the OPT-Param header */ - _FALLTHROUGH + fallthrough; case OPT_PARAM: printf("len: %u\n", len); /* peek_for_as4 wants getp at capibility*/ diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index cebdda9e5c71..44a210403f40 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -23,6 +23,7 @@ #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" @@ -1075,6 +1076,7 @@ int main(void) vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); bgp_attr_init(); + bgp_labels_init(); if (fileno(stdout) >= 0) tty = isatty(fileno(stdout)); diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c index a83276be0796..e050fd4c711b 100644 --- a/tests/bgpd/test_packet.c +++ b/tests/bgpd/test_packet.c @@ -7,6 +7,7 @@ */ #include +#include #include "qobj.h" #include "vty.h" diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index bc6eba906905..767c41cfee67 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -18,6 +18,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -261,24 +262,10 @@ static struct test_peer_attr test_peer_attrs[] = { .u.flag = PEER_FLAG_CAPABILITY_ENHE, .type = PEER_AT_GLOBAL_FLAG, }, - { - .cmd = "capability extended-nexthop", - .u.flag = PEER_FLAG_CAPABILITY_ENHE, - .type = PEER_AT_GLOBAL_FLAG, - .o.invert_peer = true, - .o.use_iface_peer = true, - }, - { - .cmd = "capability software-version", - .u.flag = PEER_FLAG_CAPABILITY_SOFT_VERSION, - .type = PEER_AT_GLOBAL_FLAG, - }, { .cmd = "capability software-version", .u.flag = PEER_FLAG_CAPABILITY_SOFT_VERSION, .type = PEER_AT_GLOBAL_FLAG, - .o.invert_peer = true, - .o.use_iface_peer = true, }, { .cmd = "description", @@ -297,9 +284,11 @@ static struct test_peer_attr test_peer_attrs[] = { .type = PEER_AT_GLOBAL_FLAG, }, { - .cmd = "enforce-first-as", - .u.flag = PEER_FLAG_ENFORCE_FIRST_AS, + .cmd = "capability fqdn", + .u.flag = PEER_FLAG_CAPABILITY_FQDN, .type = PEER_AT_GLOBAL_FLAG, + .o.invert_peer = true, + .o.invert_group = true, }, { .cmd = "local-as", @@ -1386,6 +1375,7 @@ static void bgp_shutdown(void) bgp_route_finish(); bgp_route_map_terminate(); bgp_attr_finish(); + bgp_labels_finish(); bgp_pthreads_finish(); access_list_add_hook(NULL); access_list_delete_hook(NULL); diff --git a/tests/bgpd/test_peer_attr.py b/tests/bgpd/test_peer_attr.py index eb5761843496..b1f88d2ce196 100644 --- a/tests/bgpd/test_peer_attr.py +++ b/tests/bgpd/test_peer_attr.py @@ -15,7 +15,7 @@ class TestFlag(frrtest.TestMultiOut): TestFlag.okfail("peer\\description") TestFlag.okfail("peer\\disable-connected-check") TestFlag.okfail("peer\\dont-capability-negotiate") -TestFlag.okfail("peer\\enforce-first-as") +TestFlag.okfail("peer\\capability fqdn") TestFlag.okfail("peer\\local-as") TestFlag.okfail("peer\\local-as 1 no-prepend") TestFlag.okfail("peer\\local-as 1 no-prepend replace-as") diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c index 8af53a2ea40b..fdda7f1e2a28 100644 --- a/tests/helpers/c/main.c +++ b/tests/helpers/c/main.c @@ -3,6 +3,7 @@ */ #include +#include #include #include "getopt.h" diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 6eb180b501db..93009a1b84e1 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -5,6 +5,7 @@ */ #include +#include #include #include "getopt.h" @@ -54,7 +55,7 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology, isis_run_spf(spftree); /* Print the SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); isis_print_routes(vty, spftree, NULL, false, false); /* Cleanup SPF tree. */ @@ -84,7 +85,7 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology, isis_lfa_compute(area, NULL, spftree_self, protected_resource); /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -147,7 +148,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, vty_out(vty, "\n"); /* Print the post-convergence SPT. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); /* * Activate the computed RLFAs (if any) using artificial LDP labels for @@ -163,7 +164,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, } /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -227,7 +228,7 @@ static void test_run_ti_lfa(struct vty *vty, /* * Print the post-convergence SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); isis_print_routes(vty, spftree_self, NULL, false, true); /* Cleanup everything. */ @@ -244,12 +245,25 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, struct isis_area *area; struct lfa_protected_resource protected_resource = {}; uint8_t fail_id[ISIS_SYS_ID_LEN] = {}; + static char sysidstr[ISO_SYSID_STRLEN]; + char net_title[255]; + uint8_t buff[255]; + struct iso_address *addr = NULL; /* Init topology. */ area = isis_area_create("1", NULL); memcpy(area->isis->sysid, root->sysid, sizeof(area->isis->sysid)); area->is_type = IS_LEVEL_1_AND_2; area->srdb.enabled = true; + area->area_addrs = list_new(); + area->area_addrs->del = isis_area_address_delete; + addr = XMALLOC(MTYPE_ISIS_AREA_ADDR, sizeof(struct iso_address)); + snprintfrr(sysidstr, sizeof(sysidstr), "%pSY", area->isis->sysid); + snprintf(net_title, sizeof(net_title), "49.%s.00", sysidstr); + addr->addr_len = dotformat2buff(buff, net_title); + memcpy(addr->area_addr, buff, addr->addr_len); + addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); + listnode_add(area->area_addrs, addr); if (test_topology_load(topology, area, area->lspdb) != 0) { vty_out(vty, "%% Failed to load topology\n"); return CMD_WARNING; @@ -539,7 +553,7 @@ int main(int argc, char **argv) zlog_aux_init("NONE: ", ZLOG_DISABLED); /* IS-IS inits. */ - yang_module_load("frr-isisd"); + yang_module_load("frr-isisd", NULL); SET_FLAG(im->options, F_ISIS_UNIT_TEST); debug_spf_events |= DEBUG_SPF_EVENTS; debug_lfa |= DEBUG_LFA; diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index 23d41b9e5dd0..255d920c10cb 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -1,20 +1,22 @@ test# test isis topology 1 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -29,21 +31,23 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -59,22 +63,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -10.0.255.3/32 IP TE 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -89,22 +95,24 @@ IS-IS L1 IPv4 routing table: - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -120,19 +128,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -147,23 +157,25 @@ IS-IS L1 IPv4 routing table: test# test isis topology 4 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -180,25 +192,27 @@ IS-IS L1 IPv4 routing table: test# test isis topology 5 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -216,33 +230,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 6 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -rt5 TE-IS 40 rt2 - rt6(4) - rt3 - -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - -rt7 TE-IS 50 rt2 - rt5(4) - rt3 - rt8(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) - rt3 - -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - -10.0.255.7/32 IP TE 60 rt2 - rt7(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + rt5 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt3 - rt8(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + rt3 - rt5(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -264,34 +280,36 @@ IS-IS L1 IPv4 routing table: test# test isis topology 7 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -312,33 +330,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 8 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt3 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt2 - rt2(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt6 TE-IS 30 rt2 - rt3(4) - rt5(4) -rt8 TE-IS 30 rt2 - rt5(4) -rt10 TE-IS 30 rt4 - rt7(4) -10.0.255.3/32 IP TE 30 rt2 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt9 TE-IS 40 rt2 - rt8(4) -rt11 TE-IS 40 rt2 - rt8(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -10.0.255.10/32 IP TE 40 rt4 - rt10(4) -rt12 TE-IS 50 rt2 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.11/32 IP TE 50 rt2 - rt11(4) -10.0.255.12/32 IP TE 60 rt2 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt3 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt2 - rt2(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt6 TE-IS 30 rt2 - rt3(4) + rt5(4) + rt8 TE-IS 30 rt2 - rt5(4) + rt10 TE-IS 30 rt4 - rt7(4) + 10.0.255.3/32 IP TE 30 rt2 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt9 TE-IS 40 rt2 - rt8(4) + rt11 TE-IS 40 rt2 - rt8(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + 10.0.255.10/32 IP TE 40 rt4 - rt10(4) + rt12 TE-IS 50 rt2 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.11/32 IP TE 50 rt2 - rt11(4) + 10.0.255.12/32 IP TE 60 rt2 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -359,28 +379,30 @@ IS-IS L1 IPv4 routing table: test# test isis topology 9 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -397,28 +419,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 50 - rt2 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -436,23 +460,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -468,23 +494,25 @@ IS-IS L1 IPv4 routing table: 10.0.255.8/32 40 - rt2 16080 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -501,22 +529,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -531,22 +561,24 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -562,27 +594,29 @@ IS-IS L1 IPv6 routing table: test# test isis topology 12 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -rt9 TE-IS 40 rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.9/32 IP TE 50 rt3 - rt9(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt9 TE-IS 40 rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.9/32 IP TE 50 rt3 - rt9(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -601,24 +635,26 @@ IS-IS L1 IPv4 routing table: test# test isis topology 13 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -636,23 +672,25 @@ IS-IS L1 IPv4 routing table: test# test# test isis topology 4 root rt1 reverse-spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -669,21 +707,23 @@ IS-IS L1 IPv4 routing table: test# test isis topology 11 root rt1 reverse-spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -10.0.255.4/32 IP TE 30 rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 10.0.255.4/32 IP TE 30 rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -695,21 +735,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -2001:db8::4/128 IP6 internal 30 rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 2001:db8::4/128 IP6 internal 30 rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -723,21 +765,23 @@ IS-IS L1 IPv6 routing table: test# test# test isis topology 1 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -756,21 +800,23 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -790,21 +836,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -826,21 +874,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 50 - rt2 implicit-null IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -863,21 +913,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -899,21 +951,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 30 - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -936,19 +990,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -973,10 +1029,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -986,19 +1044,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1020,10 +1080,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.3/32 30 - rt2 16030 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1033,34 +1095,36 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt1 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -1098,10 +1162,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 90 - rt2 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 40 rt2 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 40 rt2 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1111,40 +1177,42 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt7 lfa system-id rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt7 -10.0.255.7/32 IP internal 0 rt7(4) -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) -rt1 TE-IS 20 rt4 - rt4(4) -rt5 TE-IS 20 rt4 - rt4(4) - rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) -rt11 TE-IS 20 rt8 - rt8(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt2 TE-IS 30 rt4 - rt5(4) - rt8 - -rt6 TE-IS 30 rt4 - rt5(4) - rt8 - -rt12 TE-IS 30 rt8 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 30 rt10 - rt10(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) - rt8 - -10.0.255.9/32 IP TE 30 rt8 - rt9(4) -10.0.255.11/32 IP TE 30 rt8 - rt11(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt8 - rt6(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) - rt8 - -10.0.255.6/32 IP TE 40 rt4 - rt6(4) - rt8 - -10.0.255.12/32 IP TE 40 rt8 - rt12(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt7 + 10.0.255.7/32 IP internal 0 rt7(4) + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + rt1 TE-IS 20 rt4 - rt4(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt11 TE-IS 20 rt8 - rt8(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt12 TE-IS 30 rt8 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 30 rt10 - rt10(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + rt8 - rt5(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + 10.0.255.11/32 IP TE 30 rt8 - rt11(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt8 - rt6(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + rt8 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + rt8 - rt6(4) + 10.0.255.12/32 IP TE 40 rt8 - rt12(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + rt8 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -1179,11 +1247,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 50 - rt10 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt7 -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt7 + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + Main: IS-IS L1 IPv6 routing table: @@ -1193,38 +1263,40 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt8 lfa system-id rt11 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) - rt7 - rt7(4) -rt6 TE-IS 20 rt5 - rt5(4) -rt12 TE-IS 20 rt9 - rt9(4) - rt11 - rt11(4) -rt10 TE-IS 20 rt11 - rt11(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.9/32 IP TE 20 rt9 - rt9(4) -10.0.255.11/32 IP TE 20 rt11 - rt11(4) -rt3 TE-IS 30 rt5 - rt2(4) - rt6(4) -rt1 TE-IS 30 rt5 - rt4(4) - rt7 - -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) - rt7 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) -10.0.255.12/32 IP TE 30 rt9 - rt12(4) - rt11 - -10.0.255.10/32 IP TE 30 rt11 - rt10(4) -10.0.255.3/32 IP TE 40 rt5 - rt3(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) - rt7 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt7 - rt7(4) + rt6 TE-IS 20 rt5 - rt5(4) + rt12 TE-IS 20 rt9 - rt9(4) + rt11 - rt11(4) + rt10 TE-IS 20 rt11 - rt11(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.9/32 IP TE 20 rt9 - rt9(4) + 10.0.255.11/32 IP TE 20 rt11 - rt11(4) + rt3 TE-IS 30 rt5 - rt2(4) + rt6(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + 10.0.255.12/32 IP TE 30 rt9 - rt12(4) + rt11 - rt12(4) + 10.0.255.10/32 IP TE 30 rt11 - rt10(4) + 10.0.255.3/32 IP TE 40 rt5 - rt3(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt7 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -1255,12 +1327,14 @@ IS-IS L1 IPv4 routing table: 10.0.255.10/32 40 - rt7 16100 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt8 + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1270,28 +1344,30 @@ IS-IS L1 IPv6 routing table: test# test isis topology 9 root rt3 lfa system-id rt1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -10.0.255.2/32 IP TE 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -10.0.255.4/32 IP TE 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -10.0.255.5/32 IP TE 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 60 rt1 - rt9(4) -10.0.255.6/32 IP TE 70 rt1 - rt6(4) -10.0.255.7/32 IP TE 70 rt1 - rt7(4) -10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 10.0.255.2/32 IP TE 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 10.0.255.4/32 IP TE 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 10.0.255.5/32 IP TE 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 60 rt1 - rt9(4) + 10.0.255.6/32 IP TE 70 rt1 - rt6(4) + 10.0.255.7/32 IP TE 70 rt1 - rt7(4) + 10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -1323,28 +1399,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 130 - rt4 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) -2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) -2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) -2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) + 2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) + 2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) + 2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1377,23 +1455,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt8 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -10.0.255.6/32 IP TE 60 rt6 - rt6(4) -10.0.255.7/32 IP TE 60 rt7 - rt7(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) -10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 10.0.255.6/32 IP TE 60 rt6 - rt6(4) + 10.0.255.7/32 IP TE 60 rt7 - rt7(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + 10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Main: IS-IS L1 IPv4 routing table: @@ -1426,23 +1506,25 @@ IS-IS L1 IPv4 routing table: - rt7 16050 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -2001:db8::8/128 IP6 internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) -2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) -2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt8 + 2001:db8::8/128 IP6 internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) + 2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + 2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1476,22 +1558,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt3 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt5 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1515,22 +1599,24 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt2 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) - rt5 - -2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt5 - rt4(4) + 2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1555,24 +1641,26 @@ IS-IS L1 IPv6 routing table: test# test isis topology 13 root rt4 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -1599,11 +1687,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.7/32 120 - rt5 16070 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt5 TE-IS 100 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt4 + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt5 TE-IS 100 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1613,18 +1703,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1641,18 +1733,20 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1670,18 +1764,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1702,18 +1798,20 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 30 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1735,19 +1833,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt5 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.3/32 IP TE 30 rt4 - rt3(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.3/32 IP TE 30 rt4 - rt3(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Main: IS-IS L1 IPv4 routing table: @@ -1771,19 +1871,21 @@ IS-IS L1 IPv4 routing table: 10.0.255.4/32 70 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) -2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) -2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) + 2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) + 2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Main: IS-IS L1 IPv6 routing table: @@ -1823,36 +1925,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1890,36 +1996,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1964,39 +2074,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -2041,39 +2155,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -2123,38 +2241,42 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2210,36 +2332,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2276,44 +2402,48 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -2362,46 +2492,50 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -2452,64 +2586,68 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt8 TE-IS 10 rt8 - rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt5 TE-IS 20 rt8 - rt8(4) -rt7 TE-IS 20 rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) - rt12 - rt12(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt2 TE-IS 30 rt8 - rt5(4) -rt4 TE-IS 30 rt8 - rt5(4) - rt7(4) -rt6 TE-IS 30 rt8 - rt5(4) -10.0.255.5/32 IP TE 30 rt8 - rt5(4) -10.0.255.7/32 IP TE 30 rt8 - rt7(4) -10.0.255.9/32 IP TE 30 rt8 - rt9(4) - rt12 - -rt3 TE-IS 40 rt8 - rt2(4) - rt6(4) -rt1 TE-IS 40 rt8 - rt4(4) -10.0.255.2/32 IP TE 40 rt8 - rt2(4) -10.0.255.4/32 IP TE 40 rt8 - rt4(4) -10.0.255.6/32 IP TE 40 rt8 - rt6(4) -10.0.255.3/32 IP TE 50 rt8 - rt3(4) -10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt8 TE-IS 10 rt8 - rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt5 TE-IS 20 rt8 - rt8(4) + rt7 TE-IS 20 rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt12 - rt12(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt2 TE-IS 30 rt8 - rt5(4) + rt4 TE-IS 30 rt8 - rt5(4) + rt7(4) + rt6 TE-IS 30 rt8 - rt5(4) + 10.0.255.5/32 IP TE 30 rt8 - rt5(4) + 10.0.255.7/32 IP TE 30 rt8 - rt7(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + rt12 - rt9(4) + rt3 TE-IS 40 rt8 - rt2(4) + rt6(4) + rt1 TE-IS 40 rt8 - rt4(4) + 10.0.255.2/32 IP TE 40 rt8 - rt2(4) + 10.0.255.4/32 IP TE 40 rt8 - rt4(4) + 10.0.255.6/32 IP TE 40 rt8 - rt6(4) + 10.0.255.3/32 IP TE 50 rt8 - rt3(4) + 10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2577,73 +2715,77 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt5 TE-IS 10 rt5 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt9 - rt6(4) - rt5 - rt8(4) -rt1 TE-IS 30 rt5 - rt4(4) -rt7 TE-IS 30 rt5 - rt4(4) - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) - rt5 - -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt9 - rt9(4) - rt5 - rt11(4) -rt10 TE-IS 40 rt5 - rt11(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) - rt5 - -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -10.0.255.7/32 IP TE 40 rt5 - rt7(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt9 - rt12(4) - rt5 - -10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt5 TE-IS 10 rt5 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 - rt8(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 TE-IS 30 rt5 - rt4(4) + rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt5 - rt11(4) + rt10 TE-IS 40 rt5 - rt11(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + rt5 - rt9(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + 10.0.255.7/32 IP TE 40 rt5 - rt7(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + rt5 - rt12(4) + 10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Main: IS-IS L1 IPv4 routing table: @@ -2706,62 +2848,66 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -2815,36 +2961,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) -10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + 10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2893,36 +3043,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) -2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) + 2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -2966,42 +3120,46 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -3044,19 +3202,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3080,19 +3240,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3127,22 +3289,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3175,22 +3339,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -3217,20 +3383,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -10.0.255.4/32 IP TE 65 rt2 - rt4(4) -10.0.255.6/32 IP TE 75 rt2 - rt6(4) -10.0.255.5/32 IP TE 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 10.0.255.4/32 IP TE 65 rt2 - rt4(4) + 10.0.255.6/32 IP TE 75 rt2 - rt6(4) + 10.0.255.5/32 IP TE 75 rt2 - rt5(4) + IS-IS L1 IPv4 routing table: @@ -3258,20 +3426,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) -2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) -2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) + 2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) + 2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + IS-IS L1 IPv6 routing table: @@ -3303,20 +3473,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3347,20 +3519,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3396,21 +3570,23 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3450,19 +3626,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3484,23 +3662,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 70 rt3 - rt5(4) -rt4 TE-IS 80 rt3 - rt6(4) -rt8 TE-IS 80 rt3 - rt6(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) -rt2 TE-IS 90 rt3 - rt4(4) -10.0.255.4/32 IP TE 90 rt3 - rt4(4) -10.0.255.8/32 IP TE 90 rt3 - rt8(4) -10.0.255.2/32 IP TE 100 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 70 rt3 - rt5(4) + rt4 TE-IS 80 rt3 - rt6(4) + rt8 TE-IS 80 rt3 - rt6(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + rt2 TE-IS 90 rt3 - rt4(4) + 10.0.255.4/32 IP TE 90 rt3 - rt4(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + 10.0.255.2/32 IP TE 100 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3531,23 +3711,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt1(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -rt5 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -rt6 TE-IS 90 rt2 - rt5(4) -rt8 TE-IS 100 rt2 - rt6(4) -10.0.255.6/32 IP TE 100 rt2 - rt6(4) -10.0.255.8/32 IP TE 110 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt1(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt5 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt6 TE-IS 90 rt2 - rt5(4) + rt8 TE-IS 100 rt2 - rt6(4) + 10.0.255.6/32 IP TE 100 rt2 - rt6(4) + 10.0.255.8/32 IP TE 110 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -3575,23 +3757,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3624,24 +3808,26 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -3676,33 +3862,35 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3750,39 +3938,41 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -3829,34 +4019,36 @@ Q-space: rt10 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) -rt10 TE-IS 60 rt5 - rt11(4) -rt7 TE-IS 70 rt5 - rt10(4) -10.0.255.10/32 IP TE 70 rt5 - rt10(4) -rt4 TE-IS 80 rt5 - rt7(4) -10.0.255.7/32 IP TE 80 rt5 - rt7(4) -rt1 TE-IS 90 rt5 - rt4(4) -10.0.255.4/32 IP TE 90 rt5 - rt4(4) -10.0.255.1/32 IP TE 100 rt5 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + rt10 TE-IS 60 rt5 - rt11(4) + rt7 TE-IS 70 rt5 - rt10(4) + 10.0.255.10/32 IP TE 70 rt5 - rt10(4) + rt4 TE-IS 80 rt5 - rt7(4) + 10.0.255.7/32 IP TE 80 rt5 - rt7(4) + rt1 TE-IS 90 rt5 - rt4(4) + 10.0.255.4/32 IP TE 90 rt5 - rt4(4) + 10.0.255.1/32 IP TE 100 rt5 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3894,32 +4086,34 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -3954,28 +4148,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -10.0.255.3/32 IP TE 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 10.0.255.3/32 IP TE 130 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4005,28 +4201,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4051,28 +4249,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -10.0.255.4/32 IP TE 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -10.0.255.2/32 IP TE 130 rt3 - rt2(4) -10.0.255.5/32 IP TE 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 140 rt3 - rt9(4) -10.0.255.6/32 IP TE 150 rt3 - rt6(4) -10.0.255.7/32 IP TE 150 rt3 - rt7(4) -10.0.255.8/32 IP TE 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 10.0.255.4/32 IP TE 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 10.0.255.2/32 IP TE 130 rt3 - rt2(4) + 10.0.255.5/32 IP TE 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 140 rt3 - rt9(4) + 10.0.255.6/32 IP TE 150 rt3 - rt6(4) + 10.0.255.7/32 IP TE 150 rt3 - rt7(4) + 10.0.255.8/32 IP TE 150 rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -4102,28 +4302,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) -2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) -2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) -2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) + 2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) + 2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) + 2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -4160,45 +4362,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -10.0.255.4/32 IP TE 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.2/32 IP TE 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.5/32 IP TE 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.1/32 IP TE 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.3/32 IP TE 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 10.0.255.4/32 IP TE 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.2/32 IP TE 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.5/32 IP TE 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.1/32 IP TE 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.3/32 IP TE 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4242,45 +4446,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + 2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4329,25 +4535,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -10.0.255.2/32 IP TE 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -10.0.255.1/32 IP TE 50 rt5 - rt1(4) -10.0.255.8/32 IP TE 60 rt5 - rt8(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 10.0.255.2/32 IP TE 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 10.0.255.1/32 IP TE 50 rt5 - rt1(4) + 10.0.255.8/32 IP TE 60 rt5 - rt8(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4381,25 +4589,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) -2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) + 2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4428,29 +4638,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -10.0.255.8/32 IP TE 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -10.0.255.5/32 IP TE 100 rt3 - rt5(4) - rt4 - -10.0.255.2/32 IP TE 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.5/32 IP TE 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.2/32 IP TE 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -4483,29 +4695,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) - rt4 - -2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -4540,23 +4754,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -10.0.255.7/32 IP TE 90 rt2 - rt7(4) -10.0.255.4/32 IP TE 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 10.0.255.7/32 IP TE 90 rt2 - rt7(4) + 10.0.255.4/32 IP TE 100 rt2 - rt4(4) + IS-IS L1 IPv4 routing table: @@ -4586,23 +4802,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) -2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) + 2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + IS-IS L1 IPv6 routing table: @@ -4633,20 +4851,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -4679,20 +4899,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -4723,27 +4945,29 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) -rt7 TE-IS 140 rt2 - rt8(4) -rt9 TE-IS 150 rt2 - rt7(4) -10.0.255.7/32 IP TE 150 rt2 - rt7(4) -10.0.255.9/32 IP TE 160 rt2 - rt9(4) -rt5 TE-IS 340 rt2 - rt7(4) -10.0.255.5/32 IP TE 350 rt2 - rt5(4) -rt3 TE-IS 740 rt2 - rt5(4) -10.0.255.3/32 IP TE 750 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + rt7 TE-IS 140 rt2 - rt8(4) + rt9 TE-IS 150 rt2 - rt7(4) + 10.0.255.7/32 IP TE 150 rt2 - rt7(4) + 10.0.255.9/32 IP TE 160 rt2 - rt9(4) + rt5 TE-IS 340 rt2 - rt7(4) + 10.0.255.5/32 IP TE 350 rt2 - rt5(4) + rt3 TE-IS 740 rt2 - rt5(4) + 10.0.255.3/32 IP TE 750 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4770,22 +4994,24 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -4796,5 +5022,5 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt2 16040/16060 10.0.255.7/32 60 - rt2 16040/16070 -test# -end. +test# +end. diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index e0981b991acb..f9f584f450f6 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -7,6 +7,7 @@ */ #include +#include #include "frrevent.h" #include "vty.h" diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c index f82eddd3bf1b..321f158668e2 100644 --- a/tests/lib/northbound/test_oper_data.c +++ b/tests/lib/northbound/test_oper_data.c @@ -5,6 +5,7 @@ */ #include +#include #include "frrevent.h" #include "vty.h" @@ -13,6 +14,7 @@ #include "lib_vty.h" #include "log.h" #include "northbound.h" +#include "northbound_cli.h" static struct event_loop *master; @@ -199,6 +201,38 @@ static struct yang_data *frr_test_module_vrfs_vrf_routes_route_active_get_elem( return NULL; } +/* + * XPath: /frr-test-module:frr-test-module/vrfs/vrf/ping + */ +static int frr_test_module_vrfs_vrf_ping(struct nb_cb_rpc_args *args) +{ + const char *vrf = yang_dnode_get_string(args->input, "../name"); + const char *data = yang_dnode_get_string(args->input, "data"); + + yang_dnode_rpc_output_add(args->output, "vrf", vrf); + yang_dnode_rpc_output_add(args->output, "data-out", data); + + return NB_OK; +} + +/* + * XPath: /frr-test-module:frr-test-module/c1value + */ +static struct yang_data * +frr_test_module_c1value_get_elem(struct nb_cb_get_elem_args *args) +{ + return yang_data_new_uint8(args->xpath, 21); +} + +/* + * XPath: /frr-test-module:frr-test-module/c2cont/c2value + */ +static struct yang_data * +frr_test_module_c2cont_c2value_get_elem(struct nb_cb_get_elem_args *args) +{ + return yang_data_new_uint32(args->xpath, 0xAB010203); +} + /* clang-format off */ const struct frr_yang_module_info frr_test_module_info = { .name = "frr-test-module", @@ -242,6 +276,18 @@ const struct frr_yang_module_info frr_test_module_info = { .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/routes/route/active", .cbs.get_elem = frr_test_module_vrfs_vrf_routes_route_active_get_elem, }, + { + .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/ping", + .cbs.rpc = frr_test_module_vrfs_vrf_ping, + }, + { + .xpath = "/frr-test-module:frr-test-module/c1value", + .cbs.get_elem = frr_test_module_c1value_get_elem, + }, + { + .xpath = "/frr-test-module:frr-test-module/c2cont/c2value", + .cbs.get_elem = frr_test_module_c2cont_c2value_get_elem, + }, { .xpath = NULL, }, @@ -249,6 +295,33 @@ const struct frr_yang_module_info frr_test_module_info = { }; /* clang-format on */ +DEFUN(test_rpc, test_rpc_cmd, "test rpc", + "Test\n" + "RPC\n") +{ + struct lyd_node *output = NULL; + char xpath[XPATH_MAXLEN]; + int ret; + + snprintf(xpath, sizeof(xpath), + "/frr-test-module:frr-test-module/vrfs/vrf[name='testname']/ping"); + + nb_cli_rpc_enqueue(vty, "data", "testdata"); + + ret = nb_cli_rpc(vty, xpath, &output); + if (ret != CMD_SUCCESS) { + vty_out(vty, "RPC failed\n"); + return ret; + } + + vty_out(vty, "vrf %s data %s\n", yang_dnode_get_string(output, "vrf"), + yang_dnode_get_string(output, "data-out")); + + yang_dnode_free(output); + + return CMD_SUCCESS; +} + static const struct frr_yang_module_info *const modules[] = { &frr_test_module_info, }; @@ -388,6 +461,8 @@ int main(int argc, char **argv) lib_cmd_init(); nb_init(master, modules, array_size(modules), false); + install_element(ENABLE_NODE, &test_rpc_cmd); + /* Create artificial data. */ create_data(num_vrfs, num_interfaces, num_routes); diff --git a/tests/lib/northbound/test_oper_data.in b/tests/lib/northbound/test_oper_data.in index a6c4f874f500..f7c44cad3154 100644 --- a/tests/lib/northbound/test_oper_data.in +++ b/tests/lib/northbound/test_oper_data.in @@ -1 +1,2 @@ show yang operational-data /frr-test-module:frr-test-module +test rpc diff --git a/tests/lib/northbound/test_oper_data.refout b/tests/lib/northbound/test_oper_data.refout index 57ecd2f0a0a1..7c565641431c 100644 --- a/tests/lib/northbound/test_oper_data.refout +++ b/tests/lib/northbound/test_oper_data.refout @@ -112,8 +112,14 @@ test# show yang operational-data /frr-test-module:frr-test-module } } ] + }, + "c1value": 21, + "c2cont": { + "c2value": 2868969987 } } } +test# test rpc +vrf testname data testdata test# end. diff --git a/tests/lib/subdir.am b/tests/lib/subdir.am index 6c1be5020181..1a21684f16ca 100644 --- a/tests/lib/subdir.am +++ b/tests/lib/subdir.am @@ -25,7 +25,7 @@ copy_script: tests/lib/script1.lua $(INSTALL_SCRIPT) $< tests/lib/script1.lua ############################################################################## -GRPC_TESTS_LDADD = staticd/libstatic.a grpc/libfrrgrpc_pb.la -lgrpc++ -lprotobuf $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm +GRPC_TESTS_LDADD = mgmtd/libmgmt_be_nb.la staticd/libstatic.a grpc/libfrrgrpc_pb.la $(GRPC_LIBS) $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm if GRPC check_PROGRAMS += tests/lib/test_grpc @@ -34,6 +34,10 @@ tests_lib_test_grpc_CXXFLAGS = $(WERROR) $(TESTS_CXXFLAGS) tests_lib_test_grpc_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_grpc_LDADD = $(GRPC_TESTS_LDADD) tests_lib_test_grpc_SOURCES = tests/lib/test_grpc.cpp +nodist_tests_lib_test_grpc_SOURCES = \ + yang/frr-bfdd.yang.c \ + yang/frr-staticd.yang.c \ + # end ############################################################################## @@ -96,7 +100,7 @@ check_PROGRAMS += tests/lib/cli/test_commands tests_lib_cli_test_commands_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_commands_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) -nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c +nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c $(vtysh_cmd_split) tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands.c tests/helpers/c/prng.c tests/lib/cli/test_commands_defun.c: vtysh/vtysh_cmd.c @$(MKDIR_P) tests/lib/cli @@ -162,6 +166,7 @@ tests_lib_test_darr_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_darr_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_darr_LDADD = $(ALL_TESTS_LDADD) tests_lib_test_darr_SOURCES = tests/lib/test_darr.c +EXTRA_DIST += tests/lib/test_darr.py check_PROGRAMS += tests/lib/test_graph diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index b50216cf9292..afcfa9879138 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -62,7 +62,7 @@ static struct asort_head shead; static struct testthread { pthread_t pt; struct seqlock sqlo; - size_t counter, nullops; + _Atomic size_t counter, nullops; } thr[NTHREADS]; struct testrun { @@ -97,10 +97,10 @@ static void trfunc_##name(unsigned int offset) \ { \ size_t i = 0, n = 0; -#define endtestrun \ - thr[offset].counter = i; \ - thr[offset].nullops = n; \ -} +#define endtestrun \ + atomic_store_explicit(&thr[offset].counter, i, memory_order_seq_cst); \ + atomic_store_explicit(&thr[offset].nullops, n, memory_order_seq_cst); \ + } deftestrun(add, "add vs. add", 0, false) for (; i < NITEM / NTHREADS; i++) @@ -288,10 +288,10 @@ static void run_tr(struct testrun *tr) sv = seqlock_bump(&sqlo) - SEQLOCK_INCR; for (size_t i = 0; i < NTHREADS; i++) { seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo)); - s += thr[i].counter; - n += thr[i].nullops; - thr[i].counter = 0; - thr[i].nullops = 0; + s += atomic_load_explicit(&thr[i].counter, memory_order_seq_cst); + n += atomic_load_explicit(&thr[i].nullops, memory_order_seq_cst); + atomic_store_explicit(&thr[i].counter, 0, memory_order_seq_cst); + atomic_store_explicit(&thr[i].nullops, 0, memory_order_seq_cst); } delta = monotime_since(&tv, NULL); diff --git a/tests/lib/test_darr.c b/tests/lib/test_darr.c index 9150aed09dfa..87f9e3e5642c 100644 --- a/tests/lib/test_darr.c +++ b/tests/lib/test_darr.c @@ -14,15 +14,27 @@ * [x] - darr_append_n * [x] - darr_append_nz * [x] - darr_cap - * [-] - darr_ensure_cap + * [x] - darr_ensure_avail + * [x] - darr_ensure_cap * [x] - darr_ensure_i * [x] - darr_foreach_i * [x] - darr_foreach_p * [x] - darr_free + * [x] - darr_free_free + * [x] - darr_free_func * [x] - darr_insert * [ ] - darr_insertz * [x] - darr_insert_n * [x] - darr_insert_nz + * [x] - darr_in_sprintf + * [x] - darr_in_strcat + * [x] - darr_in_strcat_tail + * [ ] - darr_in_strcatf + * [ ] - darr_in_vstrcatf + * [x] - darr_in_strdup + * [x] - darr_in_strdup_cap + * [-] - darr_in_vsprintf + * [x] - darr_lasti * [x] - darr_maxi * [x] - darr_pop * [x] - darr_push @@ -31,6 +43,13 @@ * [x] - darr_remove_n * [x] - darr_reset * [x] - darr_setlen + * [x] - darr_set_strlen + * [x] - darr_sprintf + * [x] - darr_strdup + * [x] - darr_strdup_cap + * [x] - darr_strlen + * [x] - darr_strnul + * [ ] - darr_vsprintf */ static void test_int(void) @@ -43,6 +62,11 @@ static void test_int(void) int *dap; uint i; + assert(darr_len(da1) == 0); + assert(darr_lasti(da1) == -1); + assert(darr_last(da1) == NULL); + assert(darr_end(da1) == NULL); + darr_ensure_i(da1, 0); da1[0] = 0; assert(darr_len(da1) == 1); @@ -57,9 +81,11 @@ static void test_int(void) da1[i] = i; assert(darr_len(da1) == 5); + assert(darr_lasti(da1) == 4); /* minimum non-pow2 array size for long long and smaller */ assert(darr_cap(da1) == 8); assert(!memcmp(da1, a1, sizeof(a1))); + assert(&da1[darr_lasti(da1)] == darr_last(da1)); /* reverse the numbers */ darr_foreach_p (da1, dap) @@ -185,6 +211,20 @@ static void test_struct(void) assert(darr_cap(da1) == 8); assert(!memcmp(da1, a1, sizeof(a1))); + assert(darr_cap(da1) - darr_len(da1) == 3); + darr_ensure_avail(da1, 2); + assert(darr_cap(da1) == 8); + darr_ensure_avail(da1, 3); + assert(darr_cap(da1) == 8); + darr_ensure_avail(da1, 4); + assert(darr_cap(da1) == 16); + + darr_ensure_cap(da1, 16); + assert(darr_cap(da1) == 16); + + darr_ensure_cap(da1, 20); + assert(darr_cap(da1) == 32); + darr_append_n(da1, 100); assert(darr_len(da1) == 105); @@ -272,8 +312,138 @@ static void test_struct(void) darr_free(da2); } +static void test_string(void) +{ + const char *src = "ABCDE"; + const char *add = "FGHIJ"; + uint srclen = strlen(src); + uint addlen = strlen(add); + char *da1 = NULL; + char *da2 = NULL; + const char **strings = NULL; + uint sum = 0; + + assert(darr_strlen(da1) == 0); + + da1 = darr_strdup(src); + assert(darr_strlen(da1) == strlen(da1)); + assert(darr_strlen(da1) == srclen); + assert(darr_len(da1) == srclen + 1); + assert(darr_ilen(da1) == (int)srclen + 1); + assert(darr_cap(da1) >= 8); + assert(darr_last(da1) == darr_strnul(da1)); + assert(darr_strnul(da1) == da1 + darr_strlen(da1)); + + da2 = da1; + darr_in_strdup(da1, src); + assert(da1 == da2); + assert(darr_strlen(da1) == strlen(da1)); + assert(darr_strlen(da1) == srclen); + assert(darr_len(da1) == srclen + 1); + darr_free(da1); + assert(da1 == NULL); + + da1 = darr_strdup_cap(src, 128); + assert(darr_strlen(da1) == srclen); + assert(darr_cap(da1) >= 128); + + darr_in_strdup_cap(da1, src, 256); + assert(darr_strlen(da1) == srclen); + assert(darr_cap(da1) >= 256); + darr_free(da1); + + da1 = darr_strdup_cap(add, 2); + assert(darr_strlen(da1) == addlen); + assert(darr_cap(da1) >= 8); + + darr_in_strdup(da1, "ab"); + darr_in_strcat(da1, "/"); + darr_in_strcat(da1, "foo"); + assert(!strcmp("ab/foo", da1)); + darr_free(da1); + + da1 = darr_in_strcat(da1, "ab"); + darr_in_strcat(da1, "/"); + darr_in_strcat(da1, "foo"); + assert(!strcmp("ab/foo", da1)); + + darr_set_strlen(da1, 5); + assert(!strcmp("ab/fo", da1)); + darr_set_strlen(da1, 1); + assert(!strcmp("a", da1)); + + darr_in_strdup(da1, "ab"); + da2 = darr_strdup(add); + darr_in_strcat_tail(da1, da2); + assert(!strcmp("abHIJ", da1)); + assert(darr_strlen(da1) == 5); + assert(darr_len(da1) == 6); + darr_free(da1); + darr_free(da2); + + da1 = darr_strdup("abcde"); + da2 = darr_strdup(add); + darr_in_strcat_tail(da1, da2); + assert(!strcmp("abcde", da1)); + assert(darr_strlen(da1) == 5); + assert(darr_len(da1) == 6); + darr_free(da1); + darr_free(da2); + + da1 = darr_sprintf("0123456789: %08X", 0xDEADBEEF); + assert(!strcmp(da1, "0123456789: DEADBEEF")); + assert(darr_strlen(da1) == 20); + assert(darr_cap(da1) == 128); + da2 = da1; + darr_in_sprintf(da1, "9876543210: %08x", 0x0BADF00D); + assert(da1 == da2); + assert(!strcmp("9876543210: 0badf00d", da2)); + darr_free(da1); + da2 = NULL; + + da1 = NULL; + darr_in_sprintf(da1, "0123456789: %08X", 0xDEADBEEF); + assert(!strcmp(da1, "0123456789: DEADBEEF")); + assert(darr_strlen(da1) == 20); + assert(darr_cap(da1) == 128); + darr_free(da1); + + da1 = darr_sprintf("0123456789: %08x", 0xDEADBEEF); + darr_in_strcatf(da1, " 9876543210: %08x", 0x0BADF00D); + assert(!strcmp("0123456789: deadbeef 9876543210: 0badf00d", da1)); + darr_free(da1); + + da1 = darr_in_strcatf(da1, "0123456789: %08x", 0xDEADBEEF); + assert(!strcmp("0123456789: deadbeef", da1)); + darr_free(da1); + + sum = 0; + *darr_append(strings) = "1"; + *darr_append(strings) = "2"; + *darr_append(strings) = "3"; +#define adder(x) (sum += atoi(x)) + darr_free_func(strings, adder); + assert(sum == 6); + assert(strings == NULL); + + sum = 0; + darr_free_func(strings, adder); + assert(sum == 0); + assert(strings == NULL); + + *darr_append(strings) = NULL; + *darr_append(strings) = darr_strdup("2"); + *darr_append(strings) = darr_strdup("3"); + darr_free_free(strings); + assert(strings == NULL); + + darr_free_free(strings); + assert(strings == NULL); +} + int main(int argc, char **argv) { test_int(); test_struct(); + test_string(); } diff --git a/tests/lib/test_darr.py b/tests/lib/test_darr.py new file mode 100644 index 000000000000..dea3bdf7858b --- /dev/null +++ b/tests/lib/test_darr.py @@ -0,0 +1,8 @@ +import frrtest + + +class TestDarr(frrtest.TestMultiOut): + program = "./test_darr" + + +TestDarr.exit_cleanly() diff --git a/tests/lib/test_frrlua.c b/tests/lib/test_frrlua.c index 701e171c84ac..2760a273bddd 100644 --- a/tests/lib/test_frrlua.c +++ b/tests/lib/test_frrlua.c @@ -13,14 +13,22 @@ static void test_encode_decode(void) { lua_State *L = luaL_newstate(); - long long a = 123; - long long b = a; + int a = 123; + int b = a; lua_pushintegerp(L, &a); lua_decode_integerp(L, -1, &a); assert(a == b); assert(lua_gettop(L) == 0); + long long ll_a = 123L; + long long ll_b = a; + + lua_pushlonglongp(L, &ll_a); + lua_decode_longlongp(L, -1, &ll_a); + assert(ll_a == ll_b); + assert(lua_gettop(L) == 0); + time_t time_a = 100; time_t time_b; diff --git a/tests/lib/test_frrscript.c b/tests/lib/test_frrscript.c index 7d4746cf3ea2..9698aeaa6cb1 100644 --- a/tests/lib/test_frrscript.c +++ b/tests/lib/test_frrscript.c @@ -32,7 +32,7 @@ int main(int argc, char **argv) assert(result == 0); result = frrscript_call(fs, "bar", ("a", &a), ("b", &b)); assert(result == 0); - long long *cptr = frrscript_get_result(fs, "bar", "c", lua_tointegerp); + long long *cptr = frrscript_get_result(fs, "bar", "c", lua_tolonglongp); /* a should not occur in the returned table in script */ assert(a == 100); @@ -47,7 +47,7 @@ int main(int argc, char **argv) result = frrscript_call(fs, "fact", ("n", &n)); assert(result == 0); long long *ansptr = - frrscript_get_result(fs, "fact", "ans", lua_tointegerp); + frrscript_get_result(fs, "fact", "ans", lua_tolonglongp); assert(*ansptr == 120); /* check consecutive call + get_result without re-loading */ diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp index 182c1d338dc7..202313603d0e 100644 --- a/tests/lib/test_grpc.cpp +++ b/tests/lib/test_grpc.cpp @@ -92,6 +92,17 @@ static void static_startup(void) grpc_module = frrmod_load("grpc:50051", modpath.c_str(), _err_print, 0); } + if (!grpc_module) { + modpath = std::string(binpath) + + std::string("../../../lib/.libs"); + grpc_module = frrmod_load("grpc:50051", modpath.c_str(), + _err_print, 0); + } + if (!grpc_module) { + modpath = std::string(binpath) + std::string("../../../lib"); + grpc_module = frrmod_load("grpc:50051", modpath.c_str(), + _err_print, 0); + } if (!grpc_module) exit(1); @@ -108,8 +119,10 @@ static void static_startup(void) hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); - - routing_control_plane_protocols_register_vrf_dependency(); + hook_register(routing_create, + routing_control_plane_protocols_staticd_create); + hook_register(routing_destroy, + routing_control_plane_protocols_staticd_destroy); // Add a route vty = vty_new(); diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c index 225573ae92f6..8c2765cfdfa2 100644 --- a/tests/lib/test_heavy_wq.c +++ b/tests/lib/test_heavy_wq.c @@ -76,12 +76,6 @@ static wq_item_status slow_func(struct work_queue *wq, void *data) for (j = 0; j < 300; j++) x += sin(x) * j; - if ((hn->i % ITERS_LATER) == 0) - return WQ_RETRY_LATER; - - if ((hn->i % ITERS_ERR) == 0) - return WQ_RETRY_NOW; - if ((hn->i % ITERS_PRINT) == 0) printf("%s did %d, x = %g\n", hn->str, hn->i, x); diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 66699ec7c056..a81ebcdbcd78 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -143,6 +143,8 @@ int main(int argc, char **argv) NAN, }; uint64_t ui64 = 0xfeed1278cafef00d; + uint16_t i16 = -23456; + int_fast8_t if8 = 123; struct in_addr ip; char *p; char buf[256]; @@ -169,6 +171,16 @@ int main(int argc, char **argv) FMT_NSTD(printchk("11110000000011111010010111000011", "%b", 0xf00fa5c3)); FMT_NSTD(printchk("0b01011010", "%#010b", 0x5a)); +/* FMT_NSTD is conditional on the frr-format plugin being NOT enabled. + * However, the frr-format plugin does not support %wd/%wfd yet, so this needs + * to be unconditional. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" + printchk("123 -23456 feed1278cafef00d 9876", "%wf8d %w16d %w64x %d", + if8, i16, ui64, 9876); +#pragma GCC diagnostic pop + inet_aton("192.168.1.2", &ip); printchk("192.168.1.2", "%pI4", &ip); printchk(" 192.168.1.2", "%20pI4", &ip); @@ -218,19 +230,25 @@ int main(int argc, char **argv) printchk("02:ca:fe:f0:0d:1e", "%pFXh", &pfx); struct prefix_sg sg; - sg.src.s_addr = INADDR_ANY; + SET_IPADDR_V4(&sg.src); + sg.src.ipaddr_v4.s_addr = INADDR_ANY; sg.grp.s_addr = INADDR_ANY; printchk("(*,*)", "%pPSG4", &sg); - inet_aton("192.168.1.2", &sg.src); + inet_aton("192.168.1.2", &sg.src.ipaddr_v4); printchk("(192.168.1.2,*)", "%pPSG4", &sg); inet_aton("224.1.2.3", &sg.grp); printchk("(192.168.1.2,224.1.2.3)", "%pPSG4", &sg); - sg.src.s_addr = INADDR_ANY; + SET_IPADDR_NONE(&sg.src); + sg.src.ipaddr_v4.s_addr = INADDR_ANY; printchk("(*,224.1.2.3)", "%pPSG4", &sg); + SET_IPADDR_V6(&sg.src); + inet_pton(AF_INET6, "1:2:3:4::5", &sg.src.ipaddr_v6); + printchk("(1:2:3:4::5,224.1.2.3)", "%pPSG4", &sg); + uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 }; FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.8pHX", randhex)); diff --git a/tests/lib/test_privs.c b/tests/lib/test_privs.c index e26754857b89..caf55c718f16 100644 --- a/tests/lib/test_privs.c +++ b/tests/lib/test_privs.c @@ -3,6 +3,7 @@ */ #include +#include #include #include "getopt.h" diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c index 288d4a8c2554..937b3f34f55f 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -82,11 +82,11 @@ int main(int argc, char **argv) assert(seqlock_held(&sqlo)); assert(seqlock_cur(&sqlo) == 1); - assert(seqlock_bump(&sqlo) == 1); - assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 5); + assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 9); assert(seqlock_bump(&sqlo) == 13); + assert(seqlock_bump(&sqlo) == 17); assert(seqlock_cur(&sqlo) == 17); assert(seqlock_held(&sqlo)); @@ -111,4 +111,5 @@ int main(int argc, char **argv) writestr("main @release\n"); seqlock_release(&sqlo); sleep(1); + pthread_join(thr1, NULL); } diff --git a/tests/ospfd/test_ospf_spf.c b/tests/ospfd/test_ospf_spf.c index fc6b8e89ec6e..932763100b33 100644 --- a/tests/ospfd/test_ospf_spf.c +++ b/tests/ospfd/test_ospf_spf.c @@ -1,4 +1,5 @@ #include +#include #include "getopt.h" #include "frrevent.h" diff --git a/tests/topotests/all_protocol_startup/r1/ip_nht.ref b/tests/topotests/all_protocol_startup/r1/ip_nht.ref index a2f3d3b0db4e..3592f29b5454 100644 --- a/tests/topotests/all_protocol_startup/r1/ip_nht.ref +++ b/tests/topotests/all_protocol_startup/r1/ip_nht.ref @@ -55,19 +55,19 @@ VRF default: Client list: pbr(fd XX) 192.168.0.2 resolved via connected - is directly connected, r1-eth0 (vrf default) + is directly connected, r1-eth0 (vrf default), weight 1 Client list: static(fd XX) 192.168.0.4 resolved via connected - is directly connected, r1-eth0 (vrf default) + is directly connected, r1-eth0 (vrf default), weight 1 Client list: static(fd XX) 192.168.7.10 resolved via connected - is directly connected, r1-eth7 (vrf default) + is directly connected, r1-eth7 (vrf default), weight 1 Client list: bgp(fd XX) 192.168.7.20(Connected) resolved via connected - is directly connected, r1-eth7 (vrf default) + is directly connected, r1-eth7 (vrf default), weight 1 Client list: bgp(fd XX) 192.168.161.4 unresolved diff --git a/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref b/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref index 044cffae7a45..33c44780b454 100644 --- a/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref +++ b/tests/topotests/all_protocol_startup/r1/ipv4_routes.ref @@ -1,13 +1,23 @@ -C>* 192.168.0.0/24 is directly connected, r1-eth0, XX:XX:XX -C>* 192.168.1.0/26 is directly connected, r1-eth1, XX:XX:XX -C>* 192.168.2.0/26 is directly connected, r1-eth2, XX:XX:XX -C>* 192.168.3.0/26 is directly connected, r1-eth3, XX:XX:XX -C>* 192.168.4.0/26 is directly connected, r1-eth4, XX:XX:XX -C>* 192.168.5.0/26 is directly connected, r1-eth5, XX:XX:XX -C>* 192.168.6.0/26 is directly connected, r1-eth6, XX:XX:XX -C>* 192.168.7.0/26 is directly connected, r1-eth7, XX:XX:XX -C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX -C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX +C>* 192.168.0.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX +C>* 192.168.1.0/26 is directly connected, r1-eth1, weight 1, XX:XX:XX +C>* 192.168.2.0/26 is directly connected, r1-eth2, weight 1, XX:XX:XX +C>* 192.168.3.0/26 is directly connected, r1-eth3, weight 1, XX:XX:XX +C>* 192.168.4.0/26 is directly connected, r1-eth4, weight 1, XX:XX:XX +C>* 192.168.5.0/26 is directly connected, r1-eth5, weight 1, XX:XX:XX +C>* 192.168.6.0/26 is directly connected, r1-eth6, weight 1, XX:XX:XX +C>* 192.168.7.0/26 is directly connected, r1-eth7, weight 1, XX:XX:XX +C>* 192.168.8.0/26 is directly connected, r1-eth8, weight 1, XX:XX:XX +C>* 192.168.9.0/26 is directly connected, r1-eth9, weight 1, XX:XX:XX +L>* 192.168.0.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX +L>* 192.168.1.1/32 is directly connected, r1-eth1, weight 1, XX:XX:XX +L>* 192.168.2.1/32 is directly connected, r1-eth2, weight 1, XX:XX:XX +L>* 192.168.3.1/32 is directly connected, r1-eth3, weight 1, XX:XX:XX +L>* 192.168.4.1/32 is directly connected, r1-eth4, weight 1, XX:XX:XX +L>* 192.168.5.1/32 is directly connected, r1-eth5, weight 1, XX:XX:XX +L>* 192.168.6.1/32 is directly connected, r1-eth6, weight 1, XX:XX:XX +L>* 192.168.7.1/32 is directly connected, r1-eth7, weight 1, XX:XX:XX +L>* 192.168.8.1/32 is directly connected, r1-eth8, weight 1, XX:XX:XX +L>* 192.168.9.1/32 is directly connected, r1-eth9, weight 1, XX:XX:XX O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, weight 1, XX:XX:XX S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref index 100a36a8d6ab..7b71761185d8 100644 --- a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref +++ b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref @@ -2,14 +2,14 @@ VRF default: Resolve via default: on fc00::2 resolved via connected - is directly connected, r1-eth0 (vrf default) + is directly connected, r1-eth0 (vrf default), weight 1 Client list: static(fd XX) fc00:0:0:8::1000 resolved via connected - is directly connected, r1-eth8 (vrf default) + is directly connected, r1-eth8 (vrf default), weight 1 Client list: bgp(fd XX) fc00:0:0:8::2000(Connected) resolved via connected - is directly connected, r1-eth8 (vrf default) + is directly connected, r1-eth8 (vrf default), weight 1 Client list: bgp(fd XX) diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref b/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref index ef12d615dc89..f5c1d6d7d232 100644 --- a/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref +++ b/tests/topotests/all_protocol_startup/r1/ipv6_routes.ref @@ -1,24 +1,34 @@ -C>* fc00:0:0:1::/64 is directly connected, r1-eth1, XX:XX:XX -C>* fc00:0:0:2::/64 is directly connected, r1-eth2, XX:XX:XX -C>* fc00:0:0:3::/64 is directly connected, r1-eth3, XX:XX:XX -C>* fc00:0:0:4::/64 is directly connected, r1-eth4, XX:XX:XX -C>* fc00:0:0:5::/64 is directly connected, r1-eth5, XX:XX:XX -C>* fc00:0:0:6::/64 is directly connected, r1-eth6, XX:XX:XX -C>* fc00:0:0:7::/64 is directly connected, r1-eth7, XX:XX:XX -C>* fc00:0:0:8::/64 is directly connected, r1-eth8, XX:XX:XX -C>* fc00:0:0:9::/64 is directly connected, r1-eth9, XX:XX:XX -C>* fc00::/64 is directly connected, r1-eth0, XX:XX:XX -C>* fe80::/64 is directly connected, lo, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth0, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth1, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth2, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth3, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth4, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth5, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth6, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth7, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth8, XX:XX:XX -C * fe80::/64 is directly connected, r1-eth9, XX:XX:XX +C>* fc00:0:0:1::/64 is directly connected, r1-eth1, weight 1, XX:XX:XX +C>* fc00:0:0:2::/64 is directly connected, r1-eth2, weight 1, XX:XX:XX +C>* fc00:0:0:3::/64 is directly connected, r1-eth3, weight 1, XX:XX:XX +C>* fc00:0:0:4::/64 is directly connected, r1-eth4, weight 1, XX:XX:XX +C>* fc00:0:0:5::/64 is directly connected, r1-eth5, weight 1, XX:XX:XX +C>* fc00:0:0:6::/64 is directly connected, r1-eth6, weight 1, XX:XX:XX +C>* fc00:0:0:7::/64 is directly connected, r1-eth7, weight 1, XX:XX:XX +C>* fc00:0:0:8::/64 is directly connected, r1-eth8, weight 1, XX:XX:XX +C>* fc00:0:0:9::/64 is directly connected, r1-eth9, weight 1, XX:XX:XX +C>* fc00::/64 is directly connected, r1-eth0, weight 1, XX:XX:XX +C>* fe80::/64 is directly connected, lo, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth0, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth1, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth2, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth3, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth4, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth5, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth6, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth7, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth8, weight 1, XX:XX:XX +C * fe80::/64 is directly connected, r1-eth9, weight 1, XX:XX:XX +L>* fc00:0:0:1::1/128 is directly connected, r1-eth1, weight 1, XX:XX:XX +L>* fc00:0:0:2::1/128 is directly connected, r1-eth2, weight 1, XX:XX:XX +L>* fc00:0:0:3::1/128 is directly connected, r1-eth3, weight 1, XX:XX:XX +L>* fc00:0:0:4::1/128 is directly connected, r1-eth4, weight 1, XX:XX:XX +L>* fc00:0:0:5::1/128 is directly connected, r1-eth5, weight 1, XX:XX:XX +L>* fc00:0:0:6::1/128 is directly connected, r1-eth6, weight 1, XX:XX:XX +L>* fc00:0:0:7::1/128 is directly connected, r1-eth7, weight 1, XX:XX:XX +L>* fc00:0:0:8::1/128 is directly connected, r1-eth8, weight 1, XX:XX:XX +L>* fc00:0:0:9::1/128 is directly connected, r1-eth9, weight 1, XX:XX:XX +L>* fc00::1/128 is directly connected, r1-eth0, weight 1, XX:XX:XX O fc00:0:0:4::/64 [110/10] is directly connected, r1-eth4, weight 1, XX:XX:XX S>* 4:5::6:10/128 [1/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX S>* 4:5::6:11/128 [1/0] via fc00::2, r1-eth0, weight 1, XX:XX:XX diff --git a/tests/topotests/all_protocol_startup/r1/ospf6d.conf b/tests/topotests/all_protocol_startup/r1/ospf6d.conf index 33c26501ba35..31c904b41592 100644 --- a/tests/topotests/all_protocol_startup/r1/ospf6d.conf +++ b/tests/topotests/all_protocol_startup/r1/ospf6d.conf @@ -6,12 +6,12 @@ log file ospf6d.log ! debug ospf6 neighbor ! interface r1-eth4 - ipv6 ospf6 hello-interval 1 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 hello-interval 1 ! router ospf6 ospf6 router-id 192.168.0.1 log-adjacency-changes - interface r1-eth4 area 0.0.0.0 ! line vty ! diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref index b2e8de5ce13b..eb4e51a074cb 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref @@ -1,9 +1,9 @@ BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete RPKI validation codes: V valid, I invalid, N Not found - Network Next Hop Metric LocPrf Weight Path - *> 192.168.0.0 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 192.168.0.0 0.0.0.0 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref index 7bee704182ed..8fe3ea41a66f 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref @@ -1,9 +1,9 @@ BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete RPKI validation codes: V valid, I invalid, N Not found - Network Next Hop Metric LocPrf Weight Path - *> 192.168.0.0/24 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 192.168.0.0/24 0.0.0.0 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref index 31071e760d46..67b907131c2b 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref @@ -1,10 +1,10 @@ BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 Default local pref 100, local AS 100 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete RPKI validation codes: V valid, I invalid, N Not found - Network Next Hop Metric LocPrf Weight Path - *> 192.168.0.0/24 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 192.168.0.0/24 0.0.0.0 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref index 53c4793bf4ce..4f21a5711b88 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref @@ -1,7 +1,7 @@ BGP table version is 1, local router ID is 192.168.0.1 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete - Network Next Hop Metric LocPrf Weight Path - *> 192.168.0.0 0.0.0.0 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> 192.168.0.0 0.0.0.0 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref index fe3f0720d814..69e44e77edc5 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref @@ -1,9 +1,9 @@ BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete RPKI validation codes: V valid, I invalid, N Not found - Network Next Hop Metric LocPrf Weight Path - *> fc00::/64 :: 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref index 363b4f5349e2..77aab38b0d0b 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref @@ -1,7 +1,7 @@ BGP table version is 1, local router ID is 192.168.0.1 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Origin codes: i - IGP, e - EGP, ? - incomplete - Network Next Hop Metric LocPrf Weight Path - *> fc00::/64 :: 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref index 8c3229b45d00..a99400a6b0c4 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref @@ -1,10 +1,10 @@ BGP table version is 1, local router ID is 192.168.0.1, vrf id 0 Default local pref 100, local AS 100 -Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, +Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete RPKI validation codes: V valid, I invalid, N Not found - Network Next Hop Metric LocPrf Weight Path - *> fc00::/64 :: 0 32768 i + Network Next Hop Metric LocPrf Weight Path + *> fc00::/64 :: 0 32768 i diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref index 02466872000a..4464e231f867 100644 --- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref +++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_summary.ref @@ -1,4 +1,4 @@ -BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP router identifier 192.168.0.1, local AS number 100 VRF default vrf-id 0 BGP table version 1 RIB entries 1, using XXXX bytes of memory Peers 2, using XXXX KiB of memory diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref b/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref index deeae87fa3b7..9baec12b100b 100644 --- a/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref +++ b/tests/topotests/all_protocol_startup/r1/show_ip_bgp_summary.ref @@ -1,4 +1,4 @@ -BGP router identifier 192.168.0.1, local AS number 100 vrf-id 0 +BGP router identifier 192.168.0.1, local AS number 100 VRF default vrf-id 0 BGP table version 1 RIB entries 1, using XXXX bytes of memory Peers 4, using XXXX KiB of memory diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref index 7e28f04e1c91..e4e329011163 100644 --- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref +++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref @@ -1,5 +1,5 @@ r1-eth0 is up - ifindex X, MTU 1500 bytes, BW XX Mbit + ifindex X, MTU 1500 bytes, BW XX Mbit Internet Address 192.168.0.1/24, Broadcast 192.168.0.255, Area 0.0.0.0 MTU mismatch detection: enabled Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 @@ -11,8 +11,9 @@ r1-eth0 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 r1-eth3 is up - ifindex X, MTU 1500 bytes, BW XX Mbit + ifindex X, MTU 1500 bytes, BW XX Mbit Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 MTU mismatch detection: enabled Router ID 192.168.0.1, Network Type BROADCAST, Cost: 10 @@ -24,3 +25,4 @@ r1-eth3 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py index 4b7c4de80618..80bd2505a73d 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -38,6 +38,10 @@ required_linux_kernel_version, ) +import json +import functools + +# Global that must be set on a failure to stop subsequent tests from being run fatal_error = "" @@ -51,7 +55,7 @@ def build_topo(tgen): router = tgen.add_router("r1") for i in range(0, 10): - tgen.add_switch("sw%d" % i).add_link(router) + tgen.add_switch("sw{}".format(i)).add_link(router) ##################################################### @@ -64,7 +68,7 @@ def build_topo(tgen): def setup_module(module): global fatal_error - print("\n\n** %s: Setup Topology" % module.__name__) + print("\n\n** {}: Setup Topology".format(module.__name__)) print("******************************************\n") thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -82,34 +86,36 @@ def setup_module(module): # # Main router for i in range(1, 2): - net["r%s" % i].loadConf("mgmtd", "%s/r%s/zebra.conf" % (thisDir, i)) - net["r%s" % i].loadConf("zebra", "%s/r%s/zebra.conf" % (thisDir, i)) - net["r%s" % i].loadConf("ripd", "%s/r%s/ripd.conf" % (thisDir, i)) - net["r%s" % i].loadConf("ripngd", "%s/r%s/ripngd.conf" % (thisDir, i)) - net["r%s" % i].loadConf("ospfd", "%s/r%s/ospfd.conf" % (thisDir, i)) + net["r{}".format(i)].loadConf("mgmtd", "{}/r{}/zebra.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("zebra", "{}/r{}/zebra.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("ripd", "{}/r{}/ripd.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("ripngd", "{}/r{}/ripngd.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("ospfd", "{}/r{}/ospfd.conf".format(thisDir, i)) if net["r1"].checkRouterVersion("<", "4.0"): - net["r%s" % i].loadConf( - "ospf6d", "%s/r%s/ospf6d.conf-pre-v4" % (thisDir, i) + net["r{}".format(i)].loadConf( + "ospf6d", "{}/r{}/ospf6d.conf-pre-v4".format(thisDir, i) ) else: - net["r%s" % i].loadConf("ospf6d", "%s/r%s/ospf6d.conf" % (thisDir, i)) - net["r%s" % i].loadConf("isisd", "%s/r%s/isisd.conf" % (thisDir, i)) - net["r%s" % i].loadConf("bgpd", "%s/r%s/bgpd.conf" % (thisDir, i)) - if net["r%s" % i].daemon_available("ldpd"): + net["r{}".format(i)].loadConf( + "ospf6d", "{}/r{}/ospf6d.conf".format(thisDir, i) + ) + net["r{}".format(i)].loadConf("isisd", "{}/r{}/isisd.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("bgpd", "{}/r{}/bgpd.conf".format(thisDir, i)) + if net["r{}".format(i)].daemon_available("ldpd"): # Only test LDPd if it's installed and Kernel >= 4.5 - net["r%s" % i].loadConf("ldpd", "%s/r%s/ldpd.conf" % (thisDir, i)) - net["r%s" % i].loadConf("sharpd") - net["r%s" % i].loadConf("nhrpd", "%s/r%s/nhrpd.conf" % (thisDir, i)) - net["r%s" % i].loadConf("babeld", "%s/r%s/babeld.conf" % (thisDir, i)) - net["r%s" % i].loadConf("pbrd", "%s/r%s/pbrd.conf" % (thisDir, i)) - tgen.gears["r%s" % i].start() + net["r{}".format(i)].loadConf("ldpd", "{}/r{}/ldpd.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("sharpd") + net["r{}".format(i)].loadConf("nhrpd", "{}/r{}/nhrpd.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("babeld", "{}/r{}/babeld.conf".format(thisDir, i)) + net["r{}".format(i)].loadConf("pbrd", "{}/r{}/pbrd.conf".format(thisDir, i)) + tgen.gears["r{}".format(i)].start() # For debugging after starting FRR daemons, uncomment the next line # tgen.mininet_cli() def teardown_module(module): - print("\n\n** %s: Shutdown Topology" % module.__name__) + print("\n\n** {}: Shutdown Topology".format(module.__name__)) print("******************************************\n") tgen = get_topogen() tgen.stop_topology() @@ -130,7 +136,7 @@ def test_router_running(): # Starting Routers for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error # For debugging after starting FRR daemons, uncomment the next line @@ -148,14 +154,15 @@ def test_error_messages_vtysh(): print("\n\n** Check for error messages on VTYSH") print("******************************************\n") - failures = 0 for i in range(1, 2): # # First checking Standard Output # # VTYSH output from router - vtystdout = net["r%s" % i].cmd('vtysh -c "show version" 2> /dev/null').rstrip() + vtystdout = ( + net["r{}".format(i)].cmd('vtysh -c "show version" 2> /dev/null').rstrip() + ) # Fix newlines (make them all the same) vtystdout = ("\n".join(vtystdout.splitlines()) + "\n").rstrip() @@ -163,16 +170,20 @@ def test_error_messages_vtysh(): vtystdout = re.sub(r"FRRouting [0-9]+.*", "", vtystdout, flags=re.DOTALL) if vtystdout == "": - print("r%s StdOut ok" % i) + print("r{} StdOut ok".format(i)) - assert vtystdout == "", "Vtysh StdOut Output check failed for router r%s" % i + assert ( + vtystdout == "" + ), "Vtysh StdOut Output check failed for router r{}".format(i) # # Second checking Standard Error # # VTYSH StdErr output from router - vtystderr = net["r%s" % i].cmd('vtysh -c "show version" > /dev/null').rstrip() + vtystderr = ( + net["r{}".format(i)].cmd('vtysh -c "show version" > /dev/null').rstrip() + ) # Fix newlines (make them all the same) vtystderr = ("\n".join(vtystderr.splitlines()) + "\n").rstrip() @@ -180,13 +191,15 @@ def test_error_messages_vtysh(): # vtystderr = re.sub(r"FRRouting [0-9]+.*", "", vtystderr, flags=re.DOTALL) if vtystderr == "": - print("r%s StdErr ok" % i) + print("r{} StdErr ok".format(i)) - assert vtystderr == "", "Vtysh StdErr Output check failed for router r%s" % i + assert ( + vtystderr == "" + ), "Vtysh StdErr Output check failed for router r{}".format(i) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -210,37 +223,37 @@ def test_error_messages_daemons(): error_logs = "" for i in range(1, 2): - log = net["r%s" % i].getStdErr("ripd") + log = net["r{}".format(i)].getStdErr("ripd") if log: - error_logs += "r%s RIPd StdErr Output:\n" % i + error_logs += "r{} RIPd StdErr Output:\n".format(i) error_logs += log - log = net["r%s" % i].getStdErr("ripngd") + log = net["r{}".format(i)].getStdErr("ripngd") if log: - error_logs += "r%s RIPngd StdErr Output:\n" % i + error_logs += "r{} RIPngd StdErr Output:\n".format(i) error_logs += log - log = net["r%s" % i].getStdErr("ospfd") + log = net["r{}".format(i)].getStdErr("ospfd") if log: - error_logs += "r%s OSPFd StdErr Output:\n" % i + error_logs += "r{} OSPFd StdErr Output:\n".format(i) error_logs += log - log = net["r%s" % i].getStdErr("ospf6d") + log = net["r{}".format(i)].getStdErr("ospf6d") if log: - error_logs += "r%s OSPF6d StdErr Output:\n" % i + error_logs += "r{} OSPF6d StdErr Output:\n".format(i) error_logs += log - log = net["r%s" % i].getStdErr("isisd") + log = net["r{}".format(i)].getStdErr("isisd") # ISIS shows debugging enabled status on StdErr # Remove these messages log = re.sub(r"^IS-IS .* debugging is on.*", "", log).rstrip() if log: - error_logs += "r%s ISISd StdErr Output:\n" % i + error_logs += "r{} ISISd StdErr Output:\n".format(i) error_logs += log - log = net["r%s" % i].getStdErr("bgpd") + log = net["r{}".format(i)].getStdErr("bgpd") if log: - error_logs += "r%s BGPd StdErr Output:\n" % i + error_logs += "r{} BGPd StdErr Output:\n".format(i) error_logs += log - if net["r%s" % i].daemon_available("ldpd"): - log = net["r%s" % i].getStdErr("ldpd") + if net["r{}".format(i)].daemon_available("ldpd"): + log = net["r{}".format(i)].getStdErr("ldpd") if log: - error_logs += "r%s LDPd StdErr Output:\n" % i + error_logs += "r{} LDPd StdErr Output:\n".format(i) error_logs += log log = net["r1"].getStdErr("nhrpd") @@ -248,27 +261,27 @@ def test_error_messages_daemons(): # Ignore these log = re.sub(r".*YANG model.*not embedded.*", "", log).rstrip() if log: - error_logs += "r%s NHRPd StdErr Output:\n" % i + error_logs += "r{} NHRPd StdErr Output:\n".format(i) error_logs += log log = net["r1"].getStdErr("babeld") if log: - error_logs += "r%s BABELd StdErr Output:\n" % i + error_logs += "r{} BABELd StdErr Output:\n".format(i) error_logs += log log = net["r1"].getStdErr("pbrd") if log: - error_logs += "r%s PBRd StdErr Output:\n" % i + error_logs += "r{} PBRd StdErr Output:\n".format(i) error_logs += log - log = net["r%s" % i].getStdErr("zebra") + log = net["r{}".format(i)].getStdErr("zebra") if log: - error_logs += "r%s Zebra StdErr Output:\n" % i + error_logs += "r{} Zebra StdErr Output:\n".format(i) error_logs += log if error_logs: sys.stderr.write( - "Failed check for StdErr Output on daemons:\n%s\n" % error_logs + "Failed check for StdErr Output on daemons:\n{}\n".format(error_logs) ) # Ignoring the issue if told to ignore (ie not yet fixed) @@ -314,18 +327,20 @@ def test_converge_protocols(): # Make sure that all daemons are running failures = 0 for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error print("Show that v4 routes are right\n") - v4_routesFile = "%s/r%s/ipv4_routes.ref" % (thisDir, i) + v4_routesFile = "{}/r{}/ipv4_routes.ref".format(thisDir, i) expected = ( - net["r%s" % i].cmd("sort {} 2> /dev/null".format(v4_routesFile)).rstrip() + net["r{}".format(i)] + .cmd("sort {} 2> /dev/null".format(v4_routesFile)) + .rstrip() ) expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd( "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null" ) @@ -341,24 +356,26 @@ def test_converge_protocols(): title2="Expected IP RoutingTable", ) if diff: - sys.stderr.write("r%s failed IP Routing table check:\n%s\n" % (i, diff)) + sys.stderr.write("r{} failed IP Routing table check:\n{}\n".format(i, diff)) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) - assert failures == 0, "IP Routing table failed for r%s\n%s" % (i, diff) + assert failures == 0, "IP Routing table failed for r{}\n{}".format(i, diff) failures = 0 print("Show that v6 routes are right\n") - v6_routesFile = "%s/r%s/ipv6_routes.ref" % (thisDir, i) + v6_routesFile = "{}/r{}/ipv6_routes.ref".format(thisDir, i) expected = ( - net["r%s" % i].cmd("sort {} 2> /dev/null".format(v6_routesFile)).rstrip() + net["r{}".format(i)] + .cmd("sort {} 2> /dev/null".format(v6_routesFile)) + .rstrip() ) expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd( "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null" ) @@ -374,24 +391,38 @@ def test_converge_protocols(): title2="Expected IPv6 RoutingTable", ) if diff: - sys.stderr.write("r%s failed IPv6 Routing table check:\n%s\n" % (i, diff)) + sys.stderr.write( + "r{} failed IPv6 Routing table check:\n{}\n".format(i, diff) + ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) - assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff) + assert failures == 0, "IPv6 Routing table failed for r{}\n{}".format(i, diff) def route_get_nhg_id(route_str): - net = get_topogen().net - output = net["r1"].cmd('vtysh -c "show ip route %s nexthop-group"' % route_str) - match = re.search(r"Nexthop Group ID: (\d+)", output) - assert match is not None, ( - "Nexthop Group ID not found for sharpd route %s" % route_str - ) + global fatal_error + + def get_func(route_str): + net = get_topogen().net + output = net["r1"].cmd( + 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) + ) + match = re.search(r"Nexthop Group ID: (\d+)", output) + if match is not None: + nhg_id = int(match.group(1)) + return nhg_id + else: + return None - nhg_id = int(match.group(1)) - return nhg_id + test_func = functools.partial(get_func, route_str) + _, nhg_id = topotest.run_and_expect_type(test_func, int, count=30, wait=1) + if nhg_id == None: + fatal_error = "Nexthop Group ID not found for route {}".format(route_str) + assert nhg_id != None, fatal_error + else: + return nhg_id def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): @@ -407,7 +438,7 @@ def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): while not found and count < 10: count += 1 # Verify NHG is valid/installed - output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + output = net["r1"].cmd('vtysh -c "show nexthop-group rib {}"'.format(nhg_id)) valid = re.search(r"Valid", output) if valid is None: found = False @@ -446,26 +477,34 @@ def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): continue found = True - assert valid is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id + assert valid is not None, "Nexthop Group ID={} not marked Valid".format(nhg_id) if ecmp or recursive: - assert ecmpcount is not None, "Nexthop Group ID=%d has no depends" % nhg_id + assert ecmpcount is not None, "Nexthop Group ID={} has no depends".format( + nhg_id + ) if ecmp: - assert len(depends) == ecmp, ( - "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id - ) + assert ( + len(depends) == ecmp + ), "Nexthop Group ID={} doesn't match ecmp size".format(nhg_id) else: - assert len(depends) == 1, ( - "Nexthop Group ID=%d should only have one recursive depend" % nhg_id + assert ( + len(depends) == 1 + ), "Nexthop Group ID={} should only have one recursive depend".format( + nhg_id ) else: - assert installed is not None, ( - "Nexthop Group ID=%d not marked Installed" % nhg_id + assert installed is not None, "Nexthop Group ID={} not marked Installed".format( + nhg_id ) def verify_route_nexthop_group(route_str, recursive=False, ecmp=0): + global fatal_error + # Verify route and that zebra created NHGs for and they are valid/installed + nhg_id = route_get_nhg_id(route_str) + verify_nexthop_group(nhg_id, recursive, ecmp) @@ -596,18 +635,19 @@ def test_nexthop_groups(): count = 0 dups = [] nhg_id = route_get_nhg_id("6.6.6.1/32") - while (len(dups) != 3) and count < 10: - output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + while (len(dups) != 4) and count < 10: + output = net["r1"].cmd('vtysh -c "show nexthop-group rib {}"'.format(nhg_id)) dups = re.findall(r"(via 1\.1\.1\.1)", output) - if len(dups) != 3: + if len(dups) != 4: count += 1 sleep(1) # Should find 3, itself is inactive - assert len(dups) == 3, ( - "Route 6.6.6.1/32 with Nexthop Group ID=%d has wrong number of resolved nexthops" - % nhg_id + assert ( + len(dups) == 4 + ), "Route 6.6.6.1/32 with Nexthop Group ID={} has wrong number of resolved nexthops".format( + nhg_id ) ## Remove all NHG routes @@ -637,7 +677,7 @@ def test_rip_status(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/rip_status.ref" % (thisDir, i) + refTableFile = "{}/r{}/rip_status.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -646,7 +686,7 @@ def test_rip_status(): # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd('vtysh -c "show ip rip status" 2> /dev/null') .rstrip() ) @@ -667,16 +707,20 @@ def test_rip_status(): # Empty string if it matches, otherwise diff contains unified diff if diff: - sys.stderr.write("r%s failed IP RIP status check:\n%s\n" % (i, diff)) + sys.stderr.write( + "r{} failed IP RIP status check:\n{}\n".format(i, diff) + ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) - assert failures == 0, "IP RIP status failed for router r%s:\n%s" % (i, diff) + assert failures == 0, "IP RIP status failed for router r{}:\n{}".format( + i, diff + ) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -694,7 +738,7 @@ def test_ripng_status(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/ripng_status.ref" % (thisDir, i) + refTableFile = "{}/r{}/ripng_status.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -703,7 +747,7 @@ def test_ripng_status(): # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd('vtysh -c "show ipv6 ripng status" 2> /dev/null') .rstrip() ) @@ -727,20 +771,19 @@ def test_ripng_status(): # Empty string if it matches, otherwise diff contains unified diff if diff: sys.stderr.write( - "r%s failed IPv6 RIPng status check:\n%s\n" % (i, diff) + "r{} failed IPv6 RIPng status check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) - assert failures == 0, "IPv6 RIPng status failed for router r%s:\n%s" % ( - i, - diff, + assert failures == 0, "IPv6 RIPng status failed for router r{}:\n{}".format( + i, diff ) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -758,7 +801,7 @@ def test_ospfv2_interfaces(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/show_ip_ospf_interface.ref" % (thisDir, i) + refTableFile = "{}/r{}/show_ip_ospf_interface.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -767,7 +810,7 @@ def test_ospfv2_interfaces(): # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd('vtysh -c "show ip ospf interface" 2> /dev/null') .rstrip() ) @@ -800,11 +843,11 @@ def test_ospfv2_interfaces(): # Empty string if it matches, otherwise diff contains unified diff if diff: sys.stderr.write( - "r%s failed SHOW IP OSPF INTERFACE check:\n%s\n" % (i, diff) + "r{} failed SHOW IP OSPF INTERFACE check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) # Ignoring the issue if told to ignore (ie not yet fixed) if failures != 0: @@ -818,11 +861,11 @@ def test_ospfv2_interfaces(): assert ( failures == 0 - ), "SHOW IP OSPF INTERFACE failed for router r%s:\n%s" % (i, diff) + ), "SHOW IP OSPF INTERFACE failed for router r{}:\n{}".format(i, diff) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -840,7 +883,7 @@ def test_isis_interfaces(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/show_isis_interface_detail.ref" % (thisDir, i) + refTableFile = "{}/r{}/show_isis_interface_detail.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -849,7 +892,7 @@ def test_isis_interfaces(): # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd('vtysh -c "show isis interface detail" 2> /dev/null') .rstrip() ) @@ -873,19 +916,19 @@ def test_isis_interfaces(): # Empty string if it matches, otherwise diff contains unified diff if diff: sys.stderr.write( - "r%s failed SHOW ISIS INTERFACE DETAIL check:\n%s\n" % (i, diff) + "r{} failed SHOW ISIS INTERFACE DETAIL check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) assert ( failures == 0 - ), "SHOW ISIS INTERFACE DETAIL failed for router r%s:\n%s" % (i, diff) + ), "SHOW ISIS INTERFACE DETAIL failed for router r{}:\n{}".format(i, diff) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -903,7 +946,7 @@ def test_bgp_summary(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/show_ip_bgp_summary.ref" % (thisDir, i) + refTableFile = "{}/r{}/show_ip_bgp_summary.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected_original = open(refTableFile).read().rstrip() @@ -930,7 +973,7 @@ def test_bgp_summary(): ]: # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd( 'vtysh -c "show ip bgp summary ' + arguments + '" 2> /dev/null' ) @@ -948,26 +991,24 @@ def test_bgp_summary(): actual = re.sub(r"Total number.*", "", actual) actual = re.sub(r"Displayed.*", "", actual) # Remove IPv4 Unicast Summary (Title only) - actual = re.sub(r"IPv4 Unicast Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv4 Unicast Summary:", "", actual) # Remove IPv4 Multicast Summary (all of it) - actual = re.sub(r"IPv4 Multicast Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv4 Multicast Summary:", "", actual) actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual) # Remove IPv4 VPN Summary (all of it) - actual = re.sub(r"IPv4 VPN Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv4 VPN Summary:", "", actual) actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual) # Remove IPv4 Encap Summary (all of it) - actual = re.sub(r"IPv4 Encap Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv4 Encap Summary:", "", actual) actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual) # Remove Unknown Summary (all of it) - actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual) + actual = re.sub(r"Unknown Summary:", "", actual) actual = re.sub(r"No Unknown neighbor is configured", "", actual) # Make Connect/Active/Idle the same (change them all to Active) actual = re.sub(r" Connect ", " Active ", actual) actual = re.sub(r" Idle ", " Active ", actual) - actual = re.sub( - r"IPv4 labeled-unicast Summary \(VRF default\):", "", actual - ) + actual = re.sub(r"IPv4 labeled-unicast Summary:", "", actual) actual = re.sub( r"No IPv4 labeled-unicast neighbor is configured", "", actual ) @@ -1048,22 +1089,19 @@ def test_bgp_summary(): # Empty string if it matches, otherwise diff contains unified diff if diff: sys.stderr.write( - "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i, diff) + "r{} failed SHOW IP BGP SUMMARY check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) assert ( failures == 0 - ), "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % ( - i, - diff, - ) + ), "SHOW IP BGP SUMMARY failed for router r{}:\n{}".format(i, diff) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -1081,7 +1119,7 @@ def test_bgp_ipv6_summary(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/show_bgp_ipv6_summary.ref" % (thisDir, i) + refTableFile = "{}/r{}/show_bgp_ipv6_summary.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -1090,7 +1128,7 @@ def test_bgp_ipv6_summary(): # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd('vtysh -c "show bgp ipv6 summary" 2> /dev/null') .rstrip() ) @@ -1105,27 +1143,25 @@ def test_bgp_ipv6_summary(): actual = re.sub(r"Total number.*", "", actual) actual = re.sub(r"Displayed.*", "", actual) # Remove IPv4 Unicast Summary (Title only) - actual = re.sub(r"IPv6 Unicast Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv6 Unicast Summary:", "", actual) # Remove IPv4 Multicast Summary (all of it) - actual = re.sub(r"IPv6 Multicast Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv6 Multicast Summary:", "", actual) actual = re.sub(r"No IPv6 Multicast neighbor is configured", "", actual) # Remove IPv4 VPN Summary (all of it) - actual = re.sub(r"IPv6 VPN Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv6 VPN Summary:", "", actual) actual = re.sub(r"No IPv6 VPN neighbor is configured", "", actual) # Remove IPv4 Encap Summary (all of it) - actual = re.sub(r"IPv6 Encap Summary \(VRF default\):", "", actual) + actual = re.sub(r"IPv6 Encap Summary:", "", actual) actual = re.sub(r"No IPv6 Encap neighbor is configured", "", actual) # Remove Unknown Summary (all of it) - actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual) + actual = re.sub(r"Unknown Summary:", "", actual) actual = re.sub(r"No Unknown neighbor is configured", "", actual) # Make Connect/Active/Idle the same (change them all to Active) actual = re.sub(r" Connect ", " Active ", actual) actual = re.sub(r" Idle ", " Active ", actual) # Remove Labeled Unicast Summary (all of it) - actual = re.sub( - r"IPv6 labeled-unicast Summary \(VRF default\):", "", actual - ) + actual = re.sub(r"IPv6 labeled-unicast Summary:", "", actual) actual = re.sub( r"No IPv6 labeled-unicast neighbor is configured", "", actual ) @@ -1148,20 +1184,19 @@ def test_bgp_ipv6_summary(): # Empty string if it matches, otherwise diff contains unified diff if diff: sys.stderr.write( - "r%s failed SHOW BGP IPv6 SUMMARY check:\n%s\n" % (i, diff) + "r{} failed SHOW BGP IPv6 SUMMARY check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) - assert failures == 0, "SHOW BGP IPv6 SUMMARY failed for router r%s:\n%s" % ( - i, - diff, - ) + assert ( + failures == 0 + ), "SHOW BGP IPv6 SUMMARY failed for router r{}:\n{}".format(i, diff) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -1178,11 +1213,13 @@ def test_nht(): thisDir = os.path.dirname(os.path.realpath(__file__)) for i in range(1, 2): - nhtFile = "%s/r%s/ip_nht.ref" % (thisDir, i) + nhtFile = "{}/r{}/ip_nht.ref".format(thisDir, i) expected = open(nhtFile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) - actual = net["r%s" % i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip() + actual = ( + net["r{}".format(i)].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip() + ) actual = re.sub(r"fd [0-9]+", "fd XX", actual) actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) @@ -1194,15 +1231,17 @@ def test_nht(): ) if diff: - assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff) + assert 0, "r{} failed ip nht check:\n{}\n".format(i, diff) else: print("show ip nht is ok\n") - nhtFile = "%s/r%s/ipv6_nht.ref" % (thisDir, i) + nhtFile = "{}/r{}/ipv6_nht.ref".format(thisDir, i) expected = open(nhtFile).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) - actual = net["r%s" % i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip() + actual = ( + net["r{}".format(i)].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip() + ) actual = re.sub(r"fd [0-9]+", "fd XX", actual) actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) @@ -1214,7 +1253,7 @@ def test_nht(): ) if diff: - assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff) + assert 0, "r{} failed ipv6 nht check:\n{}\n".format(i, diff) else: print("show ipv6 nht is ok\n") @@ -1234,7 +1273,7 @@ def test_bgp_ipv4(): diffresult = {} for i in range(1, 2): success = 0 - for refTableFile in glob.glob("%s/r%s/show_bgp_ipv4*.ref" % (thisDir, i)): + for refTableFile in glob.glob("{}/r{}/show_bgp_ipv4*.ref".format(thisDir, i)): if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -1243,7 +1282,9 @@ def test_bgp_ipv4(): # Actual output from router actual = ( - net["r%s" % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip() + net["r{}".format(i)] + .cmd('vtysh -c "show bgp ipv4" 2> /dev/null') + .rstrip() ) # Remove summary line (changed recently) actual = re.sub(r"Total number.*", "", actual) @@ -1265,24 +1306,26 @@ def test_bgp_ipv4(): diffresult[refTableFile] = diff else: success = 1 - print("template %s matched: r%s ok" % (refTableFile, i)) + print("template {} matched: r{} ok".format(refTableFile, i)) break if not success: resultstr = "No template matched.\n" for f in diffresult.keys(): - resultstr += "template %s: r%s failed SHOW BGP IPv4 check:\n%s\n" % ( - f, - i, - diffresult[f], + resultstr += ( + "template {}: r{} failed SHOW BGP IPv4 check:\n{}\n".format( + f, + i, + diffresult[f], + ) ) raise AssertionError( - "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr) + "SHOW BGP IPv4 failed for router r{}:\n{}".format(i, resultstr) ) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -1301,7 +1344,7 @@ def test_bgp_ipv6(): diffresult = {} for i in range(1, 2): success = 0 - for refTableFile in glob.glob("%s/r%s/show_bgp_ipv6*.ref" % (thisDir, i)): + for refTableFile in glob.glob("{}/r{}/show_bgp_ipv6*.ref".format(thisDir, i)): if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -1310,7 +1353,9 @@ def test_bgp_ipv6(): # Actual output from router actual = ( - net["r%s" % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip() + net["r{}".format(i)] + .cmd('vtysh -c "show bgp ipv6" 2> /dev/null') + .rstrip() ) # Remove summary line (changed recently) actual = re.sub(r"Total number.*", "", actual) @@ -1332,23 +1377,25 @@ def test_bgp_ipv6(): diffresult[refTableFile] = diff else: success = 1 - print("template %s matched: r%s ok" % (refTableFile, i)) + print("template {} matched: r{} ok".format(refTableFile, i)) if not success: resultstr = "No template matched.\n" for f in diffresult.keys(): - resultstr += "template %s: r%s failed SHOW BGP IPv6 check:\n%s\n" % ( - f, - i, - diffresult[f], + resultstr += ( + "template {}: r{} failed SHOW BGP IPv6 check:\n{}\n".format( + f, + i, + diffresult[f], + ) ) raise AssertionError( - "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr) + "SHOW BGP IPv6 failed for router r{}:\n{}".format(i, resultstr) ) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error @@ -1365,13 +1412,15 @@ def test_route_map(): print("*******************************************************\n") failures = 0 for i in range(1, 2): - refroutemap = "%s/r%s/show_route_map.ref" % (thisDir, i) + refroutemap = "{}/r{}/show_route_map.ref".format(thisDir, i) if os.path.isfile(refroutemap): expected = open(refroutemap).read().rstrip() expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1) actual = ( - net["r%s" % i].cmd('vtysh -c "show route-map" 2> /dev/null').rstrip() + net["r{}".format(i)] + .cmd('vtysh -c "show route-map" 2> /dev/null') + .rstrip() ) actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1) @@ -1384,15 +1433,15 @@ def test_route_map(): if diff: sys.stderr.write( - "r%s failed show route-map command Check:\n%s\n" % (i, diff) + "r{} failed show route-map command Check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) assert ( failures == 0 - ), "Show route-map command failed for router r%s:\n%s" % (i, diff) + ), "Show route-map command failed for router r{}:\n{}".format(i, diff) def test_nexthop_groups_with_route_maps(): @@ -1419,28 +1468,34 @@ def test_nexthop_groups_with_route_maps(): src_str = "192.168.0.1" net["r1"].cmd( - 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src %s"' % src_str + 'vtysh -c "c t" -c "route-map NH-SRC permit 111" -c "set src {}"'.format( + src_str + ) ) net["r1"].cmd('vtysh -c "c t" -c "ip protocol sharp route-map NH-SRC"') - net["r1"].cmd('vtysh -c "sharp install routes %s nexthop-group test 1"' % route_str) + net["r1"].cmd( + 'vtysh -c "sharp install routes {} nexthop-group test 1"'.format(route_str) + ) - verify_route_nexthop_group("%s/32" % route_str) + verify_route_nexthop_group("{}/32".format(route_str)) # Only a valid test on linux using nexthop objects if sys.platform.startswith("linux"): - output = net["r1"].cmd("ip route show %s/32" % route_str) - match = re.search(r"src %s" % src_str, output) - assert match is not None, "Route %s/32 not installed with src %s" % ( + output = net["r1"].cmd("ip route show {}/32".format(route_str)) + match = re.search(r"src {}".format(src_str), output) + assert match is not None, "Route {}/32 not installed with src {}".format( route_str, src_str, ) # Remove NHG routes and route-map - net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % route_str) + net["r1"].cmd('vtysh -c "sharp remove routes {} 1"'.format(route_str)) net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NH-SRC"') net["r1"].cmd( - 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src %s"' % src_str + 'vtysh -c "c t" -c "no route-map NH-SRC permit 111" # -c "set src {}"'.format( + src_str + ) ) net["r1"].cmd('vtysh -c "c t" -c "no route-map NH-SRC"') @@ -1450,7 +1505,9 @@ def test_nexthop_groups_with_route_maps(): deny_route_str = "3.3.3.2" net["r1"].cmd( - 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str + 'vtysh -c "c t" -c "ip prefix-list NOPE seq 5 permit {}/32"'.format( + permit_route_str + ) ) net["r1"].cmd( 'vtysh -c "c t" -c "route-map NOPE permit 111" -c "match ip address prefix-list NOPE"' @@ -1460,35 +1517,42 @@ def test_nexthop_groups_with_route_maps(): # This route should be permitted net["r1"].cmd( - 'vtysh -c "sharp install routes %s nexthop-group test 1"' % permit_route_str + 'vtysh -c "sharp install routes {} nexthop-group test 1"'.format( + permit_route_str + ) ) - verify_route_nexthop_group("%s/32" % permit_route_str) + verify_route_nexthop_group("{}/32".format(permit_route_str)) # This route should be denied net["r1"].cmd( - 'vtysh -c "sharp install routes %s nexthop-group test 1"' % deny_route_str + 'vtysh -c "sharp install routes {} nexthop-group test 1"'.format(deny_route_str) ) nhg_id = route_get_nhg_id(deny_route_str) - output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + output = net["r1"].cmd('vtysh -c "show nexthop-group rib {}"'.format(nhg_id)) match = re.search(r"Valid", output) - assert match is None, "Nexthop Group ID=%d should not be marked Valid" % nhg_id + assert match is None, "Nexthop Group ID={} should not be marked Valid".format( + nhg_id + ) match = re.search(r"Installed", output) - assert match is None, "Nexthop Group ID=%d should not be marked Installed" % nhg_id + assert match is None, "Nexthop Group ID={} should not be marked Installed".format( + nhg_id + ) # Remove NHG routes and route-map - net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % permit_route_str) - net["r1"].cmd('vtysh -c "sharp remove routes %s 1"' % deny_route_str) + net["r1"].cmd('vtysh -c "sharp remove routes {} 1"'.format(permit_route_str)) + net["r1"].cmd('vtysh -c "sharp remove routes {} 1"'.format(deny_route_str)) net["r1"].cmd('vtysh -c "c t" -c "no ip protocol sharp route-map NOPE"') net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE permit 111"') net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE deny 222"') net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"') net["r1"].cmd( - 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"' - % permit_route_str + 'vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit {}/32"'.format( + permit_route_str + ) ) @@ -1551,7 +1615,7 @@ def test_mpls_interfaces(): print("******************************************\n") failures = 0 for i in range(1, 2): - refTableFile = "%s/r%s/show_mpls_ldp_interface.ref" % (thisDir, i) + refTableFile = "{}/r{}/show_mpls_ldp_interface.ref".format(thisDir, i) if os.path.isfile(refTableFile): # Read expected result from file expected = open(refTableFile).read().rstrip() @@ -1560,7 +1624,7 @@ def test_mpls_interfaces(): # Actual output from router actual = ( - net["r%s" % i] + net["r{}".format(i)] .cmd('vtysh -c "show mpls ldp interface" 2> /dev/null') .rstrip() ) @@ -1580,28 +1644,33 @@ def test_mpls_interfaces(): # Empty string if it matches, otherwise diff contains unified diff if diff: sys.stderr.write( - "r%s failed MPLS LDP Interface status Check:\n%s\n" % (i, diff) + "r{} failed MPLS LDP Interface status Check:\n{}\n".format(i, diff) ) failures += 1 else: - print("r%s ok" % i) + print("r{} ok".format(i)) if failures > 0: fatal_error = "MPLS LDP Interface status failed" assert ( failures == 0 - ), "MPLS LDP Interface status failed for router r%s:\n%s" % (i, diff) + ), "MPLS LDP Interface status failed for router r{}:\n{}".format(i, diff) # Make sure that all daemons are running for i in range(1, 2): - fatal_error = net["r%s" % i].checkRouterRunning() + fatal_error = net["r{}".format(i)].checkRouterRunning() assert fatal_error == "", fatal_error def test_resilient_nexthop_group(): + global fatal_error net = get_topogen().net + # Skip if previous fatal error condition is raised + if fatal_error != "": + pytest.skip(fatal_error) + result = required_linux_kernel_version("5.19") if result is not True: pytest.skip("Kernel requirements are not met, kernel version should be >= 5.19") @@ -1610,11 +1679,38 @@ def test_resilient_nexthop_group(): 'vtysh -c "conf" -c "nexthop-group resilience" -c "resilient buckets 64 idle-timer 128 unbalanced-timer 256" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"' ) - output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') - output = re.findall(r"Buckets", output) + # Temporary helper function + def _show_func(): + output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') + buckets = re.findall(r"Buckets", output) + + return len(buckets) + + _, result = topotest.run_and_expect(_show_func, 1, count=30, wait=1) + if result != 1: + fatal_error = "Resilient NHG not created in zebra" + + assert result == 1, fatal_error + + output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp json"') + + joutput = json.loads(output) + + # Use the json output and collect the nhg id from it + + for nhgid in joutput: + n = joutput[nhgid] + if "buckets" in n: + break + + if "buckets" not in n: + fatal_error = "Resilient NHG not found in json output" + assert "buckets" in n, fatal_error + + verify_nexthop_group(int(nhgid)) - verify_nexthop_group(185483878) - assert len(output) == 1, "Resilient NHG not created in zebra" + # Remove NHG + net["r1"].cmd('vtysh -c "conf" -c "no nexthop-group resilience"') def test_shutdown_check_stderr(): @@ -1697,8 +1793,8 @@ def test_shutdown_check_memleak(): thisDir = os.path.dirname(os.path.realpath(__file__)) for i in range(1, 2): - net["r%s" % i].stopRouter() - net["r%s" % i].report_memory_leaks( + net["r{}".format(i)].stopRouter() + net["r{}".format(i)].report_memory_leaks( os.environ.get("TOPOTESTS_CHECK_MEMLEAK"), os.path.basename(__file__) ) diff --git a/tests/topotests/analyze.py b/tests/topotests/analyze.py index 690786a07c53..a1ac9a2212bb 100755 --- a/tests/topotests/analyze.py +++ b/tests/topotests/analyze.py @@ -262,7 +262,7 @@ def main(): capture_output=True, ) except subprocess.CalledProcessError: - print(f"{docker_bin} container '{contid}' does not exist") + logging.critical(f"{docker_bin} container '{contid}' does not exist") sys.exit(1) # If you need container info someday... # cont_info = json.loads(p.stdout) @@ -278,7 +278,7 @@ def main(): if scount and args.results and not os.path.exists(args.results): if not contid: if not os.path.exists(cppath): - print(f"'{cppath}' doesn't exist to save") + logging.critical(f"'{cppath}' doesn't exist to save") sys.exit(1) if args.save_xml: subprocess.run(["cp", cppath, args.results]) @@ -294,7 +294,7 @@ def main(): capture_output=True, ) except subprocess.CalledProcessError as error: - print(f"Can't {docker_bin} cp '{cppath}': %s", str(error)) + logging.critical(f"Can't {docker_bin} cp '{cppath}': %s", str(error)) sys.exit(1) if "SUDO_USER" in os.environ: @@ -303,7 +303,7 @@ def main(): # User doesn't want to save results just use them inplace if not contid: if not os.path.exists(cppath): - print(f"'{cppath}' doesn't exist") + logging.critical(f"'{cppath}' doesn't exist") sys.exit(1) args.results = cppath else: @@ -321,7 +321,7 @@ def main(): capture_output=True, ) except subprocess.CalledProcessError as error: - print(f"Can't {docker_bin} cp '{cppath}': %s", str(error)) + logging.critical(f"Can't {docker_bin} cp '{cppath}': %s", str(error)) sys.exit(1) args.results = tresname diff --git a/tests/topotests/babel_topo1/test_babel_topo1.py b/tests/topotests/babel_topo1/test_babel_topo1.py index decf0c2a6faf..13bbe5bd4eb8 100644 --- a/tests/topotests/babel_topo1/test_babel_topo1.py +++ b/tests/topotests/babel_topo1/test_babel_topo1.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -130,7 +129,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format( diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgp_ipv6_routes_down.json b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgp_ipv6_routes_down.json index 5cba71ef200e..61be1df92a31 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgp_ipv6_routes_down.json +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgp_ipv6_routes_down.json @@ -4,51 +4,6 @@ "localAS": 101, "routes": { - "2001:db8:6::/64": [ - { - "stale": true, - "valid": true, - "bestpath": true, - "pathFrom": "external", - "prefix": "2001:db8:6::", - "prefixLen": 64, - "network": "2001:db8:6::\/64", - "metric": 0, - "weight": 0, - "peerId": "2001:db8:4::1", - "origin": "IGP", - "nexthops": [ - { "ip": "2001:db8:4::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], - "2001:db8:7::/64": [ - { - "stale": true, - "valid": true, - "bestpath": true, - "pathFrom": "external", - "prefix": "2001:db8:7::", - "prefixLen": 64, "network": - "2001:db8:7::\/64", - "metric": 0, - "weight": 0, - "peerId": "2001:db8:4::1", - "origin": "IGP", - "nexthops": [ - { - "ip": "2001:db8:4::1", - "afi": "ipv6", - "scope": "global", - "used": true - } - ] - } - ], "2001:db8:8::/64": [ { "valid": true, diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf index f8ad1f3a6661..054b12832a9b 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf @@ -7,6 +7,7 @@ router bgp 101 bgp graceful-restart neighbor 2001:db8:4::1 remote-as 102 neighbor 2001:db8:4::1 timers 3 10 + neighbor 2001:db8:4::1 timers connect 1 neighbor 2001:db8:4::1 remote-as external neighbor 2001:db8:4::1 bfd neighbor 2001:db8:4::1 bfd check-control-plane-failure diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/ipv6_routes.json b/tests/topotests/bfd_bgp_cbit_topo3/r1/ipv6_routes.json index 8eea183285f1..36cdcc307d66 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/ipv6_routes.json +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/ipv6_routes.json @@ -32,49 +32,5 @@ } ] } - ], - "2001:db8:6::/64": [{ - "distance": 20, - "protocol": "bgp", - "metric": 0, - "selected": true, - "destSelected": true, - "prefix": "2001:db8:6::/64", - "nexthops": [{ - "ip":"2001:db8:4::1", - "active": true, - "afi": "ipv6", - "recursive":true - }, - { - "fib":true, - "ip":"2001:db8:1::2", - "afi": "ipv6", - "interfaceName": "r1-eth0" - } - ] - } - ], - "2001:db8:7::/64": [{ - "distance": 20, - "protocol": "bgp", - "metric": 0, - "selected": true, - "destSelected": true, - "prefix": "2001:db8:7::/64", - "nexthops": [{ - "ip":"2001:db8:4::1", - "active": true, - "afi": "ipv6", - "recursive": true - }, - { - "fib":true, - "ip":"2001:db8:1::2", - "afi": "ipv6", - "interfaceName":"r1-eth0" - } - ] - } ] } diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf index 42953a075c29..d7e10210f385 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf @@ -11,6 +11,7 @@ router bgp 102 bgp graceful-restart restart-time 900 neighbor 2001:db8:1::1 remote-as 101 neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 update-source 2001:db8:4::1 neighbor 2001:db8:1::1 bfd diff --git a/tests/topotests/bfd_bgp_cbit_topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd_bgp_cbit_topo3/test_bfd_bgp_cbit_topo3.py index 906687d1cdf8..d478e9902f61 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/test_bfd_bgp_cbit_topo3.py +++ b/tests/topotests/bfd_bgp_cbit_topo3/test_bfd_bgp_cbit_topo3.py @@ -122,21 +122,23 @@ def test_bfd_connection(): def test_bfd_loss_intermediate(): """ - Assert that BFD notices the bfd link down failure. - but BGP entries should still be present + Assert that BGP notices the BFD link down failure. + The BGP entries should be flushed as the C-bit is set in both directions. """ tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] - expected = { "as":101, "peers":{ "2001:db8:4::1": { "state":"Established" } } } - test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv6 uni summ json", expected) + expected = {"as": 101, "peers": {"2001:db8:4::1": {"state": "Established"}}} + test_func = partial( + topotest.router_json_cmp, r1, "show bgp ipv6 uni summ json", expected + ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) - assertmsg ='"r1" has not established bgp peering yet' + assertmsg = '"r1" has not established bgp peering yet' assert result is None, assertmsg - #assert False + # assert False logger.info("removing IPv6 address from r2 to simulate loss of connectivity") # Disable r2-eth0 ipv6 address cmd = 'vtysh -c "configure terminal" -c "interface r2-eth1" -c "no ipv6 address 2001:db8:4::2/64"' @@ -160,7 +162,7 @@ def test_bfd_loss_intermediate(): assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg - logger.info("waiting for BGP entries to become stale") + logger.info("waiting for BGP entries to be removed") for router in tgen.routers().values(): if router.name == "r2": continue diff --git a/tests/topotests/bfd_ospf_topo1/rt1/ospf6d.conf b/tests/topotests/bfd_ospf_topo1/rt1/ospf6d.conf index 98da8c261920..a8ce562da21e 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/ospf6d.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/ospf6d.conf @@ -6,12 +6,14 @@ hostname rt1 password 1 ! interface eth-rt2 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ipv6 ospf6 bfd ! interface eth-rt3 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast @@ -19,7 +21,5 @@ interface eth-rt3 ! router ospf6 ospf6 router-id 1.1.1.1 - interface eth-rt2 area 0.0.0.0 - interface eth-rt3 area 0.0.0.0 redistribute connected ! diff --git a/tests/topotests/bfd_ospf_topo1/rt2/ospf6d.conf b/tests/topotests/bfd_ospf_topo1/rt2/ospf6d.conf index 34b09020949a..f04d01768127 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/ospf6d.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/ospf6d.conf @@ -5,19 +5,19 @@ hostname rt2 password 1 ! interface eth-rt1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ipv6 ospf6 bfd ! interface eth-rt5 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ! router ospf6 ospf6 router-id 2.2.2.2 - interface eth-rt1 area 0.0.0.0 - interface eth-rt5 area 0.0.0.0 redistribute connected ! diff --git a/tests/topotests/bfd_ospf_topo1/rt3/ospf6d.conf b/tests/topotests/bfd_ospf_topo1/rt3/ospf6d.conf index 8ab4eee1d3c4..faf975497d92 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/ospf6d.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/ospf6d.conf @@ -5,19 +5,19 @@ hostname rt3 password 1 ! interface eth-rt1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ipv6 ospf6 bfd ! interface eth-rt4 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ! router ospf6 ospf6 router-id 3.3.3.3 - interface eth-rt1 area 0.0.0.0 - interface eth-rt4 area 0.0.0.0 redistribute connected ! diff --git a/tests/topotests/bfd_ospf_topo1/rt4/ospf6d.conf b/tests/topotests/bfd_ospf_topo1/rt4/ospf6d.conf index 138b688140d9..c96093b98a88 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/ospf6d.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/ospf6d.conf @@ -5,18 +5,18 @@ hostname rt4 password 1 ! interface eth-rt3 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ! interface eth-rt5 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ipv6 ospf6 network broadcast ! router ospf6 ospf6 router-id 4.4.4.4 - interface eth-rt3 area 0.0.0.0 - interface eth-rt5 area 0.0.0.0 redistribute connected ! diff --git a/tests/topotests/bfd_ospf_topo1/rt5/ospf6d.conf b/tests/topotests/bfd_ospf_topo1/rt5/ospf6d.conf index 6eb4fe59a887..6d40d17d503f 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/ospf6d.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/ospf6d.conf @@ -5,18 +5,18 @@ hostname rt5 password 1 ! interface eth-rt2 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ! interface eth-rt4 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 8 ! router ospf6 ospf6 router-id 5.5.5.5 - interface eth-rt2 area 0.0.0.0 - interface eth-rt4 area 0.0.0.0 redistribute connected ! diff --git a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py index b9e8b73c1d02..6919371ac521 100755 --- a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py @@ -59,7 +59,6 @@ import sys import pytest import json -from time import sleep from functools import partial # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bfd_profiles_topo1/r4/ospf6d.conf b/tests/topotests/bfd_profiles_topo1/r4/ospf6d.conf index 4ef28c39caa8..948874c0e55b 100644 --- a/tests/topotests/bfd_profiles_topo1/r4/ospf6d.conf +++ b/tests/topotests/bfd_profiles_topo1/r4/ospf6d.conf @@ -1,4 +1,5 @@ interface r4-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 bfd profile fast-tx ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 @@ -6,5 +7,4 @@ interface r4-eth1 router ospf6 ospf6 router-id 10.254.254.4 redistribute connected - interface r4-eth1 area 0.0.0.0 ! diff --git a/tests/topotests/bfd_profiles_topo1/r5/ospf6d.conf b/tests/topotests/bfd_profiles_topo1/r5/ospf6d.conf index 20b53cfc5555..f6e8dc3b670a 100644 --- a/tests/topotests/bfd_profiles_topo1/r5/ospf6d.conf +++ b/tests/topotests/bfd_profiles_topo1/r5/ospf6d.conf @@ -1,4 +1,5 @@ interface r5-eth0 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 bfd ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 @@ -6,5 +7,4 @@ interface r5-eth0 router ospf6 ospf6 router-id 10.254.254.5 redistribute connected - interface r5-eth0 area 0.0.0.0 ! diff --git a/tests/topotests/bfd_topo3/test_bfd_topo3.py b/tests/topotests/bfd_topo3/test_bfd_topo3.py index c0dc052a38d9..a899a2b464d2 100644 --- a/tests/topotests/bfd_topo3/test_bfd_topo3.py +++ b/tests/topotests/bfd_topo3/test_bfd_topo3.py @@ -65,6 +65,41 @@ def setup_module(mod): tgen.start_router() +def expect_static_bfd_output(router, filename): + "Load JSON file and compare with 'show bfd peer json'" + + tgen = get_topogen() + + logger.info("waiting BFD configuration on router {}".format(router)) + bfd_config = json.loads(open("{}/{}/{}.json".format(CWD, router, filename)).read()) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show bfd static route json", + bfd_config, + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assertmsg = '"{}" BFD static route status failure'.format(router) + assert result is None, assertmsg + + +def expect_route_missing(router, iptype, route): + "Wait until route is present on RIB for protocol." + + tgen = get_topogen() + + logger.info("waiting route {} to disapear in {}".format(route, router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show {} route json".format(iptype), + {route: None}, + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + def test_wait_bgp_convergence(): "Wait for BGP to converge" tgen = get_topogen() @@ -154,7 +189,7 @@ def expect_bfd_configuration(router): "show bfd peers json", bfd_config, ) - _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=200, wait=1) assertmsg = '"{}" BFD configuration failure'.format(router) assert result is None, assertmsg @@ -166,7 +201,7 @@ def expect_bfd_configuration(router): expect_bfd_configuration("r6") -def test_static_route_monitoring(): +def test_static_route_monitoring_convergence(): "Test static route monitoring output." tgen = get_topogen() if tgen.routers_have_failure(): @@ -174,31 +209,47 @@ def test_static_route_monitoring(): logger.info("test BFD static route status") - def expect_static_bfd_output(router, filename): - "Load JSON file and compare with 'show bfd peer json'" - logger.info("waiting BFD configuration on router {}".format(router)) - bfd_config = json.loads( - open("{}/{}/{}.json".format(CWD, router, filename)).read() - ) - test_func = partial( - topotest.router_json_cmp, - tgen.gears[router], - "show bfd static route json", - bfd_config, - ) - _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) - assertmsg = '"{}" BFD static route status failure'.format(router) - assert result is None, assertmsg - expect_static_bfd_output("r3", "bfd-static") expect_static_bfd_output("r6", "bfd-static") - logger.info("Setting r4 link down ...") - tgen.gears["r4"].link_enable("r4-eth0", False) +def test_static_route_monitoring_wrong_source(): + "Test that static monitoring fails if setting a wrong source." - expect_static_bfd_output("r3", "bfd-static-down") - expect_static_bfd_output("r6", "bfd-static-down") + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("test route wrong ") + + tgen.gears["r3"].vtysh_cmd( + """ +configure +ipv6 route 2001:db8:5::/64 2001:db8:4::3 bfd multi-hop source 2001:db8:4::2 profile slow-tx +""" + ) + + expect_route_missing("r3", "ipv6", "2001:db8:5::/64") + + +def test_static_route_monitoring_unset_source(): + "Test that static monitoring fails if setting a wrong source." + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("test route wrong ") + + tgen.gears["r3"].vtysh_cmd( + """ +configure +ipv6 route 2001:db8:5::/64 2001:db8:4::3 bfd multi-hop profile slow-tx +""" + ) + + expect_static_bfd_output("r3", "bfd-static") + expect_static_bfd_output("r6", "bfd-static") def test_expect_static_rib_removal(): @@ -208,18 +259,12 @@ def test_expect_static_rib_removal(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def expect_route_missing(router, iptype, route): - "Wait until route is present on RIB for protocol." - logger.info("waiting route {} to disapear in {}".format(route, router)) - test_func = partial( - topotest.router_json_cmp, - tgen.gears[router], - "show {} route json".format(iptype), - {route: None}, - ) - rv, result = topotest.run_and_expect(test_func, None, count=20, wait=1) - assertmsg = '"{}" convergence failure'.format(router) - assert result is None, assertmsg + logger.info("Setting r4 link down ...") + + tgen.gears["r4"].link_enable("r4-eth0", False) + + expect_static_bfd_output("r3", "bfd-static-down") + expect_static_bfd_output("r6", "bfd-static-down") expect_route_missing("r1", "ip", "10.254.254.5/32") expect_route_missing("r2", "ip", "10.254.254.5/32") diff --git a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py index a532f3a2d7f3..f6adff61d0ed 100644 --- a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() # check for zebra capability - for rname, router in router_list.items(): + for _, router in router_list.items(): if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False: return pytest.skip( "Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR" @@ -84,6 +84,7 @@ def setup_module(mod): router.net.set_intf_netns(rname + "-eth2", ns, up=True) for rname, router in router_list.items(): + router.load_config(TopoRouter.RD_MGMTD, None, "--vrfwnetns") router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)), diff --git a/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py b/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py index 30f4a2f9b574..fee5f2d53640 100644 --- a/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py +++ b/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py @@ -81,8 +81,7 @@ def setup_module(mod): for rname, router in router_list.items(): router.load_config( - TopoRouter.RD_ZEBRA, - os.path.join(CWD, "{}/zebra.conf".format(rname)) + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) router.load_config( TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) @@ -114,8 +113,8 @@ def test_bfd_connection(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info("waiting for bfd peers to go up") - router = tgen.gears['r1'] - json_file = "{}/{}/bfd_peers_status.json".format(CWD, 'r1') + router = tgen.gears["r1"] + json_file = "{}/{}/bfd_peers_status.json".format(CWD, "r1") expected = json.loads(open(json_file).read()) test_func = partial( diff --git a/tests/topotests/bgp_accept_own/pe1/bgpd.conf b/tests/topotests/bgp_accept_own/pe1/bgpd.conf index 15466b4259c2..1f7abac98f2a 100644 --- a/tests/topotests/bgp_accept_own/pe1/bgpd.conf +++ b/tests/topotests/bgp_accept_own/pe1/bgpd.conf @@ -25,7 +25,7 @@ router bgp 65001 vrf Customer neighbor 192.168.1.1 timers connect 1 address-family ipv4 unicast redistribute connected - label vpn export 10 + label vpn export 250 rd vpn export 192.168.1.2:2 rt vpn import 192.168.1.2:2 rt vpn export 192.168.1.2:2 @@ -40,7 +40,7 @@ router bgp 65001 vrf Service neighbor 192.168.2.1 timers 1 3 neighbor 192.168.2.1 timers connect 1 address-family ipv4 unicast - label vpn export 20 + label vpn export 350 rd vpn export 192.168.2.2:2 rt vpn import 192.168.2.2:2 rt vpn export 192.168.2.2:2 diff --git a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py index d294da0934b9..11b24baa826c 100644 --- a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py +++ b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py @@ -68,7 +68,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py index 2a610c901ec3..3d17a2b70977 100644 --- a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/eigrpd/eigrp_pkt_tlv1.c b/tests/topotests/bgp_addpath_paths_limit/__init__.py similarity index 100% rename from eigrpd/eigrp_pkt_tlv1.c rename to tests/topotests/bgp_addpath_paths_limit/__init__.py diff --git a/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf new file mode 100644 index 000000000000..65beb7f28686 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers connect 5 + address-family ipv4 unicast + neighbor 192.168.1.2 addpath-rx-paths-limit 2 + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf new file mode 100644 index 000000000000..796b4d0ba7fd --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r2/frr.conf @@ -0,0 +1,37 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +int r2-eth2 + ip address 192.168.7.2/24 +! +router bgp 65002 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.7.7 remote-as external + neighbor 192.168.7.7 timers connect 5 + neighbor 192.168.2.3 remote-as external + neighbor 192.168.2.3 timers connect 5 + neighbor 192.168.2.3 weight 3 + neighbor 192.168.2.4 remote-as external + neighbor 192.168.2.4 timers connect 5 + neighbor 192.168.2.4 weight 4 + neighbor 192.168.2.5 remote-as external + neighbor 192.168.2.5 timers connect 5 + neighbor 192.168.2.5 weight 5 + neighbor 192.168.2.6 remote-as external + neighbor 192.168.2.6 timers connect 5 + neighbor 192.168.2.6 weight 6 + address-family ipv4 unicast + neighbor 192.168.1.1 addpath-tx-all-paths + neighbor 192.168.1.1 prefix-list announce out + neighbor 192.168.7.7 addpath-tx-all-paths + neighbor 192.168.7.7 prefix-list announce out + exit-address-family +! +ip prefix-list announce seq 5 permit 172.16.16.254/32 +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf new file mode 100644 index 000000000000..4d834d3113bf --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r3/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r3-eth0 + ip address 192.168.2.3/24 +! +router bgp 65003 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf new file mode 100644 index 000000000000..01e0aa99d36f --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r4/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r4-eth0 + ip address 192.168.2.4/24 +! +router bgp 65004 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf new file mode 100644 index 000000000000..02bb84798781 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r5/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r5-eth0 + ip address 192.168.2.5/24 +! +router bgp 65005 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf new file mode 100644 index 000000000000..39fdbcce3256 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r6/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ip address 172.16.16.254/32 +! +int r6-eth0 + ip address 192.168.2.6/24 +! +router bgp 65006 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers connect 5 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf b/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf new file mode 100644 index 000000000000..8c44566b2f70 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/r7/frr.conf @@ -0,0 +1,13 @@ +! +int r7-eth0 + ip address 192.168.7.7/24 +! +router bgp 65007 + timers bgp 3 10 + no bgp ebgp-requires-policy + neighbor 192.168.7.2 remote-as external + neighbor 192.168.7.2 timers connect 5 + address-family ipv4 unicast + neighbor 192.168.7.2 addpath-rx-paths-limit 3 + exit-address-family +! diff --git a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py new file mode 100644 index 000000000000..fb863e454f14 --- /dev/null +++ b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if Paths-Limit capability works as expected. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 8): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r7"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_addpath_paths_limit(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r7 = tgen.gears["r7"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.7.7": { + "neighborCapabilities": { + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 0, + "receivedPathsLimit": 3, + } + } + } + }, + "192.168.1.1": { + "neighborCapabilities": { + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 0, + "receivedPathsLimit": 2, + } + } + } + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge initially" + + def _bgp_check_received_routes(router, expected): + output = json.loads( + router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.254/32 json") + ) + + if "paths" not in output: + return "No paths received" + + return topotest.json_cmp(len(output["paths"]), expected) + + test_func = functools.partial(_bgp_check_received_routes, r1, 2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Received routes count is not as expected" + + test_func = functools.partial(_bgp_check_received_routes, r7, 3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Received routes count is not as expected" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py index 5a4a5fb657cf..0520b5e1369d 100644 --- a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py +++ b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py index 739685d41764..188bbd0b98af 100644 --- a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py +++ b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,12 +89,12 @@ def _bgp_aggregate_address_has_metric(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_aggregate_address_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py index cec06920cb8b..2343440aaf25 100644 --- a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py +++ b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -74,7 +74,8 @@ def test_bgp_maximum_prefix_invalid(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - router = tgen.gears["r2"] + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] def _bgp_converge(router): output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) @@ -86,22 +87,30 @@ def _bgp_converge(router): } return topotest.json_cmp(output, expected) - def _bgp_aggregate_address_has_metric(router): + def _bgp_aggregate_address_has_metric(router, metric): output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.0/24 json")) - expected = {"paths": [{"metric": 123}]} + expected = {"paths": [{"metric": metric}]} return topotest.json_cmp(output, expected) - test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - - assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) - - test_func = functools.partial(_bgp_aggregate_address_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - - assert ( - result is None - ), 'Failed to see applied metric for aggregated prefix in "{}"'.format(router) + test_func = functools.partial(_bgp_converge, r2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Failed to see bgp convergence in r2" + + test_func = functools.partial(_bgp_aggregate_address_has_metric, r2, 123) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Failed to see applied metric for aggregated prefix in r2" + + r1.vtysh_cmd( + """ + configure terminal + route-map aggr-rmap permit 10 + set metric 666 + """ + ) + + test_func = functools.partial(_bgp_aggregate_address_has_metric, r2, 666) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Failed to see applied metric for aggregated prefix in r2" if __name__ == "__main__": diff --git a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py index d9ef3e1ce151..1a52f8c90ee6 100644 --- a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py +++ b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py @@ -73,7 +73,7 @@ def _bgp_converge(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"]) @@ -99,7 +99,7 @@ def _bgp_has_correct_aggregator_route_with_good_asn(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_aggregator_route_with_good_asn) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Aggregator AS attribute not found in "{}"'.format( tgen.gears["r1"] diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py index 655e9ad18485..b81c5432972d 100644 --- a/tests/topotests/bgp_aigp/test_bgp_aigp.py +++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py @@ -29,7 +29,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -73,7 +72,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py index c49a2e5384d5..537ccc9df6d0 100644 --- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py +++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py @@ -28,7 +28,6 @@ import os import sys import time -import json import pytest # Save the Current Working Directory to find configuration files. @@ -59,7 +58,7 @@ create_router_bgp, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_as_override/test_bgp_as_override.py b/tests/topotests/bgp_as_override/test_bgp_as_override.py index 7cb4f81cfc18..dbbdf2c88f8e 100644 --- a/tests/topotests/bgp_as_override/test_bgp_as_override.py +++ b/tests/topotests/bgp_as_override/test_bgp_as_override.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py index 5c09a6b0e0b9..e8e3b4171a66 100644 --- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py +++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,12 +85,12 @@ def _bgp_failed(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Failed to converge: "{}"'.format(tgen.gears["r1"]) test_func = functools.partial(_bgp_failed, tgen.gears["r3"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Bad BGP Identifier notification not sent: "{}"'.format( tgen.gears["r3"] diff --git a/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json index e3703bf95394..39ed61f718eb 100644 --- a/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json +++ b/tests/topotests/bgp_asdot_regex/r1/show_bgp_ipv4.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 3, "routerId": "192.168.255.1", "defaultLocPrf": 100, "localAS": "1.1", diff --git a/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json index 1af4ff7e3d73..30133175e2c5 100644 --- a/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json +++ b/tests/topotests/bgp_asdot_regex/r2/show_bgp_ipv4.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 3, "routerId": "192.168.255.2", "defaultLocPrf": 100, "localAS": 65538, diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py index 5d5f1659e973..09803dfa842b 100644 --- a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py +++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py @@ -44,8 +44,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 3): @@ -62,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -99,7 +97,7 @@ def _bgp_converge(router): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) diff --git a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py index 0f1a08308fd0..fe89a87621ca 100644 --- a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py +++ b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py @@ -73,7 +73,7 @@ def _bgp_converge(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "More than one prefix seen at r1, SHOULD be only one." def _bgp_has_correct_routes_without_asn_0(): @@ -82,7 +82,7 @@ def _bgp_has_correct_routes_without_asn_0(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_routes_without_asn_0) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted." diff --git a/tests/topotests/bgp_auth/bgp_auth_common.py b/tests/topotests/bgp_auth/bgp_auth_common.py index 824498ef90ae..7ba3169cafb7 100644 --- a/tests/topotests/bgp_auth/bgp_auth_common.py +++ b/tests/topotests/bgp_auth/bgp_auth_common.py @@ -34,16 +34,9 @@ import json import os -import platform -import sys -from time import sleep - -from lib import common_config, topotest -from lib.common_config import ( - save_initial_config_on_routers, - reset_with_new_configs, -) -from lib.topogen import Topogen, TopoRouter, get_topogen + +from lib import common_config +from lib.topogen import get_topogen CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_auth/test_bgp_auth1.py b/tests/topotests/bgp_auth/test_bgp_auth1.py index 9d47106c072f..b0389474d425 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth1.py +++ b/tests/topotests/bgp_auth/test_bgp_auth1.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -156,7 +154,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth2.py b/tests/topotests/bgp_auth/test_bgp_auth2.py index 6b920367270f..2b8f4673ea53 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth2.py +++ b/tests/topotests/bgp_auth/test_bgp_auth2.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -156,7 +154,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth3.py b/tests/topotests/bgp_auth/test_bgp_auth3.py index 2237c6b1b6dc..d103d8075d7e 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth3.py +++ b/tests/topotests/bgp_auth/test_bgp_auth3.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -155,7 +153,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth4.py b/tests/topotests/bgp_auth/test_bgp_auth4.py index d6fe42504bc2..792aa80d50d7 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth4.py +++ b/tests/topotests/bgp_auth/test_bgp_auth4.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -155,7 +153,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf index 0ae384eb53ca..1033b27c568d 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf @@ -1,5 +1,9 @@ bfd + profile r1 + exit + ! peer 192.168.255.2 interface r1-eth0 + profile r1 exit ! exit diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf index e855f75c20de..58a90d1a490c 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 3 10 neighbor 192.168.255.2 timers connect 1 - neighbor 192.168.255.2 bfd + neighbor 192.168.255.2 bfd profile r1 neighbor 192.168.255.2 passive address-family ipv4 redistribute connected diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py index 00142981c502..f18e8bd3883d 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,6 +89,9 @@ def _bgp_bfd_down_notification(): "192.168.255.1": { "lastNotificationReason": "Cease/BFD Down", "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Up", + }, } } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py new file mode 100644 index 000000000000..5ffeed5033ae --- /dev/null +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# bgp_bfd_down_cease_notification_shutdown.py +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Check if Cease/BFD Down notification message is sent/received +when the BFD is down (administratively). +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import kill_router_daemons, step + +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_bfd_down_notification_shutdown(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, + "peerBfdInfo": {"status": "Up"}, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_bfd_down_notification(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "lastNotificationReason": "Cease/BFD Down", + "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Down", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP convergence on R2" + + r1.vtysh_cmd( + """ + configure + bfd + profile r1 + shutdown + """ + ) + + step("Check if we received Cease/BFD Down notification message") + test_func = functools.partial(_bgp_bfd_down_notification) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP Cease/BFD Down notification message on R2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py index 9f5c0ef924bd..05a9a1e7f616 100644 --- a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py +++ b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,14 +125,14 @@ def _bgp_verify_nexthop_validity(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) step("Check if 172.16.255.254/32 is not advertised to eBGP peers") test_func = functools.partial(_bgp_no_advertise_ebgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -142,7 +142,7 @@ def _bgp_verify_nexthop_validity(): step("Check if 172.16.255.254/32 is advertised to iBGP peers") test_func = functools.partial(_bgp_no_advertise_ibgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -152,7 +152,7 @@ def _bgp_verify_nexthop_validity(): step("Verify if the nexthop set via route-map on r4 is marked valid") test_func = functools.partial(_bgp_verify_nexthop_validity) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Nexthops are not valid "{}"'.format(tgen.gears["r4"]) diff --git a/tests/topotests/bgp_bmp/r1/bgpd.conf b/tests/topotests/bgp_bmp/r1/bgpd.conf index 69acf6e75076..24505de4a841 100644 --- a/tests/topotests/bgp_bmp/r1/bgpd.conf +++ b/tests/topotests/bgp_bmp/r1/bgpd.conf @@ -6,9 +6,17 @@ router bgp 65501 neighbor 192:168::2 remote-as 65502 ! bmp targets bmp1 - bmp connect 192.0.178.10 port 1789 min-retry 100 max-retry 10000 + bmp connect 192.0.2.10 port 1789 min-retry 100 max-retry 10000 exit ! + address-family ipv4 vpn + neighbor 192.168.0.2 activate + neighbor 192.168.0.2 soft-reconfiguration inbound + exit-address-family + address-family ipv6 vpn + neighbor 192:168::2 activate + neighbor 192:168::2 soft-reconfiguration inbound + exit-address-family address-family ipv4 unicast neighbor 192.168.0.2 activate neighbor 192.168.0.2 soft-reconfiguration inbound @@ -20,3 +28,21 @@ router bgp 65501 neighbor 192:168::2 soft-reconfiguration inbound exit-address-family ! +router bgp 65502 vrf vrf1 + bgp router_id 192.168.0.1 + bgp log-neighbor-changes + address-family ipv4 unicast + label vpn export 101 + rd vpn export 444:1 + rt vpn both 52:100 + export vpn + import vpn + exit-address-family + address-family ipv6 unicast + label vpn export 103 + rd vpn export 555:1 + rt vpn both 54:200 + export vpn + import vpn + exit-address-family +exit diff --git a/tests/topotests/bgp_bmp/r1/zebra.conf b/tests/topotests/bgp_bmp/r1/zebra.conf index 6a25a6f4c238..0b523c9e18d8 100644 --- a/tests/topotests/bgp_bmp/r1/zebra.conf +++ b/tests/topotests/bgp_bmp/r1/zebra.conf @@ -1,5 +1,5 @@ interface r1-eth0 - ip address 192.0.178.1/24 + ip address 192.0.2.1/24 ! interface r1-eth1 ip address 192.168.0.1/24 diff --git a/tests/topotests/bgp_bmp/r2/bgpd.conf b/tests/topotests/bgp_bmp/r2/bgpd.conf index 7c8255a17563..40e2cd5bbcb9 100644 --- a/tests/topotests/bgp_bmp/r2/bgpd.conf +++ b/tests/topotests/bgp_bmp/r2/bgpd.conf @@ -11,9 +11,36 @@ router bgp 65502 no neighbor 192:168::1 activate redistribute connected exit-address-family +! + address-family ipv4 vpn + neighbor 192.168.0.1 activate + exit-address-family +! + address-family ipv6 vpn + neighbor 192:168::1 activate + exit-address-family ! address-family ipv6 unicast neighbor 192:168::1 activate redistribute connected exit-address-family ! +router bgp 65502 vrf vrf1 + bgp router-id 192.168.0.2 + bgp log-neighbor-changes + no bgp network import-check + address-family ipv4 unicast + label vpn export 102 + rd vpn export 444:2 + rt vpn both 52:100 + export vpn + import vpn + exit-address-family + address-family ipv6 unicast + label vpn export 105 + rd vpn export 555:2 + rt vpn both 54:200 + export vpn + import vpn + exit-address-family +exit diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py index 65f191b33aa7..80e291b2bdb6 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp.py @@ -26,7 +26,6 @@ from ipaddress import ip_network import json import os -import platform import pytest import sys @@ -49,12 +48,13 @@ PRE_POLICY = "pre-policy" POST_POLICY = "post-policy" +LOC_RIB = "loc-rib" def build_topo(tgen): tgen.add_router("r1") tgen.add_router("r2") - tgen.add_bmp_server("bmp1", ip="192.0.178.10", defaultRoute="via 192.0.178.1") + tgen.add_bmp_server("bmp1", ip="192.0.2.10", defaultRoute="via 192.0.2.1") switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) @@ -80,8 +80,8 @@ def setup_module(mod): tgen.start_router() logger.info("starting BMP servers") - for _, server in tgen.get_bmp_servers().items(): - server.start() + for bmp_name, server in tgen.get_bmp_servers().items(): + server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log")) def teardown_module(_mod): @@ -104,7 +104,9 @@ def get_bmp_messages(): """ messages = [] tgen = get_topogen() - text_output = tgen.gears["bmp1"].run("cat /var/log/bmp.log") + text_output = tgen.gears["bmp1"].run( + "cat {}".format(os.path.join(tgen.logdir, "bmp1", "bmp.log")) + ) for m in text_output.splitlines(): # some output in the bash can break the message decoding @@ -120,7 +122,7 @@ def get_bmp_messages(): return messages -def check_for_prefixes(expected_prefixes, bmp_log_type, post_policy): +def check_for_prefixes(expected_prefixes, bmp_log_type, policy, labels=None): """ Check for the presence of the given prefixes in the BMP server logs with the given message type and the set policy. @@ -138,7 +140,13 @@ def check_for_prefixes(expected_prefixes, bmp_log_type, post_policy): if "ip_prefix" in m.keys() and "bmp_log_type" in m.keys() and m["bmp_log_type"] == bmp_log_type - and m["post_policy"] == post_policy + and m["policy"] == policy + and ( + labels is None + or ( + m["ip_prefix"] in labels.keys() and m["label"] == labels[m["ip_prefix"]] + ) + ) ] # check for prefixes @@ -173,7 +181,7 @@ def configure_prefixes(tgen, node, asn, safi, prefixes, vrf=None, update=True): Configure the bgp prefixes. """ withdraw = "no " if not update else "" - vrf = " vrf {}" if vrf else "" + vrf = " vrf {}".format(vrf) if vrf else "" for p in prefixes: ip = ip_network(p) cmd = [ @@ -202,7 +210,7 @@ def unicast_prefixes(policy): logger.info("checking for updated prefixes") # check - test_func = partial(check_for_prefixes, prefixes, "update", policy == POST_POLICY) + test_func = partial(check_for_prefixes, prefixes, "update", policy) success, _ = topotest.run_and_expect(test_func, True, wait=0.5) assert success, "Checking the updated prefixes has been failed !." @@ -210,7 +218,46 @@ def unicast_prefixes(policy): configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, update=False) logger.info("checking for withdrawed prefxies") # check - test_func = partial(check_for_prefixes, prefixes, "withdraw", policy == POST_POLICY) + test_func = partial(check_for_prefixes, prefixes, "withdraw", policy) + success, _ = topotest.run_and_expect(test_func, True, wait=0.5) + assert success, "Checking the withdrawed prefixes has been failed !." + + +def vpn_prefixes(policy): + """ + Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes. + Check if the previous actions are logged in the BMP server with the right + message type and the right policy. + """ + tgen = get_topogen() + set_bmp_policy(tgen, "r1", 65501, "bmp1", "vpn", policy) + + prefixes = ["172.31.10.1/32", "2001::2222/128"] + + if policy == PRE_POLICY: + # labels are not yet supported in adj-RIB-in. Do not test for the moment + labels = None + else: + # "label vpn export" value in r2/bgpd.conf + labels = { + "172.31.10.1/32": 102, + "2001::2222/128": 105, + } + + # add prefixes + configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, vrf="vrf1") + + logger.info("checking for updated prefixes") + # check + test_func = partial(check_for_prefixes, prefixes, "update", policy, labels=labels) + success, _ = topotest.run_and_expect(test_func, True, wait=0.5) + assert success, "Checking the updated prefixes has been failed !." + + # withdraw prefixes + configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, vrf="vrf1", update=False) + logger.info("checking for withdrawed prefixes") + # check + test_func = partial(check_for_prefixes, prefixes, "withdraw", policy) success, _ = topotest.run_and_expect(test_func, True, wait=0.5) assert success, "Checking the withdrawed prefixes has been failed !." @@ -222,7 +269,9 @@ def test_bmp_server_logging(): def check_for_log_file(): tgen = get_topogen() - output = tgen.gears["bmp1"].run("ls /var/log/") + output = tgen.gears["bmp1"].run( + "ls {}".format(os.path.join(tgen.logdir, "bmp1")) + ) if "bmp.log" not in output: return False return True @@ -239,6 +288,18 @@ def test_bmp_bgp_unicast(): unicast_prefixes(PRE_POLICY) logger.info("*** Unicast prefixes post-policy logging ***") unicast_prefixes(POST_POLICY) + logger.info("*** Unicast prefixes loc-rib logging ***") + unicast_prefixes(LOC_RIB) + + +def test_bmp_bgp_vpn(): + # check for the prefixes in the BMP server logging file + logger.info("***** VPN prefixes pre-policy logging *****") + vpn_prefixes(PRE_POLICY) + logger.info("***** VPN prefixes post-policy logging *****") + vpn_prefixes(POST_POLICY) + logger.info("***** VPN prefixes loc-rib logging *****") + vpn_prefixes(LOC_RIB) if __name__ == "__main__": diff --git a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py index 6d17cdb4d9cc..09091198a8c5 100644 --- a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py +++ b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py @@ -16,7 +16,6 @@ import sys import json import functools -from functools import partial import pytest # Save the Current Working Directory to find configuration files. @@ -117,7 +116,9 @@ def _bgp_check_route(router, exists): test_func = functools.partial(_bgp_check_route, r2, True) _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) - assert result is None, "10.10.10.0/24 ext community is correctly not installed, but SHOULD be" + assert ( + result is None + ), "10.10.10.0/24 ext community is correctly not installed, but SHOULD be" if __name__ == "__main__": diff --git a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py index efc8f200a35e..2064dac6e65b 100644 --- a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_comm_list_match/r1/bgpd.conf b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf index 89c9f7728e60..bac841208818 100644 --- a/tests/topotests/bgp_comm_list_match/r1/bgpd.conf +++ b/tests/topotests/bgp_comm_list_match/r1/bgpd.conf @@ -11,6 +11,7 @@ router bgp 65001 ! ip prefix-list p1 seq 5 permit 172.16.255.1/32 ip prefix-list p3 seq 5 permit 172.16.255.3/32 +ip prefix-list p4 seq 5 permit 172.16.255.4/32 ! route-map r2 permit 10 match ip address prefix-list p1 @@ -19,5 +20,9 @@ route-map r2 permit 20 match ip address prefix-list p3 set community 65001:3 route-map r2 permit 30 + match ip address prefix-list p4 + set community 65001:10 65001:12 65001:13 +exit +route-map r2 permit 40 exit ! diff --git a/tests/topotests/bgp_comm_list_match/r1/zebra.conf b/tests/topotests/bgp_comm_list_match/r1/zebra.conf index 17d0ecceaf0d..4219a7ca3a4e 100644 --- a/tests/topotests/bgp_comm_list_match/r1/zebra.conf +++ b/tests/topotests/bgp_comm_list_match/r1/zebra.conf @@ -3,6 +3,7 @@ interface lo ip address 172.16.255.1/32 ip address 172.16.255.2/32 ip address 172.16.255.3/32 + ip address 172.16.255.4/32 ! interface r1-eth0 ip address 192.168.0.1/24 diff --git a/tests/topotests/bgp_comm_list_match/r2/bgpd.conf b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf index 98a978068888..cb2f89e5c5ad 100644 --- a/tests/topotests/bgp_comm_list_match/r2/bgpd.conf +++ b/tests/topotests/bgp_comm_list_match/r2/bgpd.conf @@ -6,6 +6,9 @@ router bgp 65002 neighbor 192.168.0.1 remote-as external neighbor 192.168.0.1 timers 1 3 neighbor 192.168.0.1 timers connect 1 + neighbor 192.168.1.3 remote-as external + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 address-family ipv4 neighbor 192.168.0.1 route-map r1 in neighbor 192.168.0.1 soft-reconfiguration inbound diff --git a/tests/topotests/bgp_comm_list_match/r2/zebra.conf b/tests/topotests/bgp_comm_list_match/r2/zebra.conf index a69c622352b8..7fe82bac8ff7 100644 --- a/tests/topotests/bgp_comm_list_match/r2/zebra.conf +++ b/tests/topotests/bgp_comm_list_match/r2/zebra.conf @@ -2,5 +2,8 @@ interface r2-eth0 ip address 192.168.0.2/24 ! +interface r2-eth1 + ip address 192.168.1.2/24 +! ip forwarding ! diff --git a/tests/topotests/bgp_comm_list_match/r3/bgpd.conf b/tests/topotests/bgp_comm_list_match/r3/bgpd.conf new file mode 100644 index 000000000000..e68a3e44e0c7 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r3/bgpd.conf @@ -0,0 +1,21 @@ +! +!debug bgp updates +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 + neighbor 192.168.1.2 route-map r1 in + neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +bgp community-list 2 seq 10 permit 65001:12 +! +route-map r1 deny 10 + match community 2 any +exit +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_comm_list_match/r3/zebra.conf b/tests/topotests/bgp_comm_list_match/r3/zebra.conf new file mode 100644 index 000000000000..755dd18bfe88 --- /dev/null +++ b/tests/topotests/bgp_comm_list_match/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.1.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py index 03fa8da9d4bc..d0cab26e1afe 100644 --- a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py +++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py @@ -39,12 +39,15 @@ def build_topo(tgen): - for routern in range(1, 3): + for routern in range(1, 4): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) def setup_module(mod): @@ -53,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -95,12 +98,41 @@ def _bgp_converge(): } return topotest.json_cmp(output, expected) - step("Initial BGP converge") + step("Initial BGP converge between R1 and R2") test_func = functools.partial(_bgp_converge) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to filter BGP UPDATES with community-list on R2" +def test_bgp_comm_list_match_any(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.4/32": { + "path": "65002 65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge between R3 and R2") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to filter BGP UPDATES with community-list on R3" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py index 324f53f3a6d1..82a67a0b84cf 100644 --- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py +++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py @@ -171,7 +171,6 @@ def test_bgp_no_export_local_as_communities_p0(request): ) for comm_type in ["no-export", "local-AS"]: - step("Create a route-map on R1 to set community as {}".format(comm_type)) seq_id = 10 diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py index 000ea6075b6c..9df73a51ba8a 100644 --- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py +++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py @@ -24,8 +24,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 3): @@ -42,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -94,7 +92,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP community aliases at r1" def _bgp_show_prefixes_by_alias(router): @@ -120,7 +118,7 @@ def _bgp_show_prefixes_by_alias(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_alias, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by community alias at r1" def _bgp_show_prefixes_by_large_community_list(router): @@ -131,7 +129,7 @@ def _bgp_show_prefixes_by_large_community_list(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_large_community_list, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by large community list at r1" diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py index 5ad15e064589..c0a92efba9a7 100644 --- a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py +++ b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py @@ -97,7 +97,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -133,7 +133,7 @@ def _bgp_converge_initial(): step("Check if an initial topology is converged") test_func = functools.partial(_bgp_converge_initial) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in c1" step("Disable link between y1 and y2") @@ -146,7 +146,7 @@ def _bgp_converge_link_disabled(): step("Check if a topology is converged after a link down between y1 and y2") test_func = functools.partial(_bgp_converge_link_disabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" def _bgp_check_for_duplicate_updates(): @@ -193,7 +193,7 @@ def _bgp_converge_link_enabled(): step("Check if a topology is converged after a link up between y1 and y2") test_func = functools.partial(_bgp_converge_link_enabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" step( diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py index 0128c8834916..577bf9fd7602 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -159,7 +159,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -426,7 +426,7 @@ def test_bgp_conditional_advertisement_tc_2_1(): ) test_func = functools.partial(exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC21: exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -455,7 +455,7 @@ def test_bgp_conditional_advertisement_tc_2_2(): ) test_func = functools.partial(exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC22: exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -484,7 +484,7 @@ def test_bgp_conditional_advertisement_tc_2_3(): ) test_func = functools.partial(default_route_withdrawn, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC23: advertise-map with exist-map configuration is removed from peer - " assert result is None, msg + failed @@ -513,7 +513,7 @@ def test_bgp_conditional_advertisement_tc_3_1(): ) test_func = functools.partial(non_exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC31: non-exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -542,7 +542,7 @@ def test_bgp_conditional_advertisement_tc_3_2(): ) test_func = functools.partial(non_exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC32: non-exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -571,7 +571,7 @@ def test_bgp_conditional_advertisement_tc_3_3(): ) test_func = functools.partial(all_routes_advertised, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = ( "TC33: advertise-map with non-exist-map configuration is removed from a peer - " @@ -603,7 +603,7 @@ def test_bgp_conditional_advertisement_tc_4_1(): ) test_func = functools.partial(non_exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC41: non-exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -632,7 +632,7 @@ def test_bgp_conditional_advertisement_tc_4_2(): ) test_func = functools.partial(exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC42: exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -665,7 +665,7 @@ def test_bgp_conditional_advertisement_tc_5_1(): ) test_func = functools.partial(exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC51: exist-map routes present with route-map filter - " assert result is None, msg + failed @@ -694,7 +694,7 @@ def test_bgp_conditional_advertisement_tc_5_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC52: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -724,7 +724,7 @@ def test_bgp_conditional_advertisement_tc_5_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC53: non-exist-map routes present, with route-map filter - " assert result is None, msg + failed @@ -753,7 +753,7 @@ def test_bgp_conditional_advertisement_tc_5_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC54: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -791,7 +791,7 @@ def test_bgp_conditional_advertisement_tc_6_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC61: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -820,7 +820,7 @@ def test_bgp_conditional_advertisement_tc_6_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC62: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -850,7 +850,7 @@ def test_bgp_conditional_advertisement_tc_6_3(): ) test_func = functools.partial(non_exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC63: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -881,7 +881,7 @@ def test_bgp_conditional_advertisement_tc_6_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC64: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -919,7 +919,7 @@ def test_bgp_conditional_advertisement_tc_7_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC71: exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -948,7 +948,7 @@ def test_bgp_conditional_advertisement_tc_7_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC72: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -978,7 +978,7 @@ def test_bgp_conditional_advertisement_tc_7_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC73: non-exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -1007,7 +1007,7 @@ def test_bgp_conditional_advertisement_tc_7_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC74: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -1045,7 +1045,7 @@ def test_bgp_conditional_advertisement_tc_8_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC81: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1074,7 +1074,7 @@ def test_bgp_conditional_advertisement_tc_8_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC82: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1106,7 +1106,7 @@ def test_bgp_conditional_advertisement_tc_8_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC83: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1137,7 +1137,7 @@ def test_bgp_conditional_advertisement_tc_8_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC84: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1175,7 +1175,7 @@ def test_bgp_conditional_advertisement_tc_9_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC91: exist-map routes present, route-map filter and network - " assert result is None, msg + failed @@ -1204,7 +1204,7 @@ def test_bgp_conditional_advertisement_tc_9_2(): ) test_func = functools.partial(exist_map_routes_present_rmap2_no_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC92: exist-map routes present, route-map filter and no network - " assert result is None, msg + failed @@ -1244,7 +1244,7 @@ def test_bgp_conditional_advertisement_tc_9_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC93: non-exist-map routes not present, route-map filter and network - " assert result is None, msg + failed @@ -1275,7 +1275,7 @@ def test_bgp_conditional_advertisement_tc_9_4(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_no_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC94: non-exist-map routes not present, route-map filter and no network - " assert result is None, msg + failed diff --git a/eigrpd/eigrp_pkt_tlv2.c b/tests/topotests/bgp_conditional_advertisement_static_route/__init__.py similarity index 100% rename from eigrpd/eigrp_pkt_tlv2.c rename to tests/topotests/bgp_conditional_advertisement_static_route/__init__.py diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf b/tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf new file mode 100644 index 000000000000..3e51337eee90 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement_static_route/r1/frr.conf @@ -0,0 +1,10 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as internal + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 +! diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf b/tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf new file mode 100644 index 000000000000..3ced9340ca15 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement_static_route/r2/frr.conf @@ -0,0 +1,40 @@ +! +!debug bgp conditional-advertisement +!debug bgp updates +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + bgp conditional-advertisement timer 5 + neighbor 192.168.1.1 remote-as internal + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.2.1 remote-as internal + neighbor 192.168.2.1 timers 1 3 + neighbor 192.168.2.1 timers connect 1 + address-family ipv4 unicast + redistribute static + neighbor 192.168.1.1 advertise-map advertise-map exist-map exist-map + neighbor 192.168.1.1 route-map deny-all out + exit-address-family +! +ip route 10.10.10.1/32 r2-eth0 +ip route 10.10.10.2/32 r2-eth0 +! +ip prefix-list default seq 5 permit 0.0.0.0/0 +ip prefix-list advertise seq 5 permit 10.10.10.1/32 +! +route-map deny-all deny 10 +! +route-map exist-map permit 10 + match ip address prefix-list default +! +route-map advertise-map permit 10 + match ip address prefix-list advertise + set community 65000:1 +! diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf b/tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf new file mode 100644 index 000000000000..a24a2cb04ed6 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement_static_route/r3/frr.conf @@ -0,0 +1,19 @@ +! +int lo + ip address 10.10.10.1/32 + ip address 10.10.10.2/32 +! +int r3-eth0 + ip address 192.168.2.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.2.2 remote-as internal + neighbor 192.168.2.2 timers 1 3 + neighbor 192.168.2.2 timers connect 1 + ! + address-family ipv4 unicast + neighbor 192.168.2.2 default-originate + exit-address-family +! diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py new file mode 100644 index 000000000000..ea0f53cc9787 --- /dev/null +++ b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if static route with BGP conditional advertisement works correctly +if we modify the prefix-lists. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_conditional_advertisements_static_route(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads( + r2.vtysh_cmd( + "show bgp ipv4 unicast neighbor 192.168.1.1 advertised-routes json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.1/32": { + "valid": True, + } + }, + "totalPrefixCounter": 1, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + step("Append prefix-list to advertise 10.10.10.2/32") + + r2.vtysh_cmd( + """ + configure terminal + ip prefix-list advertise seq 10 permit 10.10.10.2/32 + """ + ) + + def _bgp_check_advertised_after_update(): + output = json.loads( + r2.vtysh_cmd( + "show bgp ipv4 unicast neighbor 192.168.1.1 advertised-routes json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.1/32": { + "valid": True, + }, + "10.10.10.2/32": { + "valid": True, + }, + }, + "totalPrefixCounter": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_advertised_after_update, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.2/32 is not advertised after prefix-list update" + + def _bgp_check_received_routes(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.1/32 json")) + expected = { + "paths": [ + { + "community": { + "string": "65000:1", + } + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_received_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.1/32 does not have 65000:1 community attached" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py index e76307291e4a..bb98e2fad017 100644 --- a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py +++ b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_confed1/r2/bgpd.conf b/tests/topotests/bgp_confed1/r2/bgpd.conf index fe13dfe72994..ba2da4160e3d 100644 --- a/tests/topotests/bgp_confed1/r2/bgpd.conf +++ b/tests/topotests/bgp_confed1/r2/bgpd.conf @@ -4,7 +4,6 @@ !debug bgp updates out ! router bgp 200 - no bgp ebgp-requires-policy bgp confederation identifier 300 bgp confederation peers 300 neighbor 192.0.2.1 remote-as 100 @@ -12,7 +11,9 @@ router bgp 200 ! address-family ipv4 unicast network 203.0.113.16/28 + neighbor 192.0.2.1 route-map any in + neighbor 192.0.2.1 route-map any out neighbor 192.0.2.18 default-originate exit-address-family ! - +route-map any permit 10 diff --git a/tests/topotests/bgp_confed1/test_bgp_confed1.py b/tests/topotests/bgp_confed1/test_bgp_confed1.py index 57a8522020e7..7b37f4f6c732 100644 --- a/tests/topotests/bgp_confed1/test_bgp_confed1.py +++ b/tests/topotests/bgp_confed1/test_bgp_confed1.py @@ -32,7 +32,7 @@ def build_topo(tgen): - for routern in range(1, 5): + for routern in range(1, 5): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") @@ -47,8 +47,8 @@ def build_topo(tgen): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) -def setup_module(mod): +def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() @@ -67,6 +67,7 @@ def setup_module(mod): # Initialize all routers. tgen.start_router() + def teardown_module(_mod): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py index 5310d3b59574..44b1a2f7041f 100644 --- a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py +++ b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py @@ -18,7 +18,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -27,8 +27,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r3")} @@ -37,7 +35,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff b/tests/topotests/bgp_dampening_per_peer/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff rename to tests/topotests/bgp_dampening_per_peer/__init__.py diff --git a/tests/topotests/bgp_dampening_per_peer/r1/frr.conf b/tests/topotests/bgp_dampening_per_peer/r1/frr.conf new file mode 100644 index 000000000000..45899559cdad --- /dev/null +++ b/tests/topotests/bgp_dampening_per_peer/r1/frr.conf @@ -0,0 +1,15 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 capability dynamic + ! + address-family ipv4 unicast + neighbor 192.168.1.2 dampening 1 1 1 1 + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_peer/r2/frr.conf b/tests/topotests/bgp_dampening_per_peer/r2/frr.conf new file mode 100644 index 000000000000..d68d13d07599 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_peer/r2/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py new file mode 100644 index 000000000000..f8916e1c4dd8 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dampening_per_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + #### + # Withdraw 10.10.10.10/32, and check if it's flagged as history. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no redistribute connected + """ + ) + + def _check_bgp_dampening_history(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "dampeningHistoryEntry": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_history, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as history entry" + + #### + # Reannounce 10.10.10.10/32, and check if it's flagged as dampened. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + redistribute connected + """ + ) + + def _check_bgp_dampening_dampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningSuppressed": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_dampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as dampened entry" + + #### + # Check if the route becomes non-dampened again after some time. + #### + def _check_bgp_dampening_undampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningHistoryEntry": None, + "dampeningSuppressed": None, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_undampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=10) + assert result is None, "10.10.10.10/32 is flagged as history/dampened" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/bgp_dampening_per_safi/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff rename to tests/topotests/bgp_dampening_per_safi/__init__.py diff --git a/tests/topotests/bgp_dampening_per_safi/r1/frr.conf b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf new file mode 100644 index 000000000000..b4e82f581de1 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 unicast + bgp dampening 1 1 1 1 + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/r2/frr.conf b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf new file mode 100644 index 000000000000..d68d13d07599 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py new file mode 100644 index 000000000000..c8d7e675d103 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dampening_per_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _show_dampening_parameters(): + output = json.loads(r1.vtysh_cmd("show ip bgp dampening parameters json")) + expected = { + "halfLifeSecs": 60, + "reusePenalty": 1, + "suppressPenalty": 1, + "maxSuppressTimeSecs": 60, + "maxSuppressPenalty": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _show_dampening_parameters, + ) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert result is None, "Can't show BGP per-safi dampening parameters" + + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + #### + # Withdraw 10.10.10.10/32, and check if it's flagged as history. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no redistribute connected + """ + ) + + def _check_bgp_dampening_history(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "dampeningHistoryEntry": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_history, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as history entry" + + #### + # Reannounce 10.10.10.10/32, and check if it's flagged as dampened. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + redistribute connected + """ + ) + + def _check_bgp_dampening_dampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningSuppressed": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_dampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as dampened entry" + + #### + # Check if the route becomes non-dampened again after some time. + #### + def _check_bgp_dampening_undampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningHistoryEntry": None, + "dampeningSuppressed": None, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_undampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=10) + assert result is None, "10.10.10.10/32 is flagged as history/dampened" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py index a0014c72e64f..48dddb464895 100644 --- a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py +++ b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py @@ -30,8 +30,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.common_config import step -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 5): @@ -50,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py index 75e66566b75b..f4f874f94221 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py @@ -17,7 +17,6 @@ import time import pytest import datetime -from copy import deepcopy from lib.topolog import logger from time import sleep @@ -214,7 +213,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): logger.info("Entering lib API: get_rib_route_uptime()") route_time = [] - out_route_dict = {} router_list = tgen.routers() for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -234,7 +232,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): for static_route in static_routes: if "vrf" in static_route and static_route["vrf"] is not None: - logger.info( "[DUT: {}]: Verifying routes for VRF:" " {}".format(router, static_route["vrf"]) @@ -307,7 +304,6 @@ def get_best_path_route_in_FIB(tgen, topo, dut, network): on failure : return error message with boolean False """ is_ipv4_best_path_found = False - is_ipv6_best_path_found = False rnode = tgen.routers()[dut] ipv4_show_bgp_json = run_frr_cmd(rnode, "sh ip bgp json ", isjson=True) ipv6_show_bgp_json = run_frr_cmd( @@ -1575,7 +1571,7 @@ def ping_router(): ipv_dict = get_best_path_route_in_FIB(tgen, topo, dut="r2", network=network) dut_links = topo["routers"]["r1"]["links"] active_interface = None - for key, values in dut_links.items(): + for key, _ in dut_links.items(): ipv4_address = dut_links[key]["ipv4"].split("/")[0] ipv6_address = dut_links[key]["ipv6"].split("/")[0] if ipv_dict["ipv4"] == ipv4_address and ipv_dict["ipv6"] == ipv6_address: diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py index 6156968ded7d..142b3e430f11 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py @@ -18,8 +18,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -30,32 +28,18 @@ from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -325,12 +309,14 @@ def teardown_module(): ) logger.info("=" * 40) + ##################################################### # # Testcases # ##################################################### + def test_verify_bgp_default_originate_in_IBGP_p0(request): """ Verify BGP default-originate route with IBGP peer @@ -396,7 +382,9 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): step("After changing the BGP AS Path Verify the BGP Convergence") BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) - assert BGP_CONVERGENCE is True, " Complete Convergence is expected after changing the ASN but failed to converge --> :Failed \n Error: {}".format( + assert ( + BGP_CONVERGENCE is True + ), " Complete Convergence is expected after changing the ASN but failed to converge --> :Failed \n Error: {}".format( BGP_CONVERGENCE ) @@ -413,8 +401,10 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): } } result = create_static_routes(tgen, static_routes_input) - assert result is True, "Testcase {} : Failed to configure the static routes {} on router R1 \n Error: {}".format( - tc_name,static_routes_input, result + assert ( + result is True + ), "Testcase {} : Failed to configure the static routes {} on router R1 \n Error: {}".format( + tc_name, static_routes_input, result ) step("verify IPv4 and IPv6 static route are configured and up on R1") for addr_type in ADDR_TYPES: @@ -429,8 +419,10 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input) - assert result is True, "Testcase {} : Failed \n After configuring the static routes {} , the routes are not found in FIB \n Error: {}".format( - tc_name,static_routes_input, result + assert ( + result is True + ), "Testcase {} : Failed \n After configuring the static routes {} , the routes are not found in FIB \n Error: {}".format( + tc_name, static_routes_input, result ) step( @@ -483,7 +475,11 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): }, } result = create_router_bgp(tgen, topo, redistribute_static) - assert result is True, "Testcase {} : Failed to configure the redistribute static configuration \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the redistribute static configuration \n Error: {}".format( + tc_name, result + ) step( "After configuring redistribute command , verify static and connected routes ( loopback connected routes) are advertised on R2" @@ -517,13 +513,17 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : After redistributing static routes the routes {} expected in FIB but NOT FOUND ......! \n Error: {}".format( - tc_name, static_routes_input,result + assert ( + result is True + ), "Testcase {} : After redistributing static routes the routes {} expected in FIB but NOT FOUND ......! \n Error: {}".format( + tc_name, static_routes_input, result ) result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : After redistributing static routes the routes {} expected in RIB but NOT FOUND ......! \n Error: {}".format( - tc_name, static_routes_input , result + assert ( + result is True + ), "Testcase {} : After redistributing static routes the routes {} expected in RIB but NOT FOUND ......! \n Error: {}".format( + tc_name, static_routes_input, result ) step( @@ -547,7 +547,11 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed Configuring default originate configuration. \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed Configuring default originate configuration. \n Error: {}".format( + tc_name, result + ) step( "After configuring default-originate command , verify default routes are advertised on R2 " @@ -574,12 +578,16 @@ def test_verify_bgp_default_originate_in_IBGP_p0(request): } result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : post configuring the BGP Default originate configuration static and connected routes should not be effected but impacted on FIB .......! FAILED \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : post configuring the BGP Default originate configuration static and connected routes should not be effected but impacted on FIB .......! FAILED \n Error: {}".format( tc_name, result ) result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : Failedpost configuring the BGP Default originate configuration static and connected routes should not be effected but impacted on RIB......! FAILED \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failedpost configuring the BGP Default originate configuration static and connected routes should not be effected but impacted on RIB......! FAILED \n Error: {}".format( tc_name, result ) step( @@ -686,7 +694,9 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): step("After changing the BGP AS Path Verify the BGP Convergence") BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) - assert BGP_CONVERGENCE is True, "Complete convergence is expeceted after changing the ASN os the routes ..! :Failed \n Error: {}".format( + assert ( + BGP_CONVERGENCE is True + ), "Complete convergence is expeceted after changing the ASN os the routes ..! :Failed \n Error: {}".format( BGP_CONVERGENCE ) @@ -703,7 +713,9 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): } } result = create_static_routes(tgen, static_routes_input) - assert result is True, "Testcase {} : Failed to configure the static routes ....! Failed \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed to configure the static routes ....! Failed \n Error: {}".format( tc_name, result ) step("verify IPv4 and IPv6 static route are configured and up on R1") @@ -719,8 +731,10 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input) - assert result is True, "Testcase {} : Route is not found in {} in FIB ......! Failed \n Error: {}".format( - tc_name, static_routes_input,result + assert ( + result is True + ), "Testcase {} : Route is not found in {} in FIB ......! Failed \n Error: {}".format( + tc_name, static_routes_input, result ) step( @@ -773,7 +787,11 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): }, } result = create_router_bgp(tgen, topo, redistribute_static) - assert result is True, "Testcase {} : Failed to configure redistribute configuratin \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure redistribute configuratin \n Error: {}".format( + tc_name, result + ) step( "After configuring redistribute command , verify static and connected routes ( loopback connected routes) are advertised on R2" @@ -806,11 +824,15 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : static & and connected routes are expected but not found in FIB .... ! \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : static & and connected routes are expected but not found in FIB .... ! \n Error: {}".format( tc_name, result ) result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : static & and connected routes are expected but not found in RIB .... ! \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : static & and connected routes are expected but not found in RIB .... ! \n Error: {}".format( tc_name, result ) snapshot1 = get_prefix_count_route(tgen, topo, dut="r2", peer="r3") @@ -830,7 +852,11 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed to configure the default originate configuration \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the default originate configuration \n Error: {}".format( + tc_name, result + ) step( "After configuring default-originate command , verify default routes are advertised on R2 on both BGP RIB and FIB" @@ -853,13 +879,17 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): } result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : static route from R1 {} and default route from R3 is expected in R2 FIB .....! NOT FOUND \n Error: {}".format( - tc_name, NETWORK1_1,result + assert ( + result is True + ), "Testcase {} : static route from R1 {} and default route from R3 is expected in R2 FIB .....! NOT FOUND \n Error: {}".format( + tc_name, NETWORK1_1, result ) result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input) - assert result is True, "Testcase {} : static route from R1 {} and default route from R3 is expected in R2 RIB .....! NOT FOUND \n Error: {}".format( - tc_name,NETWORK1_1, result + assert ( + result is True + ), "Testcase {} : static route from R1 {} and default route from R3 is expected in R2 RIB .....! NOT FOUND \n Error: {}".format( + tc_name, NETWORK1_1, result ) step( @@ -875,7 +905,11 @@ def test_verify_bgp_default_originate_in_EBGP_p0(request): metric=0, expected_aspath="4000", ) - assert result is True, "Testcase {} : Default route from R3 is expected with attributes in R2 RIB .....! NOT FOUND Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Default route from R3 is expected with attributes in R2 RIB .....! NOT FOUND Error: {}".format( + tc_name, result + ) step( "Taking the snapshot2 of the prefix count after configuring the default originate" @@ -968,7 +1002,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): step("After changing the BGP AS Path Verify the BGP Convergence") BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) - assert BGP_CONVERGENCE is True, "Complete convergence is expected after changing ASN ....! ERROR :Failed \n Error: {}".format( + assert ( + BGP_CONVERGENCE is True + ), "Complete convergence is expected after changing ASN ....! ERROR :Failed \n Error: {}".format( BGP_CONVERGENCE ) @@ -989,7 +1025,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_static_routes(tgen, static_routes_input) - assert result is True, "Testcase {} : Static Configuration is Failed \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Static Configuration is Failed \n Error: {}".format( tc_name, result ) @@ -1010,8 +1048,10 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r0", static_routes_input) - assert result is True, "Testcase {} : routes {} unable is not found in R0 FIB \n Error: {}".format( - tc_name, static_routes_input,result + assert ( + result is True + ), "Testcase {} : routes {} unable is not found in R0 FIB \n Error: {}".format( + tc_name, static_routes_input, result ) step( @@ -1028,7 +1068,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_router_bgp(tgen, topo, redistribute_static) - assert result is True, "Testcase {} : Failed to configure redistribute static configuration....! \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure redistribute static configuration....! \n Error: {}".format( + tc_name, result + ) step("verify IPv4 and IPv6 static route are configured and up on R1") for addr_type in ADDR_TYPES: @@ -1047,13 +1091,17 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input) - assert result is True, "Testcase {} : Failed... Routes {} expected in r0 FIB after configuring the redistribute config \n Error: {}".format( - tc_name,static_routes_input, result + assert ( + result is True + ), "Testcase {} : Failed... Routes {} expected in r0 FIB after configuring the redistribute config \n Error: {}".format( + tc_name, static_routes_input, result ) result = verify_bgp_rib(tgen, addr_type, "r1", static_routes_input) - assert result is True, "Testcase {} : Failed... Routes {} expected in r0 RIB after configuring the redistribute config \n Error: {}".format( - tc_name, static_routes_input,result + assert ( + result is True + ), "Testcase {} : Failed... Routes {} expected in r0 RIB after configuring the redistribute config \n Error: {}".format( + tc_name, static_routes_input, result ) step( @@ -1094,7 +1142,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to configure the prefix list \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the prefix list \n Error: {}".format( + tc_name, result + ) step( "Configure IPV4 and IPv6 route-map (RMv4 and RMv6 ) matching prefix-list (Pv4 and Pv6) respectively on R1" @@ -1120,7 +1172,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to configure the route map \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the route map \n Error: {}".format( + tc_name, result + ) step( "Configure default-originate with route-map (RMv4 and RMv6) on R1, on BGP IPv4 and IPv6 address family " @@ -1142,7 +1198,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed to configure the default originate \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the default originate \n Error: {}".format( + tc_name, result + ) step("Verify the default route is received in BGP RIB and FIB") step( @@ -1167,7 +1227,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], ) - assert result is True, "Testcase {} : Failed...! Expected default route from R1 not found in FIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed...! Expected default route from R1 not found in FIB \n Error: {}".format( tc_name, result ) @@ -1178,7 +1240,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], ) - assert result is True, "Testcase {} : Failed...! Expected default route from R1 not found in RIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed...! Expected default route from R1 not found in RIB \n Error: {}".format( tc_name, result ) step("Remove route-map RMv4 and RMv6 from default-originate command in R1") @@ -1196,7 +1260,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed to remove the default originate conditional route-map \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to remove the default originate conditional route-map \n Error: {}".format( + tc_name, result + ) step( "Verify BGP RIB and FIB After removing route-map , default route still present on R2" @@ -1221,7 +1289,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], ) - assert result is True, "Testcase {} : Failed Default route from R1 is not found in FIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default route from R1 is not found in FIB \n Error: {}".format( tc_name, result ) @@ -1232,7 +1302,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], ) - assert result is True, "Testcase {} : Failed Default route from R1 is not found in RIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default route from R1 is not found in RIB \n Error: {}".format( tc_name, result ) @@ -1266,7 +1338,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed to configure the Default originate route-map \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the Default originate route-map \n Error: {}".format( + tc_name, result + ) step( "After configuring default-originate command , verify default routes are advertised on R2 " @@ -1290,7 +1366,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], ) - assert result is True, "Testcase {} : Failed Default Route from R1 is not found in FIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default Route from R1 is not found in FIB \n Error: {}".format( tc_name, result ) @@ -1301,7 +1379,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], ) - assert result is True, "Testcase {} : Failed Default Route from R1 is not found in RIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default Route from R1 is not found in RIB \n Error: {}".format( tc_name, result ) @@ -1345,7 +1425,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to delete the prefix list Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to delete the prefix list Error: {}".format( + tc_name, result + ) step( "Verify BGP RIB and FIB After deleting prefix-list , verify IPv4 and IPv6 default route got removed from DUT " @@ -1426,7 +1510,11 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to configure the prefix lists Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the prefix lists Error: {}".format( + tc_name, result + ) step( "After configuring the Prefixlist cross checking the BGP Default route is configured again , before deleting the route map" @@ -1452,7 +1540,9 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], expected=True, ) - assert result is True, "Testcase {} : Failed Default route from R1 is expected in FIB but not found \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default route from R1 is expected in FIB but not found \n Error: {}".format( tc_name, result ) @@ -1464,14 +1554,20 @@ def test_verify_bgp_default_originate_in_IBGP_with_route_map_p0(request): next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], expected=True, ) - assert result is True, "Testcase {} : Failed Default route from R1 is expected in RIB but not found \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default route from R1 is expected in RIB but not found \n Error: {}".format( tc_name, result ) step("Deleting the routemap") input_dict = {"r1": {"route_maps": ["RMv4", "RMv6"]}} result = delete_route_maps(tgen, input_dict) - assert result is True, "Testcase {} : Failed to delete the Route-map \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to delete the Route-map \n Error: {}".format( + tc_name, result + ) step( "Verify BGP RIB and FIB ,After deleting route-map , verify IPv4 and IPv6 default route got removed from DUT" @@ -1605,7 +1701,9 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_static_routes(tgen, static_routes_input) - assert result is True, "Testcase {} : Failed to configure the static routes \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed to configure the static routes \n Error: {}".format( tc_name, result ) step("verify IPv4 and IPv6 static route are configured and up on R4") @@ -1625,8 +1723,10 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input) - assert result is True, "Testcase {} : Failed Static route {} is not found in R4 FIB \n Error: {}".format( - tc_name, static_routes_input,result + assert ( + result is True + ), "Testcase {} : Failed Static route {} is not found in R4 FIB \n Error: {}".format( + tc_name, static_routes_input, result ) step( @@ -1643,7 +1743,11 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_router_bgp(tgen, topo, redistribute_static) - assert result is True, "Testcase {} : Failed to configure the redistribute static \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the redistribute static \n Error: {}".format( + tc_name, result + ) step("verify IPv4 and IPv6 static route are configured and up on R3") for addr_type in ADDR_TYPES: @@ -1662,11 +1766,15 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = verify_fib_routes(tgen, addr_type, "r3", static_routes_input) - assert result is True, "Testcase {} : Failed static routes from R1 and R3 is not found in FIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed static routes from R1 and R3 is not found in FIB \n Error: {}".format( tc_name, result ) result = verify_bgp_rib(tgen, addr_type, "r3", static_routes_input) - assert result is True, "Testcase {} : Failed static routes from R1 and R3 is not found in RIB \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed static routes from R1 and R3 is not found in RIB \n Error: {}".format( tc_name, result ) @@ -1698,12 +1806,20 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to configure the prefix lists \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the prefix lists \n Error: {}".format( + tc_name, result + ) step("verify IPv4 and IPv6 Prefix list got configured on R3") input_dict = {"r3": {"prefix_lists": ["Pv4", "Pv6"]}} result = verify_prefix_lists(tgen, input_dict) - assert result is True, "Testcase {} : Failed ..! configured prefix lists {} are not found \n Error: {}".format(tc_name,input_dict, result) + assert ( + result is True + ), "Testcase {} : Failed ..! configured prefix lists {} are not found \n Error: {}".format( + tc_name, input_dict, result + ) step( "Configure IPv4 and IPv6 route-map ( RMv4 and RMv6 ) matching prefix-list (Pv4 and Pv6 ) respectively on R3" @@ -1729,7 +1845,11 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to configure the route-map \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the route-map \n Error: {}".format( + tc_name, result + ) step( "Taking the snapshot of the prefix count before configuring the default originate" ) @@ -1754,7 +1874,11 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed to configure default-originate \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure default-originate \n Error: {}".format( + tc_name, result + ) step("Verify the default route is NOT received in BGP RIB and FIB on R2 ") step( @@ -1836,7 +1960,11 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to configure the prefix lists Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to configure the prefix lists Error: {}".format( + tc_name, result + ) step("Verify BGP default route for IPv4 and IPv6 is received on R2") @@ -1859,7 +1987,9 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R3[addr_type], ) - assert result is True, "Testcase {} : Failed Default routes are expected in R2 FIB from R3 but not found ....! \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default routes are expected in R2 FIB from R3 but not found ....! \n Error: {}".format( tc_name, result ) @@ -1870,7 +2000,9 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): static_routes_input, next_hop=DEFAULT_ROUTE_NXT_HOP_R3[addr_type], ) - assert result is True, "Testcase {} : Failed Default routes are expected in R2 RIB from R3 but not found ....! \n Error: {}".format( + assert ( + result is True + ), "Testcase {} : Failed Default routes are expected in R2 RIB from R3 but not found ....! \n Error: {}".format( tc_name, result ) @@ -1914,7 +2046,11 @@ def test_verify_bgp_default_originate_in_EBGP_with_route_map_p0(request): } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, "Testcase {} : Failed to remove prefix-lists from R3 Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Failed to remove prefix-lists from R3 Error: {}".format( + tc_name, result + ) step( "After Removing route BGP default route for IPv4 and IPv6 is NOT received on R2" diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py index 59f833b93c52..a6918916df23 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py @@ -17,8 +17,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -31,13 +29,8 @@ verify_bgp_convergence, verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, - get_prefix_count_route, get_dut_as_number, verify_rib_default_route, verify_fib_default_route, @@ -45,16 +38,12 @@ verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, kill_router_daemons, start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -65,7 +54,6 @@ reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) @@ -955,6 +943,7 @@ def test_verify_bgp_default_originate_route_map_in_OUT_p1(request): write_test_footer(tc_name) + def test_verify_bgp_default_originate_route_map_in_IN_p1(request): """Verify BGP default originate route-map with IN route-map""" tgen = get_topogen() @@ -1472,6 +1461,7 @@ def test_verify_bgp_default_originate_route_map_in_IN_p1(request): ) write_test_footer(tc_name) + def test_verify_default_originate_after_removing_default_originate_p1(request): """Verify BGP default route after removing default-originate""" @@ -2232,9 +2222,9 @@ def test_verify_default_originate_after_removing_default_originate_p1(request): ) write_test_footer(tc_name) + def test_verify_default_originate_route_with_GR_p1(request): - """ "Verify default-originate route with GR " - """ + """ "Verify default-originate route with GR " """ tgen = get_topogen() global BGP_CONVERGENCE global topo @@ -2250,14 +2240,13 @@ def test_verify_default_originate_route_with_GR_p1(request): if BGP_CONVERGENCE != True: pytest.skip("skipped because of BGP Convergence failure") - step("Configure IPV4 and IPV6 IBGP between R1 and R2 ") step("Configure IPV4 and IPV6 EBGP between R2 to R3 ") - r0_local_as = topo['routers']['r0']['bgp']['local_as'] - r1_local_as = topo['routers']['r1']['bgp']['local_as'] - r2_local_as = topo['routers']['r2']['bgp']['local_as'] - r3_local_as = topo['routers']['r3']['bgp']['local_as'] - r4_local_as = topo['routers']['r4']['bgp']['local_as'] + r0_local_as = topo["routers"]["r0"]["bgp"]["local_as"] + r1_local_as = topo["routers"]["r1"]["bgp"]["local_as"] + r2_local_as = topo["routers"]["r2"]["bgp"]["local_as"] + r3_local_as = topo["routers"]["r3"]["bgp"]["local_as"] + r4_local_as = topo["routers"]["r4"]["bgp"]["local_as"] input_dict = { "r0": { "bgp": { @@ -2336,33 +2325,14 @@ def test_verify_default_originate_route_with_GR_p1(request): "bgp": { "local_as": local_as, "address_family": { - "ipv4": { - "unicast": { - "default_originate":{ - "r2":{ - - } - - } - - } - }, "ipv6": { - "unicast": { - "default_originate":{ - "r2":{ - - } - - } - } - } - } + "ipv4": {"unicast": {"default_originate": {"r2": {}}}}, + "ipv6": {"unicast": {"default_originate": {"r2": {}}}}, + }, } } } result = create_router_bgp(tgen, topo, default_originate_config) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step( "R2 received default-originate routes and advertised it to R3 , verify on R2 and R3" @@ -2383,17 +2353,28 @@ def test_verify_default_originate_route_with_GR_p1(request): } } - result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input,next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type]) + result = verify_fib_routes( + tgen, + addr_type, + "r2", + static_routes_input, + next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], + ) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) - result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input,next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type]) + result = verify_bgp_rib( + tgen, + addr_type, + "r2", + static_routes_input, + next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], + ) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) - step(" Kill BGPd session on R2") kill_router_daemons(tgen, "r2", ["bgpd"]) start_router_daemons(tgen, "r2", ["bgpd"]) @@ -2411,17 +2392,30 @@ def test_verify_default_originate_route_with_GR_p1(request): } } - result = verify_fib_routes(tgen, addr_type, "r2", static_routes_input,next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type]) + result = verify_fib_routes( + tgen, + addr_type, + "r2", + static_routes_input, + next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], + ) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) - result = verify_bgp_rib(tgen, addr_type, "r2", static_routes_input,next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type]) + result = verify_bgp_rib( + tgen, + addr_type, + "r2", + static_routes_input, + next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], + ) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) write_test_footer(tc_name) + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py index 4dedac5535d8..1506b02e5d40 100644 --- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py +++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py @@ -10,8 +10,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -22,32 +20,17 @@ from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, - verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_rib, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -58,7 +41,6 @@ reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py index 82c4e7e0ab5a..97a7e62e7c70 100644 --- a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py +++ b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py @@ -19,7 +19,6 @@ import sys import time import pytest -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -75,6 +74,7 @@ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"} NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} + def setup_module(mod): """ Sets up the pytest environment @@ -818,11 +818,11 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): step("Configure IPv4 and IPv6 , EBGP neighbor between R3 and R2") step("Configure IPv4 and IPv6 IBGP neighbor between R3 and R4") - r0_local_as = topo['routers']['r0']['bgp']['local_as'] - r1_local_as = topo['routers']['r1']['bgp']['local_as'] - r2_local_as = topo['routers']['r2']['bgp']['local_as'] - r3_local_as = topo['routers']['r3']['bgp']['local_as'] - r4_local_as = topo['routers']['r4']['bgp']['local_as'] + r0_local_as = topo["routers"]["r0"]["bgp"]["local_as"] + r1_local_as = topo["routers"]["r1"]["bgp"]["local_as"] + r2_local_as = topo["routers"]["r2"]["bgp"]["local_as"] + r3_local_as = topo["routers"]["r3"]["bgp"]["local_as"] + r4_local_as = topo["routers"]["r4"]["bgp"]["local_as"] input_dict = { "r0": { "bgp": { @@ -1026,22 +1026,21 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "action": "permit", "seq_id": "1", "set": { - "path": { - "as_num": "200", - "as_action": "prepend", - } + "path": { + "as_num": "200", + "as_action": "prepend", } - + }, }, { "action": "permit", "seq_id": "2", "set": { - "path": { - "as_num": "300", - "as_action": "prepend", - } + "path": { + "as_num": "300", + "as_action": "prepend", } + }, }, ], "RMv6": [ @@ -1049,21 +1048,21 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "action": "permit", "seq_id": "1", "set": { - "path": { - "as_num": "200", - "as_action": "prepend", - } + "path": { + "as_num": "200", + "as_action": "prepend", } + }, }, { "action": "permit", "seq_id": "2", "set": { - "path": { - "as_num": "300", - "as_action": "prepend", - } + "path": { + "as_num": "300", + "as_action": "prepend", } + }, }, ], } @@ -1122,22 +1121,21 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "action": "permit", "seq_id": "1", "set": { - "path": { - "as_num": "500", - "as_action": "prepend", - } + "path": { + "as_num": "500", + "as_action": "prepend", } - + }, }, { "action": "permit", "seq_id": "2", "set": { - "path": { - "as_num": "600", - "as_action": "prepend", - } + "path": { + "as_num": "600", + "as_action": "prepend", } + }, }, ], "RMv6": [ @@ -1145,21 +1143,21 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "action": "permit", "seq_id": "1", "set": { - "path": { - "as_num": "500", - "as_action": "prepend", - } + "path": { + "as_num": "500", + "as_action": "prepend", } + }, }, { "action": "permit", "seq_id": "2", "set": { - "path": { - "as_num": "600", - "as_action": "prepend", - } + "path": { + "as_num": "600", + "as_action": "prepend", } + }, }, ], } @@ -1170,7 +1168,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - step("As path 500 added to IPv4 and IPv6 default -originate route received on R2") result = verify_rib_default_route( tgen, @@ -1232,7 +1229,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes " ) - DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "::/0"} result = verify_rib_default_route( tgen, @@ -1244,7 +1240,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): expected_aspath="4000 500", ) - step( "Modify route-map seq1 configure metric 50 and route-map seq2 configure metric 100 IPv4 and IPv6 route-map " ) @@ -1294,7 +1289,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes " ) - result = verify_rib_default_route( tgen, topo, @@ -1314,7 +1308,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): { "action": "permit", "seq_id": "1", - "set": { "path": { "as_num": "500", @@ -1374,9 +1367,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "Verify AS-prepend is deleted from default originate route and metric value only present on R2 for IPv4 and IPv6 default routes " ) - - - result = verify_rib_default_route( tgen, topo, @@ -1388,7 +1378,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): ) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - step("Delete metric value from IP4 and IPv6 route-map configured on R3 ") route_map = { "r3": { @@ -1428,8 +1417,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "Verify Metric value deleted from IPv4 and IPv6 default route on R2 ,verify default routes " ) - - result = verify_rib_default_route( tgen, topo, @@ -1443,11 +1430,11 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) step("Change IPv4 and IPv6 , EBGP to IBGP neighbor between R3 and R2") step("Change IPv4 and IPv6 IBGP to EBGP neighbor between R3 and R4") - r0_local_as = topo['routers']['r0']['bgp']['local_as'] - r1_local_as = topo['routers']['r1']['bgp']['local_as'] - r2_local_as = topo['routers']['r2']['bgp']['local_as'] - r3_local_as = topo['routers']['r3']['bgp']['local_as'] - r4_local_as = topo['routers']['r4']['bgp']['local_as'] + r0_local_as = topo["routers"]["r0"]["bgp"]["local_as"] + r1_local_as = topo["routers"]["r1"]["bgp"]["local_as"] + r2_local_as = topo["routers"]["r2"]["bgp"]["local_as"] + r3_local_as = topo["routers"]["r3"]["bgp"]["local_as"] + r4_local_as = topo["routers"]["r4"]["bgp"]["local_as"] input_dict = { "r0": { "bgp": { @@ -1459,7 +1446,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "local_as": r1_local_as, } }, - "r2": { "bgp": { "local_as": 1111, @@ -1645,8 +1631,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "Verify Configured metric value received on R2 along with as-path for IPv4 and IPv6 default routes " ) - - result = verify_rib_default_route( tgen, topo, @@ -1656,7 +1640,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): locPrf=50, ) - assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) step( @@ -1708,9 +1691,6 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "Verify Modified local-preference value received on R2 for IPv4 and IPv6 default routes " ) - - - DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "::/0"} result = verify_rib_default_route( tgen, @@ -1724,13 +1704,15 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) # updating the topology with the updated AS-Number to avoid conflict in con configuring the AS updated_topo = topo - updated_topo['routers']['r0']['bgp']['local_as']=get_dut_as_number(tgen,"r0") - updated_topo['routers']['r1']['bgp']['local_as']=get_dut_as_number(tgen,"r1") - updated_topo['routers']['r2']['bgp']['local_as']=get_dut_as_number(tgen,"r2") - updated_topo['routers']['r3']['bgp']['local_as']=get_dut_as_number(tgen,"r3") - updated_topo['routers']['r4']['bgp']['local_as']=get_dut_as_number(tgen,"r4") + updated_topo["routers"]["r0"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r0") + updated_topo["routers"]["r1"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r1") + updated_topo["routers"]["r2"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r2") + updated_topo["routers"]["r3"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r3") + updated_topo["routers"]["r4"]["bgp"]["local_as"] = get_dut_as_number(tgen, "r4") - step("Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command ") + step( + "Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command " + ) local_as = get_dut_as_number(tgen, dut="r4") shut_neighbor = { "r4": { @@ -1740,46 +1722,41 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "ipv4": { "unicast": { "neighbor": { - "r3": { - "dest_link": { - "r4": {"shutdown":True} - } - } + "r3": {"dest_link": {"r4": {"shutdown": True}}} } } }, "ipv6": { "unicast": { "neighbor": { - "r3": { - "dest_link": { - "r4": {"shutdown":True} - } - } + "r3": {"dest_link": {"r4": {"shutdown": True}}} } } - } - } + }, + }, } } } result = create_router_bgp(tgen, updated_topo, shut_neighbor) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - interface = topo['routers']['r3']['links']['r4']['interface'] - input_dict = { - "r1": { - "interface_list": [interface], - "status": "down" - } - } + interface = topo["routers"]["r3"]["links"]["r4"]["interface"] + input_dict = {"r1": {"interface_list": [interface], "status": "down"}} result = interface_status(tgen, topo, input_dict) - assert result is True, "Testcase {} : Shut down the interface failed ! \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Shut down the interface failed ! \n Error: {}".format( + tc_name, result + ) step("After shutting the interface verify the BGP convergence") - result = verify_bgp_convergence(tgen,topo,expected=False) - assert result is not True, "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format(tc_name, result) + result = verify_bgp_convergence(tgen, topo, expected=False) + assert ( + result is not True + ), "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format( + tc_name, result + ) step("verify default route deleted from R2 ") result = verify_rib_default_route( @@ -1788,8 +1765,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected=False) - assert result is not True, "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in RIB -> {}".format( tc_name, result) + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in RIB -> {}".format( + tc_name, result + ) result = verify_fib_default_route( tgen, @@ -1797,11 +1779,17 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected=False) - assert result is not True, "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in FIB -> {}".format( tc_name, result) - + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: After Shut down interface the default route is NOT expected but found in FIB -> {}".format( + tc_name, result + ) - step("no Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command ") + step( + "no Shut IPv4/IPv6 BGP neighbor from R4 ( R4-R3) using 'neighbor x.x.x.x shut' command " + ) local_as = get_dut_as_number(tgen, dut="r4") shut_neighbor = { "r4": { @@ -1811,46 +1799,39 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "ipv4": { "unicast": { "neighbor": { - "r3": { - "dest_link": { - "r4": {"shutdown":False} - } - } + "r3": {"dest_link": {"r4": {"shutdown": False}}} } } }, "ipv6": { "unicast": { "neighbor": { - "r3": { - "dest_link": { - "r4": {"shutdown":False} - } - } + "r3": {"dest_link": {"r4": {"shutdown": False}}} } } - } - } + }, + }, } } } result = create_router_bgp(tgen, updated_topo, shut_neighbor) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - interface = topo['routers']['r3']['links']['r4']['interface'] - input_dict = { - "r1": { - "interface_list": [interface], - "status": "up" - } - } + interface = topo["routers"]["r3"]["links"]["r4"]["interface"] + input_dict = {"r1": {"interface_list": [interface], "status": "up"}} result = interface_status(tgen, topo, input_dict) - assert result is True, "Testcase {} : Bring up interface failed ! \n Error: {}".format(tc_name, result) + assert ( + result is True + ), "Testcase {} : Bring up interface failed ! \n Error: {}".format(tc_name, result) step("After no shutting the interface verify the BGP convergence") - result = verify_bgp_convergence(tgen,topo,expected=True) - assert result is True, "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format(tc_name, result) + result = verify_bgp_convergence(tgen, topo, expected=True) + assert ( + result is True + ), "Testcase {} : Failed \n After shutting Down BGP convergence should Fail and return False \n Error: {}".format( + tc_name, result + ) step("After no shut neighbor , verify default route relearn on R2") result = verify_rib_default_route( @@ -1859,8 +1840,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected=True) - assert result is True, "Testcase {} : Failed \n Error: After no Shut down interface the default route is expected but found in RIB -> {}".format( tc_name, result) + expected=True, + ) + assert ( + result is True + ), "Testcase {} : Failed \n Error: After no Shut down interface the default route is expected but found in RIB -> {}".format( + tc_name, result + ) result = verify_fib_default_route( tgen, @@ -1868,10 +1854,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected=True) - assert result is True, "Testcase {} : Failed \n Error: After Shut down interface the default route is expected but found in FIB -> {}".format( tc_name, result) - - + expected=True, + ) + assert ( + result is True + ), "Testcase {} : Failed \n Error: After Shut down interface the default route is expected but found in FIB -> {}".format( + tc_name, result + ) step("Remove IPv4/IPv6 static route configure on R4") for addr_type in ADDR_TYPES: @@ -1881,7 +1870,7 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): { "network": [NETWORK1_1[addr_type]], "next_hop": NEXT_HOP_IP[addr_type], - "delete": True + "delete": True, } ] } @@ -1902,12 +1891,16 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): ] } } - result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + result = verify_fib_routes( + tgen, addr_type, "r4", static_routes_input, expected=False + ) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) - result = verify_bgp_rib(tgen, addr_type, "r4", static_routes_input, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: {}".format( + result = verify_bgp_rib( + tgen, addr_type, "r4", static_routes_input, expected=False + ) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) @@ -1918,8 +1911,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= False) - assert result is not True, "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in RIB -> {}".format( tc_name, result) + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in RIB -> {}".format( + tc_name, result + ) result = verify_fib_default_route( tgen, @@ -1927,9 +1925,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= False) - assert result is not True, "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in FIB -> {}".format( tc_name, result) - + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: After removing static the default route is NOT expected but found in FIB -> {}".format( + tc_name, result + ) step("Configuring the static route back in r4") for addr_type in ADDR_TYPES: @@ -1959,12 +1961,16 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): ] } } - result = verify_fib_routes(tgen, addr_type, "r4", static_routes_input, expected=True) - assert result is True, "Testcase {} : Failed \n Error: {}".format( + result = verify_fib_routes( + tgen, addr_type, "r4", static_routes_input, expected=True + ) + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) - result = verify_bgp_rib(tgen, addr_type, "r4", static_routes_input, expected=True) - assert result is True, "Testcase {} : Failed \n Error: {}".format( + result = verify_bgp_rib( + tgen, addr_type, "r4", static_routes_input, expected=True + ) + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) @@ -1975,8 +1981,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= True) - assert result is True, "Testcase {} : Failed \n Error: After removing static the default route is expected but found in RIB -> {}".format( tc_name, result) + expected=True, + ) + assert ( + result is True + ), "Testcase {} : Failed \n Error: After removing static the default route is expected but found in RIB -> {}".format( + tc_name, result + ) result = verify_fib_default_route( tgen, @@ -1984,8 +1995,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= True) - assert result is True, "Testcase {} : Failed \n Error: After removing static the default route is expected but found in FIB -> {}".format( tc_name, result) + expected=True, + ) + assert ( + result is True + ), "Testcase {} : Failed \n Error: After removing static the default route is expected but found in FIB -> {}".format( + tc_name, result + ) step("Deactivate IPv4 and IPv6 neighbor configured from R4 ( R4-R3)") @@ -1999,15 +2015,14 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "r3": {"dest_link": {"r4": {"deactivate": "ipv4"}}} } }, - - },"ipv6": { + }, + "ipv6": { "unicast": { "neighbor": { "r3": {"dest_link": {"r4": {"deactivate": "ipv6"}}} } }, - - } + }, } } } @@ -2022,8 +2037,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= False) - assert result is not True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in RIB -> {}".format( tc_name, result) + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in RIB -> {}".format( + tc_name, result + ) result = verify_fib_default_route( tgen, @@ -2031,8 +2051,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= False) - assert result is not True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in FIB -> {}".format( tc_name, result) + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is NOT expected but found in FIB -> {}".format( + tc_name, result + ) step("Activate IPv4 and IPv6 neighbor configured from R4 ( R4-R3)") @@ -2046,15 +2071,14 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): "r3": {"dest_link": {"r4": {"activate": "ipv4"}}} } }, - - },"ipv6": { + }, + "ipv6": { "unicast": { "neighbor": { "r3": {"dest_link": {"r4": {"activate": "ipv6"}}} } }, - - } + }, } } } @@ -2064,7 +2088,7 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): step("Verify bgp convergence.") bgp_convergence = verify_bgp_convergence(tgen, updated_topo) - assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( + assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format( tc_name, bgp_convergence ) step("After Activating the BGP neighbor , verify default route learned on R2") @@ -2074,8 +2098,13 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= True) - assert result is True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in RIB -> {}".format( tc_name, result) + expected=True, + ) + assert ( + result is True + ), "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in RIB -> {}".format( + tc_name, result + ) result = verify_fib_default_route( tgen, @@ -2083,10 +2112,16 @@ def test_verify_default_originate_after_BGP_attributes_p1(request): dut="r2", routes=DEFAULT_ROUTES, expected_nexthop=DEFAULT_ROUTE_NXT_HOP_R3, - expected= True) - assert result is True, "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in FIB -> {}".format( tc_name, result) + expected=True, + ) + assert ( + result is True + ), "Testcase {} : Failed \n Error: After Deactivating the BGP neighbor the default route is expected but found in FIB -> {}".format( + tc_name, result + ) write_test_footer(tc_name) + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py index b2ba936fb1f6..c7c40c1bfbbd 100644 --- a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py +++ b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py index e25f85af8501..cd4acc9aa42f 100644 --- a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py +++ b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_route/r1/bgpd.conf b/tests/topotests/bgp_default_route/r1/bgpd.conf index 8699d62ff2de..10ced3610a02 100644 --- a/tests/topotests/bgp_default_route/r1/bgpd.conf +++ b/tests/topotests/bgp_default_route/r1/bgpd.conf @@ -3,6 +3,7 @@ router bgp 65000 neighbor 192.168.255.2 remote-as 65001 neighbor 192.168.255.2 timers 3 10 address-family ipv4 unicast + network 0.0.0.0/1 neighbor 192.168.255.2 default-originate exit-address-family ! diff --git a/tests/topotests/bgp_default_route/r1/zebra.conf b/tests/topotests/bgp_default_route/r1/zebra.conf index 0a283c06d57c..fbf97b0520ce 100644 --- a/tests/topotests/bgp_default_route/r1/zebra.conf +++ b/tests/topotests/bgp_default_route/r1/zebra.conf @@ -1,4 +1,6 @@ ! +ip route 0.0.0.0/1 blackhole +! interface lo ip address 172.16.255.254/32 ! diff --git a/tests/topotests/bgp_default_route/test_bgp_default-originate.py b/tests/topotests/bgp_default_route/test_bgp_default-originate.py index 2463b0546994..e805d06a6ac6 100644 --- a/tests/topotests/bgp_default_route/test_bgp_default-originate.py +++ b/tests/topotests/bgp_default_route/test_bgp_default-originate.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -69,33 +69,37 @@ def _bgp_check_if_received(): expected = { "192.168.255.1": { "bgpState": "Established", - "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}}, + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, } } return topotest.json_cmp(output, expected) def _bgp_check_if_originated(): output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp summary json")) - expected = {"ipv4Unicast": {"peers": {"192.168.255.2": {"pfxSnt": 1}}}} + expected = {"ipv4Unicast": {"peers": {"192.168.255.2": {"pfxSnt": 2}}}} return topotest.json_cmp(output, expected) - def _bgp_default_route_is_valid(router): - output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json")) + def _bgp_route_is_valid(router, prefix): + output = json.loads(router.vtysh_cmd("show ip bgp {} json".format(prefix))) expected = {"paths": [{"valid": True}]} return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_check_if_received) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 at r2 from r1" test_func = functools.partial(_bgp_check_if_originated) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 from r1 to r2" - test_func = functools.partial(_bgp_default_route_is_valid, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/0") + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/0 in r2" + test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/1") + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Failed to see 0.0.0.0/1 in r2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py index 9dcb5a1eef32..d866b95f7b6f 100644 --- a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py +++ b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -80,12 +80,12 @@ def _bgp_default_route_is_valid(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py index 965d348bd703..5a99878b88c6 100644 --- a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py +++ b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +84,7 @@ def _bgp_default_route_is_valid(router): step("Converge network") test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see bgp convergence at r2" step("Withdraw 10.0.0.0/22 from R2") @@ -94,7 +94,7 @@ def _bgp_default_route_is_valid(router): step("Check if we don't have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" step("Announce 10.0.0.0/22 from R2") @@ -102,7 +102,7 @@ def _bgp_default_route_is_valid(router): step("Check if we have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "0.0.0.0/0 does not exist at r2" step("Withdraw 10.0.0.0/22 from R2 again") @@ -112,7 +112,7 @@ def _bgp_default_route_is_valid(router): step("Check if we don't have 0.0.0.0/0 at R2 again") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" diff --git a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py index f94620b2c977..3a374c6e9aed 100644 --- a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py +++ b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,12 +90,12 @@ def _bgp_default_route_has_metric(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_set/r1/bgpd.conf b/tests/topotests/bgp_default_route_route_map_set/r1/bgpd.conf index 6f6d39440235..c442e06a63b2 100644 --- a/tests/topotests/bgp_default_route_route_map_set/r1/bgpd.conf +++ b/tests/topotests/bgp_default_route_route_map_set/r1/bgpd.conf @@ -1,12 +1,17 @@ -router bgp 65000 - no bgp ebgp-requires-policy - neighbor 192.168.255.2 remote-as 65001 - neighbor 192.168.255.2 timers 3 10 - address-family ipv4 unicast - neighbor 192.168.255.2 default-originate route-map default - exit-address-family +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.255.2 remote-as external + neighbor 192.168.255.2 timers 3 10 + neighbor PG peer-group + neighbor PG remote-as external + neighbor PG timers 3 10 + bgp listen range 192.168.255.0/24 peer-group PG + address-family ipv4 unicast + neighbor PG default-originate route-map default + neighbor 192.168.255.2 default-originate route-map default + exit-address-family ! route-map default permit 10 - set metric 123 - set as-path prepend 65000 65000 65000 + set metric 123 + set as-path prepend 65001 65001 65001 ! diff --git a/tests/topotests/bgp_default_route_route_map_set/r1/zebra.conf b/tests/topotests/bgp_default_route_route_map_set/r1/zebra.conf index 0a283c06d57c..4af88e523c8a 100644 --- a/tests/topotests/bgp_default_route_route_map_set/r1/zebra.conf +++ b/tests/topotests/bgp_default_route_route_map_set/r1/zebra.conf @@ -5,5 +5,3 @@ interface lo interface r1-eth0 ip address 192.168.255.1/24 ! -ip forwarding -! diff --git a/tests/topotests/bgp_default_route_route_map_set/r2/bgpd.conf b/tests/topotests/bgp_default_route_route_map_set/r2/bgpd.conf index 00c96cc58b2c..3a18a113865b 100644 --- a/tests/topotests/bgp_default_route_route_map_set/r2/bgpd.conf +++ b/tests/topotests/bgp_default_route_route_map_set/r2/bgpd.conf @@ -1,8 +1,8 @@ -router bgp 65001 - no bgp ebgp-requires-policy - neighbor 192.168.255.1 remote-as 65000 - neighbor 192.168.255.1 timers 3 10 - address-family ipv4 unicast - redistribute connected - exit-address-family +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.255.1 remote-as external + neighbor 192.168.255.1 timers 3 10 + address-family ipv4 unicast + redistribute connected + exit-address-family ! diff --git a/tests/topotests/bgp_default_route_route_map_set/r2/zebra.conf b/tests/topotests/bgp_default_route_route_map_set/r2/zebra.conf index 606c17bec9c1..c03dd7e197af 100644 --- a/tests/topotests/bgp_default_route_route_map_set/r2/zebra.conf +++ b/tests/topotests/bgp_default_route_route_map_set/r2/zebra.conf @@ -2,5 +2,3 @@ interface r2-eth0 ip address 192.168.255.2/24 ! -ip forwarding -! diff --git a/tests/topotests/bgp_default_route_route_map_set/r3/bgpd.conf b/tests/topotests/bgp_default_route_route_map_set/r3/bgpd.conf new file mode 100644 index 000000000000..c477037e34eb --- /dev/null +++ b/tests/topotests/bgp_default_route_route_map_set/r3/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.255.1 remote-as external + neighbor 192.168.255.1 timers 3 10 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_default_route_route_map_set/r3/zebra.conf b/tests/topotests/bgp_default_route_route_map_set/r3/zebra.conf new file mode 100644 index 000000000000..5ae9daf07726 --- /dev/null +++ b/tests/topotests/bgp_default_route_route_map_set/r3/zebra.conf @@ -0,0 +1,4 @@ +! +interface r3-eth0 + ip address 192.168.255.3/24 +! diff --git a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py index 3bd900bda037..ba278295a6da 100644 --- a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py +++ b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py @@ -26,12 +26,13 @@ def build_topo(tgen): - for routern in range(1, 3): + for routern in range(1, 4): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) def setup_module(mod): @@ -40,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -62,14 +63,17 @@ def test_bgp_default_originate_route_map(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - router = tgen.gears["r2"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] - def _bgp_converge(router): + def _bgp_converge(router, pfxCount): output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) expected = { "192.168.255.1": { "bgpState": "Established", - "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}}, + "addressFamilyInfo": { + "ipv4Unicast": {"acceptedPrefixCounter": pfxCount} + }, } } return topotest.json_cmp(output, expected) @@ -77,21 +81,25 @@ def _bgp_converge(router): def _bgp_default_route_has_metric(router): output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json")) expected = { - "paths": [{"aspath": {"string": "65000 65000 65000 65000"}, "metric": 123}] + "paths": [{"aspath": {"string": "65001 65001 65001 65001"}, "metric": 123}] } return topotest.json_cmp(output, expected) - test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + test_func = functools.partial(_bgp_converge, r2, 1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see bgp convergence in r2" - assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) + test_func = functools.partial(_bgp_default_route_has_metric, r2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see applied metric for default route in r2" - test_func = functools.partial(_bgp_default_route_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + test_func = functools.partial(_bgp_converge, r3, 2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see bgp convergence in r3" - assert ( - result is None - ), 'Failed to see applied metric for default route in "{}"'.format(router) + test_func = functools.partial(_bgp_default_route_has_metric, r3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see applied metric for default route in r3" if __name__ == "__main__": diff --git a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py index 70562ce31f3b..6978008740ee 100644 --- a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py +++ b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -98,7 +98,7 @@ def check_bgp_advertised_routes(router): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_advertised_routes, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath TX not working." step("Check if AddPath RX is disabled on r1 and we receive only 2 paths.") @@ -120,7 +120,7 @@ def check_bgp_disabled_addpath_rx(router): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_disabled_addpath_rx, r1) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath RX advertised, but should not." diff --git a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py index 0bd3d2814bb0..0307ee2f4edf 100755 --- a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py +++ b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py @@ -215,7 +215,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure static route in R4 and R5, redistribute in bgp") for addr_type in ADDR_TYPES: - input_dict = { "r4": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -228,7 +227,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): ) for addr_type in ADDR_TYPES: - input_dict = { "r5": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -268,7 +266,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure the static route in R3 (Dut).") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -305,7 +302,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step(" Configure the admin distance of 254 to static route in R3.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -571,7 +567,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Reconfigure the static route without admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -993,7 +988,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route Without any admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1009,7 +1003,6 @@ def test_bgp_admin_distance_ibgp_p0(): protocol = "static" for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1023,7 +1016,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route with admin distance of 253") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -1086,7 +1078,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Delete the static route.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py index 2ca50aa56ead..87802511b5e6 100644 --- a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py +++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -101,14 +101,14 @@ def _bgp_check_distance_change(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) _bgp_distance_change(router) test_func = functools.partial(_bgp_check_distance_change, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP distance in RIB "{}"'.format( router diff --git a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py index ab71f87a04bd..28d6b56303b2 100644 --- a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py +++ b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py @@ -16,7 +16,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -26,8 +26,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.common_config import step -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -36,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -122,8 +120,9 @@ def _bgp_check_fqdn(fqdn=None): step("Wait to converge") test_func = functools.partial(bgp_converge, r1) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, "Can't converge with dont-capability-negotiate" + assert result is None, "Can't converge with all capabilities" + step("Make sure FQDN capability is set") test_func = functools.partial(_bgp_check_fqdn, "r2") _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "FQDN capability enabled, but r1 can't see it" @@ -150,6 +149,49 @@ def _bgp_check_fqdn(fqdn=None): _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "FQDN capability disabled, but we still have a hostname" + step("Re-enable sending any capability from r2") + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + address-family ipv4 unicast + no neighbor 192.168.1.1 dont-capability-negotiate + end + clear bgp 192.168.1.1 + """ + ) + step("Wait to converge") + tgen = get_topogen() + test_func = functools.partial(bgp_converge, r1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge with all capabilities re enabled" + + step("Make sure FQDN capability is r2") + test_func = functools.partial(_bgp_check_fqdn, "r2") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "FQDN capability enabled, but r1 can't see it" + + step("Disable sending fqdn capability") + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + no neighbor 192.168.1.1 capability fqdn + end + clear bgp 192.168.1.1 + """ + ) + step("Wait to converge") + tgen = get_topogen() + test_func = functools.partial(bgp_converge, r1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge with no capability fqdn" + + step("Make sure FQDN capability is reset") + test_func = functools.partial(_bgp_check_fqdn) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "FQDN capability disabled, but we still have a hostname" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf new file mode 100644 index 000000000000..8084962587dd --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf @@ -0,0 +1,14 @@ +router bgp 64500 + bgp router-id 192.0.2.1 + timers bgp 3 9 + no bgp ebgp-requires-policy + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + neighbor rrserver next-hop-self + neighbor rrserver activate + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf new file mode 100644 index 000000000000..9660577f4e8f --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf @@ -0,0 +1,26 @@ +hostname r1 +interface lo + ip router isis 1 + isis passive +! +interface r1-eth1 + ip router isis 1 + isis network point-to-point +! +interface r1-eth2 + ip router isis 1 + isis network point-to-point +! +interface r1-eth4 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0001.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.1/32 index 1 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf new file mode 100644 index 000000000000..2e3549a57401 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf @@ -0,0 +1,24 @@ +log stdout +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 172.31.10.1/24 +! +interface r1-eth1 + ip address 172.31.0.1/24 + mpls enable +! +interface r1-eth2 + ip address 172.31.2.1/24 + mpls enable +! +interface r1-eth3 + ip address 172.31.11.1/24 + mpls enable +! +interface r1-eth4 + ip address 172.31.8.1/24 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf new file mode 100644 index 000000000000..7312dba40769 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf @@ -0,0 +1,17 @@ +router bgp 64500 view one + timers bgp 3 9 + bgp router-id 192.0.2.3 + neighbor rr peer-group + neighbor rr remote-as 64500 + neighbor rr update-source lo + neighbor 192.0.2.1 peer-group rr + neighbor 192.0.2.5 peer-group rr + neighbor 192.0.2.6 peer-group rr + neighbor 192.0.2.8 peer-group rr + ! + address-family ipv4 unicast + neighbor rr activate + neighbor rr route-reflector-client + neighbor rr addpath-tx-all-paths + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf new file mode 100644 index 000000000000..ae6bddee9208 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf @@ -0,0 +1,38 @@ +hostname r3 +interface lo + ip router isis 1 + isis passive +! +interface r3-eth0 + ip router isis 1 + isis network point-to-point +! +interface r3-eth1 + ip router isis 1 + isis network point-to-point +! +interface r3-eth2 + ip router isis 1 + isis network point-to-point +! +interface r3-eth3 + ip router isis 1 + isis network point-to-point +! +interface r3-eth4 + ip router isis 1 + isis network point-to-point +! +interface r3-eth5 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0003.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.3/32 index 3 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf new file mode 100644 index 000000000000..05b3769fb8bf --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf @@ -0,0 +1,16 @@ +log stdout +interface lo + ip address 192.0.2.3/32 +! +interface r3-eth0 + ip address 172.31.0.3/24 + mpls enable +! +interface r3-eth1 + ip address 172.31.4.3/24 + mpls enable +! +interface r3-eth2 + ip address 172.31.5.3/24 + mpls enable +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf new file mode 100644 index 000000000000..4d49d0de0a45 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf @@ -0,0 +1,30 @@ +hostname r4 +interface lo + ip router isis 1 + isis passive +! +interface r4-eth0 + ip router isis 1 + isis network point-to-point +! +interface r4-eth1 + ip router isis 1 + isis network point-to-point +! +interface r4-eth2 + ip router isis 1 + isis network point-to-point +! +interface r4-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0004.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.4/32 index 4 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf new file mode 100644 index 000000000000..9ea1b7ec4314 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf @@ -0,0 +1,20 @@ +log stdout +interface lo + ip address 192.0.2.4/32 +! +interface r4-eth0 + ip address 172.31.2.4/24 + mpls enable +! +interface r4-eth1 + ip address 172.31.6.4/24 + mpls enable +! +interface r4-eth2 + ip address 172.31.7.4/24 + mpls enable +! +interface r4-eth3 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf new file mode 100644 index 000000000000..e46d7c5ed4c3 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 64500 + timers bgp 3 9 + bgp router-id 192.0.2.5 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf new file mode 100644 index 000000000000..46556d9a567a --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf @@ -0,0 +1,26 @@ +hostname r5 +interface lo + ip router isis 1 + isis passive +! +interface r5-eth1 + ip router isis 1 + isis network point-to-point +! +interface r5-eth2 + ip router isis 1 + isis network point-to-point +! +interface r5-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0005.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.5/32 index 55 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf new file mode 100644 index 000000000000..6f326561e733 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf @@ -0,0 +1,19 @@ +log stdout +mpls label dynamic-block 5000 5999 +interface lo + ip address 192.0.2.5/32 +! +interface r5-eth0 + ip address 172.31.12.5/24 +! +interface r5-eth1 + ip address 172.31.4.5/24 + mpls enable +! +interface r5-eth2 + ip address 172.31.7.5/24 + mpls enable +! +interface r5-eth3 + ip address 172.31.21.5/24 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf new file mode 100644 index 000000000000..3aa9adb18bdb --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 64500 + timers bgp 3 9 + bgp router-id 192.0.2.6 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver bfd + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf new file mode 100644 index 000000000000..5126a6485846 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf @@ -0,0 +1,22 @@ +hostname r6 +interface lo + ip router isis 1 + isis passive +! +interface r6-eth1 + ip router isis 1 + isis network point-to-point +! +interface r6-eth2 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0006.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.6/32 index 6 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf new file mode 100644 index 000000000000..cda62d7e87a0 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf @@ -0,0 +1,20 @@ +log stdout +mpls label dynamic-block 6000 6999 +interface lo + ip address 192.0.2.6/32 +! +interface r6-eth0 + ip address 172.31.13.6/24 +! +interface r6-eth1 + ip address 172.31.5.6/24 + mpls enable +! +interface r6-eth2 + ip address 172.31.6.6/24 + mpls enable +! +interface r6-eth3 + ip address 172.31.22.6/24 +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py new file mode 100644 index 000000000000..5c125869e293 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -0,0 +1,458 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_duplicate_nexthop.py +# +# Copyright 2024 6WIND S.A. +# + +r""" + test_bgp_nhg_duplicate_nexthop.py: + Check that the FRR BGP daemon on r1 selects updates with same nexthops + + ++---+----+ +---+----+ +--------+ +| | | + | | +| r1 +----------+ r3 +----------+ r5 + +| | | rr + +-----+ | ++++-+----+ +--------+\ / +--------+ + | \/ + | /\ + | +--------+/ \ +--------+ + | | + +-----+ + + +---------------+ r4 +----------+ r6 + + | | | | + +--------+ +--------+ +""" + +import os +import sys +import json +from functools import partial +import pytest +import functools + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.common_check import ip_check_path_selection, iproute2_check_path_selection +from lib.common_config import step +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 7 PE routers. + tgen.add_router("r1") + tgen.add_router("r3") + tgen.add_router("r4") + tgen.add_router("r5") + tgen.add_router("r6") + + # switch + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s10") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s11") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s12") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s13") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s14") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + if rname in ("r1", "r3", "r5", "r6"): + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + tgen.stop_topology() + + +def check_ipv4_prefix_with_multiple_nexthops(prefix, multipath=True): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "192.0.2.5", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "192.0.2.6", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(nh) + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(nh) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} uses the IGP label 16055 and 16006" + + +def get_nh_formatted(nexthop, fib=True, duplicate=False): + nh = dict(nexthop) + if duplicate: + nh.update({"duplicate": True}) + if fib: + nh.update({"fib": True}) + return nh + + +def check_ipv4_prefix_recursive_with_multiple_nexthops( + prefix, recursive_nexthop, multipath=True +): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info( + f"Check that {prefix} unicast entry is correctly recursive via {recursive_nexthop} with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + + recursive_nh = [ + { + "ip": recursive_nexthop, + "active": True, + "recursive": True, + }, + ] + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh, fib=False)) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r6_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected, check_fib=True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} is correctly recursive via {recursive_nexthop}" + + +def check_ipv4_prefix_with_multiple_nexthops_linux(prefix): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + ) + + r5_nh = [ + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + r6_nh = [ + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + expected = [ + { + "dst": prefix, + "protocol": "bgp", + "metric": 20, + "nexthops": [], + } + ] + + # only one path + for nh in r5_nh: + expected[0]["nexthops"].append(nh) + for nh in r6_nh: + expected[0]["nexthops"].append(nh) + + test_func = functools.partial( + iproute2_check_path_selection, tgen.routers()["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + + +def test_bgp_ipv4_convergence(): + """ + Check that R1 has received the 192.0.2.9/32 prefix from R5, and R6 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Ensure that the 192.0.2.9/32 route is available") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.9") + + +def test_bgp_ipv4_recursive_routes(): + """ + Check that R1 has received the recursive routes, and duplicate nexthops are in zebra, but are not installed + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ipv4_prefix_recursive_with_multiple_nexthops("192.0.2.8/32", "192.0.2.9") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.8") + + +def test_bgp_ipv4_recursive_routes_when_no_mpath(): + """ + Unconfigure multipath ibgp + Check that duplicate nexthops are not in zebra + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + router bgp + address family ipv4 unicast + maximum-paths ibgp 1 + """, + isjson=False, + ) + tgen.gears["r1"].vtysh_cmd("clear bgp ipv4 *") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32", multipath=False) + + check_ipv4_prefix_recursive_with_multiple_nexthops( + "192.0.2.8/32", "192.0.2.9", multipath=False + ) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/r1/frr.conf b/tests/topotests/bgp_dynamic_capability/r1/frr.conf index 50280a912669..c9594626f50f 100644 --- a/tests/topotests/bgp_dynamic_capability/r1/frr.conf +++ b/tests/topotests/bgp_dynamic_capability/r1/frr.conf @@ -12,4 +12,11 @@ router bgp 65001 neighbor 192.168.1.2 timers 1 3 neighbor 192.168.1.2 timers connect 1 neighbor 192.168.1.2 capability dynamic + ! + address-family ipv4 unicast + neighbor 192.168.1.2 addpath-tx-all-paths + neighbor 192.168.1.2 addpath-rx-paths-limit 10 + exit-address-family +! +ip prefix-list r2 seq 5 permit 10.10.10.10/32 ! diff --git a/tests/topotests/bgp_dynamic_capability/r2/frr.conf b/tests/topotests/bgp_dynamic_capability/r2/frr.conf index 16b83a5c58d8..3cc1f1fc392c 100644 --- a/tests/topotests/bgp_dynamic_capability/r2/frr.conf +++ b/tests/topotests/bgp_dynamic_capability/r2/frr.conf @@ -3,6 +3,7 @@ ! int lo ip address 10.10.10.10/32 + ip address 10.10.10.20/32 ! int r2-eth0 ip address 192.168.1.2/24 @@ -15,6 +16,7 @@ router bgp 65002 neighbor 192.168.1.1 timers 1 3 neighbor 192.168.1.1 timers connect 1 neighbor 192.168.1.1 capability dynamic + neighbor 192.168.1.1 addpath-rx-paths-limit 20 ! address-family ipv4 unicast redistribute connected diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py new file mode 100644 index 000000000000..91df89b1b526 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py @@ -0,0 +1,313 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if Addpath/Paths-Limit capabilities are adjusted dynamically. +T1: Enable Addpath/Paths-Limit capabilities and check if they are exchanged dynamically +T2: Disable paths limit and check if it's exchanged dynamically +T3: Disable Addpath capability RX and check if it's exchanged dynamically +T4: Disable Addpath capability and check if it's exchanged dynamically +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_addpath_paths_limit(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "addPath": { + "ipv4Unicast": { + "txAdvertisedAndReceived": False, + "txAdvertised": True, + "txReceived": False, + "rxAdvertisedAndReceived": True, + "rxAdvertised": True, + "rxReceived": True, + } + }, + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 10, + "receivedPathsLimit": 20, + } + }, + }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + #### + # T1: Enable Addpath/Paths-Limit capabilities and check if they are exchanged dynamically + #### + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + neighbor 192.168.1.1 addpath-tx-all-paths + neighbor 192.168.1.1 addpath-rx-paths-limit 21 + """ + ) + + def _enable_addpath_paths_limit(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "addPath": { + "ipv4Unicast": { + "txAdvertisedAndReceived": True, + "txAdvertised": True, + "txReceived": True, + "rxAdvertisedAndReceived": True, + "rxAdvertised": True, + "rxReceived": True, + } + }, + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 10, + "receivedPathsLimit": 21, + } + }, + }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, + "messageStats": { + "notificationsRecv": 0, + "notificationsSent": 0, + "capabilityRecv": 2, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _enable_addpath_paths_limit, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Something went wrong when enabling Addpath/Paths-Limit capabilities" + + ### + # T2: Disable paths limit and check if it's exchanged dynamically + ### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no neighbor 192.168.1.1 addpath-rx-paths-limit + """ + ) + + def _disable_paths_limit(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "addPath": { + "ipv4Unicast": { + "txAdvertisedAndReceived": True, + "txAdvertised": True, + "txReceived": True, + "rxAdvertisedAndReceived": True, + "rxAdvertised": True, + "rxReceived": True, + } + }, + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 10, + "receivedPathsLimit": 0, + } + }, + }, + "messageStats": { + "notificationsRecv": 0, + "notificationsSent": 0, + "capabilityRecv": 3, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _disable_paths_limit, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Something went wrong after disabling paths limit" + + ### + # T3: Disable Addpath capability RX and check if it's exchanged dynamically + ### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + neighbor 192.168.1.1 disable-addpath-rx + """ + ) + + def _disable_addpath_rx(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "addPath": { + "ipv4Unicast": { + "txAdvertisedAndReceived": True, + "txAdvertised": True, + "txReceived": True, + "rxAdvertisedAndReceived": False, + "rxAdvertised": True, + "rxReceived": False, + } + }, + "pathsLimit": { + "ipv4Unicast": { + "advertisedAndReceived": True, + "advertisedPathsLimit": 10, + "receivedPathsLimit": 0, + } + }, + }, + "messageStats": { + "notificationsRecv": 0, + "notificationsSent": 0, + "capabilityRecv": 4, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _disable_addpath_rx, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Something went wrong after disabling Addpath RX flags" + + ### + # T4: Disable Addpath capability and check if it's exchanged dynamically + ### + r1.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no neighbor 192.168.1.2 addpath-tx-all-paths + """ + ) + + def _disable_addpath(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "addPath": { + "ipv4Unicast": { + "txAdvertisedAndReceived": False, + "txAdvertised": False, + "txReceived": True, + "rxAdvertisedAndReceived": False, + "rxAdvertised": True, + "rxReceived": False, + } + }, + }, + "messageStats": { + "notificationsRecv": 0, + "notificationsSent": 0, + "capabilitySent": 1, + "capabilityRecv": 4, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _disable_addpath, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Something went wrong when disabling Addpath capability" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py new file mode 100644 index 000000000000..bf05ce8edd78 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if fqdn capability is exchanged dynamically. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dynamic_capability_fqdn(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "hostName": { + "advHostName": "r1", + "rcvHostName": "r2", + }, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + step("Disable fqdn capability and check if it's exchanged dynamically") + + # Clear message stats to check if we receive a notification or not after we + # disable fqdn capability. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r1.vtysh_cmd( + """ + configure terminal + router bgp + no neighbor 192.168.1.2 capability fqdn + """ + ) + + def _bgp_check_if_fqdn_capability_is_absent(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "hostName": { + "advHostName": None, + "rcvHostName": "r2", + }, + }, + "messageStats": { + "notificationsRecv": 0, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_fqdn_capability_is_absent, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to disable fqdn capability" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py index db1eb2723b35..514b29cd705c 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py @@ -12,24 +12,21 @@ """ import os -import re import sys import json import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -68,6 +65,11 @@ def _bgp_converge(): "gracefulRestart": "advertisedAndReceived", "longLivedGracefulRestart": "advertisedAndReceived", }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, "gracefulRestartInfo": { "nBit": True, "timers": { @@ -116,6 +118,11 @@ def _bgp_check_if_session_not_reset_after_changing_gr_settings(): "gracefulRestart": "advertisedAndReceived", "longLivedGracefulRestart": "advertisedAndReceived", }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, "gracefulRestartInfo": { "nBit": True, "timers": { @@ -149,7 +156,7 @@ def _bgp_check_if_session_not_reset_after_changing_gr_settings(): ) # Clear message stats to check if we receive a notification or not after we - # change the settings fo LLGR. + # disable graceful-restart notification support. r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") r2.vtysh_cmd( """ @@ -197,6 +204,40 @@ def _bgp_check_if_session_not_reset_after_changing_notification(): result is None ), "Session was reset after changing Graceful-Restart notification support" + # Clear message stats to check if we receive a notification or not after we + # disable GR. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r1.vtysh_cmd( + """ + configure terminal + router bgp + bgp graceful-restart-disable + """ + ) + + def _bgp_check_if_gr_llgr_capability_is_absent(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "gracefulRestartCapability": "received", + "longLivedGracefulRestart": "received", + }, + "messageStats": { + "notificationsRecv": 0, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_llgr_capability_is_absent, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to disable GR/LLGR capabilities" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py new file mode 100644 index 000000000000..39e7ded1e60a --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if ORF capability is adjusted dynamically. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dynamic_capability_orf(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + step( + "Apply incoming prefix-list to r1 and check if we advertise only 10.10.10.20/32 from r2" + ) + + # Clear message stats to check if we receive a notification or not after we + # enable ORF capability. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r1.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + neighbor 192.168.1.2 prefix-list r2 in + neighbor 192.168.1.2 capability orf prefix-list both + """ + ) + + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + neighbor 192.168.1.1 capability orf prefix-list both + """ + ) + + def _bgp_check_if_session_not_reset(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + }, + "messageStats": { + "notificationsRecv": 0, + "notificationsSent": 0, + "capabilityRecv": 1, + "capabilitySent": 1, + }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 1, + "afDependentCap": { + "orfPrefixList": { + "sendMode": "advertisedAndReceived", + "recvMode": "advertisedAndReceived", + } + }, + "incomingUpdatePrefixFilterList": "r2", + } + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_session_not_reset, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Session was reset after setting up ORF capability" + + r1.vtysh_cmd( + """ + configure terminal + ip prefix-list r2 seq 5 permit 10.10.10.20/32 + """ + ) + + def _bgp_check_if_we_send_correct_prefix(): + output = json.loads( + r2.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.1 advertised-routes json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.20/32": { + "valid": True, + }, + }, + "totalPrefixCounter": 1, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_we_send_correct_prefix, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Only 10.10.10.20/32 SHOULD be advertised due to ORF filtering" + + # Clear message stats to check if we receive a notification or not after we + # disable ORF capability. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r1.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no neighbor 192.168.1.2 capability orf prefix-list both + """ + ) + + def _bgp_check_if_orf_capability_is_absent(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + }, + "messageStats": { + "notificationsRecv": 0, + "notificationsSent": 0, + }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 1, + "afDependentCap": { + "orfPrefixList": { + "sendMode": "received", + "recvMode": "received", + } + }, + } + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_orf_capability_is_absent, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to disable ORF capability" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py index da45110e3936..7d36634728b9 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py @@ -10,24 +10,21 @@ """ import os -import re import sys import json import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -66,6 +63,11 @@ def _bgp_converge(): "neighborCapabilities": { "dynamic": "advertisedAndReceived", }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, } } return topotest.json_cmp(output, expected) @@ -79,7 +81,7 @@ def _bgp_converge(): step("Set local-role and check if it's exchanged dynamically") # Clear message stats to check if we receive a notification or not after we - # change the settings fo LLGR. + # change the role. r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") r1.vtysh_cmd( """ @@ -108,6 +110,11 @@ def _bgp_check_if_session_not_reset(): "dynamic": "advertisedAndReceived", "role": "advertisedAndReceived", }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, "messageStats": { "notificationsRecv": 0, "capabilityRecv": 1, @@ -122,6 +129,41 @@ def _bgp_check_if_session_not_reset(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Session was reset after setting role capability" + # Clear message stats to check if we receive a notification or not after we + # change the role. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r1.vtysh_cmd( + """ + configure terminal + router bgp + no neighbor 192.168.1.2 local-role customer + """ + ) + + def _bgp_check_if_role_capability_is_absent(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "localRole": "undefined", + "remoteRole": "provider", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "role": "received", + }, + "messageStats": { + "notificationsRecv": 0, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_role_capability_is_absent, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to disable role capability" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py index d1069a876bfe..591fc5a81782 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -16,18 +16,16 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -68,6 +66,11 @@ def _bgp_converge(): "receivedSoftwareVersion": None, }, }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, } } return topotest.json_cmp(output, expected) @@ -81,7 +84,7 @@ def _bgp_converge(): step("Enable software version capability and check if it's exchanged dynamically") # Clear message stats to check if we receive a notification or not after we - # change the settings fo LLGR. + # enable software-version capability. r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") r1.vtysh_cmd( """ @@ -111,7 +114,7 @@ def _bgp_software_version(): if not adv and not rcv: return "" - pattern = "FRRouting/\\d.+" + pattern = "^FRRouting/\\d.+" if re.search(pattern, adv) and re.search(pattern, rcv): return adv, rcv except: @@ -129,6 +132,11 @@ def _bgp_software_version(): "receivedSoftwareVersion": rcv, }, }, + "addressFamilyInfo": { + "ipv4Unicast": { + "acceptedPrefixCounter": 3, + } + }, "messageStats": { "notificationsRecv": 0, "capabilityRecv": 1, @@ -145,6 +153,41 @@ def _bgp_software_version(): result is None ), "Session was reset after enabling software version capability" + # Clear message stats to check if we receive a notification or not after we + # disable software-version capability. + r1.vtysh_cmd("clear bgp 192.168.1.2 message-stats") + r1.vtysh_cmd( + """ + configure terminal + router bgp + no neighbor 192.168.1.2 capability software-version + """ + ) + + def _bgp_check_if_software_version_capability_is_absent(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "softwareVersion": { + "advertisedSoftwareVersion": None, + }, + }, + "messageStats": { + "notificationsRecv": 0, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_software_version_capability_is_absent, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to disable software version capability" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py index 34f7dc8cd4b9..a4ac249cb747 100644 --- a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py +++ b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py @@ -35,8 +35,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 4): @@ -54,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -92,7 +90,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, r3) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(r3) @@ -102,7 +100,7 @@ def _bgp_nh_unchanged(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_nh_unchanged, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Wrong next-hop in "{}"'.format(r2) diff --git a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py index 6e3b2859c431..f7c0f70445de 100644 --- a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py +++ b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py @@ -71,7 +71,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,31 +125,31 @@ def _bgp_advertised_routes(router): # Scenario 1. logger.info("Scenario 1: r2 receives 192.168.255.1/32 from r1") test_func = functools.partial(_bgp_converge, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r2)" test_func = functools.partial(_bgp_has_routes, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r2 does not receive 192.168.255.1/32" # Scenario 2. logger.info("Scenario 2: r3 must not send 192.168.255.1/32 to r4") test_func = functools.partial(_bgp_converge, "r4") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r4)" test_func = functools.partial(_bgp_advertised_routes, "r3") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r3 announced 192.168.255.1/32 to r4" # Scenario 3. logger.info("Scenario 3: r6 receives 192.168.255.1/32 from r5 (iBGP)") test_func = functools.partial(_bgp_converge, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r6)" test_func = functools.partial(_bgp_has_routes, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r6 does not receive 192.168.255.1/32" diff --git a/tests/topotests/bgp_ecmp_topo1/exabgp.env b/tests/topotests/bgp_ecmp_topo1/exabgp.env index a328e0496289..ec978c66e76e 100644 --- a/tests/topotests/bgp_ecmp_topo1/exabgp.env +++ b/tests/topotests/bgp_ecmp_topo1/exabgp.env @@ -1,5 +1,6 @@ [exabgp.api] +ack = false encoder = text highres = false respawn = false diff --git a/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer1/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer1/exabgp.cfg index 2d0ca89f0fad..97a024ce9620 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer1/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer1/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 1 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 1"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 1 10; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.101; - local-address 10.0.1.101; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 1; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.101; + local-address 10.0.1.101; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer10/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer10/exabgp.cfg index 0c842a0e7fbe..e318162a1faf 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer10/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer10/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 10 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 10"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 10 10; + encoder text; +} - neighbor 10.0.2.1 { - router-id 10.0.2.110; - local-address 10.0.2.110; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 10; + encoder text; +} +neighbor 10.0.2.1 { + router-id 10.0.2.110; + local-address 10.0.2.110; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer11/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer11/exabgp.cfg index 936dc572bdf6..ea5bdcce804a 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer11/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer11/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 11 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 11"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 11 10; + encoder text; +} - neighbor 10.0.3.1 { - router-id 10.0.3.111; - local-address 10.0.3.111; - local-as 111; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 11; + encoder text; +} +neighbor 10.0.3.1 { + router-id 10.0.3.111; + local-address 10.0.3.111; + local-as 111; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer12/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer12/exabgp.cfg index 56b33eae8ebf..81fb5035f756 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer12/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer12/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 12 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 12"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 12 10; + encoder text; +} - neighbor 10.0.3.1 { - router-id 10.0.3.112; - local-address 10.0.3.112; - local-as 112; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 12; + encoder text; +} +neighbor 10.0.3.1 { + router-id 10.0.3.112; + local-address 10.0.3.112; + local-as 112; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer13/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer13/exabgp.cfg index b933ffb5cfa1..40078411ec10 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer13/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer13/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 13 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 13"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 13 10; + encoder text; +} - neighbor 10.0.3.1 { - router-id 10.0.3.113; - local-address 10.0.3.113; - local-as 113; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 13; + encoder text; +} +neighbor 10.0.3.1 { + router-id 10.0.3.113; + local-address 10.0.3.113; + local-as 113; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer14/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer14/exabgp.cfg index bcfa41eb2e62..afb8741636d1 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer14/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer14/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 14 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 14"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 14 10; + encoder text; +} - neighbor 10.0.3.1 { - router-id 10.0.3.114; - local-address 10.0.3.114; - local-as 114; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 14; + encoder text; +} +neighbor 10.0.3.1 { + router-id 10.0.3.114; + local-address 10.0.3.114; + local-as 114; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer15/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer15/exabgp.cfg index 022e8357980d..9a4ca7f695b8 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer15/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer15/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 15 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 15"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 15 10; + encoder text; +} - neighbor 10.0.3.1 { - router-id 10.0.3.115; - local-address 10.0.3.115; - local-as 115; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 15; + encoder text; +} +neighbor 10.0.3.1 { + router-id 10.0.3.115; + local-address 10.0.3.115; + local-as 115; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer16/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer16/exabgp.cfg index 0649202f1ffc..a0bb88a3f3a3 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer16/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer16/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 16 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 16"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 16 10; + encoder text; +} - neighbor 10.0.4.1 { - router-id 10.0.4.116; - local-address 10.0.4.116; - local-as 116; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 16; + encoder text; +} +neighbor 10.0.4.1 { + router-id 10.0.4.116; + local-address 10.0.4.116; + local-as 116; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer17/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer17/exabgp.cfg index 0aeeed9d952d..870d33d45599 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer17/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer17/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 17 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 17"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 17 10; + encoder text; +} - neighbor 10.0.4.1 { - router-id 10.0.4.117; - local-address 10.0.4.117; - local-as 117; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 17; + encoder text; +} +neighbor 10.0.4.1 { + router-id 10.0.4.117; + local-address 10.0.4.117; + local-as 117; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer18/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer18/exabgp.cfg index 352c030eda7b..c5a1ca62e416 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer18/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer18/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 18 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 18"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 18 10; + encoder text; +} - neighbor 10.0.4.1 { - router-id 10.0.4.118; - local-address 10.0.4.118; - local-as 118; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 18; + encoder text; +} +neighbor 10.0.4.1 { + router-id 10.0.4.118; + local-address 10.0.4.118; + local-as 118; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer19/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer19/exabgp.cfg index 9913c226f671..f662ccf93e2b 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer19/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer19/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 19 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 19"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 19 10; + encoder text; +} - neighbor 10.0.4.1 { - router-id 10.0.4.119; - local-address 10.0.4.119; - local-as 119; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 19; + encoder text; +} +neighbor 10.0.4.1 { + router-id 10.0.4.119; + local-address 10.0.4.119; + local-as 119; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer2/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer2/exabgp.cfg index 46b436d2af05..673d6ec0eef9 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer2/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer2/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 2 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 2"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 2 10; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.102; - local-address 10.0.1.102; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 2; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.102; + local-address 10.0.1.102; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer20/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer20/exabgp.cfg index 17fb816a75f8..5ea2c91de142 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer20/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer20/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 20 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 20"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 20 10; + encoder text; +} - neighbor 10.0.4.1 { - router-id 10.0.4.120; - local-address 10.0.4.120; - local-as 120; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 20; + encoder text; +} +neighbor 10.0.4.1 { + router-id 10.0.4.120; + local-address 10.0.4.120; + local-as 120; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer3/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer3/exabgp.cfg index acd57756b9df..47a25cab223c 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer3/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer3/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 3 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 3"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 3 10; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.103; - local-address 10.0.1.103; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 3; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.103; + local-address 10.0.1.103; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer4/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer4/exabgp.cfg index 4c9a989b5ad7..376ac5f37dca 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer4/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer4/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 4 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 4"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 4 10; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.104; - local-address 10.0.1.104; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 4; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.104; + local-address 10.0.1.104; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer5/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer5/exabgp.cfg index eba2aae3784f..878d728de645 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer5/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer5/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 5 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 5"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 5 10; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.105; - local-address 10.0.1.105; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 5; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.105; + local-address 10.0.1.105; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer6/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer6/exabgp.cfg index 38b6af0e8589..fc702674cf48 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer6/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer6/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 6 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 6"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 6 10; + encoder text; +} - neighbor 10.0.2.1 { - router-id 10.0.2.106; - local-address 10.0.2.106; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 6; + encoder text; +} +neighbor 10.0.2.1 { + router-id 10.0.2.106; + local-address 10.0.2.106; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer7/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer7/exabgp.cfg index 7631e43750ab..09827a89024b 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer7/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer7/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 7 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 7"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 7 10; + encoder text; +} - neighbor 10.0.2.1 { - router-id 10.0.2.107; - local-address 10.0.2.107; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 7; + encoder text; +} +neighbor 10.0.2.1 { + router-id 10.0.2.107; + local-address 10.0.2.107; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer8/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer8/exabgp.cfg index 1cd1cd902410..37c01dabb790 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer8/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer8/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 8 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 8"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 8 10; + encoder text; +} - neighbor 10.0.2.1 { - router-id 10.0.2.108; - local-address 10.0.2.108; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 8; + encoder text; +} +neighbor 10.0.2.1 { + router-id 10.0.2.108; + local-address 10.0.2.108; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py index 6bef35508f9b..1a8e6bfe2ffd 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer9/exabgp.cfg b/tests/topotests/bgp_ecmp_topo1/peer9/exabgp.cfg index 5771553962ce..8fb5c58b6b97 100644 --- a/tests/topotests/bgp_ecmp_topo1/peer9/exabgp.cfg +++ b/tests/topotests/bgp_ecmp_topo1/peer9/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 9 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 9"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 9 10; + encoder text; +} - neighbor 10.0.2.1 { - router-id 10.0.2.109; - local-address 10.0.2.109; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 9; + encoder text; +} +neighbor 10.0.2.1 { + router-id 10.0.2.109; + local-address 10.0.2.109; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py b/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py index 97751ec8cfbe..7af3f48ff643 100644 --- a/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py +++ b/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # SPDX-License-Identifier: ISC # diff --git a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py index b347042dcf32..5991f2e7ca17 100644 --- a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py @@ -106,7 +106,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -153,7 +153,6 @@ def teardown_module(): def static_or_nw(tgen, topo, tc_name, test_type, dut): - if test_type == "redist_static": input_dict_static = { dut: { @@ -363,7 +362,6 @@ def test_ecmp_remove_redistribute_static(request): reset_config_on_routers(tgen) static_or_nw(tgen, topo, tc_name, "redist_static", "r2") for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" @@ -406,7 +404,6 @@ def test_ecmp_remove_redistribute_static(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff b/tests/topotests/bgp_evpn_maximum_prefix/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff rename to tests/topotests/bgp_evpn_maximum_prefix/__init__.py diff --git a/tests/topotests/bgp_evpn_maximum_prefix/c1/frr.conf b/tests/topotests/bgp_evpn_maximum_prefix/c1/frr.conf new file mode 100644 index 000000000000..7476a3723db5 --- /dev/null +++ b/tests/topotests/bgp_evpn_maximum_prefix/c1/frr.conf @@ -0,0 +1,4 @@ +! +int c1-eth0 + ip address 192.168.0.1/24 +! diff --git a/tests/topotests/bgp_evpn_maximum_prefix/c2/frr.conf b/tests/topotests/bgp_evpn_maximum_prefix/c2/frr.conf new file mode 100644 index 000000000000..a203daae05df --- /dev/null +++ b/tests/topotests/bgp_evpn_maximum_prefix/c2/frr.conf @@ -0,0 +1,4 @@ +! +int c2-eth0 + ip address 192.168.0.2/24 +! diff --git a/tests/topotests/bgp_evpn_maximum_prefix/r1/frr.conf b/tests/topotests/bgp_evpn_maximum_prefix/r1/frr.conf new file mode 100644 index 000000000000..0534518cfb18 --- /dev/null +++ b/tests/topotests/bgp_evpn_maximum_prefix/r1/frr.conf @@ -0,0 +1,30 @@ +! +!debug bgp neighbor +!debug route-map detail +! +vni 10 +! +int lo + ip address 10.10.10.1/32 +! +int r1-eth1 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + network 10.10.10.10/32 + exit-address-family + ! + address-family l2vpn evpn + neighbor 192.168.1.2 activate + advertise-all-vni + advertise ipv4 unicast + exit-address-family +! diff --git a/tests/topotests/bgp_evpn_maximum_prefix/r2/frr.conf b/tests/topotests/bgp_evpn_maximum_prefix/r2/frr.conf new file mode 100644 index 000000000000..353302b9e770 --- /dev/null +++ b/tests/topotests/bgp_evpn_maximum_prefix/r2/frr.conf @@ -0,0 +1,25 @@ +! +!debug bgp neighbor +! +int lo + ip address 10.10.10.2/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family + ! + address-family l2vpn evpn + neighbor 192.168.1.1 activate + neighbor 192.168.1.1 maximum-prefix 2 + advertise-all-vni + exit-address-family +! diff --git a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py new file mode 100644 index 000000000000..876c205f1926 --- /dev/null +++ b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("c1", "r1"), "s2": ("r1", "r2"), "s3": ("r2", "c2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + tgen.net["r1"].cmd( + """ +ip link add vxlan10 type vxlan id 10 dstport 4789 local 10.10.10.1 nolearning +ip link add name br10 type bridge +ip link set dev vxlan10 master br10 +ip link set dev r1-eth0 master br10 +ip link set up dev br10 +ip link set up dev vxlan10""" + ) + + tgen.net["r2"].cmd( + """ +ip link add vxlan10 type vxlan id 10 dstport 4789 local 10.10.10.2 nolearning +ip link add name br10 type bridge +ip link set dev vxlan10 master br10 +ip link set dev r2-eth1 master br10 +ip link set up dev br10 +ip link set up dev vxlan10""" + ) + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_evpn_maximum_prefix(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp l2vpn evpn summary failed json")) + expected = { + "peers": { + "192.168.1.1": { + "lastNotificationReason": "Cease/Maximum Number of Prefixes Reached", + "lastResetDueTo": "BGP Notification send", + } + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "Can't limit maximum-prefixes for EVPN routes" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf b/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf index 33b6d08aba76..d24651789875 100644 --- a/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/leaf1/evpn.conf @@ -1,6 +1,7 @@ frr defaults datacenter ! router bgp 65101 + timers bgp 3 10 bgp router-id 192.168.100.13 no bgp ebgp-requires-policy neighbor 192.168.50.1 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf b/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf index 428998b0fe0f..6855a436d49b 100644 --- a/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/leaf2/evpn.conf @@ -1,6 +1,7 @@ frr defaults datacenter ! router bgp 65101 + timers bgp 3 10 bgp router-id 192.168.100.14 no bgp ebgp-requires-policy neighbor 192.168.61.1 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/spine1/evpn.conf b/tests/topotests/bgp_evpn_mh/spine1/evpn.conf index b9fce46ea4d1..7d6fef699dea 100644 --- a/tests/topotests/bgp_evpn_mh/spine1/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/spine1/evpn.conf @@ -1,6 +1,7 @@ frr defaults datacenter ! router bgp 65001 + timers bgp 3 10 bgp router-id 192.168.100.13 no bgp ebgp-requires-policy neighbor 192.168.50.2 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/spine2/evpn.conf b/tests/topotests/bgp_evpn_mh/spine2/evpn.conf index 1430e10b6865..c651ada686e0 100644 --- a/tests/topotests/bgp_evpn_mh/spine2/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/spine2/evpn.conf @@ -1,6 +1,7 @@ frr defaults datacenter ! router bgp 65001 + timers bgp 3 10 bgp router-id 192.168.100.14 no bgp ebgp-requires-policy neighbor 192.168.60.2 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py index ec5227809e92..ba2fb62661d2 100644 --- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py +++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py @@ -37,8 +37,6 @@ # Required to instantiate the topology builder class. from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] - ##################################################### ## ## Network Topology Definition @@ -264,7 +262,7 @@ def config_bridge(node): node.run("ip link set dev bridge type bridge mcast_snooping 0") node.run("ip link set dev bridge type bridge vlan_stats_enabled 1") node.run("ip link set dev bridge up") - node.run("/sbin/bridge vlan add vid 1000 dev bridge") + node.run("/sbin/bridge vlan add vid 1000 dev bridge self") def config_vxlan(node, node_ip): @@ -389,13 +387,6 @@ def setup_module(module): tors.append("torm22") config_tors(tgen, tors) - hosts = [] - hosts.append("hostd11") - hosts.append("hostd12") - hosts.append("hostd21") - hosts.append("hostd22") - config_hosts(tgen, hosts) - # tgen.mininet_cli() # This is a sample of configuration loading. router_list = tgen.routers() @@ -410,6 +401,13 @@ def setup_module(module): TopoRouter.RD_BGP, os.path.join(CWD, "{}/evpn.conf".format(rname)) ) tgen.start_router() + + hosts = [] + hosts.append("hostd11") + hosts.append("hostd12") + hosts.append("hostd21") + hosts.append("hostd22") + config_hosts(tgen, hosts) # tgen.mininet_cli() @@ -457,7 +455,7 @@ def check_remote_es(esi, vtep_ips, dut_name, down_vteps): else: tor_ips_rack = tor_ips_rack_1 - for tor_name, tor_ip in tor_ips_rack.items(): + for _, tor_ip in tor_ips_rack.items(): remote_ips.append(tor_ip) # remove down VTEPs from the remote check list @@ -634,6 +632,7 @@ def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None): out = dut.vtysh_cmd("show evpn mac vni %d mac %s json" % (vni, mac)) + tmp_esi = None mac_js = json.loads(out) for mac, info in mac_js.items(): tmp_esi = info.get("esi", "") @@ -642,7 +641,15 @@ def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None): if tmp_esi == esi and tmp_m_type == m_type and intf == intf: return None - return "invalid vni %d mac %s out %s" % (vni, mac, mac_js) + return "invalid vni %d mac %s expected esi %s, %s m_type %s and intf %s out %s" % ( + vni, + mac, + tmp_esi, + esi, + m_type, + intf, + mac_js, + ) def test_evpn_mac(): diff --git a/tests/topotests/bgp_evpn_mh/torm11/evpn.conf b/tests/topotests/bgp_evpn_mh/torm11/evpn.conf index 2c1c695a183a..62b7ec58558e 100644 --- a/tests/topotests/bgp_evpn_mh/torm11/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm11/evpn.conf @@ -7,6 +7,7 @@ frr defaults datacenter ! ! router bgp 65002 + timers bgp 3 10 bgp router-id 192.168.100.15 no bgp ebgp-requires-policy neighbor 192.168.1.1 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/torm12/evpn.conf b/tests/topotests/bgp_evpn_mh/torm12/evpn.conf index 8b0ce1d98fe6..3ceb974c473d 100644 --- a/tests/topotests/bgp_evpn_mh/torm12/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm12/evpn.conf @@ -7,6 +7,7 @@ frr defaults datacenter ! ! router bgp 65003 + timers bgp 3 10 bgp router-id 192.168.100.16 no bgp ebgp-requires-policy neighbor 192.168.2.1 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/torm21/evpn.conf b/tests/topotests/bgp_evpn_mh/torm21/evpn.conf index 5247dc1ebd9a..ecaf85ddb7d6 100644 --- a/tests/topotests/bgp_evpn_mh/torm21/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm21/evpn.conf @@ -7,6 +7,7 @@ frr defaults datacenter ! ! router bgp 65004 + timers bgp 3 10 bgp router-id 192.168.100.17 no bgp ebgp-requires-policy neighbor 192.168.3.1 remote-as external diff --git a/tests/topotests/bgp_evpn_mh/torm22/evpn.conf b/tests/topotests/bgp_evpn_mh/torm22/evpn.conf index ec5636017658..c7e152498cae 100644 --- a/tests/topotests/bgp_evpn_mh/torm22/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm22/evpn.conf @@ -6,6 +6,7 @@ frr defaults datacenter ! debug bgp zebra ! router bgp 65005 + timers bgp 3 10 bgp router-id 192.168.100.18 no bgp ebgp-requires-policy neighbor 192.168.4.1 remote-as external diff --git a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py index 10662692927d..d441a256fda4 100755 --- a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py +++ b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py @@ -58,7 +58,6 @@ step, write_test_header, write_test_footer, - generate_support_bundle, ) # Required to instantiate the topology builder class. @@ -180,7 +179,7 @@ def setup_module(mod): pe.cmd_raises("sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)) # For all registered routers, load the zebra configuration file - for (name, router) in tgen.routers().items(): + for name, router in tgen.routers().items(): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(name)) ) @@ -231,18 +230,18 @@ def evpn_gateway_ip_show_op_check(trigger=" "): "zebra_vrf_ipv6": "show ipv6 route vrf vrf-blue json", } - for (name, pe) in tgen.gears.items(): + for name, pe in tgen.gears.items(): if name not in PES: continue - for (cmd_key, command) in show_commands.items(): + for cmd_key, command in show_commands.items(): expected_op_file = "{0}/{1}/{2}_{3}.json".format( CWD, name, cmd_key, trigger ) expected_op = json.loads(open(expected_op_file).read()) test_func = partial(topotest.router_json_cmp, pe, command, expected_op) - ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command) if result is not None: return result, assertmsg @@ -277,8 +276,6 @@ def test_evpn_gateway_ip_basic_topo(request): result, assertmsg = evpn_gateway_ip_show_op_check("base") - if result is not None: - generate_support_bundle() assert result is None, assertmsg write_test_footer(tc_name) @@ -319,8 +316,6 @@ def test_evpn_gateway_ip_flap_rt5(request): ) result, assertmsg = evpn_gateway_ip_show_op_check("no_rt5") - if result is not None: - generate_support_bundle() assert result is None, assertmsg step("Advertise type-5 routes again") @@ -339,8 +334,6 @@ def test_evpn_gateway_ip_flap_rt5(request): ) result, assertmsg = evpn_gateway_ip_show_op_check("base") - if result is not None: - generate_support_bundle() assert result is None, assertmsg @@ -371,8 +364,6 @@ def test_evpn_gateway_ip_flap_rt2(request): pe1.cmd_raises("ip link set dev vxlan100 down") result, assertmsg = evpn_gateway_ip_show_op_check("no_rt2") - if result is not None: - generate_support_bundle() assert result is None, assertmsg step("Bring up VxLAN interface at PE1 and advertise type-2 routes again") @@ -380,8 +371,6 @@ def test_evpn_gateway_ip_flap_rt2(request): pe1.cmd_raises("ip link set dev vxlan100 up") result, assertmsg = evpn_gateway_ip_show_op_check("base") - if result is not None: - generate_support_bundle() assert result is None, assertmsg write_test_footer(tc_name) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff b/tests/topotests/bgp_evpn_route_map_match/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff rename to tests/topotests/bgp_evpn_route_map_match/__init__.py diff --git a/tests/topotests/bgp_evpn_route_map_match/c1/frr.conf b/tests/topotests/bgp_evpn_route_map_match/c1/frr.conf new file mode 100644 index 000000000000..7476a3723db5 --- /dev/null +++ b/tests/topotests/bgp_evpn_route_map_match/c1/frr.conf @@ -0,0 +1,4 @@ +! +int c1-eth0 + ip address 192.168.0.1/24 +! diff --git a/tests/topotests/bgp_evpn_route_map_match/c2/frr.conf b/tests/topotests/bgp_evpn_route_map_match/c2/frr.conf new file mode 100644 index 000000000000..a203daae05df --- /dev/null +++ b/tests/topotests/bgp_evpn_route_map_match/c2/frr.conf @@ -0,0 +1,4 @@ +! +int c2-eth0 + ip address 192.168.0.2/24 +! diff --git a/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf b/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf new file mode 100644 index 000000000000..4347052c5e75 --- /dev/null +++ b/tests/topotests/bgp_evpn_route_map_match/r1/frr.conf @@ -0,0 +1,44 @@ +! +!debug bgp neighbor +!debug route-map detail +! +vni 10 +! +int lo + ip address 10.10.10.1/32 +! +int r1-eth1 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + network 10.10.10.10/32 + exit-address-family + ! + address-family l2vpn evpn + neighbor 192.168.1.2 activate + neighbor 192.168.1.2 route-map r2 out + advertise-all-vni + advertise ipv4 unicast + exit-address-family +! +route-map r2 deny 10 + match evpn route-type macip +! +route-map r2 deny 20 + match ip address prefix-list pl + match evpn route-type prefix +! +route-map r2 permit 30 +! +ip prefix-list pl seq 5 permit 192.168.1.0/24 +ip prefix-list pl seq 10 permit 10.10.10.1/32 +ip prefix-list pl seq 15 permit 10.10.10.2/32 +! diff --git a/tests/topotests/bgp_evpn_route_map_match/r2/frr.conf b/tests/topotests/bgp_evpn_route_map_match/r2/frr.conf new file mode 100644 index 000000000000..9ed298d8fe16 --- /dev/null +++ b/tests/topotests/bgp_evpn_route_map_match/r2/frr.conf @@ -0,0 +1,24 @@ +! +!debug bgp neighbor +! +int lo + ip address 10.10.10.2/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family + ! + address-family l2vpn evpn + neighbor 192.168.1.1 activate + advertise-all-vni + exit-address-family +! diff --git a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py new file mode 100644 index 000000000000..36c79d6b2b36 --- /dev/null +++ b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if route-map match by EVPN route-type works. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("c1", "r1"), "s2": ("r1", "r2"), "s3": ("r2", "c2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + tgen.net["r1"].cmd( + """ +ip link add vxlan10 type vxlan id 10 dstport 4789 local 10.10.10.1 nolearning +ip link add name br10 type bridge +ip link set dev vxlan10 master br10 +ip link set dev r1-eth0 master br10 +ip link set up dev br10 +ip link set up dev vxlan10""" + ) + + tgen.net["r2"].cmd( + """ +ip link add vxlan10 type vxlan id 10 dstport 4789 local 10.10.10.2 nolearning +ip link add name br10 type bridge +ip link set dev vxlan10 master br10 +ip link set dev r2-eth1 master br10 +ip link set up dev br10 +ip link set up dev vxlan10""" + ) + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_evpn_route_map_match_route_type(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads( + r1.vtysh_cmd( + "show bgp l2vpn evpn neighbor 192.168.1.2 advertised-routes json" + ) + ) + expected = { + "advertisedRoutes": { + "10.10.10.1:1": { + "[5]:[0]:[32]:[10.10.10.10]": { + "valid": True, + } + }, + "10.10.10.2:2": { + "[3]:[0]:[32]:[10.10.10.2]": { + "valid": True, + } + }, + }, + "totalPrefixCounter": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "Filtered EVPN routes should not be advertised" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf index ccbeae6ed78e..c8c4faf222cc 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf @@ -20,7 +20,11 @@ router bgp 65000 vrf r1-vrf-101 address-family ipv4 unicast network 192.168.102.21/32 exit-address-family + address-family ipv6 unicast + network fd00::1/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf index 4f1804c67657..c3d508c2b628 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf @@ -17,6 +17,7 @@ interface r1-eth0 ! interface loop101 vrf r1-vrf-101 ip address 192.168.102.21/32 + ipv6 address fd00::1/128 ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf index 744c259d9a18..de5a0efc445f 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf @@ -21,7 +21,11 @@ router bgp 65000 vrf r2-vrf-101 address-family ipv4 unicast network 192.168.101.41/32 exit-address-family + address-family ipv6 unicast + network fd00::2/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf index 7d19a5b38162..7db40cb59c0d 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf @@ -11,6 +11,7 @@ vrf r2-vrf-101 ! interface loop101 vrf r2-vrf-101 ip address 192.168.101.41/32 + ipv6 address fd00::2/128 ! interface r2-eth0 ip address 192.168.100.41/24 diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index 7e4bcc8adaea..2d027081cb55 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -25,6 +25,8 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest +from lib.bgp import verify_bgp_rib +from lib.common_config import apply_raw_config from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger @@ -132,6 +134,7 @@ def setup_module(mod): for rname, router in router_list.items(): if rname == "r1": + router.load_config(TopoRouter.RD_MGMTD, None, "--vrfwnetns") router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)), @@ -178,12 +181,18 @@ def test_protocols_convergence(): output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv4", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ipv4") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv6", isjson=False) + logger.info("==== result from show bgp vrf r1-vrf-101 ipv6") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show ip route vrf r1-vrf-101", isjson=False) logger.info("==== result from show ip route vrf r1-vrf-101") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show ipv6 route vrf r1-vrf-101", isjson=False) + logger.info("==== result from show ipv6 route vrf r1-vrf-101") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn vni detail", isjson=False) logger.info("==== result from show evpn vni detail") logger.info(output) @@ -191,8 +200,49 @@ def test_protocols_convergence(): logger.info("==== result from show evpn next-hops vni all") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) - logger.info("==== result from show evpn next-hops vni all") + logger.info("==== result from show evpn rmac vni all") logger.info(output) + + expected = { + "fd00::2/128": [ + { + "prefix": "fd00::2/128", + "vrfName": "r1-vrf-101", + "nexthops": [ + { + "ip": "::ffff:c0a8:6429", + } + ], + } + ] + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show ipv6 route vrf r1-vrf-101 fd00::2/128 json", expected + ) + assert result is None, "ipv6 route check failed" + + expected = { + "101": { + "numNextHops": 2, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + "::ffff:c0a8:6429": { + "nexthopIp": "::ffff:c0a8:6429", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + # Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn) pingrouter = tgen.gears["r1"] logger.info( @@ -208,6 +258,80 @@ def test_protocols_convergence(): else: logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(r2-vrf-101 = fd00::2)") + output = pingrouter.run("ip netns exec r1-vrf-101 ping fd00::2 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assert 0, "expected ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) should be ok" + else: + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) OK") + + config_no_ipv6 = { + "r2": { + "raw_config": [ + "router bgp 65000 vrf r2-vrf-101", + "address-family ipv6 unicast", + "no network fd00::2/128", + ] + } + } + + logger.info("==== Remove IPv6 network on R2") + result = apply_raw_config(tgen, config_no_ipv6) + assert result is True, "Failed to remove IPv6 network on R2, Error: {} ".format( + result + ) + ipv6_routes = { + "r1": { + "static_routes": [ + { + "vrf": "r1-vrf-101", + "network": ["fd00::2/128"], + } + ] + } + } + result = verify_bgp_rib(tgen, "ipv6", "r1", ipv6_routes, expected=False) + assert result is not True, "expect IPv6 route fd00::2/128 withdrawn" + output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + + expected = { + "101": { + "numNextHops": 1, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + + logger.info( + "Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)" + ) + output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = ( + "expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok" + ) + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json new file mode 100644 index 000000000000..0b5b1a1e2b78 --- /dev/null +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.after.json @@ -0,0 +1 @@ +{"27.3.0.85:3":{"rd":"27.3.0.85:3","[5]:[0]:[16]:[10.27.0.0]":{"prefix":"[5]:[0]:[16]:[10.27.0.0]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":16,"ip":"10.27.0.0","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]}},"30.0.0.3:2":{"rd":"30.0.0.3:2","[5]:[0]:[32]:[4.4.4.1]":{"prefix":"[5]:[0]:[32]:[4.4.4.1]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"internal","routeType":5,"ethTag":0,"ipLen":32,"ip":"4.4.4.1","metric":0,"locPrf":100,"weight":0,"peerId":"10.30.30.30","path":"","origin":"incomplete","extendedCommunity":{"string":"RT:65000:300 ET:8 Rmac:44:20:00:ff:ff:01"},"nexthops":[{"ip":"10.30.30.30","hostname":"PE2","afi":"ipv4","used":true}]}]]}},"numPrefix":2,"numPaths":2} diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json new file mode 100644 index 000000000000..67417b5986a0 --- /dev/null +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgp.evpn.route.prefix.before.json @@ -0,0 +1 @@ +{"27.3.0.85:3":{"rd":"27.3.0.85:3","[5]:[0]:[24]:[10.27.7.0]":{"prefix":"[5]:[0]:[24]:[10.27.7.0]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":24,"ip":"10.27.7.0","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]},"[5]:[0]:[30]:[10.27.7.8]":{"prefix":"[5]:[0]:[30]:[10.27.7.8]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":30,"ip":"10.27.7.8","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]},"[5]:[0]:[32]:[10.27.7.22]":{"prefix":"[5]:[0]:[32]:[10.27.7.22]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"external","routeType":5,"ethTag":0,"ipLen":32,"ip":"10.27.7.22","metric":0,"weight":32768,"peerId":"(unspec)","path":"","origin":"incomplete","extendedCommunity":{"string":"ET:8 RT:65000:4000 Rmac:44:00:00:ff:ff:01"},"nexthops":[{"ip":"10.10.10.10","hostname":"PE1","afi":"ipv4","used":true}]}]]}},"30.0.0.3:2":{"rd":"30.0.0.3:2","[5]:[0]:[32]:[4.4.4.1]":{"prefix":"[5]:[0]:[32]:[4.4.4.1]","prefixLen":352,"paths":[[{"valid":true,"bestpath":true,"selectionReason":"First path received","pathFrom":"internal","routeType":5,"ethTag":0,"ipLen":32,"ip":"4.4.4.1","metric":0,"locPrf":100,"weight":0,"peerId":"10.30.30.30","path":"","origin":"incomplete","extendedCommunity":{"string":"RT:65000:300 ET:8 Rmac:44:20:00:ff:ff:01"},"nexthops":[{"ip":"10.30.30.30","hostname":"PE2","afi":"ipv4","used":true}]}]]}},"numPrefix":4,"numPaths":4} diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf index 9fb2bd6835c7..b58219ad8e62 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf @@ -11,9 +11,22 @@ router bgp 65000 advertise-svi-ip ! router bgp 65000 vrf vrf-red + address-family ipv4 unicast + redistribute static + exit-address-family ! address-family l2vpn evpn route-target import *:300 route-target import auto exit-address-family ! +router bgp 65000 vrf vrf-purple + address-family ipv4 unicast + redistribute static + exit-address-family + ! + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family + +! diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json index 98ae92ce55ba..45d00c6fa6ab 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/evpn.vni.json @@ -1,7 +1,7 @@ { "vni":101, "type":"L2", - "vrf":"default", + "tenantVrf":"default", "vxlanInterface":"vxlan0", "vtepIp":"10.10.10.10", "mcastGroup":"0.0.0.0", diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf index 8c6cf3e6d46e..cea60a8b1e9e 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/zebra.conf @@ -5,6 +5,12 @@ vrf vrf-red vni 100 exit-vrf ! +vrf vrf-purple + vni 4000 + ip route 10.27.7.0/24 blackhole + ip route 10.27.7.22/32 blackhole + ip route 10.27.7.10/30 blackhole +exit-vrf ! interface lo ip address 10.10.10.10/32 diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json index 5c059786b2db..f480b567ae14 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE2/evpn.vni.json @@ -1,7 +1,7 @@ { "vni":101, "type":"L2", - "vrf":"default", + "tenantVrf":"default", "vxlanInterface":"vxlan0", "vtepIp":"10.30.30.30", "mcastGroup":"0.0.0.0", diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py index 65c0c3532a9c..fd75c34ebf46 100755 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/test_bgp_evpn_vxlan_svd.py @@ -91,6 +91,10 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("ip link add name bridge type bridge stp_state 0") pe.run("ip link set dev bridge type bridge vlan_filtering 1") pe.run("bridge vlan add vid 1 dev bridge self") + if pe_name == "PE1": + pe.run("ip link set dev bridge address 44:00:00:ff:ff:01") + if pe_name == "PE2": + pe.run("ip link set dev bridge address 44:20:00:ff:ff:01") pe.run("ip link set dev bridge up") # setup svi @@ -113,6 +117,18 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("bridge vlan add dev vxlan0 vid 1 tunnel_info id 101") pe.run("ip link set up dev vxlan0") + # VRF creation + pe.run("ip link add vrf-purple type vrf table 1003") + pe.run("ip link set dev vrf-purple up") + if pe_name == "PE1": + pe.run("ip link add vrf-blue type vrf table 1002") + pe.run("ip link set dev vrf-blue up") + pe.run("ip addr add 27.2.0.85/32 dev vrf-blue") + pe.run("ip addr add 27.3.0.85/32 dev vrf-purple") + if pe_name == "PE2": + pe.run("ip link add vrf-blue type vrf table 2400") + pe.run("ip link set dev vrf-blue up") + # setup PE interface pe.run("ip link set dev {0}-{1} master bridge".format(pe_name, intf)) pe.run("bridge vlan del vid 1 dev {0}-{1}".format(pe_name, intf)) @@ -120,7 +136,7 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("bridge vlan add vid 1 dev {0}-{1}".format(pe_name, intf)) pe.run("bridge vlan add vid 1 pvid untagged dev {0}-{1}".format(pe_name, intf)) - # l3vni 100 + # L3VNI 100 pe.run("ip link add vrf-red type vrf table 1400") pe.run("ip link add link bridge name vlan100 type vlan id 100 protocol 802.1q") pe.run("ip link set dev vlan100 master vrf-blue") @@ -129,9 +145,16 @@ def setup_pe_router(tgen, pe_name, tunnel_local_ip, svi_ip, intf): pe.run("bridge vlan add dev vxlan0 vid 100") pe.run("bridge vlan add dev vxlan0 vid 100 tunnel_info id 100") + # L3VNI 4000 + pe.run("ip link add link bridge name vlan400 type vlan id 400 protocol 802.1q") + pe.run("ip link set dev vlan400 master vrf-purple") + pe.run("ip link set dev vlan400 up") + pe.run("bridge vlan add vid 400 dev bridge self") + pe.run("bridge vlan add dev vxlan0 vid 400") + pe.run("bridge vlan add dev vxlan0 vid 400 tunnel_info id 4000") + # add a vrf for testing DVNI if pe_name == "PE2": - pe.run("ip link add vrf-blue type vrf table 2400") pe.run("ip link add link bridge name vlan300 type vlan id 300 protocol 802.1q") pe.run("ip link set dev vlan300 master vrf-blue") pe.run("ip link set dev vlan300 up") @@ -199,6 +222,14 @@ def show_vni_json_elide_ifindex(pe, vni, expected): return topotest.json_cmp(output_json, expected) +def show_bgp_l2vpn_evpn_route_type_prefix_json(pe, expected): + output_json = pe.vtysh_cmd( + "show bgp l2vpn evpn route type prefix json", isjson=True + ) + + return topotest.json_cmp(output_json, expected) + + def check_vni_macs_present(tgen, router, vni, maclist): result = router.vtysh_cmd("show evpn mac vni {} json".format(vni), isjson=True) for rname, ifname in maclist: @@ -331,6 +362,7 @@ def mac_test_local_remote(local, remote): remote_output_json = json.loads(remote_output) local_output_vni_json = json.loads(local_output_vni) + # breakpoint() for vni in local_output_json: if vni not in remote_output_json: continue @@ -542,6 +574,42 @@ def test_dvni(): # tgen.mininet_cli() +def test_pe_advertise_aggr_evpn_route(): + "BGP advertise aggregated Type-5 prefix route" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking BGP EVPN route contains non-aggregate prefixes") + pe1 = tgen.gears["PE1"] + json_file = "{}/{}/bgp.evpn.route.prefix.before.json".format(CWD, pe1.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(show_bgp_l2vpn_evpn_route_type_prefix_json, pe1, expected) + _, result = topotest.run_and_expect(test_func, None, count=45, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(pe1.name) + assert result is None, assertmsg + + logger.info("Configure BGP aggregate-address summary-only under ipv4-unicast") + pe1.cmd( + 'vtysh -c "config t" -c "router bgp 65000 vrf vrf-purple" ' + + ' -c "address-family ipv4 unicast" ' + + ' -c "aggregate-address 10.27.0.0/16 summary-only" ' + ) + + logger.info("Checking BGP EVPN route contains aggregated prefix") + pe1 = tgen.gears["PE1"] + json_file = "{}/{}/bgp.evpn.route.prefix.after.json".format(CWD, pe1.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(show_bgp_l2vpn_evpn_route_type_prefix_json, pe1, expected) + _, result = topotest.run_and_expect(test_func, None, count=45, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(pe1.name) + assert result is None, assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py index eb05986fe177..e4d330e13c0d 100644 --- a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py +++ b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py @@ -25,7 +25,6 @@ # pylint: disable=C0413 from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib import topotest @@ -47,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -124,7 +123,8 @@ def test_rt_extcomm_list_delete(): # check for the deletion of the extended community test_func = functools.partial( - _bgp_extcomm_list_del_check, r2, "10.10.10.1/32", r"1.1.1.1:1") + _bgp_extcomm_list_del_check, r2, "10.10.10.1/32", r"1.1.1.1:1" + ) _, result = topotest.run_and_expect(test_func, True, count=60, wait=0.5) assert result, "RT extended community 1.1.1.1:1 was not stripped." @@ -138,7 +138,8 @@ def test_soo_extcomm_list_delete(): # check for the deletion of the extended community test_func = functools.partial( - _bgp_extcomm_list_del_check, r2, "10.10.10.2/32", r"2.2.2.2:2") + _bgp_extcomm_list_del_check, r2, "10.10.10.2/32", r"2.2.2.2:2" + ) _, result = topotest.run_and_expect(test_func, True, count=60, wait=0.5) assert result, "SoO extended community 2.2.2.2:2 was not stripped." @@ -152,7 +153,8 @@ def test_nt_extcomm_list_delete(): # check for the deletion of the extended community test_func = functools.partial( - _bgp_extcomm_list_del_check, r2, "10.10.10.3/32", r"3.3.3.3") + _bgp_extcomm_list_del_check, r2, "10.10.10.3/32", r"3.3.3.3" + ) _, result = topotest.run_and_expect(test_func, True, count=60, wait=0.5) assert result, "NT extended community 3.3.3.3:0 was not stripped." diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff b/tests/topotests/bgp_extended_link_bandwidth/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff rename to tests/topotests/bgp_extended_link_bandwidth/__init__.py diff --git a/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf new file mode 100644 index 000000000000..d0c0813e842d --- /dev/null +++ b/tests/topotests/bgp_extended_link_bandwidth/r1/frr.conf @@ -0,0 +1,32 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as internal + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 extended-link-bandwidth + address-family ipv4 unicast + network 10.10.10.40/32 + network 10.10.10.100/32 + network 10.10.10.200/32 + neighbor 192.168.1.2 route-map r2 out + exit-address-family +! +ip prefix-list p40 seq 5 permit 10.10.10.40/32 +ip prefix-list p100 seq 5 permit 10.10.10.100/32 +ip prefix-list p200 seq 5 permit 10.10.10.200/32 +! +route-map r2 permit 10 + match ip address prefix-list p40 + set extcommunity bandwidth 40000 +route-map r2 permit 20 + match ip address prefix-list p100 + set extcommunity bandwidth 100000 +route-map r2 permit 30 + match ip address prefix-list p200 + set extcommunity bandwidth 200000 +exit diff --git a/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf b/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf new file mode 100644 index 000000000000..5cad150aef0b --- /dev/null +++ b/tests/topotests/bgp_extended_link_bandwidth/r2/frr.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as internal + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py new file mode 100644 index 000000000000..e9006b81c930 --- /dev/null +++ b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dynamic_capability_role(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail")) + expected = { + "routes": { + "10.10.10.40/32": { + "paths": [ + { + "extendedIpv6Community": { + "string": "LB:65000:5000000000 (40.000 Gbps)", + } + } + ] + }, + "10.10.10.100/32": { + "paths": [ + { + "extendedIpv6Community": { + "string": "LB:65000:12500000000 (100.000 Gbps)", + } + } + ] + }, + "10.10.10.200/32": { + "paths": [ + { + "extendedIpv6Community": { + "string": "LB:65000:25000000000 (200.000 Gbps)", + } + } + ] + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see link bandwidths as expected" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py index eef122b369a0..c67bc91f631e 100644 --- a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py +++ b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py @@ -17,7 +17,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -26,8 +26,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -36,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_features/r1/ip_route.json b/tests/topotests/bgp_features/r1/ip_route.json index 34c58033ad51..3f95e27078ff 100644 --- a/tests/topotests/bgp_features/r1/ip_route.json +++ b/tests/topotests/bgp_features/r1/ip_route.json @@ -29,7 +29,7 @@ "metric":0, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"lo", "active":true, @@ -109,7 +109,7 @@ "table":254, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"r1-eth1", "active":true, @@ -175,7 +175,7 @@ "metric":10, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"r1-eth2", "active":true, @@ -210,7 +210,7 @@ "metric":10, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"r1-eth0", "active":true, diff --git a/tests/topotests/bgp_features/r1/ip_route_norib.json b/tests/topotests/bgp_features/r1/ip_route_norib.json index f6536d1e9f31..b8e0fc288306 100644 --- a/tests/topotests/bgp_features/r1/ip_route_norib.json +++ b/tests/topotests/bgp_features/r1/ip_route_norib.json @@ -7,7 +7,7 @@ "metric":0, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"lo", "active":true, @@ -86,7 +86,7 @@ "metric":10, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"r1-eth1", "active":true, @@ -152,7 +152,7 @@ "metric":10, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"r1-eth2", "active":true, @@ -187,7 +187,7 @@ "metric":10, "nexthops":[ { - "flags":1, + "flags":3, "directlyConnected":true, "interfaceName":"r1-eth0", "active":true, diff --git a/tests/topotests/bgp_features/r1/ospf6d.conf b/tests/topotests/bgp_features/r1/ospf6d.conf index 9afc6f491923..3e6196ecafdd 100644 --- a/tests/topotests/bgp_features/r1/ospf6d.conf +++ b/tests/topotests/bgp_features/r1/ospf6d.conf @@ -3,19 +3,19 @@ log file ospf6d.log ! debug ospf6 neighbor ! interface r1-lo + ipv6 ospf6 area 0.0.0.0 ! interface r1-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 priority 10 ! interface r1-eth2 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 priority 10 ! router ospf6 ospf6 router-id 192.168.0.1 log-adjacency-changes - interface r1-lo area 0.0.0.0 - interface r1-eth1 area 0.0.0.0 - interface r1-eth2 area 0.0.0.0 ! line vty ! diff --git a/tests/topotests/bgp_features/r2/ospf6d.conf b/tests/topotests/bgp_features/r2/ospf6d.conf index 7fe535651e50..56aecd006c54 100644 --- a/tests/topotests/bgp_features/r2/ospf6d.conf +++ b/tests/topotests/bgp_features/r2/ospf6d.conf @@ -3,19 +3,19 @@ log file ospf6d.log ! debug ospf6 neighbor ! interface r2-lo + ipv6 ospf6 area 0.0.0.0 ! interface r2-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 priority 5 ! interface r2-eth2 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 priority 10 ! router ospf6 ospf6 router-id 192.168.0.2 log-adjacency-changes - interface r2-lo area 0.0.0.0 - interface r2-eth1 area 0.0.0.0 - interface r2-eth2 area 0.0.0.0 ! line vty ! diff --git a/tests/topotests/bgp_features/r3/ospf6d.conf b/tests/topotests/bgp_features/r3/ospf6d.conf index 07325b69b0d5..f15b9d9ea524 100644 --- a/tests/topotests/bgp_features/r3/ospf6d.conf +++ b/tests/topotests/bgp_features/r3/ospf6d.conf @@ -3,19 +3,19 @@ log file ospf6d.log ! debug ospf6 neighbor ! interface r3-lo + ipv6 ospf6 area 0.0.0.0 ! interface r3-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 priority 5 ! interface r3-eth2 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 priority 5 ! router ospf6 ospf6 router-id 192.168.0.3 log-adjacency-changes - interface r3-lo area 0.0.0.0 - interface r3-eth1 area 0.0.0.0 - interface r3-eth2 area 0.0.0.0 ! line vty ! diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 43f4905d4186..0f5d9dea4285 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -18,7 +18,6 @@ import os import sys import pytest -import re import time # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py b/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py index a2be85962feb..57aeea87cb39 100644 --- a/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py +++ b/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py @@ -51,7 +51,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import generate_support_bundle # Required to instantiate the topology builder class. @@ -140,10 +139,7 @@ def test_bgp_convergence(): ) _, res = topotest.run_and_expect(test_func, None, count=210, wait=1) assertmsg = "BGP router network did not converge" - if res is not None: - generate_support_bundle() - assert res is None, assertmsg - generate_support_bundle() + assert res is None, assertmsg def test_bgp_flowspec(): diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py index 5e2b2f37b234..2e2c8119a251 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py @@ -102,7 +102,6 @@ verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py index 13c5ba538c4a..9f79c52e3a6b 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py @@ -117,8 +117,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py index 1a8f8302ffef..0873c24b7fcf 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py @@ -117,7 +117,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py index 31aaa0b8a6df..710514b056ee 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -81,6 +81,8 @@ import sys import time import pytest +import functools +import json # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -91,6 +93,7 @@ # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from lib.topolog import logger +from lib import topotest # Required to instantiate the topology builder class. @@ -101,8 +104,6 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) @@ -117,7 +118,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, @@ -1680,6 +1680,304 @@ def BGP_GR_TC_52_p1(request): write_test_footer(tc_name) +def test_BGP_GR_TC_53_p1(request): + """ + Test Objective : Peer-level inherit from BGP wide Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart + + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Check router status + check_router_status(tgen) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Configure R1 as GR restarting node in global level") + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart + ! + """ + ) + + step("Verify that R2 receives GR restarting capabilities" " from R1") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGPd on router R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in FIB and R2 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Configure graceful-restart-disable at config global level verify that the functionality works + step("Bring up BGP on R1 and configure graceful-restart-disable") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart-disable": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart-disable + ! + """ + ) + + step("Verify on R2 that R1 does't advertise any GR capabilities") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGP on R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step("Verify on R2 and R1 that none of the routers keep stale entries") + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} BGP RIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + step( + "Bring up BGP on R1, enable GR and configure bgp graceful-restart restart-time at global level" + ) + + start_router_daemons(tgen, "r1", ["bgpd"]) + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + no bgp graceful-restart-disable + bgp graceful-restart + bgp graceful-restart stalepath-time 420 + bgp graceful-restart restart-time 240 + bgp graceful-restart select-defer-time 420 + ! + """ + ) + + step("Verify on R2 that R1 sent the updated GR restart-time") + + def _bgp_check_if_gr_restart_time_was_updated(): + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + "fd00::1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_restart_time_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "R2 did not receive the updated GR restart-time of 240s" + + def _bgp_check_if_gr_timer_on_restarting_node_was_updated(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv4Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + "fd00::2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv6Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_timer_on_restarting_node_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "R1 did not update the GR select-deferral and stale-path timer to 420s" + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py index cb6bf56967b0..01ab10b82ff1 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py @@ -94,13 +94,10 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py index cf9a474a8125..989d2d554a10 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py @@ -95,7 +95,6 @@ verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_eor, verify_f_bit, verify_bgp_convergence, verify_gr_address_family, @@ -114,7 +113,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +167,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py index 4746d71a323f..05fb8bf79655 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py @@ -98,9 +98,7 @@ verify_eor, verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -114,7 +112,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py index 1c41df98e163..950733c3afc4 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py @@ -96,13 +96,9 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -116,7 +112,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -171,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py index 593a8d64179e..e24f31d8624a 100644 --- a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py +++ b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py @@ -12,7 +12,6 @@ import pytest from time import sleep -import traceback import ipaddress # Save the Current Working Directory to find configuration files. @@ -34,37 +33,21 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, - modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) # Import common_config to use commomnly used APIs from lib.common_config import ( - create_common_configuration, - InvalidCLIError, - retry, generate_ips, - FRRCFG_FILE, - find_interface_with_greater_ip, check_address_types, validate_ip_address, run_frr_cmd, - get_frr_ipv6_linklocal, ) from lib.common_config import ( write_test_header, - reset_config_on_routers, start_topology, - kill_router_daemons, - start_router_daemons, - verify_rib, check_address_types, write_test_footer, check_router_status, @@ -154,9 +137,6 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict): """ logger.debug("Entering lib API: verify_stale_routes_list()") router_list = tgen.routers() - additional_nexthops_in_required_nhs = [] - list1 = [] - list2 = [] found_hops = [] for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -266,7 +246,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -442,7 +422,7 @@ def test_bgp_gr_stale_routes(request): ) assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - for iteration in range(5): + for _ in range(5): step("graceful-restart-disable:True at R3") input_dict = { "r3": { diff --git a/tests/topotests/bgp_gr_notification/r1/bgpd.conf b/tests/topotests/bgp_gr_notification/r1/bgpd.conf index 6119f6743629..0af042f6be59 100644 --- a/tests/topotests/bgp_gr_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 bgp graceful-restart neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 1 3 - neighbor 192.168.255.2 timers connect 1 + neighbor 192.168.255.2 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/r2/bgpd.conf b/tests/topotests/bgp_gr_notification/r2/bgpd.conf index 05e17f056488..8325e21d2c1e 100644 --- a/tests/topotests/bgp_gr_notification/r2/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r2/bgpd.conf @@ -4,7 +4,7 @@ router bgp 65002 bgp graceful-restart neighbor 192.168.255.1 remote-as external neighbor 192.168.255.1 timers 1 3 - neighbor 192.168.255.1 timers connect 1 + neighbor 192.168.255.1 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 2ffcb723ec42..5d8338d6eb2a 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -195,16 +195,16 @@ def _bgp_clear_r1_and_shutdown(): step("Reset and shutdown R1") _bgp_clear_r1_and_shutdown() - step("Check if Hard Reset notification wasn't sent from R2") - test_func = functools.partial(_bgp_check_hard_reset) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, "Failed to send Administrative Reset notification from R2" - step("Check if stale routes are retained on R1") test_func = functools.partial(_bgp_check_gr_notification_stale) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see retained stale routes on R1" + step("Check if Hard Reset notification wasn't sent from R2") + test_func = functools.partial(_bgp_check_hard_reset) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to send Administrative Reset notification from R2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf b/tests/topotests/bgp_gr_restart_retain_routes/r1/frr.conf similarity index 75% rename from tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf rename to tests/topotests/bgp_gr_restart_retain_routes/r1/frr.conf index 50d158387306..3d4d3a8ee54d 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf +++ b/tests/topotests/bgp_gr_restart_retain_routes/r1/frr.conf @@ -1,3 +1,10 @@ +! +interface lo + ip address 172.16.255.1/32 +! +interface r1-eth0 + ip address 192.168.255.1/24 +! router bgp 65001 no bgp ebgp-requires-policy bgp graceful-restart diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf b/tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf deleted file mode 100644 index e65bfb2c3ad4..000000000000 --- a/tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf +++ /dev/null @@ -1,7 +0,0 @@ -! -interface lo - ip address 172.16.255.1/32 -! -interface r1-eth0 - ip address 192.168.255.1/24 -! diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf b/tests/topotests/bgp_gr_restart_retain_routes/r2/frr.conf similarity index 73% rename from tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf rename to tests/topotests/bgp_gr_restart_retain_routes/r2/frr.conf index 97418ca9a042..f5ba4eae053c 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf +++ b/tests/topotests/bgp_gr_restart_retain_routes/r2/frr.conf @@ -1,3 +1,8 @@ +no zebra nexthop kernel enable +! +interface r2-eth0 + ip address 192.168.255.2/24 +! router bgp 65002 no bgp ebgp-requires-policy bgp graceful-restart diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf b/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf deleted file mode 100644 index 758d797ad693..000000000000 --- a/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf +++ /dev/null @@ -1,5 +0,0 @@ -no zebra nexthop kernel enable -! -interface r2-eth0 - ip address 192.168.255.2/24 -! diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r3/frr.conf b/tests/topotests/bgp_gr_restart_retain_routes/r3/frr.conf new file mode 100644 index 000000000000..1d84ec6eee5b --- /dev/null +++ b/tests/topotests/bgp_gr_restart_retain_routes/r3/frr.conf @@ -0,0 +1,19 @@ +no zebra nexthop kernel enable +! +interface lo + ip address 172.16.255.3/32 +! +interface r3-eth0 + ip address 192.168.34.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + bgp graceful-restart preserve-fw-state + neighbor 192.168.34.4 remote-as external + neighbor 192.168.34.4 timers 1 3 + neighbor 192.168.34.4 timers connect 1 + neighbor 192.168.34.4 graceful-restart + address-family ipv4 + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r4/frr.conf b/tests/topotests/bgp_gr_restart_retain_routes/r4/frr.conf new file mode 100644 index 000000000000..58907916f4b9 --- /dev/null +++ b/tests/topotests/bgp_gr_restart_retain_routes/r4/frr.conf @@ -0,0 +1,13 @@ +no zebra nexthop kernel enable +! +interface r4-eth0 + ip address 192.168.34.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + bgp graceful-restart preserve-fw-state + neighbor 192.168.34.3 remote-as external + neighbor 192.168.34.3 timers 1 3 + neighbor 192.168.34.3 timers connect 1 + neighbor 192.168.34.3 graceful-restart +! diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py new file mode 100644 index 000000000000..e61efefa5aab --- /dev/null +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if routes are retained during BGP restarts using + Graceful Restart per-neighbor. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.common_config import step, stop_router + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_gr_restart_retain_routes(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r4 = tgen.gears["r4"] + + def _bgp_converge(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 neighbors 192.168.34.3 json")) + expected = { + "192.168.34.3": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_check_bgp_retained_routes(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 172.16.255.3/32 json")) + expected = {"paths": [{"stale": True}]} + return topotest.json_cmp(output, expected) + + def _bgp_check_kernel_retained_routes(): + output = json.loads( + r4.cmd("ip -j route show 172.16.255.3/32 proto bgp dev r4-eth0") + ) + expected = [{"dst": "172.16.255.3", "gateway": "192.168.34.3", "metric": 20}] + return topotest.json_cmp(output, expected) + + step("Initial BGP converge") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP convergence on R4" + + step("Restart R3") + stop_router(tgen, "r3") + + step("Check if routes (BGP) are retained at R4") + test_func = functools.partial(_bgp_check_bgp_retained_routes) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP retained routes on R4" + + step("Check if routes (Kernel) are retained at R4") + assert ( + _bgp_check_kernel_retained_routes() is None + ), "Failed to retain BGP routes in kernel on R4" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py index a820b4b2211b..d7ae43338a03 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] @@ -42,13 +42,8 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): - router.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) - ) - router.load_config( - TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() @@ -83,8 +78,10 @@ def _bgp_check_bgp_retained_routes(): return topotest.json_cmp(output, expected) def _bgp_check_kernel_retained_routes(): - output = json.loads(r2.cmd("ip -j route show 172.16.255.1/32 proto bgp dev r2-eth0")) - expected = [{"dst":"172.16.255.1","gateway":"192.168.255.1","metric":20}] + output = json.loads( + r2.cmd("ip -j route show 172.16.255.1/32 proto bgp dev r2-eth0") + ) + expected = [{"dst": "172.16.255.1", "gateway": "192.168.255.1", "metric": 20}] return topotest.json_cmp(output, expected) step("Initial BGP converge") @@ -101,7 +98,9 @@ def _bgp_check_kernel_retained_routes(): assert result is None, "Failed to see BGP retained routes on R2" step("Check if routes (Kernel) are retained at R2") - assert _bgp_check_kernel_retained_routes() is None, "Failed to retain BGP routes in kernel on R2" + assert ( + _bgp_check_kernel_retained_routes() is None + ), "Failed to retain BGP routes in kernel on R2" if __name__ == "__main__": diff --git a/tests/topotests/bgp_gshut/test_bgp_gshut.py b/tests/topotests/bgp_gshut/test_bgp_gshut.py index 61a0fe63c180..cfe63d20bafd 100644 --- a/tests/topotests/bgp_gshut/test_bgp_gshut.py +++ b/tests/topotests/bgp_gshut/test_bgp_gshut.py @@ -108,7 +108,7 @@ def setup_module(mod): r2.run("ip link set r2-eth3 master vrf1") # Load FRR config and initialize all routers - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py index c7cb213de5d7..66eeeb468daa 100644 --- a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py +++ b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py index 395ef2d91946..803b51c04327 100644 --- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py +++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py @@ -23,7 +23,7 @@ from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( write_test_header, diff --git a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py index ea974b5302fe..aaa68ea340aa 100644 --- a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py +++ b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff b/tests/topotests/bgp_l3vpn_label_export/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff rename to tests/topotests/bgp_l3vpn_label_export/__init__.py diff --git a/tests/topotests/bgp_l3vpn_label_export/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_label_export/r1/bgpd.conf new file mode 100644 index 000000000000..bb1ed4c1eab0 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r1/bgpd.conf @@ -0,0 +1,22 @@ +router bgp 65001 + bgp router-id 192.0.2.1 + no bgp default ipv4-unicast + no bgp ebgp-requires-policy + neighbor 192.0.2.2 remote-as 65002 + neighbor 192.0.2.2 timers 1 3 + neighbor 192.0.2.2 timers connect 1 + neighbor 192.0.2.2 ebgp-multihop 2 + address-family ipv4 vpn + neighbor 192.0.2.2 activate + exit-address-family +! +router bgp 65001 vrf vrf1 + address-family ipv4 unicast + redistribute connected + label vpn export 1111 + rd vpn export 101:1 + rt vpn both 52:100 + import vpn + export vpn + exit-address-family +! diff --git a/tests/topotests/bgp_l3vpn_label_export/r1/ldpd.conf b/tests/topotests/bgp_l3vpn_label_export/r1/ldpd.conf new file mode 100644 index 000000000000..04ae06877a2d --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r1/ldpd.conf @@ -0,0 +1,26 @@ +hostname r1 +log file ldpd.log +password zebra +! +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent +! +mpls ldp + router-id 192.0.2.1 + ! + address-family ipv4 + discovery transport-address 192.0.2.1 + ! + interface r1-eth0 + ! + interface r1-eth1 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_label_export/r1/staticd.conf b/tests/topotests/bgp_l3vpn_label_export/r1/staticd.conf new file mode 100644 index 000000000000..7f2f057bfeec --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r1/staticd.conf @@ -0,0 +1 @@ +ip route 192.0.2.2/32 192.168.1.2 diff --git a/tests/topotests/bgp_l3vpn_label_export/r1/zebra.conf b/tests/topotests/bgp_l3vpn_label_export/r1/zebra.conf new file mode 100644 index 000000000000..7bdacb1ca30c --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_l3vpn_label_export/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_label_export/r2/bgpd.conf new file mode 100644 index 000000000000..18a11cfb40d6 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r2/bgpd.conf @@ -0,0 +1,23 @@ +router bgp 65002 + bgp router-id 192.0.2.2 + no bgp default ipv4-unicast + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as 65001 + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.1.1 ebgp-multihop 2 + neighbor 192.168.1.1 update-source 192.0.2.2 + address-family ipv4 vpn + neighbor 192.168.1.1 activate + exit-address-family +! +router bgp 65002 vrf vrf1 + address-family ipv4 unicast + redistribute connected + label vpn export 2222 + rd vpn export 102:1 + rt vpn both 52:100 + import vpn + export vpn + exit-address-family +! diff --git a/tests/topotests/bgp_l3vpn_label_export/r2/ldpd.conf b/tests/topotests/bgp_l3vpn_label_export/r2/ldpd.conf new file mode 100644 index 000000000000..f4307f1ab07f --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r2/ldpd.conf @@ -0,0 +1,24 @@ +hostname r2 +log file ldpd.log +password zebra +! +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent +! +mpls ldp + router-id 192.0.2.2 + ! + address-family ipv4 + discovery transport-address 192.0.2.2 + ! + interface r2-eth0 + ! + ! +! +line vty +! diff --git a/tests/topotests/bgp_l3vpn_label_export/r2/staticd.conf b/tests/topotests/bgp_l3vpn_label_export/r2/staticd.conf new file mode 100644 index 000000000000..e3f5d7dba054 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r2/staticd.conf @@ -0,0 +1 @@ +ip route 192.0.2.1/32 192.168.1.1 diff --git a/tests/topotests/bgp_l3vpn_label_export/r2/zebra.conf b/tests/topotests/bgp_l3vpn_label_export/r2/zebra.conf new file mode 100644 index 000000000000..40dfa9854c27 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/r2/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 192.0.2.2/32 +! +interface r2-eth0 + ip address 192.168.1.2/24 +! diff --git a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py new file mode 100644 index 000000000000..a0871a492235 --- /dev/null +++ b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py @@ -0,0 +1,587 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2023 by Louis Scalbert +# Copyright 2023 6WIND S.A. +# + +""" + +""" + +import os +import re +import sys +import json +import pytest +import functools + +from copy import deepcopy + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import kill_router_daemons, start_router_daemons, step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for rtr in [1, 2]: + tgen.add_router("r{}".format(rtr)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rtr in [1, 2]: + tgen.gears["r{}".format(rtr)].cmd("ip link add vrf1 type vrf table 10") + tgen.gears["r{}".format(rtr)].cmd("ip link set vrf1 up") + tgen.gears["r{}".format(rtr)].cmd( + "ip address add dev vrf1 192.0.3.{}/32".format(rtr) + ) + tgen.gears["r{}".format(rtr)].run( + "sysctl -w net.mpls.conf.r{}-eth0.input=1".format(rtr) + ) + tgen.gears["r{}".format(rtr)].run("sysctl -w net.mpls.conf.vrf1.input=1") + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def check_bgp_vpn_prefix(label, rname="r1", rd=None): + tgen = get_topogen() + + if rd: + output = json.loads( + tgen.gears[rname].vtysh_cmd( + "show bgp ipv4 vpn rd {} 192.0.3.2/32 json".format(rd) + ) + ) + else: + output = json.loads( + tgen.gears[rname].vtysh_cmd( + "show bgp vrf vrf1 ipv4 unicast 192.0.3.2/32 json" + ) + ) + + if label == "auto": + expected = { + "paths": [ + { + "valid": True, + "aspath": {"string": "65002"}, + "nexthops": [{"ip": "192.0.2.2"}], + }, + ] + } + elif label and not rd: + expected = { + "paths": [ + { + "valid": True, + "remoteLabel": label, + "aspath": {"string": "65002"}, + "nexthops": [{"ip": "192.0.2.2"}], + }, + ] + } + elif label and rd: + expected = { + "102:1": { + "prefix": "192.0.3.2/32", + "paths": [ + { + "valid": True, + "remoteLabel": label, + "nexthops": [{"ip": "0.0.0.0"}], + } + ], + } + } + else: + expected = {} + + return topotest.json_cmp(output, expected, exact=(label is None)) + + +def check_mpls_table(label, protocol): + tgen = get_topogen() + + if label == "auto": + cmd = "show mpls table json" + else: + cmd = "show mpls table {} json".format(label) + + output = json.loads(tgen.gears["r2"].vtysh_cmd(cmd)) + + if label == "auto" and protocol: + output_copy = deepcopy(output) + for _, data in output_copy.items(): + for nexthop in data.get("nexthops", []): + if nexthop.get("type", None) != protocol: + continue + output = data + break + + if protocol: + expected = { + "nexthops": [ + { + "type": protocol, + }, + ] + } + else: + expected = {} + + return topotest.json_cmp(output, expected, exact=(protocol is None)) + + +def check_mpls_ldp_binding(): + tgen = get_topogen() + + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show mpls ldp binding 192.0.2.2/32 json") + ) + expected = { + "bindings": [ + { + "prefix": "192.0.2.2/32", + "localLabel": "16", # first available label + "inUse": 1, + }, + ] + } + + return topotest.json_cmp(output, expected) + + +def test_convergence(): + "Test protocol convergence" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Check BGP and LDP convergence") + test_func = functools.partial(check_bgp_vpn_prefix, 2222) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP prefix on R1" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, 2222, "BGP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: [2222/2222]" in output, "Failed to see BGP label chunk" + + +def test_vpn_label_export_16(): + "Test that assigning the label value of 16 is not possible because it used by LDP" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export 16" + ) + + step("Check that label vpn export 16 fails") + test_func = functools.partial(check_bgp_vpn_prefix, None) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected BGP prefix on R1" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, 2222, None) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp" not in output, "Unexpected BGP label chunk" + + +def test_vpn_label_export_2222(): + "Test that setting back the label value of 2222 works" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export 2222" + ) + + step("Check that label vpn export 2222 is OK") + test_func = functools.partial(check_bgp_vpn_prefix, 2222) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP prefix on R1" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, "auto", "BGP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: [2222/2222]" in output, "Failed to see BGP label chunk" + + +def test_vpn_label_export_auto(): + "Test that setting label vpn export auto works" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export auto" + ) + + step("Check that label vpn export auto is OK") + test_func = functools.partial(check_bgp_vpn_prefix, "auto") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP prefix on R1" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, "auto", "BGP") + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result is None, "Failed to see BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " in output, "Failed to see BGP label chunk" + + +def test_vpn_label_export_no_auto(): + "Test that UNsetting label vpn export auto removes the prefix from R1 table and R2 LDP table" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.3.2/32 json") + ) + + auto_label = output.get("paths")[0].get("remoteLabel", None) + assert auto_label is not None, "Failed to fetch prefix label on R1" + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "no label vpn export auto" + ) + + step("Check that no label vpn export auto is OK") + test_func = functools.partial(check_bgp_vpn_prefix, 3, rname="r2", rd="102:1") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected BGP prefix on R2" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, auto_label, None) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result is None, "Unexpected BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " not in output, "Unexpected BGP label chunk" + + +def test_vpn_label_export_auto_back(): + "Test that setting back label vpn export auto works" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + output = json.loads( + tgen.gears["r2"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.3.2/32 json") + ) + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export auto" + ) + + step("Check that label vpn export auto is OK") + test_func = functools.partial(check_bgp_vpn_prefix, "auto") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP prefix on R1" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, "auto", "BGP") + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result is None, "Failed to see BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " in output, "Failed to see BGP label chunk" + + +def test_vpn_label_export_manual_from_auto(): + "Test that setting a manual label value from the BGP chunk range works" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.3.2/32 json") + ) + + auto_label = output.get("paths")[0].get("remoteLabel", None) + assert auto_label is not None, "Failed to fetch prefix label on R1" + + auto_label = auto_label + 1 + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export {}".format(auto_label) + ) + + step("Check that label vpn export {} is OK".format(auto_label)) + test_func = functools.partial( + check_bgp_vpn_prefix, auto_label, rname="r2", rd="102:1" + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see BGP prefix on R2" + + test_func = functools.partial(check_mpls_ldp_binding) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP binding on R2" + + test_func = functools.partial(check_mpls_table, 16, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + test_func = functools.partial(check_mpls_table, auto_label, "BGP") + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result is None, "Failed to see BGP label on R2" + + output = tgen.net["r2"].cmd("vtysh -c 'show debugging label-table' | grep Proto") + assert re.match( + r"Proto ldp: \[16/(1[7-9]|[2-9]\d+|\d{3,})\]", output + ), "Failed to see LDP label chunk" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " in output, "Failed to see BGP label chunk" + + +def test_vpn_label_configure_dynamic_range(): + "Test that if a dynamic range is configured, then the next dynamic allocations will be done in that block" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + tgen.gears["r2"].vtysh_cmd("conf\n" "mpls label dynamic-block 500 1000\n") + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export auto" + ) + step("Check that label vpn export auto starting at 500 is OK") + test_func = functools.partial(check_bgp_vpn_prefix, 500, rname="r2", rd="102:1") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected BGP prefix on R2" + + test_func = functools.partial(check_mpls_table, 500, "BGP") + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result is None, "Unexpected BGP label on R2" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " in output, "Failed to see BGP label chunk" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + + +def test_vpn_label_restart_ldp(): + "Test that if a dynamic range is configured, then when LDP restarts, it follows the new dynamic range" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router_list = tgen.routers() + + step("Kill LDP on R2") + kill_router_daemons(tgen, "r2", ["ldpd"]) + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto ldp: " not in output, "Unexpected LDP label chunk" + + step("Bring up LDP on R2") + + start_router_daemons(tgen, "r2", ["ldpd"]) + + test_func = functools.partial(check_mpls_table, 628, "LDP") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see LDP label on R2" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto ldp: [628/691]" in output, "Failed to see LDP label chunk [628/691]" + assert "Proto ldp: [692/755]" in output, "Failed to see LDP label chunk [692/755]" + + +def test_vpn_label_unconfigure_dynamic_range(): + "Test that if the dynamic range is unconfigured, then the next dynamic allocations will be done at the first free place." + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + tgen.gears["r2"].vtysh_cmd("conf\n" "no mpls label dynamic-block 500 1000\n") + step("Check that unconfiguring label vpn export auto will remove BGP label chunk") + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "no label vpn export auto" + ) + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " not in output, "Unexpected BGP label chunk" + + tgen.gears["r2"].vtysh_cmd( + "conf\n" + "router bgp 65002 vrf vrf1\n" + "address-family ipv4 unicast\n" + "label vpn export auto" + ) + step("Check that label vpn export auto starting at 16 is OK") + test_func = functools.partial(check_bgp_vpn_prefix, 16, rname="r2", rd="102:1") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected BGP prefix on R2" + + test_func = functools.partial(check_mpls_table, 16, "BGP") + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result is None, "Unexpected BGP label on R2" + + output = tgen.gears["r2"].vtysh_cmd("show debugging label-table") + assert "Proto bgp: " in output, "Failed to see BGP label chunk" diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py index 0deb181f3e5c..489c59fa4051 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/add_routes.py @@ -1,17 +1,17 @@ from lib.lutil import luCommand luCommand( - "r1", 'vtysh -c "show bgp next"', "99.0.0.. valid", "wait", "See CE static NH" + "r1", 'vtysh -c "show bgp nexthop"', "99.0.0.. valid", "wait", "See CE static NH" ) luCommand( - "r3", 'vtysh -c "show bgp next"', "99.0.0.. valid", "wait", "See CE static NH" + "r3", 'vtysh -c "show bgp nexthop"', "99.0.0.. valid", "wait", "See CE static NH" ) luCommand( - "r4", 'vtysh -c "show bgp next"', "99.0.0.. valid", "wait", "See CE static NH" + "r4", 'vtysh -c "show bgp nexthop"', "99.0.0.. valid", "wait", "See CE static NH" ) -luCommand("r1", 'vtysh -c "show bgp ipv4 uni"', "i5.*i5", "wait", "See CE routes") -luCommand("r3", 'vtysh -c "show bgp ipv4 uni"', "i5.*i5", "wait", "See CE routes") -luCommand("r4", 'vtysh -c "show bgp ipv4 uni"', "i5.*i5", "wait", "See CE routes") +luCommand("r1", 'vtysh -c "show bgp ipv4 uni"', "i 5.*i 5", "wait", "See CE routes") +luCommand("r3", 'vtysh -c "show bgp ipv4 uni"', "i 5.*i 5", "wait", "See CE routes") +luCommand("r4", 'vtysh -c "show bgp ipv4 uni"', "i 5.*i 5", "wait", "See CE routes") luCommand("ce1", 'vtysh -c "show bgp ipv4 uni 5.1.0.0/24"', "", "none", "See CE routes") luCommand("r1", 'vtysh -c "show bgp ipv4 uni 5.1.0.0/24"', "", "none", "See CE routes") luCommand("ce2", 'vtysh -c "show bgp ipv4 uni 5.1.0.0/24"', "", "none", "See CE routes") @@ -39,22 +39,22 @@ luCommand( "r3", 'vtysh -c "show bgp ipv4 vpn"', - "i99.0.0.1/32", + "i 99.0.0.1/32", "wait", "See R1s static address", ) luCommand( "r4", 'vtysh -c "show bgp ipv4 vpn"', - "i99.0.0.1/32", + "i 99.0.0.1/32", "wait", "See R1s static address", ) luCommand( - "r3", 'vtysh -c "show bgp ipv4 vpn rd 10:1"', "i5.*i5", "wait", "See R1s imports" + "r3", 'vtysh -c "show bgp ipv4 vpn rd 10:1"', "i 5.*i 5", "wait", "See R1s imports" ) luCommand( - "r4", 'vtysh -c "show bgp ipv4 vpn rd 10:1"', "i5.*i5", "wait", "See R1s imports" + "r4", 'vtysh -c "show bgp ipv4 vpn rd 10:1"', "i 5.*i 5", "wait", "See R1s imports" ) luCommand( @@ -86,14 +86,14 @@ luCommand( "r1", 'vtysh -c "show bgp ipv4 vpn"', - "i99.0.0.2/32", + "i 99.0.0.2/32", "wait", "See R3s static address", ) luCommand( "r4", 'vtysh -c "show bgp ipv4 vpn"', - "i99.0.0.2/32", + "i 99.0.0.2/32", "wait", "See R3s static address", ) @@ -101,14 +101,14 @@ luCommand( "r1", 'vtysh -c "show bgp ipv4 vpn rd 10:3"', - "i5.*i5", + "i 5.*i 5", "none", "See R3s imports", ) luCommand( "r4", 'vtysh -c "show bgp ipv4 vpn rd 10:3"', - "i5.*i5", + "i 5.*i 5", "none", "See R3s imports", ) @@ -133,22 +133,22 @@ luCommand( "r1", 'vtysh -c "show bgp ipv4 vpn"', - "i99.0.0.3/32", + "i 99.0.0.3/32", "wait", "See R4s static address", ) luCommand( "r3", 'vtysh -c "show bgp ipv4 vpn"', - "i99.0.0.3/32", + "i 99.0.0.3/32", "wait", "See R4s static address", ) luCommand( - "r1", 'vtysh -c "show bgp ipv4 vpn rd 10:4"', "i5.*i5", "wait", "See R4s imports" + "r1", 'vtysh -c "show bgp ipv4 vpn rd 10:4"', "i 5.*i 5", "wait", "See R4s imports" ) luCommand( - "r3", 'vtysh -c "show bgp ipv4 vpn rd 10:4"', "i5.*i5", "wait", "See R4s imports" + "r3", 'vtysh -c "show bgp ipv4 vpn rd 10:4"', "i 5.*i 5", "wait", "See R4s imports" ) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py index 6cd92e293d1a..c9666601aa7e 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py @@ -7,18 +7,36 @@ luCommand("ce2", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up", 180) luCommand("ce3", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up", 180) luCommand( - "r1", 'vtysh -c "show ip route ospf"', "2.2.2.2", "wait", "OSPF Route has Arrived", 60) + "r1", + 'vtysh -c "show ip route ospf"', + "2.2.2.2", + "wait", + "OSPF Route has Arrived", + 60, +) luCommand( "r1", "ping 2.2.2.2 -c 1", " 0. packet loss", "wait", "PE->P2 (loopback) ping", 60 ) luCommand( - "r3", 'vtysh -c "show ip route ospf"', "2.2.2.2", "wait", "OSPF Route has Arrived", 60) + "r3", + 'vtysh -c "show ip route ospf"', + "2.2.2.2", + "wait", + "OSPF Route has Arrived", + 60, +) luCommand( "r3", "ping 2.2.2.2 -c 1", " 0. packet loss", "wait", "PE->P2 (loopback) ping", 60 ) luCommand( - "r4", 'vtysh -c "show ip route ospf"', "2.2.2.2", "wait", "OSPF Route has Arrived", 60) + "r4", + 'vtysh -c "show ip route ospf"', + "2.2.2.2", + "wait", + "OSPF Route has Arrived", + 60, +) luCommand( "r4", "ping 2.2.2.2 -c 1", " 0. packet loss", "wait", "PE->P2 (loopback) ping", 60 ) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py index 0ac535030846..45c44ba5dba5 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py @@ -161,6 +161,17 @@ def ltemplatePreRouterStartHook(): logger.info( "setup {0} vrf {0}-cust1, {0}-eth4. enabled mpls input.".format(rtr) ) + # configure cust4 VRFs & MPLS + cmds = [ + "ip link add {0}-cust4 type vrf table 30", + "ip link set dev {0}-cust4 up", + "ip link add {0}-cust5 type vrf table 40", + "ip link set dev {0}-cust5 up", + ] + rtr = "r1" + for cmd in cmds: + cc.doCmd(tgen, rtr, cmd.format(rtr)) + logger.info("setup {0} vrf {0}-cust3 and{0}-cust4.".format(rtr)) # configure cust2 VRFs & MPLS rtrs = ["r4"] cmds = [ diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf index 72211fee7f10..0d652dac0739 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -50,6 +50,31 @@ router bgp 5227 vrf r1-cust1 export vpn exit-address-family +router bgp 5227 vrf r1-cust4 + no bgp network import-check -! -end + bgp router-id 192.168.1.1 + + address-family ipv4 unicast + network 172.16.0.0/24 + + rd vpn export 10:14 + rt vpn export 52:100 + + import vpn + export vpn + exit-address-family + +router bgp 5227 vrf r1-cust5 + bgp router-id 192.168.1.1 + + address-family ipv4 unicast + network 172.16.1.1/32 + + label vpn export 105 + rd vpn export 10:15 + rt vpn both 52:100 + + import vpn + export vpn + exit-address-family diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf index 221bc7a839c8..9a5b0a605e0e 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf @@ -18,6 +18,10 @@ interface r1-eth4 ip address 192.168.1.1/24 no link-detect +interface r1-cust5 + ip address 172.16.1.1/32 + no link-detect + ip forwarding diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py index 1e2758c1c962..217657d35868 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py @@ -59,12 +59,28 @@ {"p": "5.1.1.0/24", "n": "99.0.0.1"}, {"p": "6.0.1.0/24", "n": "99.0.0.1"}, {"p": "6.0.2.0/24", "n": "99.0.0.1"}, + {"p": "172.16.0.0/24", "n": "0.0.0.0", "bp": True}, + {"p": "172.16.1.1/32", "n": "0.0.0.0", "bp": True}, {"p": "99.0.0.1/32", "n": "192.168.1.2"}, ] bgpribRequireUnicastRoutes( "r1", "ipv4", "r1-cust1", "Customer 1 routes in r1 vrf", want_r1_cust1_routes ) +want_r1_cust4_routes = [ + {"p": "172.16.0.0/24", "n": "0.0.0.0", "bp": True}, +] +bgpribRequireUnicastRoutes( + "r1", "ipv4", "r1-cust4", "Customer 4 routes in r1 vrf", want_r1_cust4_routes +) + +want_r1_cust5_routes = [ + {"p": "172.16.1.1/32", "n": "0.0.0.0", "bp": True}, +] +bgpribRequireUnicastRoutes( + "r1", "ipv4", "r1-cust5", "Customer 5 routes in r1 vrf", want_r1_cust5_routes +) + want_r3_cust1_routes = [ {"p": "5.1.0.0/24", "n": "99.0.0.2"}, {"p": "5.1.1.0/24", "n": "99.0.0.2"}, @@ -667,7 +683,7 @@ luCommand( "ce1", 'vtysh -c "show bgp ipv4 uni"', - "12 routes and 12", + "14 routes and 14", "wait", "Local and remote routes", 10, @@ -689,7 +705,7 @@ luCommand( "ce2", 'vtysh -c "show bgp ipv4 uni"', - "12 routes and 15", + "14 routes and 17", "wait", "Local and remote routes", 10, @@ -721,7 +737,7 @@ luCommand( "ce3", 'vtysh -c "show bgp ipv4 uni"', - "12 routes and 13", + "14 routes and 15", "wait", "Local and remote routes", 10, @@ -743,7 +759,7 @@ luCommand( "ce4", 'vtysh -c "show bgp vrf ce4-cust2 ipv4 uni"', - "12 routes and 14", + "14 routes and 16", "wait", "Local and remote routes", 10, @@ -875,4 +891,11 @@ "pass", "Redundant route 2 details", ) +luCommand( + "r1", + 'vtysh -c "show ip route vrf r1-cust5 5.1.0.0/24"', + "Known via .bgp., distance 200, .* vrf r1-cust5, best", + "pass", + "Recursive route leak details", +) # done diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py index 36be926227d0..190879cc278f 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py @@ -49,7 +49,7 @@ luCommand( rtr, 'vtysh -c "show bgp ipv4 uni" | grep Display', - " 12 route", + " 14 route", "wait", "BGP routes removed", wait, diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py index 46993c7d9a46..2ce4bc59be9d 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py @@ -70,7 +70,7 @@ "See all sharp routes in rib on ce1", wait, wait_time=10, - ) + ) luCommand( "ce2", 'vtysh -c "show ip route summ" | grep "sharp" | cut -d " " -f 33', @@ -79,7 +79,7 @@ "See all sharp routes in rib on ce2", wait, wait_time=10, - ) + ) rtrs = ["ce1", "ce2", "ce3"] for rtr in rtrs: @@ -226,7 +226,7 @@ ave_b = float(delta_b) / float(num) luCommand( rtr, - 'vtysh -c "show thread cpu"', + 'vtysh -c "show event cpu"', ".", "pass", "BGPd heap: {0} {1} --> {2} {3} ({4} {1}/vpn route)".format( @@ -239,7 +239,7 @@ ) luCommand( rtr, - 'vtysh -c "show thread cpu"', + 'vtysh -c "show event cpu"', ".", "pass", "Zebra heap: {0} {1} --> {2} {3} ({4} {1}/vpn route)".format( diff --git a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py index f4bb487e4091..25fd0dbb71a4 100644 --- a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py +++ b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py @@ -57,7 +57,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py index 34c23d9b6fe7..009b39eef0ca 100644 --- a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py +++ b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py @@ -22,7 +22,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -42,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ip_route.ref.diff b/tests/topotests/bgp_large_comm_list_match/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step2/show_ip_route.ref.diff rename to tests/topotests/bgp_large_comm_list_match/__init__.py diff --git a/tests/topotests/bgp_large_comm_list_match/r1/bgpd.conf b/tests/topotests/bgp_large_comm_list_match/r1/bgpd.conf new file mode 100644 index 000000000000..1a91f0f5ccfe --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r1/bgpd.conf @@ -0,0 +1,28 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.0.2 remote-as external + neighbor 192.168.0.2 timers 1 3 + neighbor 192.168.0.2 timers connect 1 + address-family ipv4 + redistribute connected + neighbor 192.168.0.2 route-map r2 out + exit-address-family +! +ip prefix-list p1 seq 5 permit 172.16.255.1/32 +ip prefix-list p3 seq 5 permit 172.16.255.3/32 +ip prefix-list p4 seq 5 permit 172.16.255.4/32 +! +route-map r2 permit 10 + match ip address prefix-list p1 + set large-community 65001:1:1 65001:2:1 +route-map r2 permit 20 + match ip address prefix-list p3 + set large-community 65001:3:1 +route-map r2 permit 30 + match ip address prefix-list p4 + set large-community 65001:10:1 65001:12:1 65001:13:1 +exit +route-map r2 permit 40 +exit +! diff --git a/tests/topotests/bgp_large_comm_list_match/r1/zebra.conf b/tests/topotests/bgp_large_comm_list_match/r1/zebra.conf new file mode 100644 index 000000000000..4219a7ca3a4e --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r1/zebra.conf @@ -0,0 +1,12 @@ +! +interface lo + ip address 172.16.255.1/32 + ip address 172.16.255.2/32 + ip address 172.16.255.3/32 + ip address 172.16.255.4/32 +! +interface r1-eth0 + ip address 192.168.0.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_large_comm_list_match/r2/bgpd.conf b/tests/topotests/bgp_large_comm_list_match/r2/bgpd.conf new file mode 100644 index 000000000000..779b705b58ba --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r2/bgpd.conf @@ -0,0 +1,24 @@ +! +!debug bgp updates +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as external + neighbor 192.168.0.1 timers 1 3 + neighbor 192.168.0.1 timers connect 1 + neighbor 192.168.1.3 remote-as external + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + address-family ipv4 + neighbor 192.168.0.1 route-map r1 in + neighbor 192.168.0.1 soft-reconfiguration inbound + exit-address-family +! +bgp large-community-list 1 seq 5 permit 65001:1:1 65001:2:1 +bgp large-community-list 1 seq 10 permit 65001:3:1 +! +route-map r1 deny 10 + match large-community 1 +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_large_comm_list_match/r2/zebra.conf b/tests/topotests/bgp_large_comm_list_match/r2/zebra.conf new file mode 100644 index 000000000000..7fe82bac8ff7 --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r2/zebra.conf @@ -0,0 +1,9 @@ +! +interface r2-eth0 + ip address 192.168.0.2/24 +! +interface r2-eth1 + ip address 192.168.1.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_large_comm_list_match/r3/bgpd.conf b/tests/topotests/bgp_large_comm_list_match/r3/bgpd.conf new file mode 100644 index 000000000000..e7cb76a43665 --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r3/bgpd.conf @@ -0,0 +1,21 @@ +! +!debug bgp updates +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 + neighbor 192.168.1.2 route-map r1 in + neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +bgp large-community-list 2 seq 10 permit 65001:12:1 +! +route-map r1 deny 10 + match large-community 2 any +exit +route-map r1 permit 20 +exit +! diff --git a/tests/topotests/bgp_large_comm_list_match/r3/zebra.conf b/tests/topotests/bgp_large_comm_list_match/r3/zebra.conf new file mode 100644 index 000000000000..755dd18bfe88 --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.1.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py new file mode 100644 index 000000000000..49681c6a690a --- /dev/null +++ b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright 2023 by 6WIND S.A. +# + +""" +Check if BGP large-community-list works +when used as match rule in incoming route-maps. + +- case 1 should deny incoming updates with large-community-list 1 +bgp large-community-list 1 seq 5 permit 65001:1:1 65001:2:1 +bgp large-community-list 1 seq 10 permit 65001:3:1 +! +route-map r1 deny 10 + match large-community 1 + +route-map test deny 10 + match community 1 + +- case 2 should deny incoming updates with any large-community-list 1 +bgp large-community-list 2 seq 10 permit 65001:12:1 +! +route-map r1 deny 10 + match large-community 2 any +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_large_comm_list_match(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.0.1 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.1/32": { + "path": "65001", + }, + "172.16.255.3/32": { + "path": "65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("BGP filtering check with large-community-list on R2") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), "Failed to filter BGP UPDATES with large-community-list on R2" + + +def test_bgp_large_comm_list_match_any(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads( + router.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 filtered-routes json" + ) + ) + expected = { + "receivedRoutes": { + "172.16.255.4/32": { + "path": "65002 65001", + }, + } + } + return topotest.json_cmp(output, expected) + + step("BGP filtering check with large-community-list on R3") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), "Failed to filter BGP UPDATES with large-community-list on R3" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json index 3c02e2675d12..5773d8606533 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-1.json @@ -7,12 +7,12 @@ { "fib":true, "ip":"11.1.1.6", - "weight":25 + "weight":84 }, { "fib":true, "ip":"11.1.1.2", - "weight":75 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json index 3c2d42caaca3..a65eb8f59175 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-2.json @@ -7,12 +7,12 @@ { "fib":true, "ip":"11.1.1.6", - "weight":33 + "weight":127 }, { "fib":true, "ip":"11.1.1.2", - "weight":66 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json index 3d80018ceab5..a1546f57ec72 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-3.json @@ -7,12 +7,12 @@ { "fib":true, "ip":"11.1.1.6", - "weight":33 + "weight":127 }, { "fib":true, "ip":"11.1.1.2", - "weight":66 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json index 6ed3f8ef556e..0444d2d6cb12 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-6.json @@ -7,7 +7,7 @@ { "fib":true, "ip":"11.1.1.2", - "weight":100 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json index 95531d99be93..dd84a0f373fc 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-7.json @@ -7,7 +7,7 @@ { "fib":true, "ip":"11.1.1.2", - "weight":100 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json index beac5013601e..63b7a6b5086b 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-8.json @@ -12,7 +12,7 @@ { "fib":true, "ip":"11.1.1.2", - "weight":100 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json b/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json index eb27ce2633b0..edd764a80acc 100644 --- a/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json +++ b/tests/topotests/bgp_link_bw_ip/r1/ip-route-9.json @@ -12,7 +12,7 @@ { "fib":true, "ip":"11.1.1.2", - "weight":100 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json b/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json index dfc4171bad7a..6289a2eea359 100644 --- a/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json +++ b/tests/topotests/bgp_link_bw_ip/r2/bgp-route-3.json @@ -4,7 +4,7 @@ { "valid":true, "multipath":true, - "extendedCommunity":{ + "extendedIpv6Community":{ "string":"LB:65302:125000 (1.000 Mbps)" }, "nexthops":[ diff --git a/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json b/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json index 7e2fa6be2504..05928b11677c 100644 --- a/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json +++ b/tests/topotests/bgp_link_bw_ip/r2/ip-route-2.json @@ -7,12 +7,12 @@ { "fib":true, "ip":"11.1.2.6", - "weight":33 + "weight":127 }, { "fib":true, "ip":"11.1.2.2", - "weight":66 + "weight":254 } ] } diff --git a/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf index 4014bfbc8bb9..e4ed92db1d89 100644 --- a/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf +++ b/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf @@ -13,6 +13,7 @@ router bgp 65302 bgp bestpath as-path multipath-relax no bgp ebgp-requires-policy neighbor 11.1.2.5 remote-as external + neighbor 11.1.2.5 extended-link-bandwidth neighbor 11.1.2.5 timers 3 10 neighbor 11.1.5.2 remote-as external neighbor 11.1.5.2 timers 3 10 diff --git a/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py b/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py index af6976b5a6ed..fd67b2ecddff 100644 --- a/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py +++ b/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py @@ -53,7 +53,39 @@ def build_topo(tgen): - "Build function" + """ + Build function + + +------+ + | | + /| r7 |--- + / | 65351| + / +------+ + / + +------+ / +------+ + | |/ | | + /| r4 | | r8 |--- + / | 65301|------| 65352| + / +------+ +------+ + / + +------+ / +------+ +------+ + | |/ | | | | + | r2 | | r5 | | r9 |--- + | 65201|------| 65302|------| 65353| + +------+ +------+ +------+ + | + +------+ | + | |---------- + | r1 | + | 65101|---------- + +------+ | + | + +------+ +------+ +------+ + | | | | | | + | r3 |------| r6 |------| r10 |--- + | 65202| | 65303| | 65354| + +------+ +------+ +------+ + """ # Create 10 routers - 1 super-spine, 2 spines, 3 leafs # and 4 servers diff --git a/tests/topotests/bgp_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py index d604871303ff..547c998c2b19 100644 --- a/tests/topotests/bgp_llgr/test_bgp_llgr.py +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -32,12 +32,9 @@ from lib.common_config import ( kill_router_daemons, - start_router_daemons, step, ) -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(0, 6): @@ -67,7 +64,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as/test_bgp_local_as.py b/tests/topotests/bgp_local_as/test_bgp_local_as.py index 9e5f146b47cb..e61bb0d1558f 100644 --- a/tests/topotests/bgp_local_as/test_bgp_local_as.py +++ b/tests/topotests/bgp_local_as/test_bgp_local_as.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py index 930fd791b0a5..c58322a4c0ab 100644 --- a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py +++ b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py @@ -63,7 +63,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py index 9d22a799a6b5..23eb80f31676 100644 --- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py +++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py index 26e8fe970193..214b24eed862 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py @@ -25,7 +25,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, @@ -35,7 +34,7 @@ verify_rib, step, check_address_types, - check_router_status + check_router_status, ) from lib.topolog import logger diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py index 8a1157052e5b..ce448329eb85 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py @@ -21,7 +21,6 @@ import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -31,7 +30,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py index 25c9bee93c85..ff1a81472df0 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py @@ -39,7 +39,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py index 0c10c6409f18..5d290ce42721 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py @@ -31,7 +31,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py index ea6ab59b3f0f..0c7e7cf5c18d 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py @@ -26,7 +26,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py index b1204bf58366..5a0f34132a2c 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py @@ -24,7 +24,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py index cb8fa1e9f981..453f05822371 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py @@ -38,7 +38,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, @@ -48,7 +47,7 @@ verify_rib, step, check_address_types, - check_router_status + check_router_status, ) from lib.topolog import logger @@ -163,7 +162,9 @@ def test_verify_bgp_local_as_agg_in_EBGP_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -190,7 +191,9 @@ def test_verify_bgp_local_as_agg_in_EBGP_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py index 6937a61c338a..d52ed4c3342c 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py @@ -34,7 +34,6 @@ import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -44,7 +43,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py index e9234f5172c5..4ee112ebbf2e 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py @@ -52,7 +52,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, @@ -229,7 +228,9 @@ def test_verify_bgp_local_as_in_EBGP_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -256,7 +257,9 @@ def test_verify_bgp_local_as_in_EBGP_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } @@ -832,7 +835,9 @@ def test_verify_bgp_local_as_GR_EBGP_p0(request): "neighbor": { "r2": { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -861,7 +866,9 @@ def test_verify_bgp_local_as_GR_EBGP_p0(request): "neighbor": { "r4": { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -1395,7 +1402,9 @@ def test_verify_bgp_local_as_in_EBGP_aspath_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -1422,7 +1431,9 @@ def test_verify_bgp_local_as_in_EBGP_aspath_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } @@ -1593,7 +1604,10 @@ def test_verify_bgp_local_as_in_EBGP_aspath_p0(request): { "action": "permit", "set": { - "path": {"as_num": "1.1000 1.1000", "as_action": "prepend"} + "path": { + "as_num": "1.1000 1.1000", + "as_action": "prepend", + } }, } ] @@ -1778,7 +1792,9 @@ def test_verify_bgp_local_as_in_iBGP_p0(request): "neighbor": { "r4": { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -2137,7 +2153,9 @@ def test_verify_bgp_local_as_allow_as_in_iBGP_p0(request): "neighbor": { "r2": { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -2166,7 +2184,9 @@ def test_verify_bgp_local_as_allow_as_in_iBGP_p0(request): "neighbor": { "r4": { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -2484,7 +2504,9 @@ def test_verify_bgp_local_as_in_EBGP_port_reset_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -2511,7 +2533,9 @@ def test_verify_bgp_local_as_in_EBGP_port_reset_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } @@ -2824,7 +2848,9 @@ def test_verify_bgp_local_as_in_EBGP_negative2_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -2851,7 +2877,9 @@ def test_verify_bgp_local_as_in_EBGP_negative2_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } @@ -3164,7 +3192,9 @@ def test_verify_bgp_local_as_in_EBGP_negative3_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -3191,7 +3221,9 @@ def test_verify_bgp_local_as_in_EBGP_negative3_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } @@ -3354,7 +3386,9 @@ def test_verify_bgp_local_as_in_EBGP_restart_daemons_p0(request): "neighbor": { neighbor: { "dest_link": { - "r3": {"local_asn": {"local_as": "1.110"}} + "r3": { + "local_asn": {"local_as": "1.110"} + } } } } @@ -3381,7 +3415,9 @@ def test_verify_bgp_local_as_in_EBGP_restart_daemons_p0(request): "neighbor": { neighbor: { "dest_link": { - dut: {"local_asn": {"remote_as": "1.110"}} + dut: { + "local_asn": {"remote_as": "1.110"} + } } } } diff --git a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py index 0656e1ed41e4..18ffc6a17d9f 100644 --- a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py +++ b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py @@ -142,7 +142,7 @@ def test_converge_bgplu(): "192.168.2.2/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, prefix 192.168.2.2/32 from r2 not present" # Check r2 gets prefix 192.168.2.1/32 @@ -153,7 +153,7 @@ def test_converge_bgplu(): "192.168.2.1/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, prefix 192.168.2.1/32 from r1 not present" @@ -178,7 +178,7 @@ def _check_ping(name, dest_addr, src_addr): tgen = get_topogen() func = functools.partial(_check_ping, "r1", "192.168.2.2", "192.168.2.1") # tgen.mininet_cli() - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "r1, ping to 192.168.2.2 from 192.168.2.1 fails" diff --git a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json index d35e4ef46304..17b9accb4a50 100644 --- a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json +++ b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json @@ -2,5 +2,5 @@ "ledger":0, "inUse":0, "requests":0, - "labelChunks":1 + "labelChunks":0 } diff --git a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py index a9810ba264b3..545d7bd245a9 100644 --- a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py +++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -82,17 +82,17 @@ def _bgp_has_routes(router, metric): # Check session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check metric has value of max-med test_func = functools.partial(_bgp_has_routes, router2, 777) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 777" # Check that when the max-med timer expires, metric is updated test_func = functools.partial(_bgp_has_routes, router2, 0) - success, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) assert result is None, "r2 does not receive routes with metric 0" diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py index c6bdbc3c1cce..5edc0b55ffc1 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py index 0b346f63d51e..aad5f36480e8 100644 --- a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py +++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -177,7 +177,7 @@ def _bgp_converge(router, nb_prefixes): router1.vtysh_cmd(cmd) test_func = functools.partial(_bgp_converge, router2, exp_prfxs) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) diff --git a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py index 9f4d9682778a..c9ff2ffc7e7c 100755 --- a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py +++ b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -76,7 +76,7 @@ def _bgp_neighbor_check_if_notification_sent(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_neighbor_check_if_notification_sent) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) assert result is None, "Failed to send notification message\n" diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 40a28fbcf492..012b643dded9 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -1845,7 +1845,7 @@ def test_vrf_vlan_routing_table_p1(request): dut = "r3" vrf = "RED_A" - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -2634,7 +2634,7 @@ def test_delete_and_re_add_vrf_p1(request): vrfs = ["RED_A", "BLUE_A"] for vrf in vrfs: - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -3584,7 +3584,7 @@ def test_vrf_name_significance_p1(request): vrfs = ["GREY_A", "PINK_A"] for vrf in vrfs: - for c_link, c_data in topo_modify["routers"][dut]["links"].items(): + for _, c_data in topo_modify["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue diff --git a/tests/topotests/bgp_multiview_topo1/exabgp.env b/tests/topotests/bgp_multiview_topo1/exabgp.env index a328e0496289..ec978c66e76e 100644 --- a/tests/topotests/bgp_multiview_topo1/exabgp.env +++ b/tests/topotests/bgp_multiview_topo1/exabgp.env @@ -1,5 +1,6 @@ [exabgp.api] +ack = false encoder = text highres = false respawn = false diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg index 20e71c84203c..0303230b5651 100644 --- a/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer1/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 1 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 1"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 1 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.1; - local-address 172.16.1.1; - local-as 65001; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 1; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.1; + local-address 172.16.1.1; + local-as 65001; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg index 1e8eef186fad..13670c3b52fc 100644 --- a/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer2/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 2 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 2"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 2 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.2; - local-address 172.16.1.2; - local-as 65002; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 2; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.2; + local-address 172.16.1.2; + local-as 65002; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg index ef1b249aebba..0afc484c69ac 100644 --- a/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer3/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 3 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 3"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 3 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.3; - local-address 172.16.1.3; - local-as 65003; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 3; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.3; + local-address 172.16.1.3; + local-as 65003; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg index 7c50f73b260b..0f5b536d9a41 100644 --- a/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer4/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 4 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 4"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 4 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.4; - local-address 172.16.1.4; - local-as 65004; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 4; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.4; + local-address 172.16.1.4; + local-as 65004; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg index 22163c7fb18a..365aa6b8f229 100644 --- a/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer5/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 5 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 5"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 5 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.5; - local-address 172.16.1.5; - local-as 65005; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 5; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.5; + local-address 172.16.1.5; + local-as 65005; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg index 40b54c33c584..10380334b8b6 100644 --- a/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer6/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 6 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 6"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 6 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.6; - local-address 172.16.1.6; - local-as 65006; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 6; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.6; + local-address 172.16.1.6; + local-as 65006; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg index 33312d052f2a..7411338abd66 100644 --- a/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer7/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 7 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 7"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 7 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.7; - local-address 172.16.1.7; - local-as 65007; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 7; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.7; + local-address 172.16.1.7; + local-as 65007; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py index 09f6ea59e5fb..0e50d46041e7 100755 --- a/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg b/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg index 173ccb980e7f..17a4e497e1a6 100644 --- a/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg +++ b/tests/topotests/bgp_multiview_topo1/peer8/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 8 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 8"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 8 10; + encoder text; +} - neighbor 172.16.1.254 { - router-id 172.16.1.8; - local-address 172.16.1.8; - local-as 65008; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 8; + encoder text; +} +neighbor 172.16.1.254 { + router-id 172.16.1.8; + local-address 172.16.1.8; + local-as 65008; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py index 23e820b4fc39..32f78c44f9f0 100644 --- a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py +++ b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py @@ -24,7 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ipv6_route.ref.diff b/tests/topotests/bgp_oad/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step2/show_ipv6_route.ref.diff rename to tests/topotests/bgp_oad/__init__.py diff --git a/tests/topotests/bgp_oad/r1/frr.conf b/tests/topotests/bgp_oad/r1/frr.conf new file mode 100644 index 000000000000..39045ba648eb --- /dev/null +++ b/tests/topotests/bgp_oad/r1/frr.conf @@ -0,0 +1,21 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 oad + neighbor 192.168.1.4 remote-as external + neighbor 192.168.1.4 timers 1 3 + neighbor 192.168.1.4 timers connect 1 + address-family ipv4 unicast + neighbor 192.168.1.4 route-map r4 in + exit-address-family +! +route-map r4 permit 10 + set local-preference 123 + set metric 123 +exit diff --git a/tests/topotests/bgp_oad/r2/frr.conf b/tests/topotests/bgp_oad/r2/frr.conf new file mode 100644 index 000000000000..fdd23f32b48b --- /dev/null +++ b/tests/topotests/bgp_oad/r2/frr.conf @@ -0,0 +1,18 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +int r2-eth1 + ip address 192.168.2.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.1.1 oad + neighbor 192.168.2.3 remote-as external + neighbor 192.168.2.3 timers 1 3 + neighbor 192.168.2.3 timers connect 1 + neighbor 192.168.2.3 oad +! diff --git a/tests/topotests/bgp_oad/r3/frr.conf b/tests/topotests/bgp_oad/r3/frr.conf new file mode 100644 index 000000000000..02dd5adfe190 --- /dev/null +++ b/tests/topotests/bgp_oad/r3/frr.conf @@ -0,0 +1,22 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r3-eth0 + ip address 192.168.2.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as external + neighbor 192.168.2.2 timers 1 3 + neighbor 192.168.2.2 timers connect 1 + neighbor 192.168.2.2 oad + ! + address-family ipv4 unicast + redistribute connected route-map connected + exit-address-family +! +route-map connected permit 10 + set local-preference 123 + set metric 123 +! diff --git a/tests/topotests/bgp_oad/r4/frr.conf b/tests/topotests/bgp_oad/r4/frr.conf new file mode 100644 index 000000000000..83dcf391b774 --- /dev/null +++ b/tests/topotests/bgp_oad/r4/frr.conf @@ -0,0 +1,16 @@ +! +int r4-eth0 + ip address 192.168.1.4/24 +! +int r4-eth1 + ip address 192.168.4.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.4.5 remote-as external + neighbor 192.168.4.5 timers 1 3 + neighbor 192.168.4.5 timers connect 1 +! diff --git a/tests/topotests/bgp_oad/r5/frr.conf b/tests/topotests/bgp_oad/r5/frr.conf new file mode 100644 index 000000000000..f8e1609d15b0 --- /dev/null +++ b/tests/topotests/bgp_oad/r5/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r5-eth0 + ip address 192.168.4.5/24 +! +router bgp 65005 + no bgp ebgp-requires-policy + neighbor 192.168.4.4 remote-as external + neighbor 192.168.4.4 timers 1 3 + neighbor 192.168.4.4 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py new file mode 100644 index 000000000000..6dd46fbdaadc --- /dev/null +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if local-preference is passed between different EBGP peers when +EBGP-OAD is configured. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2", "r4"), "s2": ("r2", "r3"), "s3": ("r4", "r5")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_oad(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "aspath": {"string": "65002 65003"}, + "metric": 123, + "locPrf": 123, + "peer": { + "hostname": "r2", + "type": "external (oad)", + }, + }, + { + "aspath": {"string": "65004 65005"}, + "metric": 123, + "locPrf": 123, + "bestpath": {"selectionReason": "Peer Type"}, + "peer": { + "hostname": "r4", + "type": "external", + }, + }, + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_orf/test_bgp_orf.py b/tests/topotests/bgp_orf/test_bgp_orf.py index 7f45a242c9a1..bc6a85b4b9d3 100644 --- a/tests/topotests/bgp_orf/test_bgp_orf.py +++ b/tests/topotests/bgp_orf/test_bgp_orf.py @@ -20,7 +20,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -29,8 +29,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -39,7 +37,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_path_attribute_discard/peer1/exabgp.cfg b/tests/topotests/bgp_path_attribute_discard/peer1/exabgp.cfg index 7fb9210ecf6e..dccec7d15428 100644 --- a/tests/topotests/bgp_path_attribute_discard/peer1/exabgp.cfg +++ b/tests/topotests/bgp_path_attribute_discard/peer1/exabgp.cfg @@ -1,8 +1,8 @@ neighbor 10.0.0.1 { - router-id 10.0.0.2; - local-address 10.0.0.2; - local-as 65001; - peer-as 65002; + router-id 10.0.0.254; + local-address 10.0.0.254; + local-as 65254; + peer-as 65001; capability { route-refresh; @@ -12,13 +12,28 @@ neighbor 10.0.0.1 { route 192.168.100.101/32 { atomic-aggregate; community 65001:101; - next-hop 10.0.0.2; + next-hop 10.0.0.254; } route 192.168.100.102/32 { - originator-id 10.0.0.2; + originator-id 10.0.0.254; community 65001:102; - next-hop 10.0.0.2; + next-hop 10.0.0.254; + } + } +} + +neighbor 10.0.0.2 { + router-id 10.0.0.254; + local-address 10.0.0.254; + local-as 65254; + peer-as 65254; + + static { + route 192.168.100.101/32 { + # AIGP invalid attribute: flagged as transitive + optional. + attribute [0x1a 0xc0 0x00000064]; + next-hop 10.0.0.254; } } } diff --git a/tests/topotests/bgp_path_attribute_discard/r1/bgpd.conf b/tests/topotests/bgp_path_attribute_discard/r1/bgpd.conf deleted file mode 100644 index c96f354cc597..000000000000 --- a/tests/topotests/bgp_path_attribute_discard/r1/bgpd.conf +++ /dev/null @@ -1,6 +0,0 @@ -! -router bgp 65002 - no bgp ebgp-requires-policy - neighbor 10.0.0.2 remote-as external - neighbor 10.0.0.2 timers 3 10 -! diff --git a/tests/topotests/bgp_path_attribute_discard/r1/frr.conf b/tests/topotests/bgp_path_attribute_discard/r1/frr.conf new file mode 100644 index 000000000000..ae7fbdd9a93a --- /dev/null +++ b/tests/topotests/bgp_path_attribute_discard/r1/frr.conf @@ -0,0 +1,9 @@ +! +interface r1-eth0 + ip address 10.0.0.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 10.0.0.254 remote-as external + neighbor 10.0.0.254 timers 3 10 +! diff --git a/tests/topotests/bgp_path_attribute_discard/r1/zebra.conf b/tests/topotests/bgp_path_attribute_discard/r1/zebra.conf deleted file mode 100644 index 51a1b2657cd9..000000000000 --- a/tests/topotests/bgp_path_attribute_discard/r1/zebra.conf +++ /dev/null @@ -1,4 +0,0 @@ -! -interface r1-eth0 - ip address 10.0.0.1/24 -! diff --git a/tests/topotests/bgp_path_attribute_discard/r2/frr.conf b/tests/topotests/bgp_path_attribute_discard/r2/frr.conf new file mode 100644 index 000000000000..1dafbdd8e19f --- /dev/null +++ b/tests/topotests/bgp_path_attribute_discard/r2/frr.conf @@ -0,0 +1,10 @@ +! +interface r2-eth0 + ip address 10.0.0.2/24 +! +router bgp 65254 + no bgp ebgp-requires-policy + neighbor 10.0.0.254 remote-as internal + neighbor 10.0.0.254 timers 3 10 + neighbor 10.0.0.254 path-attribute discard 26 +! diff --git a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py index c97cd0bddabd..adc92f59fe4b 100644 --- a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py +++ b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py @@ -23,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -31,10 +31,12 @@ def build_topo(tgen): r1 = tgen.add_router("r1") - peer1 = tgen.add_exabgp_peer("peer1", ip="10.0.0.2", defaultRoute="via 10.0.0.1") + r2 = tgen.add_router("r2") + peer1 = tgen.add_exabgp_peer("peer1", ip="10.0.0.254", defaultRoute="via 10.0.0.1") switch = tgen.add_switch("s1") switch.add_link(r1) + switch.add_link(r2) switch.add_link(peer1) @@ -42,10 +44,10 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() - router = tgen.gears["r1"] - router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf")) - router.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "r1/bgpd.conf")) - router.start() + for _, (rname, router) in enumerate(tgen.routers().items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() peer = tgen.gears["peer1"] peer.start(os.path.join(CWD, "peer1"), os.path.join(CWD, "exabgp.env")) @@ -63,6 +65,7 @@ def test_bgp_path_attribute_discard(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] def _bgp_converge(): output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json detail")) @@ -103,7 +106,7 @@ def _bgp_converge(): """ configure terminal router bgp - neighbor 10.0.0.2 path-attribute discard 6 8 + neighbor 10.0.0.254 path-attribute discard 6 8 """ ) @@ -139,6 +142,28 @@ def _bgp_check_if_attributes_discarded(): result is None ), "Failed to discard path attributes (atomic-aggregate, community)" + def _bgp_check_if_aigp_invalid_attribute_discarded(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast json detail")) + expected = { + "routes": { + "192.168.100.101/32": { + "paths": [ + { + "valid": True, + "aigpMetric": None, + } + ], + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_if_aigp_invalid_attribute_discarded) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert ( + result is None + ), "Failed to discard AIGP invalid path attribute (iBGP session)" + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_path_attributes_topo1/test_bgp_path_attributes.py b/tests/topotests/bgp_path_attributes_topo1/test_bgp_path_attributes.py index df390327d407..8504737d82c3 100644 --- a/tests/topotests/bgp_path_attributes_topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp_path_attributes_topo1/test_bgp_path_attributes.py @@ -78,6 +78,7 @@ # Address read from env variables ADDR_TYPES = check_address_types() + #### def setup_module(mod): """ diff --git a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py index bf5737b6604d..d486a87e9c89 100644 --- a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py +++ b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py @@ -49,11 +49,15 @@ def setup_module(mod): for routern in range(1, 4): tgen.gears["r{}".format(routern)].cmd("ip link add vrf1 type vrf table 10") tgen.gears["r{}".format(routern)].cmd("ip link set vrf1 up") - tgen.gears["r{}".format(routern)].cmd("ip address add dev vrf1 {}.{}.{}.{}/32".format(routern, routern, routern,routern)) + tgen.gears["r{}".format(routern)].cmd( + "ip address add dev vrf1 {}.{}.{}.{}/32".format( + routern, routern, routern, routern + ) + ) tgen.gears["r2"].cmd("ip address add dev vrf1 192.0.2.8/32") tgen.gears["r3"].cmd("ip address add dev vrf1 192.0.2.8/32") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -74,6 +78,7 @@ def teardown_module(mod): tgen = get_topogen() tgen.stop_topology() + def test_bgp_path_selection_ecmp(): tgen = get_topogen() @@ -97,7 +102,7 @@ def _bgp_check_path_selection_ecmp(): "aspath": {"string": "65002"}, "multipath": True, "nexthops": [{"ip": "192.0.2.3", "metric": 20}], - } + }, ] } @@ -117,7 +122,9 @@ def test_bgp_path_selection_vpn_ecmp(): def _bgp_check_path_selection_vpn_ecmp(): output = json.loads( - tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.2.8/32 json") + tgen.gears["r1"].vtysh_cmd( + "show bgp vrf vrf1 ipv4 unicast 192.0.2.8/32 json" + ) ) expected = { "paths": [ @@ -132,7 +139,7 @@ def _bgp_check_path_selection_vpn_ecmp(): "aspath": {"string": "65002"}, "multipath": True, "nexthops": [{"ip": "192.0.2.3", "metric": 20}], - } + }, ] } @@ -160,13 +167,13 @@ def _bgp_check_path_selection_metric(): "valid": True, "aspath": {"string": "65002"}, "nexthops": [{"ip": "192.0.2.2", "metric": 10}], - "bestpath":{ "selectionReason":"IGP Metric"}, + "bestpath": {"selectionReason": "IGP Metric"}, }, { "valid": True, "aspath": {"string": "65002"}, "nexthops": [{"ip": "192.0.2.3", "metric": 20}], - } + }, ] } @@ -189,7 +196,9 @@ def test_bgp_path_selection_vpn_metric(): def _bgp_check_path_selection_vpn_metric(): output = json.loads( - tgen.gears["r1"].vtysh_cmd("show bgp vrf vrf1 ipv4 unicast 192.0.2.8/32 json") + tgen.gears["r1"].vtysh_cmd( + "show bgp vrf vrf1 ipv4 unicast 192.0.2.8/32 json" + ) ) expected = { "paths": [ @@ -197,13 +206,13 @@ def _bgp_check_path_selection_vpn_metric(): "valid": True, "aspath": {"string": "65002"}, "nexthops": [{"ip": "192.0.2.2", "metric": 10}], - "bestpath":{ "selectionReason":"IGP Metric"}, + "bestpath": {"selectionReason": "IGP Metric"}, }, { "valid": True, "aspath": {"string": "65002"}, "nexthops": [{"ip": "192.0.2.3", "metric": 20}], - } + }, ] } diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py index 2eb936aaa0aa..c6ee9aa73c4c 100644 --- a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py +++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py @@ -16,7 +16,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -26,8 +26,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.common_config import step -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")} @@ -36,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_group/r1/bgpd.conf b/tests/topotests/bgp_peer_group/r1/bgpd.conf index 19b490a359e8..68d8e61a5981 100644 --- a/tests/topotests/bgp_peer_group/r1/bgpd.conf +++ b/tests/topotests/bgp_peer_group/r1/bgpd.conf @@ -5,4 +5,8 @@ router bgp 65001 neighbor PG timers 3 10 neighbor 192.168.255.3 peer-group PG neighbor r1-eth0 interface peer-group PG + neighbor PG1 peer-group + neighbor PG1 remote-as external + neighbor PG1 timers 3 20 + neighbor 192.168.251.2 peer-group PG1 ! diff --git a/tests/topotests/bgp_peer_group/r1/zebra.conf b/tests/topotests/bgp_peer_group/r1/zebra.conf index e2c399e536ae..16fd8c538c4f 100644 --- a/tests/topotests/bgp_peer_group/r1/zebra.conf +++ b/tests/topotests/bgp_peer_group/r1/zebra.conf @@ -2,5 +2,8 @@ interface r1-eth0 ip address 192.168.255.1/24 ! +interface r1-eth1 + ip address 192.168.251.1/30 +! ip forwarding ! diff --git a/tests/topotests/bgp_peer_group/r2/bgpd.conf b/tests/topotests/bgp_peer_group/r2/bgpd.conf index 0880ee9fae58..d0e8f017d1d6 100644 --- a/tests/topotests/bgp_peer_group/r2/bgpd.conf +++ b/tests/topotests/bgp_peer_group/r2/bgpd.conf @@ -4,4 +4,8 @@ router bgp 65002 neighbor PG remote-as external neighbor PG timers 3 10 neighbor r2-eth0 interface peer-group PG + neighbor PG1 peer-group + neighbor PG1 remote-as external + neighbor PG1 timers 3 20 + neighbor 192.168.251.1 peer-group PG1 ! diff --git a/tests/topotests/bgp_peer_group/r2/zebra.conf b/tests/topotests/bgp_peer_group/r2/zebra.conf index 606c17bec9c1..c2ad956c9c64 100644 --- a/tests/topotests/bgp_peer_group/r2/zebra.conf +++ b/tests/topotests/bgp_peer_group/r2/zebra.conf @@ -2,5 +2,8 @@ interface r2-eth0 ip address 192.168.255.2/24 ! +interface r2-eth1 + ip address 192.168.251.2/30 +! ip forwarding ! diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py index a91fade04924..7d476b053852 100644 --- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py @@ -22,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen - +from lib.topolog import logger pytestmark = [pytest.mark.bgpd] @@ -36,6 +36,10 @@ def build_topo(tgen): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r3"]) + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) @@ -43,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -70,6 +74,7 @@ def _bgp_peer_group_configured(): expected = { "r1-eth0": {"peerGroup": "PG", "bgpState": "Established"}, "192.168.255.3": {"peerGroup": "PG", "bgpState": "Established"}, + "192.168.251.2": {"peerGroup": "PG1", "bgpState": "Established"}, } return topotest.json_cmp(output, expected) @@ -96,6 +101,48 @@ def _bgp_peer_group_check_advertised_routes(): assert result is None, "Failed checking advertised routes from r3" +def test_bgp_peer_group_remote_as_del_readd(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + logger.info("Remove bgp peer-group PG1 remote-as neighbor should be retained") + r1.cmd( + 'vtysh -c "config t" -c "router bgp 65001" ' + + ' -c "no neighbor PG1 remote-as external" ' + ) + + def _bgp_peer_group_remoteas_del(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.251.2": {"peerGroup": "PG1", "bgpState": "Active"}, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_peer_group_remoteas_del) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed bgp convergence in r1" + + logger.info("Re-add bgp peer-group PG1 remote-as neighbor should be established") + r1.cmd( + 'vtysh -c "config t" -c "router bgp 65001" ' + + ' -c "neighbor PG1 remote-as external" ' + ) + + def _bgp_peer_group_remoteas_add(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.251.2": {"peerGroup": "PG1", "bgpState": "Established"}, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_peer_group_remoteas_add) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed bgp convergence in r1" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_peer_type_multipath_relax/exabgp.env b/tests/topotests/bgp_peer_type_multipath_relax/exabgp.env index 6c554f5fa8af..989228a29327 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/exabgp.env +++ b/tests/topotests/bgp_peer_type_multipath_relax/exabgp.env @@ -1,5 +1,6 @@ [exabgp.api] +ack = false encoder = text highres = false respawn = false @@ -43,7 +44,7 @@ enable = false file = '' [exabgp.reactor] -speed = 1.0 +speed = 5.0 [exabgp.tcp] acl = false diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py index 0f998c16131c..6c1f8b092fad 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer1/exabgp.cfg b/tests/topotests/bgp_peer_type_multipath_relax/peer1/exabgp.cfg index 4a7dc481261e..e6606d22ff23 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer1/exabgp.cfg +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer1/exabgp.cfg @@ -1,21 +1,17 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in"; - encoder text; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 1"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.2; - local-address 10.0.1.2; - local-as 64510; - peer-as 64510; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 1; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.2; + local-address 10.0.1.2; + local-as 64510; + peer-as 64510; + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py index 0f998c16131c..6c1f8b092fad 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer2/exabgp.cfg b/tests/topotests/bgp_peer_type_multipath_relax/peer2/exabgp.cfg index b53b0545509a..6a6ba0bb78e6 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer2/exabgp.cfg +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer2/exabgp.cfg @@ -1,21 +1,17 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in"; - encoder text; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 2"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in; + encoder text; +} - neighbor 10.0.2.1 { - router-id 10.0.2.2; - local-address 10.0.2.2; - local-as 64511; - peer-as 64511; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 2; + encoder text; +} +neighbor 10.0.2.1 { + router-id 10.0.2.2; + local-address 10.0.2.2; + local-as 64511; + peer-as 64511; + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py index 0f998c16131c..6c1f8b092fad 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer3/exabgp.cfg b/tests/topotests/bgp_peer_type_multipath_relax/peer3/exabgp.cfg index 6a1cc2fb3fd1..9714b1f3b556 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer3/exabgp.cfg +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer3/exabgp.cfg @@ -1,21 +1,17 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in"; - encoder text; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 3"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in; + encoder text; +} - neighbor 10.0.3.1 { - router-id 10.0.3.2; - local-address 10.0.3.2; - local-as 64502; - peer-as 64501; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 3; + encoder text; +} +neighbor 10.0.3.1 { + router-id 10.0.3.2; + local-address 10.0.3.2; + local-as 64502; + peer-as 64501; + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py index 0f998c16131c..6c1f8b092fad 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer4/exabgp.cfg b/tests/topotests/bgp_peer_type_multipath_relax/peer4/exabgp.cfg index 2cc26cb80ff4..8c38a881cee0 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer4/exabgp.cfg +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer4/exabgp.cfg @@ -1,21 +1,17 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in"; - encoder text; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 4"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in; + encoder text; +} - neighbor 10.0.4.1 { - router-id 10.0.4.2; - local-address 10.0.4.2; - local-as 64503; - peer-as 64501; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 4; + encoder text; +} +neighbor 10.0.4.1 { + router-id 10.0.4.2; + local-address 10.0.4.2; + local-as 64503; + peer-as 64501; + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json index 22ec2c298b0e..483165c0f377 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json index facddcda463f..638a825395e2 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py b/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py index ad6674c52469..340df71a1994 100755 --- a/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/test_bgp_peer-type_multipath-relax.py @@ -62,6 +62,19 @@ pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] +# Prefixes used in the test +prefix1 = "203.0.113.0/30" +prefix2 = "203.0.113.4/30" +prefix3 = "203.0.113.8/30" +# Next hops used for iBGP/confed routes +resolved_nh1 = "198.51.100.1" +resolved_nh2 = "198.51.100.2" +# BGP route used for recursive resolution +bgp_resolving_prefix = "198.51.100.0/24" +# Next hop that will require non-connected recursive resolution +ebgp_resolved_nh = "198.51.100.10" + + def build_topo(tgen): "Build function" @@ -90,7 +103,6 @@ def setup_module(mod): # For all registered routers, load the zebra configuration file for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/setup_vrfs".format(CWD)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,36 +137,26 @@ def teardown_module(mod): tgen.stop_topology() -def test_bgp_peer_type_multipath_relax(): +def exabgp_cmd(peer, cmd): + pipe = open("/run/exabgp_{}.in".format(peer), "w") + with pipe: + pipe.write(cmd) + pipe.close() + + +def test_bgp_peer_type_multipath_relax_test1(): tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def exabgp_cmd(peer, cmd): - pipe = open("/run/exabgp_{}.in".format(peer), "w") - with pipe: - pipe.write(cmd) - pipe.close() - - # Prefixes used in the test - prefix1 = "203.0.113.0/30" - prefix2 = "203.0.113.4/30" - prefix3 = "203.0.113.8/30" - # Next hops used for iBGP/confed routes - resolved_nh1 = "198.51.100.1" - resolved_nh2 = "198.51.100.2" - # BGP route used for recursive resolution - bgp_resolving_prefix = "198.51.100.0/24" - # Next hop that will require non-connected recursive resolution - ebgp_resolved_nh = "198.51.100.10" + r1 = tgen.gears["r1"] # Send a non-connected route to resolve others exabgp_cmd( "peer3", "announce route {} next-hop self\n".format(bgp_resolving_prefix) ) - router = tgen.gears["r1"] # It seems that if you write to the exabgp socket too quickly in # succession, requests get lost. So verify prefix1 now instead of @@ -177,7 +179,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip bgp {} json".format(prefix1), expected, ) @@ -185,6 +187,16 @@ def exabgp_cmd(peer, cmd): assertMsg = "Mixed-type multipath not found" assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test2(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + logger.info("Create and verify eBGP and iBGP+confed multipaths") exabgp_cmd( "peer1", @@ -203,38 +215,66 @@ def exabgp_cmd(peer, cmd): reffile = os.path.join(CWD, "r1/multipath.json") expected = json.loads(open(reffile).read()) test_func = functools.partial( - topotest.router_json_cmp, router, "show ip bgp json", expected + topotest.router_json_cmp, r1, "show ip bgp json", expected ) _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) assertMsg = "Not all expected multipaths found" assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test3(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + logger.info("Toggle peer-type multipath-relax and verify the changes") - router.vtysh_cmd( + r1.vtysh_cmd( "conf\n router bgp 64510\n no bgp bestpath peer-type multipath-relax\n" ) # This file verifies "multipath" is not set reffile = os.path.join(CWD, "r1/not-multipath.json") expected = json.loads(open(reffile).read()) test_func = functools.partial( - topotest.router_json_cmp, router, "show ip bgp json", expected + topotest.router_json_cmp, r1, "show ip bgp json", expected ) _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) assertMsg = "Disabling peer-type multipath-relax did not take effect" assert res is None, assertMsg - router.vtysh_cmd( - "conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n" - ) + +def test_bgp_peer_type_multipath_relax_test4(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + r1.vtysh_cmd("conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n") reffile = os.path.join(CWD, "r1/multipath.json") expected = json.loads(open(reffile).read()) test_func = functools.partial( - topotest.router_json_cmp, router, "show ip bgp json", expected + topotest.router_json_cmp, r1, "show ip bgp json", expected ) _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) assertMsg = "Reenabling peer-type multipath-relax did not take effect" assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test5(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + logger.info("Check recursive resolution of eBGP next hops is not affected") # eBGP next hop resolution rejects recursively resolved next hops by # default, even with peer-type multipath-relax @@ -245,7 +285,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip bgp {} json".format(prefix3), expected, ) @@ -253,6 +293,16 @@ def exabgp_cmd(peer, cmd): assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3) assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test6(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + exabgp_cmd( "peer4", "announce route {} next-hop {}\n".format(prefix1, ebgp_resolved_nh) ) @@ -260,7 +310,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip bgp {} json".format(prefix1), expected, ) @@ -268,14 +318,24 @@ def exabgp_cmd(peer, cmd): assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1) assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test7(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + # When other config allows recursively resolved eBGP next hops, # such next hops in all-eBGP multipaths should be valid - router.vtysh_cmd("conf\n router bgp 64510\n neighbor 10.0.4.2 ebgp-multihop\n") + r1.vtysh_cmd("conf\n router bgp 64510\n neighbor 10.0.4.2 ebgp-multihop\n") reffile = os.path.join(CWD, "r1/prefix3-recursive.json") expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip bgp {} json".format(prefix3), expected, ) @@ -287,7 +347,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip bgp {} json".format(prefix1), expected, ) @@ -295,6 +355,16 @@ def exabgp_cmd(peer, cmd): assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1) assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test8(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + logger.info("Check mixed-type multipath next hop recursive resolution in FIB") # There are now two eBGP-learned routes with a recursively resolved next; # hop; one is all-eBGP multipath, and the other is iBGP/eBGP/ @@ -305,7 +375,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip route {} json".format(prefix3), expected, ) @@ -313,6 +383,16 @@ def exabgp_cmd(peer, cmd): assertMsg = "FIB next hops mismatch for all-eBGP multipath" assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test9(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + # check confed-external enables recursively resolved next hops by itself exabgp_cmd( "peer1", @@ -324,7 +404,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip route {} json".format(prefix1), expected, ) @@ -332,6 +412,16 @@ def exabgp_cmd(peer, cmd): assertMsg = "FIB next hops mismatch for eBGP+confed-external multipath" assert res is None, assertMsg + +def test_bgp_peer_type_multipath_relax_test10(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + # check iBGP by itself exabgp_cmd( "peer1", @@ -349,7 +439,7 @@ def exabgp_cmd(peer, cmd): expected = json.loads(open(reffile).read()) test_func = functools.partial( topotest.router_json_cmp, - router, + r1, "show ip route {} json".format(prefix1), expected, ) diff --git a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf index 14c28ca90684..593442a42a4a 100644 --- a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf @@ -4,6 +4,10 @@ router bgp 65001 no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 2001:db8:1::2 remote-as external + neighbor 192.168.1.2 timers 3 10 + neighbor 192.168.1.2 timers connect 1 + neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 1 address-family ipv4 unicast network 192.168.0.1/32 no neighbor 2001:db8:1::2 activate diff --git a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf index 733205928f3e..0de5bd335509 100644 --- a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf @@ -6,6 +6,10 @@ router bgp 65002 no bgp network import-check neighbor 192.168.1.1 remote-as external neighbor 2001:db8:1::1 remote-as external + neighbor 192.168.1.1 timers 3 10 + neighbor 192.168.1.1 timers connect 1 + neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv4 unicast network 10.10.10.1/32 network 10.10.10.2/32 diff --git a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py index 0eb244717ef8..1871d3efc8ce 100644 --- a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py +++ b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py @@ -16,7 +16,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -25,8 +25,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -35,7 +33,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_prefix_sid/exabgp.env b/tests/topotests/bgp_prefix_sid/exabgp.env index 6c554f5fa8af..bb36af522ab8 100644 --- a/tests/topotests/bgp_prefix_sid/exabgp.env +++ b/tests/topotests/bgp_prefix_sid/exabgp.env @@ -1,5 +1,6 @@ [exabgp.api] +ack = false encoder = text highres = false respawn = false diff --git a/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg b/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg index 5b55366a0e87..a5108ff0daa3 100644 --- a/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg +++ b/tests/topotests/bgp_prefix_sid/peer1/exabgp.cfg @@ -1,103 +1,101 @@ -group controller { - neighbor 10.0.0.1 { - router-id 10.0.0.101; - local-address 10.0.0.101; - local-as 2; - peer-as 1; +neighbor 10.0.0.1 { + router-id 10.0.0.101; + local-address 10.0.0.101; + local-as 2; + peer-as 1; - family { - ipv4 nlri-mpls; - } + family { + ipv4 nlri-mpls; + } - static { - # ref: draft-ietf-idr-bgp-prefix-sid-27 - # - # IANA temporarily assigned the following: - # attribute code type (suggested value: 40) to - # the BGP Prefix-SID attribute - # - # 0 1 2 3 - # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | Type | Length | RESERVED | - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | Flags | Label Index | - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | Label Index | - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # Figure. Label-Index TLV (Prefix-SID type-1) - # - # 0 1 2 3 - # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | Type | Length | Flags | - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | Flags | - # +-+-+-+-+-+-+-+-+ - # - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | SRGB 1 (6 octets) | - # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | | - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | SRGB n (6 octets) | - # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # | | - # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - # Figure. Originator SRGB TLV (Prefix-SID type-3) + static { + # ref: draft-ietf-idr-bgp-prefix-sid-27 + # + # IANA temporarily assigned the following: + # attribute code type (suggested value: 40) to + # the BGP Prefix-SID attribute + # + # 0 1 2 3 + # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Type | Length | RESERVED | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Flags | Label Index | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Label Index | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # Figure. Label-Index TLV (Prefix-SID type-1) + # + # 0 1 2 3 + # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Type | Length | Flags | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Flags | + # +-+-+-+-+-+-+-+-+ + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | SRGB 1 (6 octets) | + # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | SRGB n (6 octets) | + # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # Figure. Originator SRGB TLV (Prefix-SID type-3) - # ExaBGP generic-attribute binary pattern: - # Attribute-type: 0x28 (40:BGP_PREFIX_SID) - # Attribute-flag: 0xc0 (Option, Transitive) - # Attribute-body: Label-Index TLV and Originator SRGB TLV - # Label-Index TLV: 0x01000700000000000001 - # Type (08bit): 0x01 - # Length (16bit): 0x0007 - # RESERVED (08bit): 0x00 - # Flags (16bit): 0x0000 - # Label Index (32bit): 0x00000001 - # Originator SRGB TLV: 0x03000800000c350000000a - # Type (08bit): 0x03 - # Length (16bit): 0x0008 (nb-SRGB is 1) - # Flags (16bit): 0x0000 - # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1) - route 3.0.0.1/32 next-hop 10.0.0.101 label [800001] attribute [0x28 0xc0 0x0100070000000000000103000800000c350000000a]; + # ExaBGP generic-attribute binary pattern: + # Attribute-type: 0x28 (40:BGP_PREFIX_SID) + # Attribute-flag: 0xc0 (Option, Transitive) + # Attribute-body: Label-Index TLV and Originator SRGB TLV + # Label-Index TLV: 0x01000700000000000001 + # Type (08bit): 0x01 + # Length (16bit): 0x0007 + # RESERVED (08bit): 0x00 + # Flags (16bit): 0x0000 + # Label Index (32bit): 0x00000001 + # Originator SRGB TLV: 0x03000800000c350000000a + # Type (08bit): 0x03 + # Length (16bit): 0x0008 (nb-SRGB is 1) + # Flags (16bit): 0x0000 + # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1) + route 3.0.0.1/32 next-hop 10.0.0.101 label [800001] attribute [0x28 0xc0 0x0100070000000000000103000800000c350000000a]; - # ExaBGP generic-attribute binary pattern: - # Attribute-type: 0x28 (40:BGP_PREFIX_SID) - # Attribute-flag: 0xc0 (Option, Transitive) - # Attribute-body: Label-Index TLV and Originator SRGB TLV - # Label-Index TLV: 0x01000700000000000001 - # Type (08bit): 0x01 - # Length (16bit): 0x0007 - # RESERVED (08bit): 0x00 - # Flags (16bit): 0x0000 - # Label Index (32bit): 0x00000002 - # Originator SRGB TLV: 0x03000800000c350000000a - # Type (08bit): 0x03 - # Length (16bit): 0x0008 (nb-SRGB is 1) - # Flags (16bit): 0x0000 - # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1) - route 3.0.0.2/32 next-hop 10.0.0.101 label [800002] attribute [0x28 0xc0 0x0100070000000000000203000800000c350000000a]; + # ExaBGP generic-attribute binary pattern: + # Attribute-type: 0x28 (40:BGP_PREFIX_SID) + # Attribute-flag: 0xc0 (Option, Transitive) + # Attribute-body: Label-Index TLV and Originator SRGB TLV + # Label-Index TLV: 0x01000700000000000001 + # Type (08bit): 0x01 + # Length (16bit): 0x0007 + # RESERVED (08bit): 0x00 + # Flags (16bit): 0x0000 + # Label Index (32bit): 0x00000002 + # Originator SRGB TLV: 0x03000800000c350000000a + # Type (08bit): 0x03 + # Length (16bit): 0x0008 (nb-SRGB is 1) + # Flags (16bit): 0x0000 + # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1) + route 3.0.0.2/32 next-hop 10.0.0.101 label [800002] attribute [0x28 0xc0 0x0100070000000000000203000800000c350000000a]; - # ExaBGP generic-attribute binary pattern: - # Attribute-type: 0x28 (40:BGP_PREFIX_SID) - # Attribute-flag: 0xc0 (Option, Transitive) - # Attribute-body: Label-Index TLV and Originator SRGB TLV - # Label-Index TLV: 0x01000700000000000001 - # Type (08bit): 0x01 - # Length (16bit): 0x0007 - # RESERVED (08bit): 0x00 - # Flags (16bit): 0x0000 - # Label Index (32bit): 0x00000003 - # Originator SRGB TLV: 0x03000800000c350000000a - # Type (08bit): 0x03 - # Length (16bit): 0x0008 (nb-SRGB is 1) - # Flags (16bit): 0x0000 - # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1) - route 3.0.0.3/32 next-hop 10.0.0.101 label [800003] attribute [0x28 0xc0 0x0100070000000000000303000800000c350000000a]; - } + # ExaBGP generic-attribute binary pattern: + # Attribute-type: 0x28 (40:BGP_PREFIX_SID) + # Attribute-flag: 0xc0 (Option, Transitive) + # Attribute-body: Label-Index TLV and Originator SRGB TLV + # Label-Index TLV: 0x01000700000000000001 + # Type (08bit): 0x01 + # Length (16bit): 0x0007 + # RESERVED (08bit): 0x00 + # Flags (16bit): 0x0000 + # Label Index (32bit): 0x00000003 + # Originator SRGB TLV: 0x03000800000c350000000a + # Type (08bit): 0x03 + # Length (16bit): 0x0008 (nb-SRGB is 1) + # Flags (16bit): 0x0000 + # SRGB1 (48bit): 0x0c3500:0x00000a (800000-800010 is SRGB1) + route 3.0.0.3/32 next-hop 10.0.0.101 label [800003] attribute [0x28 0xc0 0x0100070000000000000303000800000c350000000a]; } } diff --git a/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg b/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg index 379d0a3f4312..50ebdc2319c3 100644 --- a/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg +++ b/tests/topotests/bgp_prefix_sid/peer2/exabgp.cfg @@ -1,19 +1,22 @@ -group controller { - - process receive-routes { - run "/etc/exabgp/exa-receive.py --no-timestamp 2"; - receive-routes; - encoder json; - } +process receive-routes { + run /etc/exabgp/exa-receive.py --no-timestamp 2; + encoder json; +} - neighbor 10.0.0.1 { - router-id 10.0.0.102; - local-address 10.0.0.102; - local-as 3; - peer-as 1; +neighbor 10.0.0.1 { + router-id 10.0.0.102; + local-address 10.0.0.102; + local-as 3; + peer-as 1; - family { - ipv4 nlri-mpls; + family { + ipv4 nlri-mpls; + } + api { + processes [ receive-routes ]; + receive { + parsed; + update; } } } diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py index bfc083b50640..fca60e8ceab1 100644 --- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py +++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py @@ -93,11 +93,11 @@ def _check_type1_r1(router, prefix, remoteLabel, labelIndex): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_r1, router, "3.0.0.1/32", 800001, 1) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) test_func = functools.partial(_check_type1_r1, router, "3.0.0.2/32", 800002, 2) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) @@ -120,13 +120,9 @@ def exabgp_get_update_prefix(filename, afi, nexthop, prefix): ret = ret.get(afi) if ret is None: continue - ret = ret.get(nexthop) - if ret is None: - continue - ret = ret.get(prefix) - if ret is None: - continue - return output + for nh in ret.get(nexthop, []): + if nh.get("nlri") == prefix: + return output return "Not found" @@ -135,34 +131,40 @@ def test_peer2_receive_prefix_sid_type1(): peer2 = tgen.gears["peer2"] logfile = "{}/{}-received.log".format(peer2.gearlogdir, peer2.name) - def _check_type1_peer2(prefix, labelindex): + def _check_type1_peer2(prefix, label): output = exabgp_get_update_prefix( logfile, "ipv4 nlri-mpls", "10.0.0.101", prefix ) expected = { "type": "update", "neighbor": { - "ip": "10.0.0.1", + "address": { + "peer": "10.0.0.1", + }, "message": { "update": { - "attribute": { - "attribute-0x28-0xE0": "0x010007000000{:08x}".format( - labelindex - ) + "announce": { + "ipv4 nlri-mpls": { + "10.0.0.101": [ + { + "nlri": prefix, + "label": [[label]], + } + ] + } }, - "announce": {"ipv4 nlri-mpls": {"10.0.0.101": {}}}, } }, }, } return topotest.json_cmp(output, expected) - test_func = functools.partial(_check_type1_peer2, "3.0.0.1/32", labelindex=1) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + test_func = functools.partial(_check_type1_peer2, "3.0.0.1/32", label=8001) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") - test_func = functools.partial(_check_type1_peer2, "3.0.0.2/32", labelindex=2) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + test_func = functools.partial(_check_type1_peer2, "3.0.0.2/32", label=8002) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") diff --git a/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg b/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg index 381917957035..7a291a3421d1 100644 --- a/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg +++ b/tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg @@ -1,29 +1,27 @@ -group controller { - neighbor 10.0.0.1 { - router-id 10.0.0.101; - local-address 10.0.0.101; - local-as 2; - peer-as 1; +neighbor 10.0.0.1 { + router-id 10.0.0.101; + local-address 10.0.0.101; + local-as 2; + peer-as 1; - family { - ipv6 mpls-vpn; - } + family { + ipv6 mpls-vpn; + } - static { - route 2001:1::/64 { - rd 2:10; - next-hop 2001::2; - extended-community [ target:2:10 ]; - label 3; - attribute [0x28 0xc0 0x050019000100150020010db800010001000000000000000100ffff00 ]; - } - route 2001:2::/64 { - rd 2:10; - next-hop 2001::2; - extended-community [ target:2:10 ]; - label 3; - attribute [0x28 0xc0 0x050019000100150020010db800010001000000000000000100ffff00 ]; - } + static { + route 2001:1::/64 { + rd 2:10; + next-hop 2001::2; + extended-community [ target:2:10 ]; + label 3; + attribute [0x28 0xc0 0x050019000100150020010db800010001000000000000000100ffff00 ]; + } + route 2001:2::/64 { + rd 2:10; + next-hop 2001::2; + extended-community [ target:2:10 ]; + label 3; + attribute [0x28 0xc0 0x050019000100150020010db800010001000000000000000100ffff00 ]; } } } diff --git a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf index ddc1f07e420e..b3ca0e114d17 100644 --- a/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_sid2/r1/bgpd.conf @@ -1,5 +1,4 @@ log stdout notifications -log monitor notifications !log commands ! !debug bgp zebra @@ -22,5 +21,7 @@ router bgp 1 ! address-family ipv6 vpn neighbor 10.0.0.101 activate + neighbor 10.0.0.101 route-map DENY_ALL out exit-address-family ! +route-map DENY_ALL deny 10 diff --git a/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json index 42293b1fc749..65c51f1c8cfa 100644 --- a/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json +++ b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry1.json @@ -1,10 +1,6 @@ { "2:10":{ "prefix":"2001:1::\/64", - "advertisedTo":{ - "10.0.0.101":{ - } - }, "paths":[ { "aspath":{ diff --git a/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json index c9ad8714c136..4a12c2a88049 100644 --- a/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json +++ b/tests/topotests/bgp_prefix_sid2/r1/vpnv6_rib_entry2.json @@ -1,10 +1,6 @@ { "2:10":{ "prefix":"2001:2::\/64", - "advertisedTo":{ - "10.0.0.101":{ - } - }, "paths":[ { "aspath":{ diff --git a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py index d6b94329e411..cf0c9fea2eb1 100755 --- a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py +++ b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py @@ -90,7 +90,7 @@ def check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" check("r1", "show bgp ipv6 vpn 2001:1::/64 json", "r1/vpnv6_rib_entry1.json") diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py index 35459f6f68f9..88251fae6064 100644 --- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py +++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py @@ -257,10 +257,10 @@ def test_recursive_routes_iBGP_peer_p1(request): ) dut = "r2" create_interface_in_kernel( - tgen, dut, "lo", "40.40.40.50", netmask="255.255.255.0", create=True + tgen, dut, "lo10", "40.40.40.50", netmask="255.255.255.0", create=True ) create_interface_in_kernel( - tgen, dut, "lo", "40:40::40:50", netmask="120", create=True + tgen, dut, "lo10", "40:40::40:50", netmask="120", create=True ) for addr_type in ADDR_TYPES: input_dict_3 = { diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step2/show_mpls_table.ref.diff b/tests/topotests/bgp_redistribute_table/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step2/show_mpls_table.ref.diff rename to tests/topotests/bgp_redistribute_table/__init__.py diff --git a/tests/topotests/bgp_redistribute_table/r1/bgpd.conf b/tests/topotests/bgp_redistribute_table/r1/bgpd.conf new file mode 100644 index 000000000000..c5e0fcd92bbf --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r1/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65500 + bgp router-id 192.0.2.1 + no bgp ebgp-requires-policy + neighbor 192.168.0.2 remote-as 65501 + address-family ipv4 unicast + neighbor 192.168.0.2 activate + exit-address-family +! diff --git a/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_with_all_redistribute.json b/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_with_all_redistribute.json new file mode 100644 index 000000000000..e5a27f32ea0e --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_with_all_redistribute.json @@ -0,0 +1,71 @@ +{ + "172.31.0.2/32": [ + { + "prefix": "172.31.0.2/32", + "protocol": "bgp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "nexthops": [ + { + "fib": true, + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "172.31.0.10/32": [ + { + "prefix": "172.31.0.10/32", + "protocol": "bgp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "nexthops": [ + { + "fib": true, + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "172.31.0.15/32": [ + { + "prefix": "172.31.0.15/32", + "protocol": "bgp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "nexthops": [ + { + "fib": true, + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "active": true, + "weight": 1 + } + ] + } + ] +} diff --git a/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_with_redistribute.json b/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_with_redistribute.json new file mode 100644 index 000000000000..1304edddca07 --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_with_redistribute.json @@ -0,0 +1,48 @@ +{ + "172.31.0.2/32": [ + { + "prefix": "172.31.0.2/32", + "protocol": "bgp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "nexthops": [ + { + "fib": true, + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "active": true, + "weight": 1 + } + ] + } + ], + "172.31.0.10/32": [ + { + "prefix": "172.31.0.10/32", + "protocol": "bgp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "nexthops": [ + { + "fib": true, + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "active": true, + "weight": 1 + } + ] + } + ] +} diff --git a/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_without_redistribute.json b/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_without_redistribute.json new file mode 100644 index 000000000000..74f594f9e840 --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r1/ipv4_routes_without_redistribute.json @@ -0,0 +1,25 @@ +{ + "172.31.0.2/32": [ + { + "prefix": "172.31.0.2/32", + "protocol": "bgp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 20, + "metric": 0, + "installed": true, + "nexthops": [ + { + "fib": true, + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "active": true, + "weight": 1 + } + ] + } + ] +} diff --git a/tests/topotests/bgp_redistribute_table/r1/zebra.conf b/tests/topotests/bgp_redistribute_table/r1/zebra.conf new file mode 100644 index 000000000000..abe6d395a322 --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r1/zebra.conf @@ -0,0 +1,7 @@ +log stdout +interface r1-eth1 + ip address 172.31.0.1/32 +! +interface r1-eth0 + ip address 192.168.0.1/24 +! diff --git a/tests/topotests/bgp_redistribute_table/r2/bgpd.conf b/tests/topotests/bgp_redistribute_table/r2/bgpd.conf new file mode 100644 index 000000000000..2ce704309756 --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r2/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65501 + bgp router-id 192.0.2.2 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as 65500 + address-family ipv4 unicast + network 172.31.0.2/32 + neighbor 192.168.0.1 activate + redistribute table-direct 2200 + exit-address-family +! diff --git a/tests/topotests/bgp_redistribute_table/r2/zebra.conf b/tests/topotests/bgp_redistribute_table/r2/zebra.conf new file mode 100644 index 000000000000..89ad2ec74428 --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/r2/zebra.conf @@ -0,0 +1,8 @@ +log stdout +interface r2-eth0 + ip address 192.168.0.2/24 +! +interface r2-eth1 + ip address 172.31.0.2/32 + ip address 172.31.1.2/24 +! diff --git a/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py new file mode 100644 index 000000000000..614610ccd64e --- /dev/null +++ b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_redistribute_table.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2023 by 6WIND +# + +""" + test_bgp_redistribute_table.py: Test the FRR BGP daemon with 'redistribute table-direct' +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.common_config import step +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 2 routers. + tgen.add_router("r1") + tgen.add_router("r2") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + tgen.stop_topology() + + +def _router_json_cmp_exact_filter(router, cmd, expected): + output = router.vtysh_cmd(cmd) + logger.info("{}: {}\n{}".format(router.name, cmd, output)) + + json_output = json.loads(output) + + # filter out tableVersion, version, nhVrfId and vrfId + for _, attrs in json_output.items(): + for attr in attrs: + if "table" in attr: + attr.pop("table") + if "internalStatus" in attr: + attr.pop("internalStatus") + if "internalFlags" in attr: + attr.pop("internalFlags") + if "internalNextHopNum" in attr: + attr.pop("internalNextHopNum") + if "internalNextHopActiveNum" in attr: + attr.pop("internalNextHopActiveNum") + if "nexthopGroupId" in attr: + attr.pop("nexthopGroupId") + if "installedNexthopGroupId" in attr: + attr.pop("installedNexthopGroupId") + if "uptime" in attr: + attr.pop("uptime") + if "prefixLen" in attr: + attr.pop("prefixLen") + if "asPath" in attr: + attr.pop("asPath") + for nexthop in attr.get("nexthops", []): + if "flags" in nexthop: + nexthop.pop("flags") + if "interfaceIndex" in nexthop: + nexthop.pop("interfaceIndex") + + return topotest.json_cmp(json_output, expected, exact=True) + + +def _check_zebra_rib_r1(with_redistributed_route, with_second_route=False): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + with_str = "" if with_redistributed_route else "out" + + router = tgen.gears["r1"] + if with_redistributed_route: + with_str = "" + if with_second_route: + json_file = "{}/{}/ipv4_routes_with_all_redistribute.json".format( + CWD, router.name + ) + else: + json_file = "{}/{}/ipv4_routes_with_redistribute.json".format( + CWD, router.name + ) + else: + with_str = "out" + json_file = "{}/{}/ipv4_routes_without_redistribute.json".format( + CWD, router.name + ) + + step(f"Checking IPv4 routes for convergence on r1 with{with_str} kernel route") + expected = json.loads(open(json_file).read()) + test_func = partial( + _router_json_cmp_exact_filter, + router, + "show ip route bgp json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def _test_add_and_check_kernel_route_on_table_2200(): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router_list = tgen.routers() + + step("r2, adding new kernel route 172.31.0.10/32 on table 2200") + cmd = "ip route add 172.31.0.10/32 via 172.31.1.10 table 2200" + tgen.net["r2"].cmd(cmd) + + _check_zebra_rib_r1(True) + + +def test_step1_protocols_convergence(): + """ + Assert that all protocols have converged + statuses as they depend on it. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking IPv4 routes for convergence on r1") + _check_zebra_rib_r1(False) + + +def test_step2_add_kernel_route_on_table_2200(): + """ + On r2, create a kernel route on table 2200 + * Check that the kernel route is redistributed to r1 + """ + _test_add_and_check_kernel_route_on_table_2200() + + +def test_step3_remove_kernel_route_on_table_2200(): + """ + On r2, remove a kernel route on table 2200 + * Check that the kernel route is no more redistributed to r1 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router_list = tgen.routers() + + step("r2, remove a kernel route on table 2200") + cmd = "ip route delete 172.31.0.10/32 via 172.31.1.10 table 2200" + tgen.net["r2"].cmd(cmd) + + _check_zebra_rib_r1(False) + + +def test_step4_add_kernel_route_on_table_2200(): + """ + On r2, add a kernel route on table 2200 + * Check that the kernel route is redistributed to r1 + """ + _test_add_and_check_kernel_route_on_table_2200() + + +def test_step5_no_redistribute_table_2200(): + """ + On r2, unconfigure the 'no redistribute' service + * Check that the 'redistribute' command is not configured + * Check that the kernel route is not redistributed to r1 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r2"].vtysh_cmd( + "configure terminal\nrouter bgp 65501\naddress-family ipv4 unicast\nno redistribute table-direct\n" + ) + + step("r2, check that the 'redistribute' command is not configured") + out = tgen.net["r2"].cmd( + "vtysh -c 'show running-config' | grep 'redistribute table-direct'" + ) + + if "redistribute" in out: + assert True, "r2, redistribute command still present" + + _check_zebra_rib_r1(False) + + +def test_step6_redistribute_table_2200(): + """ + On r2, configure the 'redistribute' service + * Check that the 'redistribute' command is configured + * Check that the kernel route is redistributed to r1 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r2"].vtysh_cmd( + "configure terminal\nrouter bgp 65501\naddress-family ipv4 unicast\nredistribute table-direct 2200\n" + ) + + step("r2, check that the 'redistribute' command is configured") + out = tgen.net["r2"].cmd( + "vtysh -c 'show running-config' | grep 'redistribute table-direct'" + ) + if "redistribute" not in out: + assert True, "r2, redistribute command still present" + + _check_zebra_rib_r1(True) + + +def test_step7_reset_bgp_instance_add_kernel_route_and_add_bgp(): + """ + On r2, remove BGP configuration, create a kernel route on table 2200, + then restore BGP configuration + * Check that the kernel route is redistributed to r1 + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router_list = tgen.routers() + + router = tgen.gears["r2"] + step("r2, removing r2 BGP configuration") + router.vtysh_cmd("configure terminal\nno router bgp 65501\n") + + step("r2, adding new kernel route 172.31.0.15/32 on table 2200") + cmd = "ip route add 172.31.0.15/32 via 172.31.1.100 table 2200" + tgen.net["r2"].cmd(cmd) + + router = tgen.gears["r2"] + step("r2, restoring r2 BGP configuration") + tgen.net["r2"].cmd("vtysh -f {}".format(os.path.join(CWD, "r2/bgpd.conf"))) + + _check_zebra_rib_r1(True, with_second_route=True) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py index 97366ebd5338..b9d8ce681914 100644 --- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py +++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -114,19 +114,19 @@ def _bgp_announce_route_without_as_sets(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router) test_func = functools.partial( _bgp_has_aggregated_route_with_stripped_as_set, router ) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed to see an aggregated route in "{}"'.format(router) test_func = functools.partial(_bgp_announce_route_without_as_sets, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ip_route.ref.diff b/tests/topotests/bgp_remote_as_auto/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step3/show_ip_route.ref.diff rename to tests/topotests/bgp_remote_as_auto/__init__.py diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf new file mode 100644 index 000000000000..2f1bcd275f1a --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf @@ -0,0 +1,23 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.14.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.3 remote-as auto + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_remote_as_auto/r2/frr.conf b/tests/topotests/bgp_remote_as_auto/r2/frr.conf new file mode 100644 index 000000000000..f8d19a0bfd56 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r2/frr.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r3/frr.conf b/tests/topotests/bgp_remote_as_auto/r3/frr.conf new file mode 100644 index 000000000000..fc6862764f4d --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r3/frr.conf @@ -0,0 +1,10 @@ +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r4/frr.conf b/tests/topotests/bgp_remote_as_auto/r4/frr.conf new file mode 100644 index 000000000000..e280a6c6e884 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r4/frr.conf @@ -0,0 +1,10 @@ +! +int r4-eth0 + ip address 192.168.14.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor r4-eth0 interface remote-as auto + neighbor r4-eth0 timers 1 3 + neighbor r4-eth0 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py new file mode 100644 index 000000000000..1db6d98a42e7 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2", "r3"), "s2": ("r1", "r4")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_remote_as_auto(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "r1-eth1": { + "hostname": "r4", + "remoteAs": 65004, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65001, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "state": "Established", + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP/eBGP peerings" + + def _bgp_converge_internal(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "Local", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "internal", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_internal, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP peering" + + def _bgp_converge_external(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic eBGP peering" + + def _bgp_converge_external_unnumbered(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external_unnumbered, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic unnumbered eBGP peering" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py index e48f81c53dd8..8b965a161454 100644 --- a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py +++ b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py @@ -32,7 +32,6 @@ import os import sys import json -import time import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -109,7 +108,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, f"{rname}/zebra.conf") ) diff --git a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py index 2ae6f7fc9ebe..10896e2b2202 100644 --- a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py +++ b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py @@ -10,22 +10,19 @@ """ import os -import re import sys import json import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen - -pytestmark = [pytest.mark.bgpd] +from lib.topogen import Topogen, get_topogen def build_topo(tgen): @@ -43,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py index 5c7cc8eae36b..2e5592e2ab92 100644 --- a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py +++ b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py @@ -18,7 +18,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -27,8 +27,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 3): @@ -45,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -88,7 +86,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "BGP Converge failed" def _bgp_extcommunity_strip(router): @@ -113,7 +111,7 @@ def _bgp_extcommunity_strip(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_extcommunity_strip, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to strip incoming extended communities from r2" diff --git a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py index 52fda695c3cd..9223cbd7590d 100644 --- a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py +++ b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py @@ -24,8 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -38,7 +37,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -82,9 +81,7 @@ def test_correct_pair(tgen): check_r2_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r2_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r2_established, True, count=20, wait=3) assert success, "Session with r2 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -100,7 +97,7 @@ def test_role_pair_mismatch(tgen): router = tgen.gears["r3"] neighbor_ip = "192.168.3.1" check_r3_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r3 was not correctly closed" @@ -111,9 +108,7 @@ def test_single_role_advertising(tgen): check_r4_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r4_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r4_established, True, count=20, wait=3) assert success, "Session with r4 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -129,9 +124,7 @@ def test_single_role_receiving(tgen): check_r1_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r1_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r1_established, True, count=20, wait=3) assert success, "Session with r1 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -145,7 +138,7 @@ def test_role_strict_mode(tgen): router = tgen.gears["r5"] neighbor_ip = "192.168.5.1" check_r5_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r5 was not correctly closed" diff --git a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py index b3715863b583..ffbf454ded62 100644 --- a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py +++ b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py @@ -16,7 +16,6 @@ import json import os import sys -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -24,9 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -39,7 +36,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -69,9 +66,7 @@ def _routes_half_converged(): ] return output == expected - success, result = topotest.run_and_expect( - _routes_half_converged, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(_routes_half_converged, True, count=20, wait=3) assert success, "Routes did not converged" routes_with_otc = list() diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py index 412ecc12efe8..94bf092c76bf 100644 --- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py +++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py @@ -119,7 +119,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -403,7 +403,6 @@ def test_route_summarisation_with_summary_only_p1(request): ) for action, value in zip(["removed", "add"], [True, False]): - step( "{} static routes as below: " "(no) ip route 10.1.1.0/24 and (no) ip route 10.1.2.0/24" @@ -815,7 +814,11 @@ def test_route_summarisation_with_as_set_p1(request): ) for addr_type in ADDR_TYPES: - for pfx, seq_id, network, in zip( + for ( + pfx, + seq_id, + network, + ) in zip( [1, 2, 3, 4, 5], [10, 20, 30, 40, 50], [NETWORK_1_1, NETWORK_1_2, NETWORK_1_3, NETWORK_1_4, NETWORK_1_5], diff --git a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py index 15a077da2e50..d791ef486bf0 100644 --- a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py +++ b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py @@ -15,7 +15,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -24,8 +24,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -34,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf index 8b743bd3206e..11e57ca93222 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -11,6 +11,8 @@ router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy neighbor 2001:db8::2 remote-as external + neighbor 2001:db8::2 timers 3 10 + neighbor 2001:db8::2 timers connect 1 address-family ipv6 unicast neighbor 2001:db8::2 activate neighbor 2001:db8::2 route-map r2 in diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf index 61c36d366bbe..abd0ab9a41f3 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -5,6 +5,8 @@ router bgp 65002 bgp router-id 10.10.10.2 no bgp ebgp-requires-policy neighbor 2001:db8::1 remote-as external + neighbor 2001:db8::1 timers 3 10 + neighbor 2001:db8::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8::1 activate diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py index a06e3edc44e0..35ce0926975e 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -16,7 +16,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -25,8 +25,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 3): @@ -43,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -99,7 +97,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Can't match routes using ipv6 next-hop access-list" diff --git a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py index 2828796405cd..7116deaea46a 100644 --- a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py +++ b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py @@ -22,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ipv6_route.ref.diff b/tests/topotests/bgp_route_map_match_tag_untagged/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step3/show_ipv6_route.ref.diff rename to tests/topotests/bgp_route_map_match_tag_untagged/__init__.py diff --git a/tests/topotests/bgp_route_map_match_tag_untagged/r1/frr.conf b/tests/topotests/bgp_route_map_match_tag_untagged/r1/frr.conf new file mode 100644 index 000000000000..13eced2042a1 --- /dev/null +++ b/tests/topotests/bgp_route_map_match_tag_untagged/r1/frr.conf @@ -0,0 +1,19 @@ +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + address-family ipv4 + redistribute static route-map untagged + exit-address-family +! +ip route 10.10.10.10/32 Null0 +ip route 10.10.10.20/32 Null0 tag 20 +! +route-map untagged permit 10 + match tag untagged + set tag 10 +route-map untagged permit 20 + match tag 20 + set tag untagged +exit diff --git a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py new file mode 100644 index 000000000000..6ffa078f0ca0 --- /dev/null +++ b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 2): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_route_map_match_tag_untagged(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_check_advertised_routes_r2(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show bgp ipv4 unicast detail json") + ) + expected = { + "routes": { + "10.10.10.10/32": [ + { + "tag": 10, + } + ], + "10.10.10.20/32": [ + { + "tag": None, + } + ], + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_advertised_routes_r2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Tags for static routes are not as expected" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py index 8fe45a349838..5b5256f43d92 100644 --- a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py +++ b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -83,12 +83,12 @@ def _bgp_has_routes(router, metric, weight): # Check thst session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check that metric is 0 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 0, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 0 and weight 100" # Update the route-map and add "on-match next" to entry 10 @@ -102,7 +102,7 @@ def _bgp_has_routes(router, metric, weight): # Check that metric is 20 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 20, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 20 and weight 100" diff --git a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py index 37082b484c71..a6641348f7f1 100644 --- a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py +++ b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py @@ -24,7 +24,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -61,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py index 673efc2c7332..16afda8bcc96 100644 --- a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py +++ b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py @@ -11,7 +11,6 @@ import os import sys -import json import pytest import functools diff --git a/tests/topotests/bgp_route_server_client/r1/bgpd.conf b/tests/topotests/bgp_route_server_client/r1/bgpd.conf index 9826b671f975..e464e6c50b88 100644 --- a/tests/topotests/bgp_route_server_client/r1/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r1/bgpd.conf @@ -2,6 +2,7 @@ router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy + no bgp enforce-first-as neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 timers 3 10 neighbor 2001:db8:1::1 timers connect 5 diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index 23cf041b681c..29d9842d59dd 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -15,7 +15,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -24,8 +24,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 4): @@ -46,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step3/show_mpls_table.ref.diff b/tests/topotests/bgp_rpki_topo1/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step3/show_mpls_table.ref.diff rename to tests/topotests/bgp_rpki_topo1/__init__.py diff --git a/tests/topotests/bgp_rpki_topo1/r1/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r1/bgpd.conf new file mode 100644 index 000000000000..437d393c75bb --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r1/bgpd.conf @@ -0,0 +1,14 @@ +router bgp 65530 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.0.2.2 remote-as 65002 + neighbor 192.0.2.2 timers 1 3 + neighbor 192.0.2.2 timers connect 1 + neighbor 192.0.2.2 ebgp-multihop 3 + neighbor 192.0.2.2 update-source 192.0.2.1 + address-family ipv4 unicast + network 198.51.100.0/24 + network 203.0.113.0/24 + network 10.0.0.0/24 + exit-address-family +! diff --git a/tests/topotests/bgp_rpki_topo1/r1/rtrd.py b/tests/topotests/bgp_rpki_topo1/r1/rtrd.py new file mode 100755 index 000000000000..bca58a66ac53 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r1/rtrd.py @@ -0,0 +1,330 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright (C) 2023 Tomas Hlavacek (tmshlvck@gmail.com) + +from typing import List, Tuple, Callable, Type +import socket +import threading +import socketserver +import struct +import ipaddress +import csv +import os +import sys + +LISTEN_HOST, LISTEN_PORT = "0.0.0.0", 15432 +VRPS_FILE = os.path.join(sys.path[0], "vrps.csv") + + +def dbg(m: str): + print(m) + sys.stdout.flush() + + +class RTRDatabase(object): + def __init__(self, vrps_file: str) -> None: + self.last_serial = 0 + self.ann4 = [] + self.ann6 = [] + self.withdraw4 = [] + self.withdraw6 = [] + + with open(vrps_file, "r") as fh: + for rasn, rnet, rmaxlen, _ in csv.reader(fh): + try: + net = ipaddress.ip_network(rnet) + asn = int(rasn[2:]) + maxlen = int(rmaxlen) + if net.version == 6: + self.ann6.append((asn, str(net), maxlen)) + elif net.version == 4: + self.ann4.append((asn, str(net), maxlen)) + else: + raise ValueError(f"Unknown AFI: {net.version}") + except Exception as e: + dbg( + f"VRPS load: ignoring {str((rasn, rnet,rmaxlen))} because {str(e)}" + ) + + def get_serial(self) -> int: + return self.last_serial + + def set_serial(self, serial: int) -> None: + self.last_serial = serial + + def get_announcements4(self, serial: int = 0) -> List[Tuple[int, str, int]]: + if serial > self.last_serial: + return self.ann4 + else: + return [] + + def get_withdrawals4(self, serial: int = 0) -> List[Tuple[int, str, int]]: + if serial > self.last_serial: + return self.withdraw4 + else: + return [] + + def get_announcements6(self, serial: int = 0) -> List[Tuple[int, str, int]]: + if serial > self.last_serial: + return self.ann6 + else: + return [] + + def get_withdrawals6(self, serial: int = 0) -> List[Tuple[int, str, int]]: + if serial > self.last_serial: + return self.withdraw6 + else: + return [] + + +class RTRConnHandler(socketserver.BaseRequestHandler): + PROTO_VERSION = 0 + + def setup(self) -> None: + self.session_id = 2345 + self.serial = 1024 + + dbg(f"New connection from: {str(self.client_address)} ") + # TODO: register for notifies + + def finish(self) -> None: + pass + # TODO: de-register + + HEADER_LEN = 8 + + def decode_header(self, buf: bytes) -> Tuple[int, int, int, int]: + # common header in all received packets + return struct.unpack("!BBHI", buf) + # reutnrs (proto_ver, pdu_type, sess_id, length) + + SERNOTIFY_TYPE = 0 + SERNOTIFY_LEN = 12 + + def send_sernotify(self, serial: int) -> None: + # serial notify PDU + dbg(f" None: + # cache response PDU + dbg(f"Serial query: {serial}") + if sess_id: + self.server.db.set_serial(serial) + else: + self.server.db.set_serial(0) + self.send_cacheresponse() + + for asn, ipnet, maxlen in self.server.db.get_announcements4(serial): + self.announce_ipv4(ipnet, asn, maxlen) + + for asn, ipnet, maxlen in self.server.db.get_withdrawals4(serial): + self.withdraw_ipv4(ipnet, asn, maxlen) + + for asn, ipnet, maxlen in self.server.db.get_announcements6(serial): + self.announce_ipv6(ipnet, asn, maxlen) + + for asn, ipnet, maxlen in self.server.db.get_withdrawals6(serial): + self.withdraw_ipv6(ipnet, asn, maxlen) + + self.send_endofdata(self.serial) + + RESET_TYPE = 2 + + def handle_reset(self): + dbg(">Reset") + self.session_id += 1 + self.server.db.set_serial(0) + self.send_cacheresponse() + + for asn, ipnet, maxlen in self.server.db.get_announcements4(self.serial): + self.announce_ipv4(ipnet, asn, maxlen) + + for asn, ipnet, maxlen in self.server.db.get_announcements6(self.serial): + self.announce_ipv6(ipnet, asn, maxlen) + + self.send_endofdata(self.serial) + + ERROR_TYPE = 10 + + def handle_error(self, buf: bytes): + dbg(f">Error: {str(buf)}") + self.server.shutdown() + self.server.stopped = True + raise ConnectionError("Received an RPKI error packet from FRR. Exiting") + + def handle(self): + while True: + b = self.request.recv(self.HEADER_LEN, socket.MSG_WAITALL) + if len(b) == 0: + break + proto_ver, pdu_type, sess_id, length = self.decode_header(b) + dbg( + f">Header proto_ver={proto_ver} pdu_type={pdu_type} sess_id={sess_id} length={length}" + ) + + if sess_id: + self.session_id = sess_id + + if pdu_type == self.SERIAL_QUERY_TYPE: + b = self.request.recv( + self.SERIAL_QUERY_LEN - self.HEADER_LEN, socket.MSG_WAITALL + ) + self.handle_serial_query(b, sess_id) + + elif pdu_type == self.RESET_TYPE: + self.handle_reset() + + elif pdu_type == self.ERROR_TYPE: + b = self.request.recv(length - self.HEADER_LEN, socket.MSG_WAITALL) + self.handle_error(b) + + +class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): + def __init__( + self, bind: Tuple[str, int], handler: Type[RTRConnHandler], db: RTRDatabase + ) -> None: + super().__init__(bind, handler) + self.db = db + + +def main(): + db = RTRDatabase(VRPS_FILE) + server = ThreadedTCPServer((LISTEN_HOST, LISTEN_PORT), RTRConnHandler, db) + dbg(f"Server listening on {LISTEN_HOST} port {LISTEN_PORT}") + server.serve_forever() + + +if __name__ == "__main__": + if len(sys.argv) > 1: + f = open(sys.argv[1], "w") + sys.__stdout__ = f + sys.stdout = f + sys.__stderr__ = f + sys.stderr = f + + main() diff --git a/tests/topotests/bgp_rpki_topo1/r1/staticd.conf b/tests/topotests/bgp_rpki_topo1/r1/staticd.conf new file mode 100644 index 000000000000..7f2f057bfeec --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r1/staticd.conf @@ -0,0 +1 @@ +ip route 192.0.2.2/32 192.168.1.2 diff --git a/tests/topotests/bgp_rpki_topo1/r1/vrps.csv b/tests/topotests/bgp_rpki_topo1/r1/vrps.csv new file mode 100644 index 000000000000..5a6e023bb92c --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r1/vrps.csv @@ -0,0 +1,3 @@ +ASN,IP Prefix,Max Length,Trust Anchor +AS65530,198.51.100.0/24,24,private +AS65530,203.0.113.0/24,24,private diff --git a/tests/topotests/bgp_rpki_topo1/r1/zebra.conf b/tests/topotests/bgp_rpki_topo1/r1/zebra.conf new file mode 100644 index 000000000000..b742b70356e0 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r1/zebra.conf @@ -0,0 +1,6 @@ +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_any.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_any.json new file mode 100644 index 000000000000..a04e9ef6ceb0 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_any.json @@ -0,0 +1,37 @@ +{ + "routerId": "192.0.2.2", + "defaultLocPrf": 100, + "localAS": 65002, + "routes": { + "198.51.100.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "198.51.100.0", + "prefixLen": 24, + "network": "198.51.100.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ], + "203.0.113.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "203.0.113.0", + "prefixLen": 24, + "network": "203.0.113.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ] + } +} diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_notfound.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_notfound.json new file mode 100644 index 000000000000..01e288c86fee --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_notfound.json @@ -0,0 +1,7 @@ +{ + "routerId": "192.0.2.2", + "defaultLocPrf": 100, + "localAS": 65002, + "routes": { + } +} diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_valid.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_valid.json new file mode 120000 index 000000000000..2645bfaf0e3d --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rmap_rpki_valid.json @@ -0,0 +1 @@ +bgp_table_rpki_valid.json \ No newline at end of file diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_any.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_any.json new file mode 100644 index 000000000000..5546d45c6783 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_any.json @@ -0,0 +1,52 @@ +{ + "routerId": "192.0.2.2", + "defaultLocPrf": 100, + "localAS": 65002, + "routes": { + "10.0.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.0.0.0", + "prefixLen": 24, + "network": "10.0.0.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ], + "198.51.100.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "198.51.100.0", + "prefixLen": 24, + "network": "198.51.100.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ], + "203.0.113.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "203.0.113.0", + "prefixLen": 24, + "network": "203.0.113.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ] + } +} diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_notfound.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_notfound.json new file mode 100644 index 000000000000..7b9a5c875b3a --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_notfound.json @@ -0,0 +1,22 @@ +{ + "routerId": "192.0.2.2", + "defaultLocPrf": 100, + "localAS": 65002, + "routes": { + "10.0.0.0/24": [ + { + "valid": true, + "bestpath": true, + "selectionReason": "First path received", + "pathFrom": "external", + "prefix": "10.0.0.0", + "prefixLen": 24, + "network": "10.0.0.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ] + } +} diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_valid.json b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_valid.json new file mode 100644 index 000000000000..eb3852a7898d --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgp_table_rpki_valid.json @@ -0,0 +1,35 @@ +{ + "routerId": "192.0.2.2", + "defaultLocPrf": 100, + "localAS": 65002, + "routes": { + "198.51.100.0/24": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "prefix": "198.51.100.0", + "prefixLen": 24, + "network": "198.51.100.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ], + "203.0.113.0/24": [ + { + "valid": true, + "bestpath": true, + "pathFrom": "external", + "prefix": "203.0.113.0", + "prefixLen": 24, + "network": "203.0.113.0/24", + "metric": 0, + "weight": 0, + "path": "65530", + "origin": "IGP" + } + ] + } +} diff --git a/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf new file mode 100644 index 000000000000..4de177dc2586 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/bgpd.conf @@ -0,0 +1,25 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.0.2.1 remote-as 65530 + neighbor 192.0.2.1 timers connect 1 + neighbor 192.0.2.1 ebgp-multihop 3 + neighbor 192.0.2.1 update-source 192.0.2.2 + neighbor 192.168.4.4 remote-as internal + neighbor 192.168.4.4 timers 1 3 + neighbor 192.168.4.4 timers connect 1 + address-family ipv4 unicast + neighbor 192.168.4.4 next-hop-self + exit-address-family +! +router bgp 65002 vrf vrf10 + no bgp ebgp-requires-policy + neighbor 192.0.2.3 remote-as 65530 + neighbor 192.0.2.3 timers 1 3 + neighbor 192.0.2.3 timers connect 1 + neighbor 192.0.2.3 ebgp-multihop 3 + neighbor 192.0.2.3 update-source 192.0.2.2 +! +rpki + rpki retry_interval 5 + rpki cache tcp 192.0.2.1 15432 preference 1 +exit diff --git a/tests/topotests/bgp_rpki_topo1/r2/rpki_prefix_table.json b/tests/topotests/bgp_rpki_topo1/r2/rpki_prefix_table.json new file mode 100644 index 000000000000..fbc5cc9f076e --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/rpki_prefix_table.json @@ -0,0 +1,18 @@ +{ + "prefixes":[ + { + "prefix":"198.51.100.0", + "prefixLenMin":24, + "prefixLenMax":24, + "asn":65530 + }, + { + "prefix":"203.0.113.0", + "prefixLenMin":24, + "prefixLenMax":24, + "asn":65530 + } + ], + "ipv4PrefixCount":2, + "ipv6PrefixCount":0 +} diff --git a/tests/topotests/bgp_rpki_topo1/r2/staticd.conf b/tests/topotests/bgp_rpki_topo1/r2/staticd.conf new file mode 100644 index 000000000000..de58ddef69e7 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/staticd.conf @@ -0,0 +1,5 @@ +ip route 192.0.2.1/32 192.168.1.1 +! +vrf vrf10 + ip route 192.0.2.3/32 192.168.2.3 +! diff --git a/tests/topotests/bgp_rpki_topo1/r2/zebra.conf b/tests/topotests/bgp_rpki_topo1/r2/zebra.conf new file mode 100644 index 000000000000..785dbc6ce5db --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r2/zebra.conf @@ -0,0 +1,15 @@ +interface lo + ip address 192.0.2.2/32 +! +interface vrf10 vrf vrf10 + ip address 192.0.2.2/32 +! +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 vrf vrf10 + ip address 192.168.2.2/24 +! +interface r2-eth2 + ip address 192.168.4.2/24 +! diff --git a/tests/topotests/bgp_rpki_topo1/r3/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r3/bgpd.conf new file mode 100644 index 000000000000..596dc20d3321 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r3/bgpd.conf @@ -0,0 +1,14 @@ +router bgp 65530 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.0.2.2 remote-as 65002 + neighbor 192.0.2.2 timers 1 3 + neighbor 192.0.2.2 timers connect 1 + neighbor 192.0.2.2 ebgp-multihop 3 + neighbor 192.0.2.2 update-source 192.0.2.3 + address-family ipv4 unicast + network 198.51.100.0/24 + network 203.0.113.0/24 + network 10.0.0.0/24 + exit-address-family +! diff --git a/tests/topotests/bgp_rpki_topo1/r3/rtrd.py b/tests/topotests/bgp_rpki_topo1/r3/rtrd.py new file mode 120000 index 000000000000..1c5871a2ac55 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r3/rtrd.py @@ -0,0 +1 @@ +../r1/rtrd.py \ No newline at end of file diff --git a/tests/topotests/bgp_rpki_topo1/r3/staticd.conf b/tests/topotests/bgp_rpki_topo1/r3/staticd.conf new file mode 100644 index 000000000000..6822f7ec03f2 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r3/staticd.conf @@ -0,0 +1 @@ +ip route 192.0.2.2/32 192.168.2.2 diff --git a/tests/topotests/bgp_rpki_topo1/r3/vrps.csv b/tests/topotests/bgp_rpki_topo1/r3/vrps.csv new file mode 120000 index 000000000000..8daa27f134d5 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r3/vrps.csv @@ -0,0 +1 @@ +../r1/vrps.csv \ No newline at end of file diff --git a/tests/topotests/bgp_rpki_topo1/r3/zebra.conf b/tests/topotests/bgp_rpki_topo1/r3/zebra.conf new file mode 100644 index 000000000000..097511476a1a --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r3/zebra.conf @@ -0,0 +1,5 @@ +interface lo + ip address 192.0.2.3/32 +! +interface r3-eth0 + ip address 192.168.2.3/24 \ No newline at end of file diff --git a/tests/topotests/bgp_rpki_topo1/r4/bgpd.conf b/tests/topotests/bgp_rpki_topo1/r4/bgpd.conf new file mode 100644 index 000000000000..80dc9ca86fb9 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r4/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.4.2 remote-as internal + neighbor 192.168.4.2 timers 1 3 + neighbor 192.168.4.2 timers connect 1 +! diff --git a/tests/topotests/bgp_rpki_topo1/r4/zebra.conf b/tests/topotests/bgp_rpki_topo1/r4/zebra.conf new file mode 100644 index 000000000000..ed793aeb43c9 --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/r4/zebra.conf @@ -0,0 +1,4 @@ +! +interface r4-eth0 + ip address 192.168.4.4/24 +! diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py new file mode 100644 index 000000000000..7b40bbdae82d --- /dev/null +++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py @@ -0,0 +1,453 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright 2023 6WIND S.A. + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, "{}/bgpd.conf".format(rname)), + " -M bgpd_rpki" if rname == "r2" else "", + ) + + tgen.gears["r2"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r2"].run("ip link set vrf10 up") + + tgen.gears["r2"].run("ip link set r2-eth1 master vrf10") + + tgen.start_router() + + global rtrd_process + rtrd_process = {} + + for rname in ["r1", "r3"]: + rtr_path = os.path.join(CWD, rname) + log_dir = os.path.join(tgen.logdir, rname) + log_file = os.path.join(log_dir, "rtrd.log") + + tgen.gears[rname].cmd("chmod u+x {}/rtrd.py".format(rtr_path)) + rtrd_process[rname] = tgen.gears[rname].popen( + "{}/rtrd.py {}".format(rtr_path, log_file) + ) + + +def teardown_module(mod): + tgen = get_topogen() + + for rname in ["r1", "r3"]: + logger.info("{}: sending SIGTERM to rtrd RPKI server".format(rname)) + rtrd_process[rname].kill() + + tgen.stop_topology() + + +def show_rpki_prefixes(rname, expected, vrf=None): + tgen = get_topogen() + + if vrf: + cmd = "show rpki prefix-table vrf {} json".format(vrf) + else: + cmd = "show rpki prefix-table json" + + output = json.loads(tgen.gears[rname].vtysh_cmd(cmd)) + + return topotest.json_cmp(output, expected) + + +def show_bgp_ipv4_table_rpki(rname, rpki_state, expected, vrf=None): + tgen = get_topogen() + + cmd = "show bgp" + if vrf: + cmd += " vrf {}".format(vrf) + cmd += " ipv4 unicast" + if rpki_state: + cmd += " rpki {}".format(rpki_state) + cmd += " json" + + output = json.loads(tgen.gears[rname].vtysh_cmd(cmd)) + + expected_nb = len(expected.get("routes")) + output_nb = len(output.get("routes", {})) + + if expected_nb != output_nb: + return {"error": "expected {} prefixes. Got {}".format(expected_nb, output_nb)} + + return topotest.json_cmp(output, expected) + + +def test_show_bgp_rpki_prefixes(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + rname = "r2" + + step("Check RPKI prefix table") + + expected = open(os.path.join(CWD, "{}/rpki_prefix_table.json".format(rname))).read() + expected_json = json.loads(expected) + test_func = functools.partial(show_rpki_prefixes, rname, expected_json) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see RPKI prefixes on {}".format(rname) + + for rpki_state in ["valid", "notfound", None]: + if rpki_state: + step("Check RPKI state of prefixes in BGP table: {}".format(rpki_state)) + else: + step("Check prefixes in BGP table") + expected = open( + os.path.join( + CWD, + "{}/bgp_table_rpki_{}.json".format( + rname, rpki_state if rpki_state else "any" + ), + ) + ).read() + expected_json = json.loads(expected) + test_func = functools.partial( + show_bgp_ipv4_table_rpki, rname, rpki_state, expected_json + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected prefixes RPKI state on {}".format(rname) + + +def test_show_bgp_rpki_prefixes_no_rpki_cache(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + def _show_rpki_no_connection(rname): + output = json.loads( + tgen.gears[rname].vtysh_cmd("show rpki cache-connection json") + ) + + return output == {"error": "No connection to RPKI cache server."} + + step("Remove RPKI server from configuration") + rname = "r2" + tgen.gears[rname].vtysh_cmd( + """ +configure +rpki + no rpki cache tcp 192.0.2.1 15432 preference 1 +exit +""" + ) + + step("Check RPKI connection state") + + test_func = functools.partial(_show_rpki_no_connection, rname) + _, result = topotest.run_and_expect(test_func, True, count=60, wait=0.5) + assert result, "RPKI is still connected on {}".format(rname) + + +def test_show_bgp_rpki_prefixes_reconnect(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + step("Restore RPKI server configuration") + + rname = "r2" + tgen.gears[rname].vtysh_cmd( + """ +configure +rpki + rpki cache tcp 192.0.2.1 15432 preference 1 +exit +""" + ) + + step("Check RPKI prefix table") + + expected = open(os.path.join(CWD, "{}/rpki_prefix_table.json".format(rname))).read() + expected_json = json.loads(expected) + test_func = functools.partial(show_rpki_prefixes, rname, expected_json) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see RPKI prefixes on {}".format(rname) + + for rpki_state in ["valid", "notfound", None]: + if rpki_state: + step("Check RPKI state of prefixes in BGP table: {}".format(rpki_state)) + else: + step("Check prefixes in BGP table") + expected = open( + os.path.join( + CWD, + "{}/bgp_table_rpki_{}.json".format( + rname, rpki_state if rpki_state else "any" + ), + ) + ).read() + expected_json = json.loads(expected) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected prefixes RPKI state on {}".format(rname) + + +def test_show_bgp_rpki_route_map(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + step("Apply RPKI valid route-map on neighbor") + + rname = "r2" + tgen.gears[rname].vtysh_cmd( + """ +configure +route-map RPKI permit 10 + match rpki valid +! +router bgp 65002 + address-family ipv4 unicast + neighbor 192.0.2.1 route-map RPKI in +""" + ) + + for rpki_state in ["valid", "notfound", None]: + if rpki_state: + step("Check RPKI state of prefixes in BGP table: {}".format(rpki_state)) + else: + step("Check prefixes in BGP table") + expected = open( + os.path.join( + CWD, + "{}/bgp_table_rmap_rpki_{}.json".format( + rname, rpki_state if rpki_state else "any" + ), + ) + ).read() + expected_json = json.loads(expected) + test_func = functools.partial( + show_bgp_ipv4_table_rpki, + rname, + rpki_state, + expected_json, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected prefixes RPKI state on {}".format(rname) + + +def test_show_bgp_rpki_prefixes_vrf(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + step("Configure RPKI cache server on vrf10") + + rname = "r2" + tgen.gears[rname].vtysh_cmd( + """ +configure +vrf vrf10 + rpki + rpki cache tcp 192.0.2.3 15432 preference 1 + exit +exit +""" + ) + + step("Check vrf10 RPKI prefix table") + + expected = open(os.path.join(CWD, "{}/rpki_prefix_table.json".format(rname))).read() + expected_json = json.loads(expected) + test_func = functools.partial(show_rpki_prefixes, rname, expected_json, vrf="vrf10") + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to see RPKI prefixes on {}".format(rname) + + for rpki_state in ["valid", "notfound", None]: + if rpki_state: + step( + "Check RPKI state of prefixes in vrf10 BGP table: {}".format(rpki_state) + ) + else: + step("Check prefixes in vrf10 BGP table") + expected = open( + os.path.join( + CWD, + "{}/bgp_table_rpki_{}.json".format( + rname, rpki_state if rpki_state else "any" + ), + ) + ).read() + expected_json = json.loads(expected) + test_func = functools.partial( + show_bgp_ipv4_table_rpki, rname, rpki_state, expected_json, vrf="vrf10" + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected prefixes RPKI state on {}".format(rname) + + +def test_show_bgp_rpki_route_map_vrf(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + for rname in ["r1", "r3"]: + logger.info("{}: checking if rtrd is running".format(rname)) + if rtrd_process[rname].poll() is not None: + pytest.skip(tgen.errors) + + step("Apply RPKI valid route-map on vrf10 neighbor") + + rname = "r2" + tgen.gears[rname].vtysh_cmd( + """ +configure +router bgp 65002 vrf vrf10 + address-family ipv4 unicast + neighbor 192.0.2.3 route-map RPKI in +""" + ) + + for rpki_state in ["valid", "notfound", None]: + if rpki_state: + step( + "Check RPKI state of prefixes in vrf10 BGP table: {}".format(rpki_state) + ) + else: + step("Check prefixes in vrf10 BGP table") + expected = open( + os.path.join( + CWD, + "{}/bgp_table_rmap_rpki_{}.json".format( + rname, rpki_state if rpki_state else "any" + ), + ) + ).read() + expected_json = json.loads(expected) + test_func = functools.partial( + show_bgp_ipv4_table_rpki, + rname, + rpki_state, + expected_json, + vrf="vrf10", + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Unexpected prefixes RPKI state on {}".format(rname) + + +def test_bgp_ecommunity_rpki(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r4 = tgen.gears["r4"] + + # Flush all the states what was before and try sending out the prefixes + # with RPKI extended community. + r2.vtysh_cmd("clear ip bgp 192.168.4.4 soft out") + + def _bgp_check_ecommunity_rpki(community=None): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 198.51.100.0/24 json")) + expected = { + "paths": [ + { + "extendedCommunity": community, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_ecommunity_rpki, {"string": "OVS:valid"}) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Didn't receive RPKI extended community" + + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + address-family ipv4 unicast + no neighbor 192.168.4.4 send-community extended rpki + """ + ) + + test_func = functools.partial(_bgp_check_ecommunity_rpki) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Received RPKI extended community" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py index 9984abaa8561..5022a4a4a34f 100644 --- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py +++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py @@ -132,7 +132,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py index 3886bc17723a..6983a35173cb 100644 --- a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -129,6 +129,83 @@ def _bgp_suppress_route_to_r3(): assert result is None, "Routes should not be sent to r1 from r2" +def test_remove_loop_detection_on_one_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + def _bgp_reset_route_to_r1(): + output = json.loads( + r2.vtysh_cmd("show ip bgp neighbor 192.168.255.2 advertised-routes json") + ) + expected = {"totalPrefixCounter": 3} + return topotest.json_cmp(output, expected) + + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + no neighbor 192.168.255.2 sender-as-path-loop-detection + """ + ) + + r2.vtysh_cmd( + """ + clear bgp * + """ + ) + test_func = functools.partial(_bgp_reset_route_to_r1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Failed bgp to reset route" + + +def test_loop_detection_on_peer_group(): + tgen = get_topogen() + + r2 = tgen.gears["r2"] + + def _bgp_suppress_route_to_r1(): + output = json.loads( + r2.vtysh_cmd("show ip bgp neighbor 192.168.255.2 advertised-routes json") + ) + expected = {"totalPrefixCounter": 0} + return topotest.json_cmp(output, expected) + + def _bgp_suppress_route_to_r3(): + output = json.loads( + r2.vtysh_cmd("show ip bgp neighbor 192.168.254.2 advertised-routes json") + ) + expected = {"totalPrefixCounter": 2} + return topotest.json_cmp(output, expected) + + r2.vtysh_cmd( + """ + configure terminal + router bgp 65002 + neighbor loop_group peer-group + neighbor 192.168.255.2 peer-group loop_group + neighbor loop_group sender-as-path-loop-detection + """ + ) + + r2.vtysh_cmd( + """ + clear bgp * + """ + ) + + test_func = functools.partial(_bgp_suppress_route_to_r3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Route 172.16.255.253/32 should not be sent to r3 from r2" + + test_func = functools.partial(_bgp_suppress_route_to_r1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + assert result is None, "Routes should not be sent to r1 from r2" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf index 9bef24f93154..c70b4934a079 100644 --- a/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf +++ b/tests/topotests/bgp_set_aspath_exclude/r1/bgpd.conf @@ -8,10 +8,19 @@ router bgp 65001 exit-address-family ! ip prefix-list p1 seq 5 permit 172.16.255.31/32 +ip prefix-list p2 seq 5 permit 172.16.255.32/32 +ip prefix-list p3 seq 5 permit 172.16.255.30/32 ! +bgp as-path access-list FIRST permit ^65 +bgp as-path access-list SECOND permit 2$ + +route-map r2 permit 6 + match ip address prefix-list p2 + set as-path exclude as-path-access-list SECOND route-map r2 permit 10 match ip address prefix-list p1 set as-path exclude 65003 route-map r2 permit 20 + match ip address prefix-list p3 set as-path exclude all ! diff --git a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf index 3fa6c644844c..56893158a403 100644 --- a/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf +++ b/tests/topotests/bgp_set_aspath_exclude/r3/zebra.conf @@ -1,5 +1,6 @@ ! int lo + ip address 172.16.255.30/32 ip address 172.16.255.31/32 ip address 172.16.255.32/32 ! diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py index a0cd89f064ce..63f1719e1d07 100644 --- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py +++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -62,23 +62,52 @@ def teardown_module(mod): tgen.stop_topology() +expected_1 = { + "routes": { + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65003"}], + } +} + +expected_2 = { + "routes": { + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": ""}], + } +} + +expected_3 = { + "routes": { + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65002 65003"}], + } +} + +expected_4 = { + "routes": { + "172.16.255.30/32": [{"path": ""}], + "172.16.255.31/32": [{"path": "65002"}], + "172.16.255.32/32": [{"path": "65002"}], + } +} + + +def bgp_converge(router, expected): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + + return topotest.json_cmp(output, expected) + + def test_bgp_set_aspath_exclude(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) - def _bgp_converge(router): - output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) - expected = { - "routes": { - "172.16.255.31/32": [{"path": "65002"}], - "172.16.255.32/32": [{"path": ""}], - } - } - return topotest.json_cmp(output, expected) - - test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed overriding incoming AS-PATH with route-map" @@ -92,52 +121,107 @@ def test_bgp_set_aspath_exclude_access_list(): rname = "r1" r1 = tgen.gears[rname] + # tgen.mininet_cli() r1.vtysh_cmd( """ conf bgp as-path access-list FIRST permit ^65 route-map r2 permit 6 + no set as-path exclude as-path-access-list SECOND set as-path exclude as-path-access-list FIRST """ ) + # tgen.mininet_cli() + r1.vtysh_cmd( + """ +clear bgp * + """ + ) - expected = { - "routes": { - "172.16.255.31/32": [{"path": ""}], - "172.16.255.32/32": [{"path": ""}], - } - } + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - def _bgp_regexp_1(router): - output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json")) + assert result is None, "Failed change of exclude rule in route map" + r1.vtysh_cmd( + """ +conf + route-map r2 permit 6 + no set as-path exclude as-path-access-list FIRST + set as-path exclude as-path-access-list SECOND + """ + ) - return topotest.json_cmp(output, expected) + # tgen.mininet_cli() + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) + assert result is None, "Failed reverting exclude rule in route map" + + +def test_no_bgp_set_aspath_exclude_access_list(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + rname = "r1" + r1 = tgen.gears[rname] + + r1.vtysh_cmd( + """ +conf + no bgp as-path access-list SECOND permit 2$ + """ + ) + + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - assert result is None, "Failed overriding incoming AS-PATH with regex 1 route-map" + assert result is None, "Failed to removing current accesslist" + + # tgen.mininet_cli() + r1.vtysh_cmd( + """ +conf + bgp as-path access-list SECOND permit 3$ + """ + ) + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, "Failed to renegotiate with peers 2" + r1.vtysh_cmd( """ conf - bgp as-path access-list SECOND permit 2 route-map r2 permit 6 - set as-path exclude as-path-access-list SECOND + no set as-path exclude as-path-access-list SECOND """ ) - expected = { - "routes": { - "172.16.255.31/32": [{"path": "65003"}], - "172.16.255.32/32": [{"path": "65003"}], - } - } + r1.vtysh_cmd( + """ +clear bgp * + """ + ) - test_func = functools.partial(_bgp_regexp_1, tgen.gears["r1"]) + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) - assert result is None, "Failed overriding incoming AS-PATH with regex 2 route-map" + assert result is None, "Failed to renegotiate with peers 2" if __name__ == "__main__": diff --git a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py index c0e19fa35690..fe4eda60f5c0 100644 --- a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py +++ b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py index 292cf70d3617..e201ec9ff74d 100644 --- a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py +++ b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -100,12 +100,12 @@ def _bgp_check_local_preference(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) test_func = functools.partial(_bgp_check_local_preference, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP local-preference in "{}"'.format( router diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf new file mode 100644 index 000000000000..a550b4c143b7 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/bgpd.conf @@ -0,0 +1,18 @@ +! +!debug bgp updates +! +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + no bgp default ipv4-unicast + neighbor 192.168.12.4 remote-as external + neighbor 192.168.12.4 timers 1 3 + neighbor 192.168.12.4 timers connect 1 + ! + address-family ipv4 unicast + neighbor 192.168.12.4 activate + neighbor 192.168.12.4 addpath-tx-all-paths + exit-address-family +! +agentx +! diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf new file mode 100644 index 000000000000..032b93b67615 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/snmpd.conf @@ -0,0 +1,17 @@ +agentAddress 127.0.0.1,[::1] + +group public_group v1 public +group public_group v2c public +access public_group "" any noauth prefix all all none + +rocommunity public default + +view all included .1 + +iquerySecName frr +rouser frr + +master agentx + +agentXSocket /etc/frr/agentx +agentXPerms 777 755 root frr diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf new file mode 100644 index 000000000000..d7dfd899cc43 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2_notification/r2/zebra.conf @@ -0,0 +1,4 @@ +! +interface r2-eth0 + ip address 192.168.12.2/24 +! diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf new file mode 100644 index 000000000000..145a8f008e3f --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/bgpd.conf @@ -0,0 +1,19 @@ +! +!debug bgp updates +! +router bgp 65004 + no bgp ebgp-requires-policy + no bgp network import-check + no bgp default ipv4-unicast + neighbor 192.168.12.2 remote-as external + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + ! + address-family ipv4 unicast + neighbor 192.168.12.2 activate + neighbor 192.168.12.2 addpath-tx-all-paths + neighbor 192.168.12.2 route-server-client + exit-address-family +! +agentx +! diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf new file mode 100644 index 000000000000..eb8a48643851 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2_notification/rr/zebra.conf @@ -0,0 +1,4 @@ +! +interface rr-eth0 + ip address 192.168.12.4/24 +! diff --git a/tests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py b/tests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py new file mode 100755 index 000000000000..c41ef30bb5ed --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2_notification/test_bgp_snmp_bgp4v2_notification.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright 2024 6WIND S.A. +# + + +""" +Test BGP OPEN NOTIFY (Configuration mismatch) followed by snmpwalk. +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib import topotest + +pytestmark = [pytest.mark.bgpd, pytest.mark.snmp] + + +def build_topo(tgen): + """Build function""" + + tgen.add_router("r2") + tgen.add_router("rr") + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["rr"]) + + +def setup_module(mod): + snmpd = os.system("which snmpd") + if snmpd: + error_msg = "SNMP not installed - skipping" + pytest.skip(error_msg) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, "{}/bgpd.conf".format(rname)), + "-M snmp", + ) + router.load_config( + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(rname)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX", + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_open_notification_change_configuration(): + tgen = get_topogen() + + tgen.gears["rr"].vtysh_multicmd( + """ +configure terminal +router bgp 65004 +neighbor 192.168.12.2 password 8888" +""" + ) + tgen.net["r2"].cmd("snmpwalk -v 2c -c public 127.0.0.1 .1.3.6.1.4.1.7336.4.2.1") + tgen.gears["rr"].vtysh_multicmd( + """ +configure terminal +router bgp 65004 +no neighbor 192.168.12.2 password 8888" +""" + ) + + def _check_bgp_session(): + r2 = tgen.gears["r2"] + + output = json.loads(r2.vtysh_cmd("show bgp summary json")) + expected = { + "ipv4Unicast": {"peers": {"192.168.12.4": {"state": "Established"}}} + } + + return topotest.json_cmp(output, expected) + + test_func1 = functools.partial(_check_bgp_session) + _, result1 = topotest.run_and_expect(test_func1, None, count=120, wait=0.5) + + assert result1 is None, "Failed to verify the bgp session" + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf index d82a21e1f9fe..144466e418da 100644 --- a/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf @@ -1,24 +1,28 @@ ! +!debug bgp updates +! router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check no bgp default ipv4-unicast - neighbor 192.168.12.2 remote-as external - neighbor 192.168.12.2 timers 1 3 - neighbor 192.168.12.2 timers connect 1 - neighbor 2001:db8::12:2 remote-as external - neighbor 2001:db8::12:2 timers 1 3 - neighbor 2001:db8::12:2 timers connect 1 + neighbor 192.168.12.4 remote-as external + neighbor 192.168.12.4 timers 1 3 + neighbor 192.168.12.4 timers connect 1 + neighbor 2001:db8::12:4 remote-as external + neighbor 2001:db8::12:4 timers 1 3 + neighbor 2001:db8::12:4 timers connect 1 ! address-family ipv4 unicast network 10.0.0.0/31 route-map p1 network 10.0.0.2/32 route-map p2 - neighbor 192.168.12.2 activate + neighbor 192.168.12.4 activate + neighbor 192.168.12.4 addpath-tx-all-paths + network 10.10.10.10/32 exit-address-family address-family ipv6 unicast network 2001:db8::1/128 route-map p1 network 2001:db8:1::/56 route-map p2 - neighbor 2001:db8::12:2 activate + neighbor 2001:db8::12:4 activate exit-address-family ! route-map p1 permit 10 @@ -28,4 +32,3 @@ route-map p2 permit 10 set metric 2 set origin incomplete exit -! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf index cf0013e1b7a1..55686f407a7f 100644 --- a/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf @@ -5,18 +5,20 @@ router bgp 65002 no bgp ebgp-requires-policy no bgp network import-check no bgp default ipv4-unicast - neighbor 192.168.12.1 remote-as external - neighbor 192.168.12.1 timers 1 3 - neighbor 192.168.12.1 timers connect 1 - neighbor 2001:db8::12:1 remote-as external - neighbor 2001:db8::12:1 timers 1 3 - neighbor 2001:db8::12:1 timers connect 1 + neighbor 192.168.12.4 remote-as external + neighbor 192.168.12.4 timers 1 3 + neighbor 192.168.12.4 timers connect 1 + neighbor 2001:db8::12:4 remote-as external + neighbor 2001:db8::12:4 timers 1 3 + neighbor 2001:db8::12:4 timers connect 1 ! address-family ipv4 unicast - neighbor 192.168.12.1 activate + neighbor 192.168.12.4 activate + neighbor 192.168.12.4 addpath-tx-all-paths + exit-address-family address-family ipv6 unicast - neighbor 2001:db8::12:1 activate + neighbor 2001:db8::12:4 activate exit-address-family ! agentx diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf index 032b93b67615..f0957cca7ad9 100644 --- a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf @@ -6,6 +6,15 @@ access public_group "" any noauth prefix all all none rocommunity public default +trapsess -v2c -c public 127.0.0.1 + +notificationEvent linkUpTrap linkUp ifIndex ifAdminStatus ifOperStatus +notificationEvent linkDownTrap linkDown ifIndex ifAdminStatus ifOperStatus + +monitor -r 2 -e linkUpTrap "Generate linkUp" ifOperStatus != 2 +monitor -r 2 -e linkDownTrap "Generate linkDown" ifOperStatus == 2 + + view all included .1 iquerySecName frr diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf new file mode 100644 index 000000000000..f6e4abfef779 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmptrapd.conf @@ -0,0 +1,2 @@ +authCommunity net,log public +disableAuthorization yes diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r3/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r3/bgpd.conf new file mode 100644 index 000000000000..71dbda0bc137 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r3/bgpd.conf @@ -0,0 +1,25 @@ +! +!debug bgp updates +! +router bgp 65003 + no bgp ebgp-requires-policy + no bgp network import-check + no bgp default ipv4-unicast + neighbor 192.168.12.4 remote-as external + neighbor 192.168.12.4 timers 1 3 + neighbor 192.168.12.4 timers connect 1 + neighbor 2001:db8::12:4 remote-as external + neighbor 2001:db8::12:4 timers 1 3 + neighbor 2001:db8::12:4 timers connect 1 + ! + address-family ipv4 unicast + neighbor 192.168.12.4 activate + neighbor 192.168.12.4 addpath-tx-all-paths + network 10.10.10.10/32 + exit-address-family + address-family ipv6 unicast + neighbor 2001:db8::12:4 activate + exit-address-family +! +agentx +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r3/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r3/zebra.conf new file mode 100644 index 000000000000..398af65ffe57 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/r3/zebra.conf @@ -0,0 +1,5 @@ +! +interface r3-eth0 + ip address 192.168.12.3/24 + ipv6 address 2001:db8::12:3/64 +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/rr/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/rr/bgpd.conf new file mode 100644 index 000000000000..5ebbde6703fe --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/rr/bgpd.conf @@ -0,0 +1,67 @@ +! +! debug bgp updates +! +router bgp 65004 + no bgp ebgp-requires-policy + no bgp network import-check + no bgp default ipv4-unicast + neighbor 192.168.12.1 remote-as external + neighbor 192.168.12.1 timers 1 3 + neighbor 192.168.12.1 timers connect 1 + neighbor 192.168.12.2 remote-as external + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + neighbor 192.168.12.3 remote-as external + neighbor 192.168.12.3 timers 1 3 + neighbor 192.168.12.3 timers connect 1 + neighbor 2001:db8::12:1 remote-as external + neighbor 2001:db8::12:1 timers 1 3 + neighbor 2001:db8::12:1 timers connect 1 + neighbor 2001:db8::12:2 remote-as external + neighbor 2001:db8::12:2 timers 1 3 + neighbor 2001:db8::12:2 timers connect 1 + neighbor 2001:db8::12:3 remote-as external + neighbor 2001:db8::12:3 timers 1 3 + neighbor 2001:db8::12:3 timers connect 1 + ! + address-family ipv4 unicast + network 10.0.0.0/31 route-map p1 + network 10.0.0.2/32 route-map p2 + neighbor 192.168.12.1 activate + neighbor 192.168.12.2 activate + neighbor 192.168.12.2 addpath-tx-all-paths + neighbor 192.168.12.2 route-map r2-import in + neighbor 192.168.12.2 route-map r2-export out +! neighbor 192.168.12.2 soft-reconfiguration inbound + neighbor 192.168.12.3 activate + exit-address-family + address-family ipv6 unicast + network 2001:db8::1/128 route-map p1 + network 2001:db8:1::/56 route-map p2 + neighbor 2001:db8::12:1 activate + neighbor 2001:db8::12:2 activate + neighbor 2001:db8::12:2 addpath-tx-all-paths + neighbor 2001:db8::12:3 activate + exit-address-family + + +ip prefix-list r2-toto permit any + +route-map r2-import permit 10 + match ip address prefix-list r2-toto + +route-map r2-export permit 10 + match ip address prefix-list r2-toto +! +route-map p1 permit 10 + set metric 1 +exit +route-map p2 permit 10 + set metric 2 + set origin incomplete +exit + + + +agentx +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/rr/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/rr/zebra.conf new file mode 100644 index 000000000000..092673b8a977 --- /dev/null +++ b/tests/topotests/bgp_snmp_bgp4v2mib/rr/zebra.conf @@ -0,0 +1,5 @@ +! +interface rr-eth0 + ip address 192.168.12.4/24 + ipv6 address 2001:db8::12:4/64 +! diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py index 6b6153db4630..c296aaaf6d52 100755 --- a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py +++ b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py @@ -24,6 +24,7 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.snmptest import SnmpTester from lib import topotest +from lib.topolog import logger pytestmark = [pytest.mark.bgpd, pytest.mark.snmp] @@ -31,10 +32,14 @@ def build_topo(tgen): tgen.add_router("r1") tgen.add_router("r2") + tgen.add_router("r3") + tgen.add_router("rr") switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["rr"]) def setup_module(mod): @@ -55,11 +60,18 @@ def setup_module(mod): os.path.join(CWD, "{}/bgpd.conf".format(rname)), "-M snmp", ) - router.load_config( - TopoRouter.RD_SNMP, - os.path.join(CWD, "{}/snmpd.conf".format(rname)), - "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX", - ) + + r2 = tgen.gears["r2"] + r2.load_config( + TopoRouter.RD_SNMP, + os.path.join(CWD, "{}/snmpd.conf".format(r2.name)), + "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX", + ) + r2.load_config( + TopoRouter.RD_TRAP, + os.path.join(CWD, "{}/snmptrapd.conf".format(r2.name)), + " -On -OQ ", + ) tgen.start_router() @@ -72,28 +84,31 @@ def teardown_module(mod): def test_bgp_snmp_bgp4v2(): tgen = get_topogen() + r1 = tgen.gears["r1"] r2 = tgen.gears["r2"] + rr = tgen.gears["rr"] def _bgp_converge_summary(): output = json.loads(r2.vtysh_cmd("show bgp summary json")) expected = { "ipv4Unicast": { "peers": { - "192.168.12.1": { + "192.168.12.4": { "state": "Established", - "pfxRcd": 2, + "pfxRcd": 6, } } }, "ipv6Unicast": { "peers": { - "2001:db8::12:1": { + "2001:db8::12:4": { "state": "Established", - "pfxRcd": 2, + "pfxRcd": 4, } } }, } + # tgen.mininet_cli() return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge_summary) @@ -136,6 +151,7 @@ def _bgp_converge_prefixes(): } }, } + # tgen.mininet_cli() return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge_prefixes) @@ -146,11 +162,12 @@ def _bgp_converge_prefixes(): def _snmpwalk_remote_addr(): expected = { - "1.3.6.1.3.5.1.1.2.1.5.1.1.192.168.12.1": "C0 A8 0C 01", - "1.3.6.1.3.5.1.1.2.1.5.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01", + "1.3.6.1.3.5.1.1.2.1.5.1.1.192.168.12.4": "C0 A8 0C 04", + "1.3.6.1.3.5.1.1.2.1.5.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 04", } # bgp4V2PeerRemoteAddr + # tgen.mininet_cli() output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.5") return output == expected @@ -160,8 +177,8 @@ def _snmpwalk_remote_addr(): def _snmpwalk_peer_state(): expected = { - "1.3.6.1.3.5.1.1.2.1.13.1.1.192.168.12.1": "6", - "1.3.6.1.3.5.1.1.2.1.13.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6", + "1.3.6.1.3.5.1.1.2.1.13.1.1.192.168.12.4": "6", + "1.3.6.1.3.5.1.1.2.1.13.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4": "6", } # bgp4V2PeerState @@ -174,8 +191,8 @@ def _snmpwalk_peer_state(): def _snmpwalk_peer_last_error_code_received(): expected = { - "1.3.6.1.3.5.1.1.3.1.1.1.1.192.168.12.1": "0", - "1.3.6.1.3.5.1.1.3.1.1.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0", + "1.3.6.1.3.5.1.1.3.1.1.1.1.192.168.12.4": "0", + "1.3.6.1.3.5.1.1.3.1.1.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4": "0", } # bgp4V2PeerLastErrorCodeReceived @@ -190,10 +207,16 @@ def _snmpwalk_peer_last_error_code_received(): def _snmpwalk_origin(): expected = { - "1.3.6.1.3.5.1.1.9.1.9.1.1.10.0.0.0.31.192.168.12.1": "1", - "1.3.6.1.3.5.1.1.9.1.9.1.1.10.0.0.2.32.192.168.12.1": "3", - "1.3.6.1.3.5.1.1.9.1.9.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", - "1.3.6.1.3.5.1.1.9.1.9.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3", + "1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.10.10.10.32.1.192.168.12.4.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.10.10.10.32.1.192.168.12.4.2": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.0.0.0.31.1.192.168.12.4.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.0.0.0.31.1.192.168.12.4.2": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.0.0.2.32.1.192.168.12.4.1": "3", + "1.3.6.1.3.5.1.1.9.1.9.1.1.1.1.10.0.0.2.32.1.192.168.12.4.2": "3", + "1.3.6.1.3.5.1.1.9.1.9.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.1": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.2": "1", + "1.3.6.1.3.5.1.1.9.1.9.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.1": "3", + "1.3.6.1.3.5.1.1.9.1.9.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.2": "3", } # bgp4V2NlriOrigin @@ -206,20 +229,89 @@ def _snmpwalk_origin(): def _snmpwalk_med(): expected = { - "1.3.6.1.3.5.1.1.9.1.17.1.1.10.0.0.0.31.192.168.12.1": "1", - "1.3.6.1.3.5.1.1.9.1.17.1.1.10.0.0.2.32.192.168.12.1": "2", - "1.3.6.1.3.5.1.1.9.1.17.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1", - "1.3.6.1.3.5.1.1.9.1.17.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2", + "1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.10.10.10.32.1.192.168.12.4.1": "0", + "1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.10.10.10.32.1.192.168.12.4.2": "0", + "1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.0.0.0.31.1.192.168.12.4.1": "1", + "1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.0.0.0.31.1.192.168.12.4.2": "0", + "1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.0.0.2.32.1.192.168.12.4.1": "2", + "1.3.6.1.3.5.1.1.9.1.17.1.1.1.1.10.0.0.2.32.1.192.168.12.4.2": "0", + "1.3.6.1.3.5.1.1.9.1.17.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.1": "1", + "1.3.6.1.3.5.1.1.9.1.17.1.2.1.2.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.2": "0", + "1.3.6.1.3.5.1.1.9.1.17.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.1": "2", + "1.3.6.1.3.5.1.1.9.1.17.1.2.1.2.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4.2": "0", } # bgp4V2NlriMed output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.17") + # tgen.mininet_cli() return output == expected _, result = topotest.run_and_expect(_snmpwalk_med, True, count=10, wait=1) assertmsg = "Can't fetch SNMP for bgp4V2NlriMed" assert result, assertmsg + # + # traps + # + + # + # bgp4 traps + # + def _snmptrap_ipv4(): + def __get_notif_bgp4_in_trap_file(router): + snmptrapfile = "{}/{}/snmptrapd.log".format(router.logdir, router.name) + outputfile = open(snmptrapfile).read() + output = snmp.get_notif_bgp4(outputfile) + + return output + + output = __get_notif_bgp4_in_trap_file(r2) + logger.info("output bgp4") + logger.info(output) + return snmp.is_notif_bgp4_valid(output, "192.168.12.4") + + # skip tests is SNMP not installed + if not os.path.isfile("/usr/sbin/snmptrapd"): + error_msg = "SNMP not installed - skipping" + pytest.skip(error_msg) + + rr.vtysh_cmd("clear bgp *") + _, result = topotest.run_and_expect(_snmptrap_ipv4, True, count=30, wait=1) + assertmsg = "Can't fetch SNMP trap for ipv4" + assert result, assertmsg + + # + # bgp4v2 traps + # + def _snmptrap_ipv6(): + def __get_notif_bgp4v2_in_trap_file(router): + snmptrapfile = "{}/{}/snmptrapd.log".format(router.logdir, router.name) + outputfile = open(snmptrapfile).read() + output = snmp.get_notif_bgp4v2(outputfile) + + return output + + # tgen.mininet_cli() + output = __get_notif_bgp4v2_in_trap_file(r2) + logger.info("output bgp4v2") + logger.info(output) + p_ipv4_addr = "1.192.168.12.4" + p_ipv6_addr = "2.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.4" + return ( + snmp.is_notif_bgp4v2_valid(output, p_ipv4_addr, "Estab") + and snmp.is_notif_bgp4v2_valid(output, p_ipv6_addr, "Estab") + and snmp.is_notif_bgp4v2_valid(output, p_ipv4_addr, "Backward") + and snmp.is_notif_bgp4v2_valid(output, p_ipv6_addr, "Backward") + ) + + sleep(10) + r2.vtysh_cmd("conf\nbgp snmp traps bgp4-mibv2") + r2.vtysh_cmd("conf\nno bgp snmp traps rfc4273") + rr.vtysh_cmd("clear bgp *") + _, result = topotest.run_and_expect(_snmptrap_ipv6, True, count=60, wait=1) + assertmsg = "Can't fetch SNMP trap for ipv6" + assert result, assertmsg + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py index 0131e12579b3..09eef51338d9 100755 --- a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -325,7 +325,6 @@ def router_interface_get_ifindex(router, interface): def generate_vrf_ifindex_oid(vrf, ifindex): - intoid = snmp_uint32_to_oid(int(ifindex)) vrfoid = snmp_str_to_oid(vrf) oid = "{}.{}".format(vrfoid, intoid) diff --git a/tests/topotests/bgp_software_version/test_bgp_software_version.py b/tests/topotests/bgp_software_version/test_bgp_software_version.py index 25e646cf42c2..9aff53a03082 100644 --- a/tests/topotests/bgp_software_version/test_bgp_software_version.py +++ b/tests/topotests/bgp_software_version/test_bgp_software_version.py @@ -17,7 +17,7 @@ import pytest import functools -pytestmark = pytest.mark.bgpd +pytestmark = [pytest.mark.bgpd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -26,8 +26,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -pytestmark = [pytest.mark.bgpd] - def setup_module(mod): topodef = {"s1": ("r1", "r2")} @@ -36,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_soo/test_bgp_soo.py b/tests/topotests/bgp_soo/test_bgp_soo.py index 967bed021358..b0c70f208ebb 100644 --- a/tests/topotests/bgp_soo/test_bgp_soo.py +++ b/tests/topotests/bgp_soo/test_bgp_soo.py @@ -73,7 +73,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ip_route.ref.diff b/tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step6/show_ip_route.ref.diff rename to tests/topotests/bgp_srv6_sid_reachability/c11/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf new file mode 100644 index 000000000000..bcf5a0499f09 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c11/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.1.254 +ipv6 route ::/0 2001:1::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf new file mode 100644 index 000000000000..0615cf9a95be --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c11/zebra.conf @@ -0,0 +1,6 @@ +hostname c11 +! +interface eth0 + ip address 192.168.1.1/24 + ipv6 address 2001:1::1/64 +! diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ipv6_route.ref.diff b/tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step6/show_ipv6_route.ref.diff rename to tests/topotests/bgp_srv6_sid_reachability/c12/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf new file mode 100644 index 000000000000..bcf5a0499f09 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c12/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.1.254 +ipv6 route ::/0 2001:1::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf new file mode 100644 index 000000000000..18985aa383bd --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c12/zebra.conf @@ -0,0 +1,6 @@ +hostname c12 +! +interface eth0 + ip address 192.168.1.1/24 + ipv6 address 2001:1::1/64 +! diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step6/show_mpls_table.ref.diff b/tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt1/step6/show_mpls_table.ref.diff rename to tests/topotests/bgp_srv6_sid_reachability/c21/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf new file mode 100644 index 000000000000..608e60060e80 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c21/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.2.254 +ipv6 route ::/0 2001:2::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf new file mode 100644 index 000000000000..b8b70ac96508 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c21/zebra.conf @@ -0,0 +1,6 @@ +hostname c21 +! +interface eth0 + ip address 192.168.2.1/24 + ipv6 address 2001:2::1/64 +! diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff b/tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff rename to tests/topotests/bgp_srv6_sid_reachability/c22/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf new file mode 100644 index 000000000000..277aae998cff --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c22/staticd.conf @@ -0,0 +1,5 @@ + +! +ip route 0.0.0.0/0 192.168.2.254 +ipv6 route ::/0 2001:2::ffff +! \ No newline at end of file diff --git a/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf new file mode 100644 index 000000000000..cc764cc35c2f --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c22/zebra.conf @@ -0,0 +1,9 @@ +hostname c22 +! +interface eth0 + ip address 192.168.2.1/24 + ipv6 address 2001:2::1/64 +! +ip route 0.0.0.0/0 192.168.2.254 +ipv6 route ::/0 2001:2::ffff +! diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff b/tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff rename to tests/topotests/bgp_srv6_sid_reachability/c31/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf new file mode 100644 index 000000000000..0c88575abd01 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c31/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.3.254 +ipv6 route ::/0 2001:3::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf new file mode 100644 index 000000000000..3f75641ea759 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c31/zebra.conf @@ -0,0 +1,6 @@ +hostname c31 +! +interface eth0 + ip address 192.168.3.1/24 + ipv6 address 2001:3::1/64 +! diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff b/tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff rename to tests/topotests/bgp_srv6_sid_reachability/c32/bgpd.conf diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf new file mode 100644 index 000000000000..0c88575abd01 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c32/staticd.conf @@ -0,0 +1,4 @@ +! +ip route 0.0.0.0/0 192.168.3.254 +ipv6 route ::/0 2001:3::ffff +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf new file mode 100644 index 000000000000..c06a7d19f5f9 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/c32/zebra.conf @@ -0,0 +1,6 @@ +hostname c32 +! +interface eth0 + ip address 192.168.3.1/24 + ipv6 address 2001:3::1/64 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf new file mode 100644 index 000000000000..573dbe0951ee --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r1/bgpd.conf @@ -0,0 +1,61 @@ +frr defaults traditional +! +hostname r1 +password zebra +! +log commands +! +router bgp 65001 + bgp router-id 192.0.2.1 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001:db8:12::2 remote-as 65002 + neighbor 2001:db8:12::2 timers 3 10 + neighbor 2001:db8:12::2 timers connect 1 + neighbor 2001:db8:12::2 capability extended-nexthop + neighbor 2001:db8:13::3 remote-as 65001 + neighbor 2001:db8:13::3 timers 3 10 + neighbor 2001:db8:13::3 timers connect 1 + neighbor 2001:db8:13::3 capability extended-nexthop + ! + segment-routing srv6 + locator default + ! + address-family ipv4 vpn + neighbor 2001:db8:12::2 activate + neighbor 2001:db8:13::3 activate + exit-address-family + ! +! +router bgp 65001 vrf vrf10 + bgp router-id 192.0.2.1 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 1 + rd vpn export 65001:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65001 vrf vrf20 + bgp router-id 192.0.2.1 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 2 + rd vpn export 65001:20 + rt vpn both 0:20 + import vpn + export vpn + exit-address-family + ! +! +interface eth0 + mpls bgp forwarding +! +interface eth1 + mpls bgp forwarding +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf new file mode 100644 index 000000000000..49b64fd7afc7 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r1/staticd.conf @@ -0,0 +1,4 @@ +! +ipv6 route 2001:db8:2:2::/64 2001:db8:12::2 +ipv6 route 2001:db8:3:3::/64 2001:db8:13::3 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf new file mode 100644 index 000000000000..79dbf9559308 --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r1/zebra.conf @@ -0,0 +1,32 @@ +log file zebra.log +! +hostname r1 +! +interface lo + ipv6 address 2001:db8:1:1::1/128 +! +interface eth0 + ipv6 address 2001:db8:12::1/64 +! +interface eth1 + ipv6 address 2001:db8:13::1/64 +! +interface eth2 vrf vrf10 + ip address 192.168.1.254/24 +! +interface eth3 vrf vrf20 + ip address 192.168.1.254/24 +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:1:1::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf new file mode 100644 index 000000000000..723d6fca2f7b --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r2/bgpd.conf @@ -0,0 +1,50 @@ +frr defaults traditional +! +hostname r2 +password zebra +! +log commands +! +router bgp 65002 + bgp router-id 192.0.2.2 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001:db8:12::1 remote-as 65001 + neighbor 2001:db8:12::1 timers 3 10 + neighbor 2001:db8:12::1 timers connect 1 + neighbor 2001:db8:12::1 capability extended-nexthop + ! + segment-routing srv6 + locator default + ! + address-family ipv4 vpn + neighbor 2001:db8:12::1 activate + exit-address-family + ! +! +router bgp 65002 vrf vrf10 + bgp router-id 192.0.2.2 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 1 + rd vpn export 65002:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65002 vrf vrf20 + bgp router-id 192.0.2.2 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 2 + rd vpn export 65002:20 + rt vpn both 0:20 + import vpn + export vpn + exit-address-family + ! +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf new file mode 100644 index 000000000000..8d80c1ead2cf --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r2/staticd.conf @@ -0,0 +1,4 @@ +! +ipv6 route 2001:db8:1:1::/64 2001:db8:12::1 +ipv6 route 2001:db8:3:3::/64 2001:db8:12::1 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf new file mode 100644 index 000000000000..09a65b989c1a --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r2/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ipv6 address 2001:db8:2:2::1/128 +! +interface eth0 + ipv6 address 2001:db8:12::2/64 +! +interface eth1 vrf vrf10 + ip address 192.168.2.254/24 +! +interface eth2 vrf vrf20 + ip address 192.168.2.254/24 +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:2:2::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf new file mode 100644 index 000000000000..c412cb6d29eb --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r3/bgpd.conf @@ -0,0 +1,50 @@ +frr defaults traditional +! +hostname r2 +password zebra +! +log commands +! +router bgp 65001 + bgp router-id 192.0.2.3 + no bgp ebgp-requires-policy + no bgp default ipv4-unicast + neighbor 2001:db8:13::1 remote-as 65001 + neighbor 2001:db8:13::1 timers 3 10 + neighbor 2001:db8:13::1 timers connect 1 + neighbor 2001:db8:13::1 capability extended-nexthop + ! + segment-routing srv6 + locator default + ! + address-family ipv4 vpn + neighbor 2001:db8:13::1 activate + exit-address-family + ! +! +router bgp 65001 vrf vrf10 + bgp router-id 192.0.2.3 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 1 + rd vpn export 65001:10 + rt vpn both 0:10 + import vpn + export vpn + exit-address-family + ! +! +router bgp 65001 vrf vrf20 + bgp router-id 192.0.2.2 + ! + address-family ipv4 unicast + redistribute connected + sid vpn export 2 + rd vpn export 65001:20 + rt vpn both 0:20 + import vpn + export vpn + exit-address-family + ! +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf new file mode 100644 index 000000000000..9d672d51ba7e --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r3/staticd.conf @@ -0,0 +1,6 @@ +! +ipv6 route 2001:db8:12::/64 2001:db8:13::1 +! +ipv6 route 2001:db8:1:1::/64 2001:db8:13::1 +ipv6 route 2001:db8:2:2::/64 2001:db8:13::1 +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf b/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf new file mode 100644 index 000000000000..a20cb76a744d --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/r3/zebra.conf @@ -0,0 +1,29 @@ +log file zebra.log +! +hostname r2 +! +interface lo + ipv6 address 2001:db8:3:3::1/128 +! +interface eth0 + ipv6 address 2001:db8:13::3/64 +! +interface eth1 vrf vrf10 + ip address 192.168.3.254/24 +! +interface eth2 vrf vrf20 + ip address 192.168.3.254/24 +! +segment-routing + srv6 + locators + locator default + prefix 2001:db8:3:3::/64 + ! + ! +! +ip forwarding +ipv6 forwarding +! +line vty +! diff --git a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py new file mode 100755 index 000000000000..f8385401c5ad --- /dev/null +++ b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2023 by 6WIND +# + +import os +import sys +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import required_linux_kernel_version +from lib.checkping import check_ping + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + + +def build_topo(tgen): + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("r3") + + tgen.add_router("c11") + tgen.add_router("c12") + tgen.add_router("c21") + tgen.add_router("c22") + tgen.add_router("c31") + tgen.add_router("c32") + + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0") + tgen.add_link(tgen.gears["r1"], tgen.gears["r3"], "eth1", "eth0") + tgen.add_link(tgen.gears["r1"], tgen.gears["c11"], "eth2", "eth0") + tgen.add_link(tgen.gears["r1"], tgen.gears["c12"], "eth3", "eth0") + tgen.add_link(tgen.gears["r2"], tgen.gears["c21"], "eth1", "eth0") + tgen.add_link(tgen.gears["r2"], tgen.gears["c22"], "eth2", "eth0") + tgen.add_link(tgen.gears["r3"], tgen.gears["c31"], "eth1", "eth0") + tgen.add_link(tgen.gears["r3"], tgen.gears["c32"], "eth2", "eth0") + + +def setup_module(mod): + result = required_linux_kernel_version("5.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + for rname, router in tgen.routers().items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r1"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r1"].run("ip link set vrf10 up") + tgen.gears["r1"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r1"].run("ip link set vrf20 up") + tgen.gears["r1"].run("ip link set eth2 master vrf10") + tgen.gears["r1"].run("ip link set eth3 master vrf20") + + tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r2"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r2"].run("ip link set vrf10 up") + tgen.gears["r2"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r2"].run("ip link set vrf20 up") + tgen.gears["r2"].run("ip link set eth1 master vrf10") + tgen.gears["r2"].run("ip link set eth2 master vrf20") + + tgen.gears["r3"].run("sysctl net.vrf.strict_mode=1") + tgen.gears["r3"].run("ip link add vrf10 type vrf table 10") + tgen.gears["r3"].run("ip link set vrf10 up") + tgen.gears["r3"].run("ip link add vrf20 type vrf table 20") + tgen.gears["r3"].run("ip link set vrf20 up") + tgen.gears["r3"].run("ip link set eth1 master vrf10") + tgen.gears["r3"].run("ip link set eth2 master vrf20") + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_ping(): + tgen = get_topogen() + + check_ping("c11", "192.168.2.1", True, 10, 1) + check_ping("c11", "192.168.3.1", True, 10, 1) + check_ping("c12", "192.168.2.1", True, 10, 1) + check_ping("c12", "192.168.3.1", True, 10, 1) + check_ping("c21", "192.168.3.1", True, 10, 1) + check_ping("c22", "192.168.3.1", True, 10, 1) + + +def test_sid_unreachable_nht(): + get_topogen().gears["r1"].vtysh_cmd( + """ + configure terminal + no ipv6 route 2001:db8:2:2::/64 2001:db8:12::2 + """ + ) + check_ping("c11", "192.168.2.1", False, 10, 1) + + +def test_sid_reachable_again_nht(): + get_topogen().gears["r1"].vtysh_cmd( + """ + configure terminal + ipv6 route 2001:db8:2:2::/64 2001:db8:12::2 + """ + ) + check_ping("c11", "192.168.2.1", True, 10, 1) + + +def test_sid_unreachable_bgp_update(): + get_topogen().gears["r2"].vtysh_cmd( + """ + configure terminal + router bgp 65002 + no segment-routing srv6 + exit + router bgp 65002 vrf vrf10 + address-family ipv4 unicast + no sid vpn export 1 + """ + ) + check_ping("c11", "192.168.2.1", False, 10, 1) + + +def test_sid_reachable_again_bgp_update(): + get_topogen().gears["r2"].vtysh_cmd( + """ + configure terminal + router bgp 65002 + segment-routing srv6 + locator default + exit + exit + router bgp 65002 vrf vrf10 + address-family ipv4 unicast + sid vpn export 1 + """ + ) + check_ping("c11", "192.168.2.1", True, 10, 1) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_over_ipv6/r1/bgpd.conf index 22b901429155..e8c14ab08f57 100644 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/r1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/r1/bgpd.conf @@ -4,7 +4,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! router bgp 65001 diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_over_ipv6/r2/bgpd.conf index 42b9d511d950..88de28108a91 100644 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/r2/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/r2/bgpd.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! router bgp 65002 diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/r3/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_over_ipv6/r3/bgpd.conf index 339b4eb0895c..443a64aa0a73 100644 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/r3/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/r3/bgpd.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! router bgp 65001 diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py index 14b9ba84988c..0b52c87d2770 100755 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py @@ -9,10 +9,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,9 +17,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib.common_config import required_linux_kernel_version from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf index 15779aa0d5d5..3d9c2cfd17fe 100644 --- a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/bgpd.conf @@ -4,7 +4,6 @@ hostname pe1 password zebra ! log stdout notifications -log monitor notifications log commands ! router bgp 65001 diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json index 9f78447255ff..2ce936b29145 100644 --- a/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/pe1/results/vrf20_ipv4.json @@ -12,7 +12,7 @@ { "fib": true, "directlyConnected": true, - "interfaceName": "eth0", + "interfaceName": "vrf10", "vrf": "vrf10", "active": true } diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py index 900d0c296e08..4bd5fdf16535 100755 --- a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] @@ -37,10 +34,12 @@ def setup_module(mod): tgen.start_topology() for rname, router in tgen.routers().items(): - router.load_config(TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname))) - router.load_config(TopoRouter.RD_BGP, - os.path.join(CWD, '{}/bgpd.conf'.format(rname))) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10") tgen.gears["pe1"].run("ip link set vrf10 up") @@ -62,7 +61,7 @@ def open_json_file(path): return json.load(f) except IOError: assert False, "Could not read file {}".format(path) - + def check(name, command, checker): tgen = get_topogen() @@ -80,25 +79,25 @@ def _check(): def check_vrf10_bgp_rib(output): - expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD) + expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) def check_default_bgp_vpn_rib(output): - expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD) + expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) def check_vrf20_bgp_rib(output): - expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD) + expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) def check_vrf20_rib(output): - expected = open_json_file("%s/pe1/results/vrf20_ipv4.json" % CWD) + expected = open_json_file("%s/pe1/results/vrf20_ipv4.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) diff --git a/tests/topotests/bgp_srv6l3vpn_sid/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_sid/r1/bgpd.conf index bfc9db960aa7..8805009f9e17 100644 --- a/tests/topotests/bgp_srv6l3vpn_sid/r1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_sid/r1/bgpd.conf @@ -4,7 +4,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_sid/r1/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_sid/r1/vpnv6_rib.json index 6fc43e194dfd..f054fab48f82 100644 --- a/tests/topotests/bgp_srv6l3vpn_sid/r1/vpnv6_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_sid/r1/vpnv6_rib.json @@ -1,6 +1,5 @@ { "vrfName": "default", - "tableVersion": 2, "routerId": "192.0.2.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_sid/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_sid/r1/zebra.conf index cf31a5c11b59..be438053868a 100644 --- a/tests/topotests/bgp_srv6l3vpn_sid/r1/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_sid/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_sid/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_sid/r2/bgpd.conf index 892a9f73e513..0770a96d2d2b 100644 --- a/tests/topotests/bgp_srv6l3vpn_sid/r2/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_sid/r2/bgpd.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_sid/r2/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_sid/r2/vpnv6_rib.json index 538e8955efe4..60bcb7565f8a 100644 --- a/tests/topotests/bgp_srv6l3vpn_sid/r2/vpnv6_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_sid/r2/vpnv6_rib.json @@ -1,6 +1,5 @@ { "vrfName": "default", - "tableVersion": 2, "routerId": "192.0.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_sid/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_sid/r2/zebra.conf index 9771ee1cd76d..70627adc618e 100644 --- a/tests/topotests/bgp_srv6l3vpn_sid/r2/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_sid/r2/zebra.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index 984cf97e288b..8d303a774b23 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -20,7 +20,6 @@ # import os -import re import sys import json import functools @@ -106,7 +105,7 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() router_list = tgen.routers() - for i, (rname, router) in enumerate(tgen.routers().items(), 1): + for _, (rname, router) in enumerate(tgen.routers().items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -180,7 +179,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf index d113db12b105..8079bb0c2a3f 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -6,7 +6,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json index 25b7a8616fcf..0fdd3d6dc060 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf index 8ccf7a2a3406..c84106f2bbfa 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! ! debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf index 9a7831dd2a36..c2e8530273c3 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/bgpd.conf @@ -6,7 +6,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json index 2cd47b9ce513..03bbcc008d90 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf index 839454d8a8b3..5c12429ff2b9 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! ! debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index 4afaeaf78a4e..a6938668ad3b 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -92,7 +92,8 @@ def setup_module(mod): tgen.start_topology() router_list = tgen.routers() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -147,7 +148,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf index 30a0f8fe7848..12b9e8fd0098 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf @@ -6,7 +6,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json index 3cc2fddcfa44..7a4e0d7452b2 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/vpnv4_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf index cbc5ce1f099d..f202493c53b3 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf index 7ca23002ac1a..db36c180a0d7 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf @@ -6,7 +6,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json index 95570541c807..0dcdec678f35 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/vpnv4_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf index 449ca74d5e9b..9dfed4f2d62f 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index 914c29f0c1dd..c47980744a9b 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -9,7 +9,6 @@ # import os -import re import sys import json import functools @@ -56,7 +55,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -109,7 +109,7 @@ def _check(name, dest_addr, match): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf index 01b0cc3c9e1e..57c19e25d7ea 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf @@ -6,7 +6,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json index 3cc2fddcfa44..7a4e0d7452b2 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json index eb3433301bcc..205079574c08 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 4, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json index 5517fc738ade..7a4e0d7452b2 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 6, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json index 25b7a8616fcf..0fdd3d6dc060 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json index a1f21585d745..e289df1d44da 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 4, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json index 7eeccd149644..0fdd3d6dc060 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 6, "routerId": "1.1.1.1", "defaultLocPrf": 100, "localAS": 1, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf index f913b9f00292..dd8a756a6e32 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf index 8700f12d635c..abf4971a9b22 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf @@ -6,7 +6,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json index 95570541c807..0dcdec678f35 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json index d801671fdcde..a440ab424808 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 4, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json index 25da05b0d4b9..0dcdec678f35 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 6, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json index 2cd47b9ce513..03bbcc008d90 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 2, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json index f390ef69b148..5c70cf64504a 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 4, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json index 3353d75eda5c..03bbcc008d90 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json @@ -1,7 +1,6 @@ { "vrfId": 0, "vrfName": "default", - "tableVersion": 6, "routerId": "2.2.2.2", "defaultLocPrf": 100, "localAS": 2, diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf index 201d0cce23f3..3c9e4e3b254f 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf @@ -4,7 +4,6 @@ hostname r2 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index 8a7b558be360..2400cd285349 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -53,7 +53,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -106,7 +107,7 @@ def _check(name, dest_addr, match): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index fd8a78b48500..f7ac827e2633 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -15,7 +15,6 @@ import json import pytest from functools import partial -from time import sleep from lib.topolog import logger CWD = os.path.dirname(os.path.realpath(__file__)) @@ -47,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -217,6 +216,7 @@ def test_bgp_allow_as_in(): assertmsg = '"r2" 192.168.1.1/32 route should be gone' assert result is None, assertmsg + def test_local_vs_non_local(): tgen = get_topogen() @@ -229,7 +229,7 @@ def test_local_vs_non_local(): paths = output["paths"] for i in range(len(paths)): if "fibPending" in paths[i]: - assert(False), "Route 60.0.0.0/24 should not have fibPending" + assert False, "Route 60.0.0.0/24 should not have fibPending" if __name__ == "__main__": diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py index e7948eaaac47..37949cdc9967 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py @@ -36,8 +36,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -pytestmark = [pytest.mark.bgpd] - def build_topo(tgen): for routern in range(1, 3): @@ -54,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -110,7 +108,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) @@ -131,7 +129,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Check if neighbor session is up after reset in {}".format(router1.name) ) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence after reset in "{}"'.format( router1.name ) @@ -140,7 +138,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Verify if TCP MSS value is synced with neighbor in {}".format(router1.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.255.2") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name) @@ -150,7 +148,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Verify if TCP MSS value is synced with neighbor in {}".format(router2.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.255.1") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name) diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py index 6fe044fceac6..4a03cb0a6d6b 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py @@ -17,12 +17,7 @@ import os import sys -import json import pytest -import functools -import platform -import socket -import subprocess # add after imports, before defining classes or functions: pytestmark = [pytest.mark.bgpd] @@ -31,45 +26,29 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json -from lib.topolog import logger import time from lib.bgp import ( clear_bgp, - clear_bgp_and_verify, create_router_bgp, - modify_as_number, - verify_as_numbers, verify_bgp_convergence, verify_bgp_rib, - verify_bgp_timers_and_functionality, - verify_router_id, - verify_tcp_mss + verify_tcp_mss, ) from lib.common_config import ( kill_router_daemons, start_router_daemons, - addKernelRoute, apply_raw_config, check_address_types, - create_prefix_lists, - create_route_maps, + check_router_status, create_static_routes, required_linux_kernel_version, - reset_config_on_routers, start_topology, step, - verify_admin_distance_for_static_routes, - verify_bgp_community, - verify_fib_routes, - verify_rib, write_test_footer, - write_test_header ) -pytestmark = [pytest.mark.bgpd] # Global variables NETWORK1_1 = {"ipv4": "1.1.1.1/32", "ipv6": "1::1/128"} NETWORK1_2 = {"ipv4": "1.1.1.2/32", "ipv6": "1::2/128"} @@ -85,7 +64,8 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} ## File name -TCPDUMP_FILE="test_tcp_packet_test.txt" +TCPDUMP_FILE = "test_tcp_packet_test.txt" + def setup_module(mod): """ @@ -93,7 +73,7 @@ def setup_module(mod): * `mod`: module name """ - global topo,TCPDUMP_FILE + global topo, TCPDUMP_FILE # Required linux kernel version for this suite to run. result = required_linux_kernel_version("4.15") @@ -128,6 +108,7 @@ def setup_module(mod): step("Running setup_module() done") + def teardown_module(): """Teardown the pytest environment""" @@ -138,9 +119,7 @@ def teardown_module(): # Stop toplogy and Remove tmp files tgen.stop_topology() - step( - "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) - ) + step("Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))) step("=" * 40) @@ -150,6 +129,7 @@ def teardown_module(): # ##################################################### + def test_bgp_vrf_tcp_mss(request): tgen = get_topogen() tc_name = request.node.name @@ -280,34 +260,34 @@ def test_bgp_vrf_tcp_mss(request): step("Verify the static Routes in R2 on RED VRF") for addr_type in ADDR_TYPES: static_routes_input = { - "r3": { - "static_routes": [ - { - "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - ] + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + ] } } dut = "r2" @@ -317,34 +297,34 @@ def test_bgp_vrf_tcp_mss(request): step("Verify the static Routes in R1 on RED VRF") for addr_type in ADDR_TYPES: static_routes_input = { - "r3": { - "static_routes": [ - { - "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - { - "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], - "next_hop": NEXT_HOP_IP[addr_type], - "vrf": "RED", - }, - ] + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + ] } } dut = "r1" @@ -404,9 +384,6 @@ def test_bgp_vrf_tcp_mss(request): tcp_mss_result ) - - - step("Enabling tcp-mss 500 between R2 and R3 of VRF Default") TCP_MSS = 500 raw_config = { @@ -440,8 +417,6 @@ def test_bgp_vrf_tcp_mss(request): result = apply_raw_config(tgen, raw_config) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - - step("Clear BGP at router R2 and R3") for addr_type in ADDR_TYPES: clear_bgp(tgen, topo, "r2", addr_type) @@ -550,7 +525,6 @@ def test_bgp_vrf_tcp_mss(request): tcp_mss_result is not True ), " TCP-MSS mismatch :Failed \n Error: {}".format(tcp_mss_result) - step("Removing tcp-mss 500 between R2 and R3 of VRF Default ") TCP_MSS = 500 raw_config = { diff --git a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py index cd405f7b2289..44336efed2a9 100644 --- a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py +++ b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py index f89f3378fbf7..9fbcdc26fe66 100644 --- a/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py +++ b/tests/topotests/bgp_unique_rid/test_bgp_unique_rid.py @@ -83,6 +83,7 @@ create_router_bgp, clear_bgp_and_verify, ) +from lib.ospf import verify_ospf_neighbor, clear_ospf # Global variables topo = None @@ -886,6 +887,154 @@ def test_bgp_unique_rid_chaos4_p2(): write_test_footer(tc_name) +def test_bgp_unique_rid_chaos2_p2(): + """ + TC: 8 + 8. Chaos - Verify bgp unique rid functionality when ospf and bgp share the same router ids. + + """ + tgen = get_topogen() + global bgp_convergence + + if bgp_convergence is not True: + pytest.skip("skipped because of BGP Convergence failure") + + # test case name + tc_name = inspect.stack()[0][3] + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configure base config as per the topology") + step("Redistribute routes between bgp and ospf.") + reset_config_on_routers(tgen) + + step( + "Base config should be up, verify using BGP convergence on all \ + the routers for IPv4 and IPv6 nbrs" + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut="r3") + assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format( + ospf_covergence + ) + + step( + "Configure ospf between R3 and R4 with same router ids in both ospf and bgp 10.10.10.10 on R3 BGP and OSPF, and 10.10.10.10 in R4 BGP and 11.11.11.11 in R4 OSPF." + ) + input_dict = { + "r3": {"bgp": {"router_id": "10.10.10.10"}}, + "r4": {"bgp": {"router_id": "10.10.10.10"}}, + "r5": {"bgp": {"router_id": "10.10.10.10"}}, + } + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "The session should be established between R3 & R4 between BGP process and neighborship should be full between OSPF too." + ) + + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + ospf_covergence = verify_ospf_neighbor(tgen, topo, dut="r3") + assert ospf_covergence is True, "Testcase :Failed \n Error:" " {}".format( + ospf_covergence + ) + + step("All the routes should be calculated and installed.") + # Verifying RIB routes + protocol = "bgp" + input_dict = topo["routers"] + verify_rib_rtes = { + "ipv4": { + "r3": { + "static_routes": [ + {"network": NETWORK["ipv4"], "next_hop": "Null0"}, + ] + } + }, + "ipv6": { + "r3": { + "static_routes": [ + { + "network": NETWORK["ipv6"], + "next_hop": "Null0", + } + ] + } + }, + } + dut = "r3" + for addr_type in ADDR_TYPES: + result4 = verify_rib( + tgen, + addr_type, + dut, + verify_rib_rtes, + protocol=protocol, + ) + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result4 + ) + + step("Clear ospf process.") + clear_ospf(tgen, "r3") + + step("All the routes should be calculated and installed.") + for addr_type in ADDR_TYPES: + result4 = verify_rib( + tgen, + addr_type, + dut, + verify_rib_rtes, + protocol=protocol, + ) + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result4 + ) + + step("Clear bgp process.") + clear_bgp_and_verify(tgen, topo, "r3") + + step("All the routes should be calculated and installed.") + for addr_type in ADDR_TYPES: + result4 = verify_rib( + tgen, + addr_type, + dut, + verify_rib_rtes, + protocol=protocol, + ) + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result4 + ) + + step( + "Configure ospf between R3 and R5. Configure static routes in R5 and redistribute static routes in ospf on R5." + ) + # Covered as base config. + + step("Verify routes are installed in R3 and R4 route tables.") + dut = "r4" + for addr_type in ADDR_TYPES: + result4 = verify_rib( + tgen, + addr_type, + dut, + verify_rib_rtes, + protocol=protocol, + ) + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result4 + ) + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py index 2a53547f59bd..09b13e6a2f8b 100644 --- a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py +++ b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py @@ -27,7 +27,6 @@ def build_topo(tgen): - tgen.add_router("r1") tgen.add_router("r2") @@ -42,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +83,7 @@ def _bgp_converge(): step("Ensure Convergence of BGP") test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) @@ -109,7 +108,7 @@ def _bgp_converge(): step("Ensure that BGP does not crash") test_func = functools.partial(_bgp_nexthop_cache) - success, result = topotest.run_and_expect(test_func, True, count=10, wait=1) + _, result = topotest.run_and_expect(test_func, True, count=10, wait=1) assert result is True, "BGP did not crash on r1" diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py index 4e66cf5548ab..59f4bcd38510 100644 --- a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py +++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py @@ -90,7 +90,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -169,7 +169,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check r2 initial convergence in default table test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) @@ -195,7 +195,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_update_delay_in_progress, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format( router2 @@ -203,7 +203,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check that r2 only installs route learned from r4 after the max-delay timer expires test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to install route after update-delay "{}"'.format( router2 @@ -219,7 +219,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): ) test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -229,7 +229,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -250,7 +250,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to remove update-delay delay timing "{}"'.format( router2 @@ -266,14 +266,14 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check that r2 default instance and vrf1 have the max-delay and establish set test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in default instance "{}"'.format( router2 ) test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2) @@ -281,7 +281,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None diff --git a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py index 84ef603d6e3c..08d6e140a141 100644 --- a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py +++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py @@ -22,7 +22,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -67,7 +66,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -144,7 +143,7 @@ def _bgp_verify_v6_global_nexthop_validity(): "2001:db8:1::1": { "valid": True, "complete": True, - "igpMetric": 20, + "igpMetric": 10, "pathCount": 2, "peer": "2001:db8:1::1", "nexthops": [{"interfaceName": "pe2-eth0"}], diff --git a/tests/topotests/bgp_vpnv4_asbr/r1/bgpd.conf b/tests/topotests/bgp_vpnv4_asbr/r1/bgpd.conf index 3bbcc20e9eb8..473e56b32a35 100644 --- a/tests/topotests/bgp_vpnv4_asbr/r1/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_asbr/r1/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65500 bgp router-id 192.0.2.1 no bgp ebgp-requires-policy + no bgp enforce-first-as neighbor 192.0.2.100 remote-as 65500 neighbor 192.0.2.100 update-source lo neighbor 192.168.0.100 remote-as 65500 diff --git a/tests/topotests/bgp_vpnv4_asbr/r2/bgpd.conf b/tests/topotests/bgp_vpnv4_asbr/r2/bgpd.conf index 4c84d52bd989..c7244c0e1f80 100644 --- a/tests/topotests/bgp_vpnv4_asbr/r2/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_asbr/r2/bgpd.conf @@ -1,9 +1,10 @@ -debug bgp nht -debug bgp zebra -debug bgp labelpool +!debug bgp nht +!debug bgp zebra +!debug bgp labelpool router bgp 65500 bgp router-id 192.0.2.2 no bgp ebgp-requires-policy + no bgp enforce-first-as neighbor 192.0.2.100 remote-as 65500 neighbor 192.0.2.100 update-source lo neighbor 192.168.0.100 remote-as 65500 diff --git a/tests/topotests/bgp_vpnv4_asbr/r3/bgpd.conf b/tests/topotests/bgp_vpnv4_asbr/r3/bgpd.conf index c5d5727fbaed..b7592e444d52 100644 --- a/tests/topotests/bgp_vpnv4_asbr/r3/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_asbr/r3/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65501 bgp router-id 192.0.2.3 no bgp ebgp-requires-policy + no bgp enforce-first-as neighbor 192.168.1.200 remote-as 65502 address-family ipv4 unicast no neighbor 192.168.1.200 activate diff --git a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py index a908e74cc63e..5467cf4d841b 100644 --- a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py +++ b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py @@ -48,6 +48,10 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest +from lib.bgpcheck import ( + check_show_bgp_vpn_prefix_found, + check_show_bgp_vpn_prefix_not_found, +) from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.checkping import check_ping @@ -199,7 +203,7 @@ def _check(router, prefix, rd, label, nexthop): ) func = functools.partial(_check, router, prefix, rd, label, nexthop) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert_msg = "{}, show bgp ipv4 vpn {}, rd {}, label {} nexthop {}".format( router.name, prefix, rd, label, nexthop ) @@ -259,62 +263,6 @@ def mpls_table_check_entry(router, out_label, out_nexthop): ) -def check_show_bgp_vpn_prefix_found( - router, ipversion, prefix, rd, label=None, nexthop=None -): - """ - Check if a given vpn prefix is present in the BGP RIB - * 'router': the router to check BGP VPN RIB - * 'ipversion': The ip version to check: ipv4 or ipv6 - * 'prefix': the IP prefix to check - * 'rd': the route distinguisher to check - * 'label: the label to check - """ - output = json.loads( - router.vtysh_cmd("show bgp {} vpn {} json".format(ipversion, prefix)) - ) - if label: - if nexthop: - expected = { - rd: { - "prefix": prefix, - "paths": [{"remoteLabel": label, "nexthops": [{"ip": nexthop}]}], - } - } - else: - expected = {rd: {"prefix": prefix, "paths": [{"remoteLabel": label}]}} - else: - if nexthop: - expected = { - rd: {"prefix": prefix, "paths": [{"nexthops": [{"ip": nexthop}]}]} - } - else: - expected = {rd: {"prefix": prefix}} - return topotest.json_cmp(output, expected) - - -def check_show_bgp_vpn_prefix_not_found(router, ipversion, prefix, rd, label=None): - """ - Check if a given vpn prefix is not present in the BGP RIB - * 'router': the router to check BGP VPN RIB - * 'ipversion': The ip version to check: ipv4 or ipv6 - * 'prefix': the IP prefix to check - * 'rd': the route distinguisher to check - * 'label: the label to check - """ - output = json.loads( - router.vtysh_cmd("show bgp {} vpn {} json".format(ipversion, prefix)) - ) - if label: - expected = {rd: {"prefix": prefix, "paths": [{"remoteLabel": label}]}} - else: - expected = {rd: {"prefix": prefix}} - ret = topotest.json_cmp(output, expected) - if ret is None: - return "not good" - return None - - def check_show_mpls_table_entry_label_not_found(router, inlabel): output = json.loads(router.vtysh_cmd("show mpls table {} json".format(inlabel))) expected = {"inLabel": inlabel, "installed": True} @@ -364,7 +312,7 @@ def _check_nexthop_available(router, prefix): return "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: if "remoteLabel" not in path.keys(): return "{0}, {1}, remoteLabel not present".format( @@ -376,7 +324,7 @@ def _check_nexthop_available(router, prefix): for prefix, rname_to_test in vpnv4_entries.items(): func = functools.partial(_check_nexthop_available, router, prefix) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert result is None, "Failed to detect prefix {} on router {}".format( prefix, router.name ) @@ -508,7 +456,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) # diagnostic @@ -543,7 +491,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) logger.info( @@ -554,7 +502,7 @@ def test_r3_prefixes_removed(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label_ip_entries[prefix] ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with in_label {} still present".format( label_ip_entries[prefix] ) @@ -588,7 +536,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) logger.info( @@ -616,7 +564,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) # diagnostic @@ -663,7 +611,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -678,7 +626,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", label=label, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -691,7 +639,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -779,7 +727,7 @@ def test_declare_vpn_network_with_different_label(): label=label, nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, label {} not present".format( router.name, prefix, label ) @@ -839,7 +787,7 @@ def test_filter_vpn_network_from_r1(): "172.31.0.0/24", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is still present".format( router.name, prefix ) @@ -856,7 +804,7 @@ def test_filter_vpn_network_from_r1(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, int(label) ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -885,7 +833,7 @@ def test_unfilter_vpn_network_from_r1(): test_func = functools.partial( check_show_bgp_vpn_prefix_found, router, "ipv4", prefix, "444:1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is not present".format(router.name, prefix) vpnv4_checks = { diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf index 0249279c65d2..d8a45ce2748f 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf @@ -1,3 +1,4 @@ +bgp route-map delay-timer 1 router bgp 65500 bgp router-id 192.0.2.1 no bgp ebgp-requires-policy diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_vpn_route_1723101.json b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_vpn_route_1723101.json new file mode 100644 index 000000000000..2ed76314b21c --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_vpn_route_1723101.json @@ -0,0 +1,50 @@ +{ + "444:1":{ + "prefix":"172.31.0.1/32", + "advertisedTo":{ + "192.168.0.1":{ + } + }, + "paths":[ + { + "aspath":{ + "string":"65500", + "segments":[ + { + "type":"as-sequence", + "list":[ + 65500 + ] + } + ], + "length":1 + }, + "origin":"incomplete", + "metric":0, + "valid":true, + "bestpath":{ + "overall":true, + "selectionReason":"First path received" + }, + "extendedCommunity":{ + "string":"RT:52:101" + }, + "remoteLabel":102, + "nexthops":[ + { + "ip":"192.168.0.1", + "afi":"ipv4", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"192.168.0.1", + "routerId":"192.0.2.1", + "type":"external" + } + } + ] + } +} diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 61e1163c18fe..dd9d54742b71 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -25,6 +25,10 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest +from lib.bgpcheck import ( + check_show_bgp_vpn_prefix_found, + check_show_bgp_vpn_prefix_not_found, +) from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger @@ -214,6 +218,312 @@ def test_protocols_convergence(): assert result is None, assertmsg +def test_export_route_target_empty(): + """ + Check that when removing 'rt vpn export' command, exported prefix is removed + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + logger.info("r1, Remove 'rt vpn export 52:100' command") + router.vtysh_cmd( + """ +configure terminal +router bgp 65500 vrf vrf1 + address-family ipv4 unicast + no rt vpn export 52:100 +""" + ) + + prefix = "172.31.0.1/32" + logger.info("r1, check that exported prefix {} is removed".format(prefix)) + test_func = partial( + check_show_bgp_vpn_prefix_not_found, + router, + "ipv4", + prefix, + "444:1", + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) + + +def test_export_route_target_with_routemap_with_export_route_target(): + """ + Check that when removing 'rt vpn export' command, exported prefix is added back + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + logger.info("r1, configuring route target with route-map with export route target") + router.vtysh_cmd( + """ +configure terminal +router bgp 65500 vrf vrf1 + address-family ipv4 unicast + route-map vpn export RMAP +! +route-map RMAP permit 1 + set extcommunity rt 52:100 +""" + ) + + prefix = "172.31.0.1/32" + logger.info("r1, check that exported prefix {} is added back".format(prefix)) + test_func = partial( + check_show_bgp_vpn_prefix_found, + router, + "ipv4", + prefix, + "444:1", + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) + + +def test_export_route_target_with_routemap_without_export_route_target(): + """ + Check that when removing 'set extcommunity rt' command, prefix is removed + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + logger.info("r1, removing 'set extcommunity rt 52:100.") + router.vtysh_cmd( + """ +configure terminal +route-map RMAP permit 1 + no set extcommunity rt +""" + ) + + prefix = "172.31.0.1/32" + logger.info("r1, check that exported prefix {} is removed".format(prefix)) + test_func = partial( + check_show_bgp_vpn_prefix_not_found, + router, + "ipv4", + prefix, + "444:1", + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) + + +def test_export_route_target_with_default_command(): + """ + Add back route target with 'rt vpn export' command + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + logger.info("r1, detach route-map and re-add route target vpn export") + router.vtysh_cmd( + """ +configure terminal +router bgp 65500 vrf vrf1 + address-family ipv4 unicast + rt vpn export 52:100 +""" + ) + prefix = "172.31.0.1/32" + logger.info("r1, check that exported prefix {} is added back".format(prefix)) + test_func = partial( + check_show_bgp_vpn_prefix_found, + router, + "ipv4", + prefix, + "444:1", + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) + + +def test_export_suppress_route_target_with_route_map_command(): + """ + Add back route target with 'rt vpn export' command + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + logger.info("r1, add an extended comm-list to delete 52:100") + + router.vtysh_cmd( + """ +configure terminal +bgp extcommunity-list 1 permit rt 52:100 +! +route-map RMAP permit 1 + set extended-comm-list 1 delete +""" + ) + prefix = "172.31.0.1/32" + logger.info("r1, check that exported prefix {} is removed".format(prefix)) + test_func = partial( + check_show_bgp_vpn_prefix_not_found, + router, + "ipv4", + prefix, + "444:1", + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) + + +def test_export_add_route_target_to_route_map_command(): + """ + Add route target with route-map so that route is added back + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + router = tgen.gears["r1"] + logger.info("r1, add an additional set extcommunity 52:101") + router.vtysh_cmd( + """ +configure terminal +route-map RMAP permit 1 + set extcommunity rt 52:101 +""" + ) + prefix = "172.31.0.1/32" + logger.info("r1, check that exported prefix {} is added back".format(prefix)) + test_func = partial( + check_show_bgp_vpn_prefix_found, + router, + "ipv4", + prefix, + "444:1", + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) + + +def test_adj_rib_out_label_change(): + """ + Check that changing the VPN label on r1 + is propagated on r2 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Changing VPN label value to export") + dump = tgen.gears["r1"].vtysh_cmd( + """ +configure terminal + router bgp 65500 vrf vrf1 + address-family ipv4 unicast + label vpn export 102 +""" + ) + # Check BGP IPv4 route entry for 172.31.0.1 on r1 + logger.info("Checking BGP IPv4 routes for convergence on r1") + router = tgen.gears["r2"] + json_file = "{}/{}/bgp_ipv4_vpn_route_1723101.json".format(CWD, router.name) + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, + router, + "show bgp ipv4 vpn 172.31.0.1/32 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def test_adj_rib_in_label_change(): + """ + Check that syncinig with ADJ-RIB-in on r2 + permits restoring the initial label value + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Enable soft-reconfiguration inbound on r2") + + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + """ +configure terminal +router bgp 65501 + address-family ipv4 vpn + neighbor 192.168.0.1 soft-reconfiguration inbound +""" + ) + + logger.info("Applying a deny-all route-map to input on r2") + r2.vtysh_cmd( + """ +configure terminal +route-map DENY-ALL deny 1 +! +router bgp 65501 + address-family ipv4 vpn + neighbor 192.168.0.1 route-map DENY-ALL in +""" + ) + + # check that 172.31.0.1 should not be present + logger.info("Check that received update 172.31.0.1 is not present") + + expected = {} + test_func = partial( + topotest.router_json_cmp, + r2, + "show bgp ipv4 vpn 172.31.0.1/32 json", + expected, + exact=True, + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "r2, vpnv4 update 172.31.0.1 still present" + + +def test_adj_rib_in_label_change_remove_rmap(): + """ + Check that syncinig with ADJ-RIB-in on r2 + permits restoring the initial label value + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Removing the deny-all route-map from input on r2") + + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + """ +configure terminal +router bgp 65501 + address-family ipv4 vpn + no neighbor 192.168.0.1 route-map DENY-ALL in +""" + ) + # Check BGP IPv4 route entry for 172.31.0.1 on r1 + logger.info( + "Checking that 172.31.0.1 BGP update is present and has valid label on r2" + ) + json_file = "{}/{}/bgp_ipv4_vpn_route_1723101.json".format(CWD, r2.name) + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, + r2, + "show bgp ipv4 vpn 172.31.0.1/32 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(r2.name) + assert result is None, assertmsg + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/bgp_vpnv4_gre/test_bgp_vpnv4_gre.py b/tests/topotests/bgp_vpnv4_gre/test_bgp_vpnv4_gre.py index 6f313be628f0..31743c8a6daa 100644 --- a/tests/topotests/bgp_vpnv4_gre/test_bgp_vpnv4_gre.py +++ b/tests/topotests/bgp_vpnv4_gre/test_bgp_vpnv4_gre.py @@ -52,30 +52,32 @@ def build_topo(tgen): switch = tgen.add_switch("s3") switch.add_link(tgen.gears["r2"]) + def _populate_iface(): tgen = get_topogen() cmds_list = [ - 'ip link add vrf1 type vrf table 10', - 'echo 10 > /proc/sys/net/mpls/platform_labels', - 'ip link set dev vrf1 up', - 'ip link set dev {0}-eth1 master vrf1', - 'echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input', - 'ip tunnel add {0}-gre0 mode gre ttl 64 dev {0}-eth0 local 10.125.0.{1} remote 10.125.0.{2}', - 'ip link set dev {0}-gre0 up', - 'echo 1 > /proc/sys/net/mpls/conf/{0}-gre0/input', + "ip link add vrf1 type vrf table 10", + "echo 10 > /proc/sys/net/mpls/platform_labels", + "ip link set dev vrf1 up", + "ip link set dev {0}-eth1 master vrf1", + "echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input", + "ip tunnel add {0}-gre0 mode gre ttl 64 dev {0}-eth0 local 10.125.0.{1} remote 10.125.0.{2}", + "ip link set dev {0}-gre0 up", + "echo 1 > /proc/sys/net/mpls/conf/{0}-gre0/input", ] for cmd in cmds_list: - input = cmd.format('r1', '1', '2') - logger.info('input: ' + cmd) - output = tgen.net['r1'].cmd(cmd.format('r1', '1', '2')) - logger.info('output: ' + output) + input = cmd.format("r1", "1", "2") + logger.info("input: " + cmd) + output = tgen.net["r1"].cmd(cmd.format("r1", "1", "2")) + logger.info("output: " + output) for cmd in cmds_list: - input = cmd.format('r2', '2', '1') - logger.info('input: ' + cmd) - output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1')) - logger.info('output: ' + output) + input = cmd.format("r2", "2", "1") + logger.info("input: " + cmd) + output = tgen.net["r2"].cmd(cmd.format("r2", "2", "1")) + logger.info("output: " + output) + def setup_module(mod): "Sets up the pytest environment" @@ -113,13 +115,13 @@ def test_protocols_convergence(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - router = tgen.gears['r1'] + router = tgen.gears["r1"] logger.info("Dump some context for r1") router.vtysh_cmd("show bgp ipv4 vpn") router.vtysh_cmd("show bgp summary") router.vtysh_cmd("show bgp vrf vrf1 ipv4") router.vtysh_cmd("show running-config") - router = tgen.gears['r2'] + router = tgen.gears["r2"] logger.info("Dump some context for r2") router.vtysh_cmd("show bgp ipv4 vpn") router.vtysh_cmd("show bgp summary") @@ -128,11 +130,11 @@ def test_protocols_convergence(): # Check IPv4 routing tables on r1 logger.info("Checking IPv4 routes for convergence on r1") - router = tgen.gears['r1'] + router = tgen.gears["r1"] json_file = "{}/{}/ipv4_routes.json".format(CWD, router.name) if not os.path.isfile(json_file): logger.info("skipping file {}".format(json_file)) - assert 0, 'ipv4_routes.json file not found' + assert 0, "ipv4_routes.json file not found" return expected = json.loads(open(json_file).read()) @@ -148,10 +150,10 @@ def test_protocols_convergence(): # Check BGP IPv4 routing tables on r2 not installed logger.info("Checking BGP IPv4 routes for convergence on r2") - router = tgen.gears['r2'] + router = tgen.gears["r2"] json_file = "{}/{}/bgp_ipv4_routes.json".format(CWD, router.name) if not os.path.isfile(json_file): - assert 0, 'bgp_ipv4_routes.json file not found' + assert 0, "bgp_ipv4_routes.json file not found" expected = json.loads(open(json_file).read()) test_func = partial( @@ -163,7 +165,8 @@ def test_protocols_convergence(): _, result = topotest.run_and_expect(test_func, None, count=40, wait=2) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg - + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index 037dd4039085..6237decfc328 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -141,7 +141,7 @@ def router_json_cmp_exact_filter(router, cmd, expected): # filter out tableVersion, version and nhVrfID json_output.pop("tableVersion") for rd, data in json_output["routes"]["routeDistinguishers"].items(): - for prefix, attrs in data.items(): + for _, attrs in data.items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") @@ -171,7 +171,7 @@ def router_vrf_json_cmp_exact_filter(router, cmd, expected): data.pop("tableVersion") if "routes" not in data: continue - for route, attrs in data["routes"].items(): + for _, attrs in data["routes"].items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index ce278ed7a7e8..146687d5881b 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -151,7 +151,28 @@ def teardown_module(_mod): tgen.stop_topology() -def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=None): +def check_bgp_vpnv4_prefix_presence(router, prefix, table_version): + "Check the presence of a prefix" + tgen = get_topogen() + + dump = router.vtysh_cmd("show bgp ipv4 vpn {} json".format(prefix), isjson=True) + if not dump: + return "{}, prefix ipv4 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv4 vpn {} has not been updated yet".format( + router.name, prefix + ) + + return None + + +def bgp_vpnv4_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv4 entries have the same MPLS label value * 'router': the router to check @@ -163,11 +184,19 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: + test_func = functools.partial( + check_bgp_vpnv4_prefix_presence, router, prefix, table_version + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, prefix ipv4 vpn {} is not installed yet".format( + router.name, prefix + ) + dump = router.vtysh_cmd("show bgp ipv4 vpn {} json".format(prefix), isjson=True) assert dump, "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -202,7 +231,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv4_table_check_all(router, label_list=None, same=False): +def bgp_vpnv4_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv4 entries are correctly configured with specific label values * 'router': the router to check @@ -220,6 +249,7 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version, ) else: for group in ( @@ -229,7 +259,9 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST, PREFIXES_CONNECTED, ): - bgp_vpnv4_table_check(router, group=group, label_list=label_list) + bgp_vpnv4_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -334,6 +366,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv4 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -434,7 +471,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv4", "172.31.0.11/32" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172.31.0.11/32 from r11 did not disappear. r11 still connected to rr ?" @@ -472,7 +509,7 @@ def test_flapping_bgp_vrf_up(): "172.31.0.11/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172.31.0.11/32 from r11 not present. r11 still disconnected from rr ?" @@ -502,7 +539,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 not found" bgp_vpnv4_table_check(tgen.gears["r2"], group=PREFIXES_R11 + ["172.31.0.30/32"]) @@ -528,7 +565,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 still present" @@ -554,7 +591,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" # diagnostic @@ -600,7 +637,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv4 update 172.31.0.50 with old label {0} still present".format(oldlabel) @@ -617,7 +654,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" label_list = set() @@ -670,6 +707,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export 222\n", @@ -683,13 +721,13 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok logger.info("r1, vpnv4 table, check the number of labels used after modification") label_list = set() - bgp_vpnv4_table_check_all(router, label_list) + bgp_vpnv4_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -718,6 +756,7 @@ def test_unconfigure_allocation_mode_nexthop(): logger.info("Unconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno label vpn export allocation-mode per-nexthop\n", isjson=False, @@ -730,13 +769,15 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list, same=True) + bgp_vpnv4_table_check_all( + router, label_list=label_list, same=True, table_version=table_version + ) assert len(label_list) == 1, "r1, multiple Label values found for vpnv4 updates" new_label = label_list.pop() @@ -766,6 +807,8 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -778,13 +821,15 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list) + bgp_vpnv4_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for vpnv4 updates" # Check mpls table with all values diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index e936ccc1e444..5fef6e9e6062 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -54,7 +54,7 @@ PREFIXES_R11 = ["172:31::11/128", "172:31::20/128", "172:31::111/128"] PREFIXES_R12 = ["172:31::12/128", "172:31::15/128"] PREFIXES_REDIST_R14 = ["172:31::14/128"] -PREFIXES_CONNECTED = ["192:168::255/112", "192:2::/64"] +PREFIXES_CONNECTED = ["192:168::255:0/112", "192:2::/64"] def build_topo(tgen): @@ -150,7 +150,28 @@ def teardown_module(_mod): tgen.stop_topology() -def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None): +def check_bgp_vpnv6_prefix_presence(router, prefix, table_version): + "Check the presence of a prefix" + tgen = get_topogen() + + dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) + if not dump: + return "{}, prefix ipv6 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv6 vpn {} has not been updated yet".format( + router.name, prefix + ) + + return None + + +def bgp_vpnv6_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv6 entries have the same MPLS label value * 'router': the router to check @@ -162,8 +183,16 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: + test_func = functools.partial( + check_bgp_vpnv6_prefix_presence, router, prefix, table_version + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert success, "{}, prefix ipv6 vpn {} is not installed yet".format( + router.name, prefix + ) + dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -198,7 +227,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv6_table_check_all(router, label_list=None, same=False): +def bgp_vpnv6_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv6 entries are correctly configured with specific label values * 'router': the router to check @@ -215,6 +244,7 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST_R14 + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version, ) else: for group in ( @@ -223,7 +253,9 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST_R14, PREFIXES_CONNECTED, ): - bgp_vpnv6_table_check(router, group=group, label_list=label_list) + bgp_vpnv6_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -237,7 +269,9 @@ def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=Non label_list.add(in_label) for nh in label_info["nexthops"]: if "installed" not in nh.keys(): - return "{} {} is not installed yet on {}".format(in_label, label_info, router.name) + return "{} {} is not installed yet on {}".format( + in_label, label_info, router.name + ) if nh["installed"] != True or nh["type"] != "BGP": return "{}, show mpls table, nexthop is not installed".format( router.name @@ -327,6 +361,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv6 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -428,7 +467,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv6", "172:31::11/128" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172:31::11/128 from r11 did not disappear. r11 still connected to rr ?" @@ -470,7 +509,7 @@ def test_flapping_bgp_vrf_up(): "172:31::11/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172:31::11/128 from r11 not present. r11 still disconnected from rr ?" @@ -508,7 +547,7 @@ def _prefix30_found(router): # Check r2 received vpnv6 update with 172:31::30 test_func = functools.partial(_prefix30_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 not found" # that route should be sent along with label for 192::2:11 @@ -531,7 +570,7 @@ def _prefix30_found(router): # Check r2 removed 172:31::30 vpnv6 update test_func = functools.partial(_prefix30_not_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 still present" @@ -557,7 +596,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::50 not found" # diagnostic @@ -603,7 +642,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv6 update 172:31::50 with old label {0} still present".format(oldlabel) @@ -620,7 +659,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv6 update 172:31::50 not found" label_list = set() @@ -673,6 +712,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export 222\n", @@ -686,13 +726,13 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok logger.info("r1, VPNv6 table, check the number of labels used after modification") label_list = set() - bgp_vpnv6_table_check_all(router, label_list) + bgp_vpnv6_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -732,7 +772,7 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 @@ -768,6 +808,7 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) dump = router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -780,13 +821,15 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 logger.info("Checking VPNv6 routes on r1") label_list = set() - bgp_vpnv6_table_check_all(router, label_list=label_list) + bgp_vpnv6_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for VPNv6 updates" # Check mpls table with all values diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff b/tests/topotests/bgp_vrf_different_asn/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff rename to tests/topotests/bgp_vrf_different_asn/__init__.py diff --git a/tests/topotests/bgp_vrf_different_asn/r1/frr.conf b/tests/topotests/bgp_vrf_different_asn/r1/frr.conf new file mode 100644 index 000000000000..b325dfb7f096 --- /dev/null +++ b/tests/topotests/bgp_vrf_different_asn/r1/frr.conf @@ -0,0 +1,18 @@ +! +vrf vrf100 + vni 10100 +exit-vrf +! +interface r1-eth0 vrf vrf100 + ip address 192.168.1.1/24 +! +router bgp 65000 + address-family ipv4 unicast + import vrf vrf100 + exit-address-family +! +router bgp 65100 vrf vrf100 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py new file mode 100644 index 000000000000..9a1a9ec7667a --- /dev/null +++ b/tests/topotests/bgp_vrf_different_asn/test_bgp_vrf_different_asn.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 2): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + r1 = tgen.gears["r1"] + r1.run("ip link add vrf100 type vrf table 1001") + r1.run("ip link set up dev vrf100") + r1.run("ip link set r1-eth0 master vrf100") + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_vrf_different_asn(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_check_instances(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp vrf all json")) + expected = { + "default": { + "vrfName": "default", + "localAS": 65000, + }, + "vrf100": { + "vrfName": "vrf100", + "localAS": 65100, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_instances) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see vrf100 to be under 65100 ASN" + + def _bgp_check_imported_route(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip route 192.168.1.0/24 json") + ) + expected = { + "192.168.1.0/24": [ + { + "installed": True, + "selected": True, + "nexthops": [ + { + "interfaceName": "vrf100", + "vrf": "vrf100", + "active": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_imported_route) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see 192.168.1.0/24 being imported into a default VRF" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py index 32643c27b8bd..8d73e5f8ac12 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py @@ -18,7 +18,6 @@ import os import sys -import json import time import pytest import platform @@ -58,7 +57,7 @@ verify_best_path_as_per_bgp_attribute, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py index 1787021ebcf3..25a73b58c709 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py @@ -23,7 +23,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -49,7 +48,6 @@ create_static_routes, create_prefix_lists, create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger @@ -851,23 +849,25 @@ def test_dynamic_imported_matching_prefix_based_on_community_list_p0(request): result = verify_bgp_rib( tgen, addr_type, "r3", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes["r3"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes["r3"]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, "r3", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes["r3"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes["r3"]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, "r3", static_routes) @@ -924,23 +924,25 @@ def test_dynamic_imported_matching_prefix_based_on_community_list_p0(request): result = verify_bgp_rib( tgen, addr_type, "r3", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes["r3"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes["r3"]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, "r3", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes["r3"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes["r3"]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, "r3", static_routes) @@ -1153,23 +1155,25 @@ def test_dynamic_import_routes_delete_static_route_p1(request): result = verify_bgp_rib( tgen, addr_type, "r2", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes["r2"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes["r2"]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, "r2", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) step("Delete static routes from vrf BLUE") @@ -1209,21 +1213,23 @@ def test_dynamic_import_routes_delete_static_route_p1(request): result = verify_bgp_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) result = verify_rib(tgen, addr_type, dut, static_routes, expected=False) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) step("Delete static routes from vrf default") diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py index c7fbc01eb19b..53f0239c4dea 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json @@ -320,7 +314,6 @@ def test_dynamic_import_recursive_import_tenant_vrf_p1(request): for dut, vrf_name, vrf_import, as_num in zip( ["r2", "r4"], ["GREEN", "BLUE"], ["RED", "default"], [2, 4] ): - for action, value in zip(["Delete", "Re-add"], [True, False]): step("{} the import command on {} router".format(action, dut)) temp = {} @@ -357,23 +350,25 @@ def test_dynamic_import_recursive_import_tenant_vrf_p1(request): result = verify_bgp_rib( tgen, addr_type, "r4", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes["r4"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes["r4"]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, "r4", static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes["r4"]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes["r4"]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, "r4", static_routes) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py index 02950eb3d28f..7b0eac3f7441 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json @@ -495,23 +489,25 @@ def test_dynamic_import_routes_between_two_tenant_vrf_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in Route table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, dut, static_routes) @@ -882,23 +878,25 @@ def test_dynamic_import_routes_between_two_tenant_vrf_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, dut, static_routes) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py index 4b18903429df..ec7b25c7cc17 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json @@ -356,23 +350,25 @@ def test_dynamic_import_routes_between_tenant_to_default_vrf_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, dut, static_routes) @@ -503,23 +499,25 @@ def test_dynamic_import_routes_between_tenant_to_default_vrf_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, dut, static_routes) @@ -882,23 +880,25 @@ def test_dynamic_import_routes_between_tenant_to_default_vrf_p0(request): result = verify_bgp_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed \nError {}\n" "Routes {} still in BGP table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed \nError {}\n" + "Routes {} still in BGP table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) result = verify_rib( tgen, addr_type, dut, static_routes, expected=False ) - assert ( - result is not True - ), "Testcase {} : Failed Error {}" "Routes {} still in Route table".format( - tc_name, - result, - static_routes[dut]["static_routes"][0]["network"], + assert result is not True, ( + "Testcase {} : Failed Error {}" + "Routes {} still in Route table".format( + tc_name, + result, + static_routes[dut]["static_routes"][0]["network"], + ) ) else: result = verify_bgp_rib(tgen, addr_type, dut, static_routes) diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf b/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf index 66493f0fea99..eb2563d5a9dc 100644 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/ce1/bgpd.conf @@ -4,7 +4,6 @@ hostname ce1 password zebra ! log stdout notifications -log monitor notifications log commands ! router bgp 65002 diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf index c5c99270e732..bbc5ae502fa0 100644 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/pe1/bgpd.conf @@ -4,7 +4,6 @@ hostname pe1 password zebra ! log stdout notifications -log monitor notifications log commands ! router bgp 65001 diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py index 244db6c46a18..3539d06ac313 100755 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] @@ -37,10 +34,12 @@ def setup_module(mod): tgen.start_topology() for rname, router in tgen.routers().items(): - router.load_config(TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname))) - router.load_config(TopoRouter.RD_BGP, - os.path.join(CWD, '{}/bgpd.conf'.format(rname))) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) tgen.gears["pe1"].run("ip link add vrf10 type vrf table 10") tgen.gears["pe1"].run("ip link set vrf10 up") @@ -62,22 +61,22 @@ def open_json_file(path): return json.load(f) except IOError: assert False, "Could not read file {}".format(path) - + def check_vrf10_rib(output): - expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD) + expected = open_json_file("%s/pe1/results/vrf10_ipv4_unicast.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) def check_default_vpn_rib(output): - expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD) + expected = open_json_file("%s/pe1/results/default_ipv4_vpn.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) def check_vrf20_rib(output): - expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD) + expected = open_json_file("%s/pe1/results/vrf20_ipv4_unicast.json" % CWD) actual = json.loads(output) return topotest.json_cmp(actual, expected) diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py index f3521969d3f4..3790446dc985 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py @@ -49,9 +49,7 @@ from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, - clear_bgp, verify_best_path_as_per_bgp_attribute, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py index 5d9396438088..262cacd1474a 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py @@ -19,7 +19,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -43,7 +42,7 @@ step, create_static_routes, check_router_status, - apply_raw_config + apply_raw_config, ) from lib.topolog import logger @@ -51,7 +50,7 @@ verify_bgp_convergence, create_router_bgp, verify_bgp_rib, - verify_bgp_bestpath + verify_bgp_bestpath, ) from lib.topojson import build_config_from_json @@ -84,10 +83,8 @@ COMM_VAL_1 = "100:100" COMM_VAL_2 = "500:500" COMM_VAL_3 = "600:600" -BESTPATH = { - "ipv4": "0.0.0.0", - "ipv6": "::" -} +BESTPATH = {"ipv4": "0.0.0.0", "ipv6": "::"} + def setup_module(mod): """ @@ -158,6 +155,7 @@ def teardown_module(): # ##################################################### + def test_dynamic_import_ecmp_imported_routed_diffrent_vrfs_p0(request): """ Verify ECMP for imported routes from different VRFs. @@ -170,136 +168,130 @@ def test_dynamic_import_ecmp_imported_routed_diffrent_vrfs_p0(request): check_router_status(tgen) reset_config_on_routers(tgen) - step("Configure same static routes in tenant vrfs RED and GREEN on router " - "R3 and redistribute in respective BGP process") + step( + "Configure same static routes in tenant vrfs RED and GREEN on router " + "R3 and redistribute in respective BGP process" + ) for vrf_name in ["RED", "GREEN"]: for addr_type in ADDR_TYPES: if vrf_name == "GREEN": - next_hop_vrf = topo["routers"]["r1"]["links"][ - "r3-link3"][addr_type].split("/")[0] + next_hop_vrf = topo["routers"]["r1"]["links"]["r3-link3"][ + addr_type + ].split("/")[0] else: - next_hop_vrf = topo["routers"]["r2"]["links"][ - "r3-link1"][addr_type].split("/")[0] + next_hop_vrf = topo["routers"]["r2"]["links"]["r3-link1"][ + addr_type + ].split("/")[0] static_routes = { "r3": { "static_routes": [ { "network": [NETWORK1_1[addr_type]], "next_hop": next_hop_vrf, - "vrf": vrf_name + "vrf": vrf_name, } ] } } result = create_static_routes(tgen, static_routes) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) step("Redistribute static route on BGP VRF : {}".format(vrf_name)) temp = {} for addr_type in ADDR_TYPES: - temp.update({ - addr_type: { - "unicast": { - "redistribute": [{ - "redist_type": "static" - }] - } - } - }) + temp.update( + {addr_type: {"unicast": {"redistribute": [{"redist_type": "static"}]}}} + ) - redist_dict = {"r3": {"bgp": [{ - "vrf": vrf_name, "local_as": 3, "address_family": temp - }]}} + redist_dict = { + "r3": {"bgp": [{"vrf": vrf_name, "local_as": 3, "address_family": temp}]} + } result = create_router_bgp(tgen, topo, redist_dict) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) - step("Verify that configured static routes are installed in respective " - "BGP table for vrf RED & GREEN") + step( + "Verify that configured static routes are installed in respective " + "BGP table for vrf RED & GREEN" + ) for vrf_name in ["RED", "GREEN"]: for addr_type in ADDR_TYPES: if vrf_name == "GREEN": - next_hop_vrf = topo["routers"]["r1"]["links"][ - "r3-link3"][addr_type].split("/")[0] + next_hop_vrf = topo["routers"]["r1"]["links"]["r3-link3"][ + addr_type + ].split("/")[0] else: - next_hop_vrf = topo["routers"]["r2"]["links"][ - "r3-link1"][addr_type].split("/")[0] + next_hop_vrf = topo["routers"]["r2"]["links"]["r3-link1"][ + addr_type + ].split("/")[0] static_routes = { "r3": { "static_routes": [ - { - "network": [NETWORK1_1[addr_type]], - "vrf": vrf_name - } + {"network": [NETWORK1_1[addr_type]], "vrf": vrf_name} ] } } - result = verify_bgp_rib(tgen, addr_type, "r3", static_routes, - next_hop=next_hop_vrf) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + result = verify_bgp_rib( + tgen, addr_type, "r3", static_routes, next_hop=next_hop_vrf + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) - result = verify_rib(tgen, addr_type, "r3", static_routes, - next_hop=next_hop_vrf) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + result = verify_rib( + tgen, addr_type, "r3", static_routes, next_hop=next_hop_vrf + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) step("Import vrf RED and GREEN into default vrf and Configure ECMP") bgp_val = [] for vrf_name in ["RED", "GREEN"]: temp = {} for addr_type in ADDR_TYPES: - temp.update({ - addr_type: { - "unicast": { - "import": { - "vrf": vrf_name - }, - "maximum_paths": { - "ebgp": 2 + temp.update( + { + addr_type: { + "unicast": { + "import": {"vrf": vrf_name}, + "maximum_paths": {"ebgp": 2}, } } } - }) + ) - bgp_val.append({ - "local_as": 3, "address_family": temp - }) + bgp_val.append({"local_as": 3, "address_family": temp}) import_dict = {"r3": {"bgp": bgp_val}} result = create_router_bgp(tgen, topo, import_dict) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step("Configure bgp bestpath on router r3") r3_raw_config = { - "r3": { - "raw_config": [ - "router bgp 3", - "bgp bestpath as-path multipath-relax" - ] - } + "r3": {"raw_config": ["router bgp 3", "bgp bestpath as-path multipath-relax"]} } result = apply_raw_config(tgen, r3_raw_config) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that routes are imported with two different next-hop vrfs " - "and IPs. Additionally R3 must do ECMP for both the routes.") + step( + "Verify that routes are imported with two different next-hop vrfs " + "and IPs. Additionally R3 must do ECMP for both the routes." + ) for addr_type in ADDR_TYPES: next_hop_vrf = [ - topo["routers"]["r2"]["links"]["r3-link1"][addr_type]. \ - split("/")[0], - topo["routers"]["r1"]["links"]["r3-link3"][addr_type]. \ - split("/")[0] - ] + topo["routers"]["r2"]["links"]["r3-link1"][addr_type].split("/")[0], + topo["routers"]["r1"]["links"]["r3-link3"][addr_type].split("/")[0], + ] static_routes = { "r3": { "static_routes": [ @@ -310,54 +302,61 @@ def test_dynamic_import_ecmp_imported_routed_diffrent_vrfs_p0(request): } } - result = verify_bgp_rib(tgen, addr_type, "r3", static_routes, - next_hop=next_hop_vrf) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + result = verify_bgp_rib( + tgen, addr_type, "r3", static_routes, next_hop=next_hop_vrf + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) - result = verify_rib(tgen, addr_type, "r3", static_routes, - next_hop=next_hop_vrf) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + result = verify_rib(tgen, addr_type, "r3", static_routes, next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) - step("Now change the next-hop of static routes in vrf RED and GREEN to " - "same IP address") + step( + "Now change the next-hop of static routes in vrf RED and GREEN to " + "same IP address" + ) for addr_type in ADDR_TYPES: - next_hop_vrf = topo["routers"]["r1"]["links"][ - "r3-link3"][addr_type].split("/")[0] + next_hop_vrf = topo["routers"]["r1"]["links"]["r3-link3"][addr_type].split("/")[ + 0 + ] static_routes = { "r3": { "static_routes": [ { "network": [NETWORK1_1[addr_type]], "next_hop": next_hop_vrf, - "vrf": "RED" + "vrf": "RED", }, { "network": [NETWORK1_1[addr_type]], - "next_hop": topo["routers"]["r2"]["links"][ - "r3-link1"][addr_type].split("/")[0], + "next_hop": topo["routers"]["r2"]["links"]["r3-link1"][ + addr_type + ].split("/")[0], "vrf": "RED", - "delete": True - } + "delete": True, + }, ] } } result = create_static_routes(tgen, static_routes) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) - step("Verify that now routes are imported with two different next-hop " - "vrfs but same IPs. Additionally R3 must do ECMP for both the routes") + step( + "Verify that now routes are imported with two different next-hop " + "vrfs but same IPs. Additionally R3 must do ECMP for both the routes" + ) for addr_type in ADDR_TYPES: next_hop_vrf = [ - topo["routers"]["r1"]["links"]["r3-link3"][addr_type].\ - split("/")[0], - topo["routers"]["r1"]["links"]["r3-link3"][addr_type]. \ - split("/")[0] - ] + topo["routers"]["r1"]["links"]["r3-link3"][addr_type].split("/")[0], + topo["routers"]["r1"]["links"]["r3-link3"][addr_type].split("/")[0], + ] static_routes = { "r3": { "static_routes": [ @@ -368,20 +367,24 @@ def test_dynamic_import_ecmp_imported_routed_diffrent_vrfs_p0(request): } } - result = verify_bgp_rib(tgen, addr_type, "r3", static_routes, - next_hop=next_hop_vrf) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + result = verify_bgp_rib( + tgen, addr_type, "r3", static_routes, next_hop=next_hop_vrf + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) - result = verify_rib(tgen, addr_type, "r3", static_routes, - next_hop=next_hop_vrf) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + result = verify_rib(tgen, addr_type, "r3", static_routes, next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) write_test_footer(tc_name) -def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_p0(request): +def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_p0( + request, +): """ Verify ECMP for imported routes from different VRFs. """ @@ -393,13 +396,15 @@ def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_ check_router_status(tgen) reset_config_on_routers(tgen) - step("Configure same static routes on R2 and R3 vrfs and redistribute in BGP " - "for GREEN and RED vrf instances") - for dut, network in zip(["r2", "r3"], [ - [NETWORK1_1, NETWORK1_2], [NETWORK1_1, NETWORK1_2]]): + step( + "Configure same static routes on R2 and R3 vrfs and redistribute in BGP " + "for GREEN and RED vrf instances" + ) + for dut, network in zip( + ["r2", "r3"], [[NETWORK1_1, NETWORK1_2], [NETWORK1_1, NETWORK1_2]] + ): for vrf_name, network_vrf in zip(["RED", "GREEN"], network): - step("Configure static route for VRF : {} on {}".format(vrf_name, - dut)) + step("Configure static route for VRF : {} on {}".format(vrf_name, dut)) for addr_type in ADDR_TYPES: static_routes = { dut: { @@ -407,44 +412,50 @@ def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_ { "network": [network_vrf[addr_type]], "next_hop": "blackhole", - "vrf": vrf_name + "vrf": vrf_name, } ] } } result = create_static_routes(tgen, static_routes) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) for dut, as_num in zip(["r2", "r3"], ["2", "3"]): for vrf_name in ["RED", "GREEN"]: step("Redistribute static route on BGP VRF : {}".format(vrf_name)) temp = {} for addr_type in ADDR_TYPES: - temp.update({ - addr_type: { - "unicast": { - "redistribute": [{ - "redist_type": "static" - }] + temp.update( + { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} } } - }) + ) - redist_dict = {dut: {"bgp": [{ - "vrf": vrf_name, "local_as": as_num, "address_family": temp - }]}} + redist_dict = { + dut: { + "bgp": [ + {"vrf": vrf_name, "local_as": as_num, "address_family": temp} + ] + } + } result = create_router_bgp(tgen, topo, redist_dict) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) - - step("Verify that R2 and R3 has installed redistributed routes in default " - "and RED vrfs and GREEN respectively:") - for dut, network in zip(["r2", "r3"], - [[NETWORK1_1, NETWORK1_2], - [NETWORK1_1, NETWORK1_2]]): + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify that R2 and R3 has installed redistributed routes in default " + "and RED vrfs and GREEN respectively:" + ) + for dut, network in zip( + ["r2", "r3"], [[NETWORK1_1, NETWORK1_2], [NETWORK1_1, NETWORK1_2]] + ): for vrf_name, network_vrf in zip(["RED", "GREEN"], network): for addr_type in ADDR_TYPES: static_routes = { @@ -453,38 +464,32 @@ def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_ { "network": [network_vrf[addr_type]], "next_hop": "blackhole", - "vrf": vrf_name + "vrf": vrf_name, } ] } } result = verify_bgp_rib(tgen, addr_type, dut, static_routes) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) step("Import vrf RED's route in vrf GREEN on R3") temp = {} for addr_type in ADDR_TYPES: - temp.update({ - addr_type: { - "unicast": { - "import": { - "vrf": "RED" - } - } - } - }) + temp.update({addr_type: {"unicast": {"import": {"vrf": "RED"}}}}) - import_dict = {"r3": {"bgp": [{ - "vrf": "GREEN", "local_as": 3, "address_family": temp - }]}} + import_dict = { + "r3": {"bgp": [{"vrf": "GREEN", "local_as": 3, "address_family": temp}]} + } result = create_router_bgp(tgen, topo, import_dict) - assert result is True, "Testcase {} :Failed \n Error: {}". \ - format(tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that locally imported routes are installed over eBGP imported" - " routes from VRF RED into VRF GREEN") + step( + "Verify that locally imported routes are installed over eBGP imported" + " routes from VRF RED into VRF GREEN" + ) for addr_type in ADDR_TYPES: static_routes = { "r3": { @@ -492,7 +497,7 @@ def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_ { "network": [NETWORK1_2[addr_type]], "next_hop": "blackhole", - "vrf": "GREEN" + "vrf": "GREEN", } ] } @@ -504,19 +509,21 @@ def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_ { "network": NETWORK1_2[addr_type], "bestpath": BESTPATH[addr_type], - "vrf": "GREEN" + "vrf": "GREEN", } ] } } result = verify_bgp_bestpath(tgen, addr_type, input_routes) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) result = verify_rib(tgen, addr_type, "r3", static_routes) - assert result is True, "Testcase {} : Failed \n Error {}". \ - format(tc_name, result) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_vrf_md5_peering/peer1/exabgp.cfg b/tests/topotests/bgp_vrf_md5_peering/peer1/exabgp.cfg index 326051390311..11a827a90478 100644 --- a/tests/topotests/bgp_vrf_md5_peering/peer1/exabgp.cfg +++ b/tests/topotests/bgp_vrf_md5_peering/peer1/exabgp.cfg @@ -3,7 +3,7 @@ neighbor 10.0.0.1 { local-address 10.0.0.2; local-as 65001; peer-as 65534; - md5 test123; + md5-password test123; static { route 192.168.100.1/32 { diff --git a/tests/topotests/bgp_vrf_netns/exabgp.env b/tests/topotests/bgp_vrf_netns/exabgp.env index a328e0496289..ec978c66e76e 100644 --- a/tests/topotests/bgp_vrf_netns/exabgp.env +++ b/tests/topotests/bgp_vrf_netns/exabgp.env @@ -1,5 +1,6 @@ [exabgp.api] +ack = false encoder = text highres = false respawn = false diff --git a/tests/topotests/bgp_vrf_netns/peer1/exa-send.py b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py index ab0eb8ce8f96..c6a4499bd347 100755 --- a/tests/topotests/bgp_vrf_netns/peer1/exa-send.py +++ b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg b/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg index 2d0ca89f0fad..97a024ce9620 100644 --- a/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg +++ b/tests/topotests/bgp_vrf_netns/peer1/exabgp.cfg @@ -1,21 +1,18 @@ -group controller { - - process announce-routes { - run "/etc/exabgp/exa-send.py 1 10"; - } - - process receive-routes { - run "/etc/exabgp/exa-receive.py 1"; - receive-routes; - encoder text; - } +process announce-routes { + run /etc/exabgp/exa-send.py 1 10; + encoder text; +} - neighbor 10.0.1.1 { - router-id 10.0.1.101; - local-address 10.0.1.101; - local-as 99; - peer-as 100; - graceful-restart; - } +process receive-routes { + run /etc/exabgp/exa-receive.py 1; + encoder text; +} +neighbor 10.0.1.1 { + router-id 10.0.1.101; + local-address 10.0.1.101; + local-as 99; + peer-as 100; + capability {graceful-restart;} + api {processes [ announce-routes, receive-routes ];} } diff --git a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py index 8457b752afaf..028bc353586b 100644 --- a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py +++ b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py @@ -94,6 +94,7 @@ def setup_module(module): router.net.set_intf_netns("r1-eth0", ns, up=True) # run daemons + router.load_config(TopoRouter.RD_MGMTD, None, "--vrfwnetns") router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format("r1")), @@ -205,7 +206,6 @@ def test_bgp_vrf_netns(): if __name__ == "__main__": - args = ["-s"] + sys.argv[1:] ret = pytest.main(args) diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf index 03dfbf9322c7..397f7938d2e0 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf +++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/bgpd.conf @@ -1,10 +1,19 @@ hostname r1 +router bgp 99 + no bgp ebgp-requires-policy + address-family ipv4 unicast + redistribute connected + import vrf DONNA + ! +! router bgp 99 vrf DONNA no bgp ebgp-requires-policy address-family ipv4 unicast redistribute connected import vrf EVA + import vrf ZITA + import vrf default ! ! router bgp 99 vrf EVA @@ -12,5 +21,13 @@ router bgp 99 vrf EVA address-family ipv4 unicast redistribute connected import vrf DONNA + import vrf ZITA + ! +! +router bgp 99 vrf ZITA + no bgp ebgp-requires-policy + no bgp network import-check + address-family ipv4 unicast + network 172.16.101.0/24 ! ! diff --git a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf index 35038557df7d..4de9e895a2c4 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf +++ b/tests/topotests/bgp_vrf_route_leak_basic/r1/zebra.conf @@ -1,5 +1,9 @@ hostname r1 +int dummy0 + ip address 10.0.4.1/24 + no shut +! int dummy1 ip address 10.0.0.1/24 no shut @@ -16,3 +20,9 @@ int dummy4 ip address 10.0.3.1/24 no shut ! +int EVA + no shut +! +int DONNA + no shut +! diff --git a/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs b/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs index fb67953fe395..f62c5cd21115 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs +++ b/tests/topotests/bgp_vrf_route_leak_basic/setup_vrfs @@ -3,6 +3,7 @@ ip link add DONNA type vrf table 1001 ip link add EVA type vrf table 1002 +ip link add dummy0 type dummy # vrf default ip link add dummy1 type dummy ip link add dummy2 type dummy ip link add dummy3 type dummy diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index fd7ffff17cc4..6d4b436bccf9 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -24,7 +24,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger - +from lib.checkping import check_ping pytestmark = [pytest.mark.bgpd] @@ -64,7 +64,7 @@ def teardown_module(mod): tgen.stop_topology() -def test_vrf_route_leak(): +def test_vrf_route_leak_donna(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() # Don't run this test if we have any failure. @@ -81,11 +81,61 @@ def test_vrf_route_leak(): } ], "10.0.1.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "EVA", + "vrf": "EVA", + "active": True, + }, + ], + }, ], "10.0.2.0/24": [{"protocol": "connected"}], "10.0.3.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "EVA", + "vrf": "EVA", + "active": True, + }, + ], + }, + ], + "10.0.4.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "dummy0", + "vrf": "default", + "active": True, + }, + ], + }, + ], + "172.16.101.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "unknown", + "vrf": "Unknown", + "active": None, + }, + ], + }, ], } @@ -95,10 +145,31 @@ def test_vrf_route_leak(): result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + +def test_vrf_route_leak_eva(): + logger.info("Ensure that routes are leaked back and forth") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + # Test EVA VRF. expect = { "10.0.0.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + }, + ], + }, ], "10.0.1.0/24": [ { @@ -106,13 +177,38 @@ def test_vrf_route_leak(): } ], "10.0.2.0/24": [ - {"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]} + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + }, + ], + }, ], "10.0.3.0/24": [ { "protocol": "connected", } ], + "172.16.101.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "unknown", + "vrf": "Unknown", + "active": None, + }, + ], + }, + ], } test_func = partial( @@ -122,6 +218,295 @@ def test_vrf_route_leak(): assert result, "BGP VRF EVA check failed:\n{}".format(diff) +def test_vrf_route_leak_default(): + logger.info("Ensure that routes are leaked back and forth") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + # Test default VRF. + expect = { + "10.0.0.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + }, + ], + }, + ], + "10.0.2.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + }, + ], + }, + ], + "10.0.4.0/24": [ + { + "protocol": "connected", + } + ], + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + +def test_ping(): + "Simple ping tests" + + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + logger.info("Ping from default to DONNA") + check_ping("r1", "10.0.0.1", True, 10, 0.5, source_addr="10.0.4.1") + + +def test_vrf_route_leak_donna_after_eva_down(): + logger.info("Ensure that route states change after EVA interface goes down") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface EVA + shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "10.0.1.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "EVA", + "vrf": "EVA", + "active": None, + }, + ], + }, + ], + "10.0.3.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "EVA", + "vrf": "EVA", + "active": None, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + """ + Check that "show ip route vrf DONNA json" and the JSON at key "DONNA" of + "show ip route vrf all json" gives the same result. + """ + + def check_vrf_table(router, vrf, expect): + output = router.vtysh_cmd("show ip route vrf all json", isjson=True) + vrf_table = output.get(vrf, {}) + + return topotest.json_cmp(vrf_table, expect) + + test_func = partial(check_vrf_table, r1, "DONNA", expect) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_after_eva_up(): + logger.info("Ensure that route states change after EVA interface goes up") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface EVA + no shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "10.0.1.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "EVA", + "vrf": "EVA", + "active": True, + }, + ], + }, + ], + "10.0.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "EVA", + "vrf": "EVA", + "active": True, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_add_vrf_zita(): + logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.cmd("ip link add ZITA type vrf table 1003") + + # Test DONNA VRF. + expect = { + "172.16.101.0/24": [ + { + "protocol": "bgp", + "selected": None, + "nexthops": [ + { + "fib": None, + "interfaceName": "ZITA", + "vrf": "ZITA", + "active": None, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_set_zita_up(): + logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +interface ZITA + no shutdown +""" + ) + + # Test DONNA VRF. + expect = { + "172.16.101.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "ZITA", + "vrf": "ZITA", + "active": True, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + +def test_vrf_route_leak_donna_delete_vrf_zita(): + logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted") + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.cmd("ip link delete ZITA") + + # Test DONNA VRF. + expect = { + "172.16.101.0/24": None, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route vrf DONNA json", expect + ) + result, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff b/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff rename to tests/topotests/bgp_weighted_ecmp_recursive/__init__.py diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf new file mode 100644 index 000000000000..f7c591f75fe5 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf @@ -0,0 +1,16 @@ +! +int r1-eth0 + ip address 192.168.12.1/24 +! +int r1-eth1 + ip address 192.168.13.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.2 remote-as internal + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + neighbor 192.168.13.3 remote-as internal + neighbor 192.168.13.3 timers 1 3 + neighbor 192.168.13.3 timers connect 1 +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf new file mode 100644 index 000000000000..dc25d4781c74 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf @@ -0,0 +1,20 @@ +! +int r2-eth0 + ip address 192.168.12.2/24 +! +int r2-eth1 + ip address 192.168.24.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.1 remote-as internal + neighbor 192.168.12.1 timers 1 3 + neighbor 192.168.12.1 timers connect 1 + neighbor 192.168.24.4 remote-as internal + neighbor 192.168.24.4 timers 1 3 + neighbor 192.168.24.4 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.12.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf new file mode 100644 index 000000000000..bdeb35b50f21 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf @@ -0,0 +1,20 @@ +! +int r3-eth0 + ip address 192.168.13.3/24 +! +int r3-eth1 + ip address 192.168.35.3/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.13.1 remote-as internal + neighbor 192.168.13.1 timers 1 3 + neighbor 192.168.13.1 timers connect 1 + neighbor 192.168.35.5 remote-as internal + neighbor 192.168.35.5 timers 1 3 + neighbor 192.168.35.5 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.13.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf new file mode 100644 index 000000000000..0662a4dc499e --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf @@ -0,0 +1,17 @@ +! +int r4-eth0 + ip address 192.168.24.4/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.24.2 remote-as internal + neighbor 192.168.24.2 timers 1 3 + neighbor 192.168.24.2 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 4000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf new file mode 100644 index 000000000000..bc24a96b519b --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf @@ -0,0 +1,17 @@ +! +int r5-eth0 + ip address 192.168.35.5/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.35.3 remote-as internal + neighbor 192.168.35.3 timers 1 3 + neighbor 192.168.35.3 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 5000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py new file mode 100644 index 000000000000..5dc917bd1a8a --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if weighted ECMP works and recursive weight (link bandwidth) is +inherited to non-recursive next-hops. +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = { + "s1": ("r1", "r2"), + "s2": ("r1", "r3"), + "s3": ("r2", "r4"), + "s4": ("r3", "r5"), + } + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_weighted_ecmp_recursive(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show ip route 10.10.10.10/32 json")) + expected = { + "10.10.10.10/32": [ + { + "selected": True, + "installed": True, + "nexthops": [ + { + "ip": "192.168.24.4", + "active": True, + "recursive": True, + "weight": 203, + }, + { + "ip": "192.168.12.2", + "active": True, + "resolver": True, + "weight": 203, + }, + { + "ip": "192.168.35.5", + "active": True, + "recursive": True, + "weight": 254, + }, + { + "ip": "192.168.13.3", + "active": True, + "resolver": True, + "weight": 254, + }, + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/config_timing/test_config_timing.py b/tests/topotests/config_timing/test_config_timing.py index 5c1b97262c95..52d196f12a9b 100644 --- a/tests/topotests/config_timing/test_config_timing.py +++ b/tests/topotests/config_timing/test_config_timing.py @@ -97,8 +97,8 @@ def do_config( optype = "adding" if add else "removing" iptype = "IPv6" if do_ipv6 else "IPv4" if super_prefix is None: - super_prefix = u"2001::/48" if do_ipv6 else u"10.0.0.0/8" - via = u"lo" + super_prefix = "2001::/48" if do_ipv6 else "10.0.0.0/8" + via = "lo" optyped = "added" if add else "removed" for rname, router in router_list.items(): @@ -161,8 +161,8 @@ def do_config( prefix_count = 50 prefix_base = [ - [u"10.0.0.0/8", u"11.0.0.0/8"], - [u"2100:1111:2220::/44", u"2100:3333:4440::/44"], + ["10.0.0.0/8", "11.0.0.0/8"], + ["2100:1111:2220::/44", "2100:3333:4440::/44"], ] # This apparently needed to allow for various mgmtd/staticd/zebra connections to form diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 0afebde1cf5f..a2315138cc2f 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -17,6 +17,7 @@ import lib.fixtures import pytest +from lib.common_config import generate_support_bundle from lib.micronet_compat import Mininet from lib.topogen import diagnose_env, get_topogen from lib.topolog import get_test_logdir, logger @@ -67,6 +68,10 @@ def log_handler(basename, logpath): topolog.logfinish(basename, logpath) +def is_main_runner(): + return "PYTEST_XDIST_WORKER" not in os.environ + + def pytest_addoption(parser): """ Add topology-only option to the topology tester. This option makes pytest @@ -84,6 +89,17 @@ def pytest_addoption(parser): help="Mininet cli on test failure", ) + parser.addoption( + "--cov-topotest", + action="store_true", + help="Enable reporting of coverage", + ) + + parser.addoption( + "--cov-frr-build-dir", + help="Dir of coverage-enable build being run, default is the source dir", + ) + parser.addoption( "--gdb-breakpoints", metavar="SYMBOL[,SYMBOL...]", @@ -102,6 +118,12 @@ def pytest_addoption(parser): help="Comma-separated list of routers to spawn gdb on, or 'all'", ) + parser.addoption( + "--gdb-use-emacs", + action="store_true", + help="Use emacsclient to run gdb instead of a shell", + ) + parser.addoption( "--logd", action="append", @@ -167,6 +189,24 @@ def pytest_addoption(parser): help="Options to pass to `perf record`.", ) + parser.addoption( + "--rr-daemons", + metavar="DAEMON[,DAEMON...]", + help="Comma-separated list of daemons to run `rr` on, or 'all'", + ) + + parser.addoption( + "--rr-routers", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to run `rr` on, or 'all'", + ) + + parser.addoption( + "--rr-options", + metavar="OPTS", + help="Options to pass to `rr record`.", + ) + rundir_help = "directory for running in and log files" parser.addini("rundir", rundir_help, default="/tmp/topotests") parser.addoption("--rundir", metavar="DIR", help=rundir_help) @@ -202,6 +242,12 @@ def pytest_addoption(parser): help="Generate suppression file, and enable more precise (slower) valgrind checks", ) + parser.addoption( + "--valgrind-leak-kinds", + metavar="KIND[,KIND...]", + help="Comma-separated list of valgrind leak kinds or 'all'", + ) + parser.addoption( "--valgrind-memleaks", action="store_true", @@ -425,6 +471,37 @@ def pytest_assertrepr_compare(op, left, right): return json_result.gen_report() +def setup_coverage(config): + commander = Commander("pytest") + if config.option.cov_frr_build_dir: + bdir = Path(config.option.cov_frr_build_dir).resolve() + output = commander.cmd_raises(f"find {bdir} -name zebra_nb.gcno").strip() + else: + # Support build sub-directory of main source dir + bdir = Path(__file__).resolve().parent.parent.parent + output = commander.cmd_raises(f"find {bdir} -name zebra_nb.gcno").strip() + m = re.match(f"({bdir}.*)/zebra/zebra_nb.gcno", output) + if not m: + logger.warning( + "No coverage data files (*.gcno) found, try specifying --cov-frr-build-dir" + ) + return + + bdir = Path(m.group(1)) + # Save so we can get later from g_pytest_config + rundir = Path(config.option.rundir).resolve() + gcdadir = rundir / "gcda" + os.environ["FRR_BUILD_DIR"] = str(bdir) + os.environ["GCOV_PREFIX_STRIP"] = str(len(bdir.parts) - 1) + os.environ["GCOV_PREFIX"] = str(gcdadir) + + if is_main_runner(): + commander.cmd_raises(f"find {bdir} -name '*.gc??' -exec chmod o+r {{}} +") + commander.cmd_raises(f"mkdir -p {gcdadir}") + commander.cmd_raises(f"chown -R root:frr {gcdadir}") + commander.cmd_raises(f"chmod 2775 {gcdadir}") + + def pytest_configure(config): """ Assert that the environment is correctly configured, and get extra config. @@ -525,8 +602,6 @@ def assert_feature_windows(b, feature): if config.option.topology_only and is_xdist: pytest.exit("Cannot use --topology-only with distributed test mode") - pytest.exit("Cannot use --topology-only with distributed test mode") - # Check environment now that we have config if not diagnose_env(rundir): pytest.exit("environment has errors, please read the logs in %s" % rundir) @@ -541,33 +616,36 @@ def assert_feature_windows(b, feature): if "TOPOTESTS_CHECK_STDERR" in os.environ: del os.environ["TOPOTESTS_CHECK_STDERR"] + if config.option.cov_topotest: + setup_coverage(config) + @pytest.fixture(autouse=True, scope="session") -def setup_session_auto(): +def session_autouse(): # Aligns logs nicely logging.addLevelName(logging.WARNING, " WARN") logging.addLevelName(logging.INFO, " INFO") - if "PYTEST_TOPOTEST_WORKER" not in os.environ: - is_worker = False - elif not os.environ["PYTEST_TOPOTEST_WORKER"]: - is_worker = False - else: - is_worker = True + is_main = is_main_runner() - logger.debug("Before the run (is_worker: %s)", is_worker) - if not is_worker: + logger.debug("Before the run (is_main: %s)", is_main) + if is_main: cleanup_previous() yield - if not is_worker: + if is_main: cleanup_current() - logger.debug("After the run (is_worker: %s)", is_worker) + logger.debug("After the run (is_main: %s)", is_main) def pytest_runtest_setup(item): module = item.parent.module script_dir = os.path.abspath(os.path.dirname(module.__file__)) os.environ["PYTEST_TOPOTEST_SCRIPTDIR"] = script_dir + os.environ["CONFIGDIR"] = script_dir + + +def pytest_exception_interact(node, call, report): + generate_support_bundle() def pytest_runtest_makereport(item, call): @@ -683,6 +761,49 @@ def pytest_runtest_makereport(item, call): pause_test() +def coverage_finish(terminalreporter, config): + commander = Commander("pytest") + rundir = Path(config.option.rundir).resolve() + bdir = Path(os.environ["FRR_BUILD_DIR"]) + gcdadir = Path(os.environ["GCOV_PREFIX"]) + + logger.info("Creating .gcno ssymlink from '%s' to '%s'", gcdadir, bdir) + commander.cmd_raises( + f"cd {gcdadir}; bdir={bdir}" + + """ +for f in $(find . -name '*.gcda'); do + f=${f#./}; + f=${f%.gcda}.gcno; + ln -fs $bdir/$f $f; + touch -h -r $bdir/$f $f; + echo $f; +done""" + ) + + # Get the results into a summary file + data_file = rundir / "coverage.info" + logger.info("Gathering coverage data into: %s", data_file) + commander.cmd_raises( + f"lcov --directory {gcdadir} --capture --output-file {data_file}" + ) + + # Get coverage info filtered to a specific set of files + report_file = rundir / "coverage.info" + logger.debug("Generating coverage summary from: %s\n%s", report_file) + output = commander.cmd_raises(f"lcov --summary {data_file}") + logger.info("\nCOVERAGE-SUMMARY-START\n%s\nCOVERAGE-SUMMARY-END", output) + terminalreporter.write( + f"\nCOVERAGE-SUMMARY-START\n{output}\nCOVERAGE-SUMMARY-END\n" + ) + + +def pytest_terminal_summary(terminalreporter, exitstatus, config): + # Only run if we are the top level test runner + is_xdist_worker = "PYTEST_XDIST_WORKER" in os.environ + if config.option.cov_topotest and not is_xdist_worker: + coverage_finish(terminalreporter, config) + + # # Add common fixtures available to all tests as parameters # diff --git a/tests/topotests/docker/inner/compile_frr.sh b/tests/topotests/docker/inner/compile_frr.sh index 3b296a149758..4a88dc677f3c 100755 --- a/tests/topotests/docker/inner/compile_frr.sh +++ b/tests/topotests/docker/inner/compile_frr.sh @@ -64,9 +64,9 @@ if [ ! -e Makefile ]; then --enable-dev-build \ --with-moduledir=/usr/lib/frr/modules \ --prefix=/usr \ - --localstatedir=/var/run/frr \ + --sysconfdir=/etc \ + --localstatedir=/var \ --sbindir=/usr/lib/frr \ - --sysconfdir=/etc/frr \ --enable-multipath=0 \ --enable-fpm \ --enable-sharpd \ diff --git a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py index 3c9392c3f58d..7ab1572daedd 100644 --- a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py @@ -143,7 +143,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) @@ -193,6 +192,7 @@ def test_shutdown_check_stderr(): args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) + # # Auxiliary Functions # diff --git a/tests/topotests/evpn_pim_1/spine/bgp.summ.json b/tests/topotests/evpn_pim_1/spine/bgp.summ.json index 7f37cedb2bd7..b5b03e86b4c3 100644 --- a/tests/topotests/evpn_pim_1/spine/bgp.summ.json +++ b/tests/topotests/evpn_pim_1/spine/bgp.summ.json @@ -2,7 +2,6 @@ "routerId":"192.168.100.1", "as":65001, "vrfName":"default", - "tableVersion":7, "peerCount":2, "peers":{ "192.168.1.2":{ diff --git a/tests/topotests/evpn_pim_1/test_evpn_pim_topo1.py b/tests/topotests/evpn_pim_1/test_evpn_pim_topo1.py index c0621d75a506..cfcd4a18eaf3 100644 --- a/tests/topotests/evpn_pim_1/test_evpn_pim_topo1.py +++ b/tests/topotests/evpn_pim_1/test_evpn_pim_topo1.py @@ -20,7 +20,7 @@ import json from functools import partial -pytestmark = [pytest.mark.pimd] +pytestmark = [pytest.mark.pimd, pytest.mark.bgpd] # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -32,10 +32,6 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -# Required to instantiate the topology builder class. - -pytestmark = [pytest.mark.bgpd, pytest.mark.bgpd] - ##################################################### ## diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py index 10d216ab1ed4..beb4de432e22 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py @@ -22,7 +22,6 @@ import os import sys -import json import time import pytest import platform @@ -69,7 +68,7 @@ verify_attributes_for_evpn_routes, verify_evpn_routes, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/example_test/test_template.py b/tests/topotests/example_test/test_template.py index 27975483a84f..5728ebaea23d 100644 --- a/tests/topotests/example_test/test_template.py +++ b/tests/topotests/example_test/test_template.py @@ -41,6 +41,7 @@ # pytest.mark.vrrpd, ] + # Function we pass to Topogen to create the topology def build_topo(tgen): "Build function" diff --git a/tests/topotests/fpm_testing_topo1/r1/fpm_counters.json b/tests/topotests/fpm_testing_topo1/r1/fpm_counters.json new file mode 100644 index 000000000000..05a6731e13d0 --- /dev/null +++ b/tests/topotests/fpm_testing_topo1/r1/fpm_counters.json @@ -0,0 +1,8 @@ +{ + "connected":true, + "useNHG":true, + "useRouteReplace":true, + "disabled":false, + "address":"127.0.0.1", + "port":2620 +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff b/tests/topotests/fpm_testing_topo1/r1/fpm_stub.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff rename to tests/topotests/fpm_testing_topo1/r1/fpm_stub.conf diff --git a/tests/topotests/fpm_testing_topo1/r1/routes_summ.json b/tests/topotests/fpm_testing_topo1/r1/routes_summ.json new file mode 100644 index 000000000000..e9157bc664e1 --- /dev/null +++ b/tests/topotests/fpm_testing_topo1/r1/routes_summ.json @@ -0,0 +1,27 @@ +{ + "routes":[ + { + "fib":1, + "rib":1, + "fibOffLoaded":0, + "fibTrapped":0, + "type":"connected" + }, + { + "fib":1, + "rib":1, + "fibOffLoaded":0, + "fibTrapped":0, + "type":"local" + }, + { + "fib":10000, + "rib":10000, + "fibOffLoaded":0, + "fibTrapped":0, + "type":"sharp" + } + ], + "routesTotal":10002, + "routesTotalFib":10002 +} diff --git a/tests/topotests/fpm_testing_topo1/r1/routes_summ_removed.json b/tests/topotests/fpm_testing_topo1/r1/routes_summ_removed.json new file mode 100644 index 000000000000..8585b2bb6b7c --- /dev/null +++ b/tests/topotests/fpm_testing_topo1/r1/routes_summ_removed.json @@ -0,0 +1,20 @@ +{ + "routes":[ + { + "fib":1, + "rib":1, + "fibOffLoaded":0, + "fibTrapped":0, + "type":"connected" + }, + { + "fib":1, + "rib":1, + "fibOffLoaded":0, + "fibTrapped":0, + "type":"local" + } + ], + "routesTotal":2, + "routesTotalFib":2 +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff b/tests/topotests/fpm_testing_topo1/r1/sharpd.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff rename to tests/topotests/fpm_testing_topo1/r1/sharpd.conf diff --git a/tests/topotests/fpm_testing_topo1/r1/zebra.conf b/tests/topotests/fpm_testing_topo1/r1/zebra.conf new file mode 100644 index 000000000000..c7b1646dda21 --- /dev/null +++ b/tests/topotests/fpm_testing_topo1/r1/zebra.conf @@ -0,0 +1,5 @@ +fpm address 127.0.0.1 + +interface r1-eth0 + ip address 192.168.44.1/24 +! diff --git a/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py new file mode 100644 index 000000000000..66cefcc2a06f --- /dev/null +++ b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_route_scale1.py +# +# Copyright (c) 2024 by +# Nvidia, Inc. +# Donald Sharp +# + +""" +test_fpm_topo1.py: Testing FPM module + +""" +import os +import sys +import pytest +import json +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + + +pytestmark = [pytest.mark.fpm, pytest.mark.sharpd] + + +def build_topo(tgen): + "Build function" + + # Populate routers + tgen.add_router("r1") + + switch = tgen.add_switch("sw1") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(module): + "Setup topology" + + # fpm_stub = os.system("which fpm-stub") + # if fpm-stub: + # pytest.skip("") + + tgen = Topogen(build_topo, module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, "{}/zebra.conf".format(rname)), + "-M dplane_fpm_nl", + ) + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_FPM_LISTENER, + os.path.join(CWD, "{}/fpm_stub.conf".format(rname)), + ) + + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_fpm_connection_made(): + "Test that the fpm starts up and a connection is made" + + tgen = get_topogen() + router = tgen.gears["r1"] + + fpm_counters = "{}/r1/fpm_counters.json".format(CWD) + expected = json.loads(open(fpm_counters).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show fpm status json", expected + ) + + success, result = topotest.run_and_expect(test_func, None, 30, 1) + assert success, "Unable to connect to the fpm:\n{}".format(result) + + +def test_fpm_install_routes(): + "Test that simple routes installed appears to work" + + tgen = get_topogen() + router = tgen.gears["r1"] + + # Let's install 10000 routes + router.vtysh_cmd("sharp install routes 10.0.0.0 nexthop 192.168.44.33 10000") + routes_file = "{}/r1/routes_summ.json".format(CWD) + expected = json.loads(open(routes_file).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show ip route summ json", expected + ) + + success, result = topotest.run_and_expect(test_func, None, 60, 1) + assert success, "Unable to successfully install 10000 routes: {}".format(result) + + # Let's remove 10000 routes + router.vtysh_cmd("sharp remove routes 10.0.0.0 10000") + + routes_file_removed = "{}/r1/routes_summ_removed.json".format(CWD) + expected = json.loads(open(routes_file_removed).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show ip route summ json", expected + ) + + success, result = topotest.run_and_expect(test_func, None, 60, 1) + assert success, "Unable to remove 10000 routes: {}".format(result) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/grpc_basic/test_basic_grpc.py b/tests/topotests/grpc_basic/test_basic_grpc.py index 88bfa98d2ff2..5ff2894fd1ab 100644 --- a/tests/topotests/grpc_basic/test_basic_grpc.py +++ b/tests/topotests/grpc_basic/test_basic_grpc.py @@ -9,16 +9,17 @@ test_basic_grpc.py: Test Basic gRPC. """ +import json import logging import os +import re import sys import pytest - from lib.common_config import step from lib.micronet import commander from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger +from lib.topotest import json_cmp CWD = os.path.dirname(os.path.realpath(__file__)) @@ -28,9 +29,10 @@ GRPCP_ISISD = 50054 GRPCP_OSPFD = 50055 GRPCP_PIMD = 50056 +GRPCP_MGMTD = 50057 pytestmark = [ - # pytest.mark.mgmtd -- Need a new non-protocol marker + pytest.mark.mgmtd, # pytest.mark.bfdd, # pytest.mark.isisd, # pytest.mark.ospfd, @@ -57,14 +59,17 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}") - router.load_config(TopoRouter.RD_STATIC, None, f"-M grpc:{GRPCP_STATICD}") - # router.load_config(TopoRouter.RD_BFD, None, f"-M grpc:{GRPCP_BFDD}") + router.load_config(TopoRouter.RD_STATIC, "", f"-M grpc:{GRPCP_STATICD}") + # router.load_config(TopoRouter.RD_BFDD, "", f"-M grpc:{GRPCP_BFDD}") # router.load_config(TopoRouter.RD_ISIS, None, f"-M grpc:{GRPCP_ISISD}") # router.load_config(TopoRouter.RD_OSPF, None, f"-M grpc:{GRPCP_OSPFD}") # router.load_config(TopoRouter.RD_PIM, None, f"-M grpc:{GRPCP_PIMD}") + # This doesn't work yet... + # router.load_config(TopoRouter.RD_MGMTD, "", f"-M grpc:{GRPCP_MGMTD}") + tgen.start_router() yield tgen @@ -94,40 +99,94 @@ def run_grpc_client(r, port, commands): def test_connectivity(tgen): - r1 = tgen.gears["r1"] - output = r1.cmd_raises("ping -c1 192.168.1.2") - logging.info("ping output: %s", output) + tgen.gears["r1"].cmd_raises("ping -c1 192.168.1.2") def test_capabilities(tgen): r1 = tgen.gears["r1"] - output = run_grpc_client(r1, GRPCP_ZEBRA, "GETCAP") - logging.info("grpc output: %s", output) + output = run_grpc_client(r1, GRPCP_STATICD, "GETCAP") + logging.debug("grpc output: %s", output) + + modules = sorted(re.findall('name: "([^"]+)"', output)) + expected = ["frr-interface", "frr-routing", "frr-staticd", "frr-vrf"] + assert modules == expected + + encodings = sorted(re.findall("supported_encodings: (.*)", output)) + expected = ["JSON", "XML"] + assert encodings == expected def test_get_config(tgen): nrepeat = 5 r1 = tgen.gears["r1"] - step("'GET' interface config 10 times, once per invocation") + step("'GET' interface config and state 10 times, once per invocation") for i in range(0, nrepeat): - output = run_grpc_client(r1, GRPCP_ZEBRA, "GET,/frr-interface:lib") - logging.info("[iteration %s]: grpc GET output: %s", i, output) + output = run_grpc_client(r1, GRPCP_ZEBRA, "GET-CONFIG,/frr-interface:lib") + logging.debug("[iteration %s]: grpc GET output: %s", i, output) step(f"'GET' YANG {nrepeat} times in one invocation") - commands = ["GET,/frr-interface:lib" for _ in range(0, 10)] + commands = ["GET-CONFIG,/frr-interface:lib" for _ in range(0, 10)] output = run_grpc_client(r1, GRPCP_ZEBRA, commands) - logging.info("grpc GET*{%d} output: %s", nrepeat, output) + logging.debug("grpc GET*{%d} output: %s", nrepeat, output) + + output = run_grpc_client(r1, GRPCP_ZEBRA, commands[0]) + out_json = json.loads(output) + expect = json.loads( + """{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "frr-zebra:zebra": { + "ipv4-addrs": [ + { + "ip": "192.168.1.1", + "prefix-length": 24 + } + ], + "evpn-mh": {}, + "ipv6-router-advertisements": {} + } + } + ] + }, + "frr-zebra:zebra": { + "import-kernel-table": {} + } +} """ + ) + result = json_cmp(out_json, expect, exact=True) + assert result is None def test_get_vrf_config(tgen): r1 = tgen.gears["r1"] - step("'GET' get VRF config") - - output = run_grpc_client(r1, GRPCP_ZEBRA, "GET,/frr-vrf:lib") - logging.info("grpc GET /frr-vrf:lib output: %s", output) + step("'GET' VRF config and state") + + output = run_grpc_client(r1, GRPCP_STATICD, "GET,/frr-vrf:lib") + logging.debug("grpc GET /frr-vrf:lib output: %s", output) + out_json = json.loads(output) + expect = json.loads( + """{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": 0, + "active": true + } + } + ] + } +} + """ + ) + result = json_cmp(out_json, expect, exact=True) + assert result is None def test_shutdown_checks(tgen): @@ -142,7 +201,7 @@ def test_shutdown_checks(tgen): time.sleep(1) try: for r in tgen.routers().values(): - r.net.stopRouter() + r.net.stopRouter(False) r.net.checkRouterCores() finally: if p: diff --git a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py index ada8c0f5fbda..ad896b7422af 100644 --- a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py +++ b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py @@ -30,8 +30,6 @@ import sys import pytest import json -from time import sleep -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -39,7 +37,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.common_config import ( retry, stop_router, diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py index 44b3dd0b7927..af28dbdf3ce3 100755 --- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py @@ -42,7 +42,6 @@ import sys import pytest import json -import time import tempfile from functools import partial @@ -169,7 +168,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -832,7 +831,7 @@ def _rt2_neigh_down(router): rname = "rt1" router = tgen.gears[rname] test_func = partial(_rt2_neigh_down, router) - success, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) + _, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) assert result is None, 'rt2 neighbor is still present on "{}"'.format(router) router_compare_json_output( @@ -1034,7 +1033,7 @@ def _bfd_down(router): rname = "rt1" router = tgen.gears[rname] test_func = partial(_bfd_down, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) assert result is None, 'BFD session is still up on "{}"'.format(router) router_compare_json_output( diff --git a/tests/topotests/isis_lsp_bits_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_lsp_bits_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref index f5d9aa70cb2a..8300ca0b5cd8 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_lsp_bits_topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref @@ -9,7 +9,7 @@ "adjacencies": { "adjacency": [ { - "neighbor-sys-type": "level-1-2", + "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0004", "hold-timer": 10, "neighbor-priority": 0, @@ -28,7 +28,7 @@ "adjacencies": { "adjacency": [ { - "neighbor-sys-type": "level-1-2", + "neighbor-sys-type": "level-1", "neighbor-sysid": "0000.0000.0005", "hold-timer": 10, "neighbor-priority": 0, diff --git a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py index c4ce6a30cd43..6f4653d2c295 100755 --- a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py +++ b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py @@ -131,7 +131,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py index 15327fe03adf..f97c7d2c9c9c 100755 --- a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py +++ b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py @@ -170,7 +170,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_snmp/test_isis_snmp.py b/tests/topotests/isis_snmp/test_isis_snmp.py index ddef08008b43..81c96b3daf17 100755 --- a/tests/topotests/isis_snmp/test_isis_snmp.py +++ b/tests/topotests/isis_snmp/test_isis_snmp.py @@ -147,7 +147,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_sr_flex_algo_topo1/rt1/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo1/rt1/zebra.conf index 5140eda73a76..92b619ee57ea 100644 --- a/tests/topotests/isis_sr_flex_algo_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo1/rt1/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt1 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo1/rt2/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo1/rt2/zebra.conf index 388348fced86..3ea5e0a0a6bf 100644 --- a/tests/topotests/isis_sr_flex_algo_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo1/rt2/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt2 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo1/rt3/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo1/rt3/zebra.conf index fb45ee128269..ea35de80c46e 100644 --- a/tests/topotests/isis_sr_flex_algo_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo1/rt3/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt3 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py index c81f63942bde..d1fc68291ea7 100755 --- a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py +++ b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py @@ -37,7 +37,6 @@ import sys import pytest import json -import tempfile from copy import deepcopy from functools import partial @@ -121,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt0/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt0/zebra.conf index 89837d4cf5dd..a4b1f2a6550f 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt0/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt0/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt0 ! !log stdout notifications -!log monitor notifications !log commands ! debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt1/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt1/zebra.conf index 25a96290ae88..f11daa5c2abb 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt1/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt1/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt1 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt2/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt2/zebra.conf index d739a732a927..ca3235aee594 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt2/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt2/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt2 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt3/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt3/zebra.conf index 5c3bed07632e..9a999104c912 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt3/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt3/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt3 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt4/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt4/zebra.conf index 9c00013e70c9..503704151498 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt4/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt4/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt4 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt5/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt5/zebra.conf index 61c599db7b1d..5f96fd4ae79f 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt5/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt5/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt5 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt6/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt6/zebra.conf index b63401e11478..23a99a0c9312 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt6/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt6/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt6 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt7/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt7/zebra.conf index b5a28c7f1ace..9be1b488cc1e 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt7/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt7/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt7 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt8/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt8/zebra.conf index dd63f8cc2fc3..eaaac74fc371 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt8/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt8/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt8 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/rt9/zebra.conf b/tests/topotests/isis_sr_flex_algo_topo2/rt9/zebra.conf index 378a1969bea7..513cf5610259 100644 --- a/tests/topotests/isis_sr_flex_algo_topo2/rt9/zebra.conf +++ b/tests/topotests/isis_sr_flex_algo_topo2/rt9/zebra.conf @@ -3,7 +3,6 @@ log file zebra.log hostname rt9 ! log stdout notifications -log monitor notifications log commands ! !debug zebra packet diff --git a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py index 6a5f81def658..7d063910d0f3 100755 --- a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py +++ b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py @@ -47,7 +47,6 @@ import sys import pytest import json -import time from functools import partial # Save the Current Working Directory to find configuration files. @@ -67,7 +66,6 @@ def build_topo(tgen): "Build function" - routers = [] for i in range(0, 10): rt = tgen.add_router("rt{}".format(i)) rt.run("sysctl -w net.ipv4.fib_multipath_hash_policy=1") @@ -118,11 +116,19 @@ def setup_module(mod): # For all registered routers, load the zebra configuration file for rname, router in router_list.items(): - router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))) - router.load_config( TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) if rname in ["rt0", "rt9"]: - router.load_config( TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))) - router.load_config( TopoRouter.RD_PATH, os.path.join(CWD, "{}/pathd.conf".format(rname))) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_PATH, os.path.join(CWD, "{}/pathd.conf".format(rname)) + ) router.run("ip link add dum0 type dummy") router.run("ip link set dum0 up") if rname == "rt0": @@ -132,7 +138,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -145,6 +151,7 @@ def setup_testcase(msg): pytest.skip(tgen.errors) return tgen + def open_json_file(filename): try: with open(filename, "r") as f: @@ -162,10 +169,10 @@ def _check(name, cmd, expected_file): expected = open_json_file("{}/{}".format(CWD, expected_file)) return topotest.json_cmp(output, expected) - logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) + logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=120, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=120, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py index fc2ce7cb4b66..cb4f4ffa56ef 100755 --- a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -641,7 +641,7 @@ def test_srte_route_map_with_sr_policy_check_nextop_step5(): ) # (re-)build the SR Policy two times to ensure that reinstalling still works - for i in [1, 2]: + for _ in [1, 2]: cmp_json_output( "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" ) diff --git a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py index 9a4085ab5593..baf7e98ba10a 100644 --- a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py @@ -137,7 +137,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref index bb10aba9424d..c4a5d7507b45 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref index bb10aba9424d..c4a5d7507b45 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref index bb10aba9424d..c4a5d7507b45 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref index bb10aba9424d..c4a5d7507b45 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref index bb10aba9424d..c4a5d7507b45 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref index f3399319f3e5..f8a5d93f3c78 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref index ffa626123da8..c62870587bf3 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref index 189943f737a5..cb052dbbb5fb 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref index 54780fce8adc..ec55f24d7b95 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref index 35aa61d8e6d5..abcdeddea4ef 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py index 892f6e1d0e71..9c1a23f54f42 100644 --- a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py +++ b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py @@ -60,7 +60,6 @@ """ import os -import re import sys import json import functools @@ -197,19 +196,22 @@ def setup_module(mod): # For all registered routers, load the zebra and isis configuration files for rname, router in tgen.routers().items(): - router.load_config(TopoRouter.RD_ZEBRA, - os.path.join(CWD, '{}/zebra.conf'.format(rname))) - router.load_config(TopoRouter.RD_ISIS, - os.path.join(CWD, '{}/isisd.conf'.format(rname))) - if (os.path.exists('{}/sharpd.conf'.format(rname))): - router.load_config(TopoRouter.RD_SHARP, - os.path.join(CWD, '{}/sharpd.conf'.format(rname))) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + if os.path.exists("{}/sharpd.conf".format(rname)): + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) # Start routers tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" # Teardown the topology @@ -227,7 +229,9 @@ def router_compare_json_output(rname, command, reference): expected = json.loads(open(filename).read()) # Run test function until we get an result. Wait at most 60 seconds. - test_func = functools.partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + test_func = functools.partial( + topotest.router_json_cmp, tgen.gears[rname], command, expected + ) _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) assert diff is None, assertmsg @@ -245,7 +249,7 @@ def _check(name, dest_addr, match): logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=1) + _, result = topotest.run_and_expect(func, None, count=10, wait=1) assert result is None, "Failed" @@ -308,8 +312,10 @@ def test_srv6_locator_step1(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step1/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step1/show_srv6_locator_table.ref", + ) def test_ping_step1(): @@ -326,10 +332,16 @@ def test_ping_step1(): pytest.skip(tgen.errors) # Setup encap route on rt1, decap route on rt2 - tgen.gears["rt1"].vtysh_cmd("sharp install seg6-routes fc00:0:9::1 nexthop-seg6 2001:db8:1::2 encap fc00:0:1:2:6:f00d:: 1") - tgen.gears["rt6"].vtysh_cmd("sharp install seg6local-routes fc00:0:f00d:: nexthop-seg6local eth-dst End_DT6 254 1") - tgen.gears["dst"].vtysh_cmd("sharp install route 2001:db8:1::1 nexthop 2001:db8:10::1 1") - + tgen.gears["rt1"].vtysh_cmd( + "sharp install seg6-routes fc00:0:9::1 nexthop-seg6 2001:db8:1::2 encap fc00:0:1:2:6:f00d:: 1" + ) + tgen.gears["rt6"].vtysh_cmd( + "sharp install seg6local-routes fc00:0:f00d:: nexthop-seg6local eth-dst End_DT6 254 1" + ) + tgen.gears["dst"].vtysh_cmd( + "sharp install route 2001:db8:1::1 nexthop 2001:db8:10::1 1" + ) + # Try to ping dst from rt1 check_ping6("rt1", "fc00:0:9::1", True) @@ -412,8 +424,10 @@ def test_srv6_locator_step2(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step2/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step2/show_srv6_locator_table.ref", + ) def test_ping_step2(): @@ -428,7 +442,7 @@ def test_ping_step2(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", False) @@ -512,8 +526,10 @@ def test_srv6_locator_step3(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step3/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step3/show_srv6_locator_table.ref", + ) def test_ping_step3(): @@ -528,7 +544,7 @@ def test_ping_step3(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", True) @@ -608,8 +624,10 @@ def test_srv6_locator_step4(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step4/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step4/show_srv6_locator_table.ref", + ) def test_ping_step4(): @@ -624,7 +642,7 @@ def test_ping_step4(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", False) @@ -704,8 +722,10 @@ def test_srv6_locator_step5(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step5/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step5/show_srv6_locator_table.ref", + ) def test_ping_step5(): @@ -720,7 +740,7 @@ def test_ping_step5(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", True) @@ -799,8 +819,10 @@ def test_srv6_locator_step6(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step6/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step6/show_srv6_locator_table.ref", + ) def test_ping_step6(): @@ -815,7 +837,7 @@ def test_ping_step6(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", False) @@ -895,8 +917,10 @@ def test_srv6_locator_step7(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step7/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step7/show_srv6_locator_table.ref", + ) def test_ping_step7(): @@ -911,7 +935,7 @@ def test_ping_step7(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", True) @@ -990,8 +1014,10 @@ def test_srv6_locator_step8(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step8/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step8/show_srv6_locator_table.ref", + ) def test_ping_step8(): @@ -1006,7 +1032,7 @@ def test_ping_step8(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", False) @@ -1089,8 +1115,10 @@ def test_srv6_locator_step9(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show segment-routing srv6 locator json", "step9/show_srv6_locator_table.ref" - ) + rname, + "show segment-routing srv6 locator json", + "step9/show_srv6_locator_table.ref", + ) def test_ping_step9(): @@ -1105,7 +1133,7 @@ def test_ping_step9(): # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - + check_ping6("rt1", "fc00:0:9::1", True) diff --git a/tests/topotests/isis_te_topo1/test_isis_te_topo1.py b/tests/topotests/isis_te_topo1/test_isis_te_topo1.py index 9c70e05784fc..eb4f31012b2c 100644 --- a/tests/topotests/isis_te_topo1/test_isis_te_topo1.py +++ b/tests/topotests/isis_te_topo1/test_isis_te_topo1.py @@ -189,10 +189,18 @@ def test_step3(): tgen = setup_testcase("Step3: Add IPv6 on r1 and r2 interfaces") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth0" -c "ipv6 address 2001:db8:0::1/64"') - tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth0" -c "ipv6 router isis TE"') - tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth0" -c "ipv6 address 2001:db8:0::2/64"') - tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth0" -c "ipv6 router isis TE"') + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "interface r1-eth0" -c "ipv6 address 2001:db8:0::1/64"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "interface r1-eth0" -c "ipv6 router isis TE"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth0" -c "ipv6 address 2001:db8:0::2/64"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth0" -c "ipv6 router isis TE"' + ) for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step3.json") @@ -202,8 +210,12 @@ def test_step4(): tgen = setup_testcase("Step4: Modify Prefix SID on router r4") - tgen.net["r4"].cmd('vtysh -c "conf t" -c "router isis TE" -c "segment-routing prefix 10.0.255.4/32 index 40"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "router isis TE" -c "segment-routing prefix 2001:db8:ffff::4/128 index 1040"') + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "router isis TE" -c "segment-routing prefix 10.0.255.4/32 index 40"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "router isis TE" -c "segment-routing prefix 2001:db8:ffff::4/128 index 1040"' + ) for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step4.json") @@ -229,9 +241,15 @@ def test_step6(): tgen = setup_testcase("Step6: Modify link parameters on r2 & r4") - tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth3" -c "link-params" -c "no use-bw"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay 20000"') - tgen.net["r4"].cmd('vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay-variation 10000"') + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth3" -c "link-params" -c "no use-bw"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay 20000"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay-variation 10000"' + ) for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step6.json") diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step1/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step1/show_mpls_table.ref index aa0357d75000..f73b22d9d035 100644 --- a/tests/topotests/isis_tilfa_topo1/rt1/step1/show_mpls_table.ref +++ b/tests/topotests/isis_tilfa_topo1/rt1/step1/show_mpls_table.ref @@ -7,7 +7,8 @@ "type":"SR (IS-IS)", "outLabel":3, "installed":true, - "nexthop":"10.0.1.2" + "nexthop":"10.0.1.2", + "interface":"eth-sw1" } ] }, @@ -31,7 +32,8 @@ "type":"SR (IS-IS)", "outLabel":3, "installed":true, - "nexthop":"10.0.1.3" + "nexthop":"10.0.1.3", + "interface":"eth-sw1" } ] }, @@ -55,7 +57,8 @@ "type":"SR (IS-IS)", "outLabel":16040, "installed":true, - "nexthop":"10.0.1.2" + "nexthop":"10.0.1.2", + "interface":"eth-sw1" } ] }, @@ -79,7 +82,8 @@ "type":"SR (IS-IS)", "outLabel":16050, "installed":true, - "nexthop":"10.0.1.3" + "nexthop":"10.0.1.3", + "interface":"eth-sw1" } ] }, @@ -103,13 +107,15 @@ "type":"SR (IS-IS)", "outLabel":16060, "installed":true, - "nexthop":"10.0.1.3" + "nexthop":"10.0.1.3", + "interface":"eth-sw1" }, { "type":"SR (IS-IS)", "outLabel":16060, "installed":true, - "nexthop":"10.0.1.2" + "nexthop":"10.0.1.2", + "interface":"eth-sw1" } ] }, diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref index 9c5901b90ff1..fcef68cfe3df 100644 --- a/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref @@ -10,14 +10,14 @@ "adjacency": [ { "neighbor-sys-type": "level-1", - "neighbor-sysid": "0000.0000.0003", + "neighbor-sysid": "0000.0000.0002", "hold-timer": 10, "neighbor-priority": 64, "state": "up" }, { "neighbor-sys-type": "level-1", - "neighbor-sysid": "0000.0000.0002", + "neighbor-sysid": "0000.0000.0003", "hold-timer": 10, "neighbor-priority": 64, "state": "up" diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff deleted file mode 100644 index a8d6e6c65ee1..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff +++ /dev/null @@ -1,19 +0,0 @@ ---- a/rt1/step11/show_ip_route.ref -+++ b/rt1/step12/show_ip_route.ref -@@ -110,16 +110,6 @@ - "labels":[ - 16060 - ] -- }, -- { -- "fib":true, -- "ip":"10.0.1.3", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16060 -- ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff deleted file mode 100644 index 637c59f6ef6c..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff +++ /dev/null @@ -1,18 +0,0 @@ ---- a/rt1/step11/show_ipv6_route.ref -+++ b/rt1/step12/show_ipv6_route.ref -@@ -105,15 +105,6 @@ - "labels":[ - 16061 - ] -- }, -- { -- "fib":true, -- "afi":"ipv6", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16061 -- ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff deleted file mode 100644 index e110bf48eb87..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff +++ /dev/null @@ -1,28 +0,0 @@ ---- a/rt1/step11/show_mpls_table.ref -+++ b/rt1/step12/show_mpls_table.ref -@@ -79,12 +79,6 @@ - "type":"SR (IS-IS)", - "outLabel":16060, - "installed":true, -- "nexthop":"10.0.1.3" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16060, -- "installed":true, - "nexthop":"10.0.1.2" - } - ] -@@ -96,12 +90,6 @@ - { - "type":"SR (IS-IS)", - "outLabel":16061, -- "installed":true, -- "interface":"eth-sw1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16061, - "installed":true, - "interface":"eth-sw1" - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ip_route.ref new file mode 100644 index 000000000000..92b7437324a6 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ip_route.ref @@ -0,0 +1,294 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..3232121a0fce --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step2/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step2/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step2/show_mpls_table.ref new file mode 100644 index 000000000000..f73b22d9d035 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step2/show_mpls_table.ref @@ -0,0 +1,140 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ip_route.ref new file mode 100644 index 000000000000..92b7437324a6 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ip_route.ref @@ -0,0 +1,294 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..3232121a0fce --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step3/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step3/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step3/show_mpls_table.ref new file mode 100644 index 000000000000..f73b22d9d035 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step3/show_mpls_table.ref @@ -0,0 +1,140 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ip_route.ref new file mode 100644 index 000000000000..89e0b166b1e1 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ip_route.ref @@ -0,0 +1,291 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ip_route.ref.diff deleted file mode 100644 index 10b336f5b812..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ip_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step3/show_ip_route.ref -+++ b/rt1/step4/show_ip_route.ref -@@ -60,10 +60,7 @@ - "ip":"10.0.1.2", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..0358d5d6fcfc --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ipv6_route.ref @@ -0,0 +1,118 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ipv6_route.ref.diff deleted file mode 100644 index 904aaa1ce2a1..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_ipv6_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step3/show_ipv6_route.ref -+++ b/rt1/step4/show_ipv6_route.ref -@@ -57,10 +57,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16041 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_mpls_table.ref new file mode 100644 index 000000000000..d587d4203d55 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_mpls_table.ref @@ -0,0 +1,115 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step4/show_mpls_table.ref.diff deleted file mode 100644 index d7d875313105..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step4/show_mpls_table.ref.diff +++ /dev/null @@ -1,33 +0,0 @@ ---- a/rt1/step3/show_mpls_table.ref -+++ b/rt1/step4/show_mpls_table.ref -@@ -47,30 +47,6 @@ - } - ] - }, -- "16040":{ -- "inLabel":16040, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "installed":true, -- "nexthop":"10.0.1.2" -- } -- ] -- }, -- "16041":{ -- "inLabel":16041, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "installed":true, -- "interface":"eth-sw1" -- } -- ] -- }, - "16050":{ - "inLabel":16050, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ip_route.ref new file mode 100644 index 000000000000..92b7437324a6 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ip_route.ref @@ -0,0 +1,294 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ip_route.ref.diff deleted file mode 100644 index b583fa97bde2..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ip_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step4/show_ip_route.ref -+++ b/rt1/step5/show_ip_route.ref -@@ -60,7 +60,10 @@ - "ip":"10.0.1.2", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..3232121a0fce --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ipv6_route.ref.diff deleted file mode 100644 index d608abec9820..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_ipv6_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step4/show_ipv6_route.ref -+++ b/rt1/step5/show_ipv6_route.ref -@@ -57,7 +57,10 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16041 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_mpls_table.ref new file mode 100644 index 000000000000..f73b22d9d035 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_mpls_table.ref @@ -0,0 +1,140 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step5/show_mpls_table.ref.diff deleted file mode 100644 index b5161fcd55ba..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step5/show_mpls_table.ref.diff +++ /dev/null @@ -1,33 +0,0 @@ ---- a/rt1/step4/show_mpls_table.ref -+++ b/rt1/step5/show_mpls_table.ref -@@ -47,6 +47,30 @@ - } - ] - }, -+ "16040":{ -+ "inLabel":16040, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "installed":true, -+ "nexthop":"10.0.1.2" -+ } -+ ] -+ }, -+ "16041":{ -+ "inLabel":16041, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "installed":true, -+ "interface":"eth-sw1" -+ } -+ ] -+ }, - "16050":{ - "inLabel":16050, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ip_route.ref new file mode 100644 index 000000000000..92b7437324a6 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ip_route.ref @@ -0,0 +1,294 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..3232121a0fce --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step6/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step6/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step6/show_mpls_table.ref new file mode 100644 index 000000000000..f73b22d9d035 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step6/show_mpls_table.ref @@ -0,0 +1,140 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ip_route.ref new file mode 100644 index 000000000000..270fcef5d60d --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ip_route.ref @@ -0,0 +1,291 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ip_route.ref.diff deleted file mode 100644 index 726aed514fe2..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ip_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step6/show_ip_route.ref -+++ b/rt1/step7/show_ip_route.ref -@@ -83,10 +83,7 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..7ded014425c3 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ipv6_route.ref @@ -0,0 +1,118 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ipv6_route.ref.diff deleted file mode 100644 index 2049f6fa190a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_ipv6_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step6/show_ipv6_route.ref -+++ b/rt1/step7/show_ipv6_route.ref -@@ -79,10 +79,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_mpls_table.ref new file mode 100644 index 000000000000..b4ba438bf737 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_mpls_table.ref @@ -0,0 +1,115 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step7/show_mpls_table.ref.diff deleted file mode 100644 index 22301ba1ff87..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step7/show_mpls_table.ref.diff +++ /dev/null @@ -1,33 +0,0 @@ ---- a/rt1/step6/show_mpls_table.ref -+++ b/rt1/step7/show_mpls_table.ref -@@ -71,30 +71,6 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.1.3" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -- "interface":"eth-sw1" -- } -- ] -- }, - "16060":{ - "inLabel":16060, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ip_route.ref new file mode 100644 index 000000000000..92b7437324a6 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ip_route.ref @@ -0,0 +1,294 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ip_route.ref.diff deleted file mode 100644 index 4a1d4805a4e7..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ip_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step7/show_ip_route.ref -+++ b/rt1/step8/show_ip_route.ref -@@ -83,7 +83,10 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..3232121a0fce --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ipv6_route.ref.diff deleted file mode 100644 index eaece74e48b6..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_ipv6_route.ref.diff +++ /dev/null @@ -1,14 +0,0 @@ ---- a/rt1/step7/show_ipv6_route.ref -+++ b/rt1/step8/show_ipv6_route.ref -@@ -79,7 +79,10 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_mpls_table.ref new file mode 100644 index 000000000000..f73b22d9d035 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_mpls_table.ref @@ -0,0 +1,140 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step8/show_mpls_table.ref.diff deleted file mode 100644 index 46c17de01915..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step8/show_mpls_table.ref.diff +++ /dev/null @@ -1,33 +0,0 @@ ---- a/rt1/step7/show_mpls_table.ref -+++ b/rt1/step8/show_mpls_table.ref -@@ -71,6 +71,30 @@ - } - ] - }, -+ "16050":{ -+ "inLabel":16050, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "installed":true, -+ "nexthop":"10.0.1.3" -+ } -+ ] -+ }, -+ "16051":{ -+ "inLabel":16051, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "installed":true, -+ "interface":"eth-sw1" -+ } -+ ] -+ }, - "16060":{ - "inLabel":16060, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ip_route.ref new file mode 100644 index 000000000000..841c902a37df --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ip_route.ref @@ -0,0 +1,294 @@ +{ + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ip_route.ref.diff deleted file mode 100644 index 06efdc96ce59..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ip_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt1/step8/show_ip_route.ref -+++ b/rt1/step9/show_ip_route.ref -@@ -85,7 +85,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..4d35cf1d9ee3 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16501 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ipv6_route.ref.diff deleted file mode 100644 index a58f2d447cd6..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_ipv6_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt1/step8/show_ipv6_route.ref -+++ b/rt1/step9/show_ipv6_route.ref -@@ -81,7 +81,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16051 -+ 16501 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_mpls_table.ref new file mode 100644 index 000000000000..dc64494aa289 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_mpls_table.ref @@ -0,0 +1,140 @@ +{ + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16500":{ + "inLabel":16500, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16501":{ + "inLabel":16501, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "installed":true, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step9/show_mpls_table.ref.diff deleted file mode 100644 index c0a1ac592b51..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt1/step9/show_mpls_table.ref.diff +++ /dev/null @@ -1,64 +0,0 @@ ---- a/rt1/step8/show_mpls_table.ref -+++ b/rt1/step9/show_mpls_table.ref -@@ -71,30 +71,6 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.1.3" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -- "interface":"eth-sw1" -- } -- ] -- }, - "16060":{ - "inLabel":16060, - "installed":true, -@@ -129,6 +105,30 @@ - "installed":true, - "interface":"eth-sw1" - } -+ ] -+ }, -+ "16500":{ -+ "inLabel":16500, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16500, -+ "installed":true, -+ "nexthop":"10.0.1.3" -+ } -+ ] -+ }, -+ "16501":{ -+ "inLabel":16501, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16501, -+ "installed":true, -+ "interface":"eth-sw1" -+ } - ] - } - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step1/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step1/show_ipv6_route.ref index 6d31f6f26b8b..95432310fd4c 100644 --- a/tests/topotests/isis_tilfa_topo1/rt2/step1/show_ipv6_route.ref +++ b/tests/topotests/isis_tilfa_topo1/rt2/step1/show_ipv6_route.ref @@ -152,7 +152,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt4-1", + "interfaceName":"eth-sw1", "active":true, "labels":[ 16051 @@ -161,7 +161,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-sw1", + "interfaceName":"eth-rt4-1", "active":true, "labels":[ 16051 diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step1/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step1/show_mpls_table.ref index b9b906a31d9c..8580cb0e7c0c 100644 --- a/tests/topotests/isis_tilfa_topo1/rt2/step1/show_mpls_table.ref +++ b/tests/topotests/isis_tilfa_topo1/rt2/step1/show_mpls_table.ref @@ -8,6 +8,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.1.1", + "interface":"eth-sw1", "backupIndex":[ 0, 1 @@ -18,12 +19,14 @@ { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.2.4" + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" }, { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.3.4" + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" } ] }, @@ -64,6 +67,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.1.3", + "interface":"eth-sw1", "backupIndex":[ 0, 1 @@ -74,12 +78,14 @@ { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.2.4" + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" }, { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.3.4" + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" } ] }, @@ -120,6 +126,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", "backupIndex":[ 0 ] @@ -129,6 +136,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", "backupIndex":[ 0 ] @@ -138,7 +146,8 @@ { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.1.3" + "nexthop":"10.0.1.3", + "interface":"eth-sw1" } ] }, @@ -181,19 +190,22 @@ "type":"SR (IS-IS)", "outLabel":16050, "installed":true, - "nexthop":"10.0.3.4" + "nexthop":"10.0.1.3", + "interface":"eth-sw1" }, { "type":"SR (IS-IS)", "outLabel":16050, "installed":true, - "nexthop":"10.0.2.4" + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" }, { "type":"SR (IS-IS)", "outLabel":16050, "installed":true, - "nexthop":"10.0.1.3" + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" } ] }, @@ -205,19 +217,19 @@ "type":"SR (IS-IS)", "outLabel":16051, "installed":true, - "interface":"eth-rt4-2" + "interface":"eth-sw1" }, { "type":"SR (IS-IS)", "outLabel":16051, "installed":true, - "interface":"eth-rt4-1" + "interface":"eth-rt4-2" }, { "type":"SR (IS-IS)", "outLabel":16051, "installed":true, - "interface":"eth-sw1" + "interface":"eth-rt4-1" } ] }, @@ -230,6 +242,7 @@ "outLabel":16060, "installed":true, "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", "backupIndex":[ 0 ] @@ -239,6 +252,7 @@ "outLabel":16060, "installed":true, "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", "backupIndex":[ 0 ] @@ -248,7 +262,8 @@ { "type":"SR (IS-IS)", "outLabel":16060, - "nexthop":"10.0.1.3" + "nexthop":"10.0.1.3", + "interface":"eth-sw1" } ] }, diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff deleted file mode 100644 index 84a36442d35e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff +++ /dev/null @@ -1,20 +0,0 @@ ---- a/rt2/step11/show_mpls_table.ref -+++ b/rt2/step12/show_mpls_table.ref -@@ -199,7 +199,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16060, -+ "outLabel":16500, - "nexthop":"10.0.1.3" - } - ] -@@ -230,7 +230,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16061, -+ "outLabel":16501, - "interface":"eth-sw1" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ip_route.ref new file mode 100644 index 000000000000..374eec7d508a --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ip_route.ref @@ -0,0 +1,447 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050, + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ip_route.ref.diff deleted file mode 100644 index 90e0895639b2..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ip_route.ref.diff +++ /dev/null @@ -1,169 +0,0 @@ ---- a/rt2/step1/show_ip_route.ref -+++ b/rt2/step2/show_ip_route.ref -@@ -15,36 +15,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050, -- 16010 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050, -- 16010 -- ] -- } - ] - } - ], -@@ -64,36 +38,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050, -- 16030 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050, -- 16030 -- ] -- } - ] - } - ], -@@ -251,40 +199,12 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -+ "interfaceName":"eth-sw1" - }, - { - "ip":"10.0.1.3", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "interfaceName":"eth-sw1" - } - ] - } -@@ -380,24 +300,6 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true, -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", - "active":true - } - ] -@@ -418,24 +320,6 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true, -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", - "active":true - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..ca4f96f0d043 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ipv6_route.ref @@ -0,0 +1,181 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051, + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ipv6_route.ref.diff deleted file mode 100644 index 2d19f20f633f..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_ipv6_route.ref.diff +++ /dev/null @@ -1,72 +0,0 @@ ---- a/rt2/step1/show_ipv6_route.ref -+++ b/rt2/step2/show_ipv6_route.ref -@@ -14,34 +14,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051, -- 16011 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051, -- 16011 -- ] -- } - ] - } - ], -@@ -60,34 +36,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051, -- 16031 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051, -- 16031 -- ] -- } - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_mpls_table.ref new file mode 100644 index 000000000000..7b48e861f076 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_mpls_table.ref @@ -0,0 +1,233 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step2/show_mpls_table.ref.diff deleted file mode 100644 index 01fc74a60b75..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step2/show_mpls_table.ref.diff +++ /dev/null @@ -1,102 +0,0 @@ ---- a/rt2/step1/show_mpls_table.ref -+++ b/rt2/step2/show_mpls_table.ref -@@ -7,23 +7,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.1.1" - } - ] - }, -@@ -35,23 +19,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-2" -+ "interface":"eth-sw1" - } - ] - }, -@@ -63,23 +31,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.3", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.1.3" - } - ] - }, -@@ -91,23 +43,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-2" -+ "interface":"eth-sw1" - } - ] - }, diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ip_route.ref new file mode 100644 index 000000000000..7e1ccd10a2b7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16010 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16030 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050, + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ip_route.ref.diff deleted file mode 100644 index d93f03622910..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ip_route.ref.diff +++ /dev/null @@ -1,169 +0,0 @@ ---- a/rt2/step2/show_ip_route.ref -+++ b/rt2/step3/show_ip_route.ref -@@ -15,10 +15,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16010 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16010 -+ ] -+ } - ] - } - ], -@@ -38,10 +64,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16030 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16030 -+ ] -+ } - ] - } - ], -@@ -199,12 +251,40 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] - }, - { - "ip":"10.0.1.3", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -300,6 +380,24 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -+ "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", - "active":true - } - ] -@@ -320,6 +418,24 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -+ "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", - "active":true - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..95432310fd4c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16031 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051, + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ipv6_route.ref.diff deleted file mode 100644 index 68b618e91db7..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_ipv6_route.ref.diff +++ /dev/null @@ -1,72 +0,0 @@ ---- a/rt2/step2/show_ipv6_route.ref -+++ b/rt2/step3/show_ipv6_route.ref -@@ -14,10 +14,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16011 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16011 -+ ] -+ } - ] - } - ], -@@ -36,10 +60,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16031 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16031 -+ ] -+ } - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_mpls_table.ref new file mode 100644 index 000000000000..8580cb0e7c0c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step3/show_mpls_table.ref.diff deleted file mode 100644 index 966e153a6b6a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step3/show_mpls_table.ref.diff +++ /dev/null @@ -1,102 +0,0 @@ ---- a/rt2/step2/show_mpls_table.ref -+++ b/rt2/step3/show_mpls_table.ref -@@ -7,7 +7,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1" -+ "nexthop":"10.0.1.1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.3.4" - } - ] - }, -@@ -19,7 +35,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1" -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-2" - } - ] - }, -@@ -31,7 +63,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.3" -+ "nexthop":"10.0.1.3", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.3.4" - } - ] - }, -@@ -43,7 +91,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1" -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-2" - } - ] - }, diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ip_route.ref new file mode 100644 index 000000000000..c5fc51b8628a --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ip_route.ref @@ -0,0 +1,464 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ip_route.ref.diff deleted file mode 100644 index dd75d76b9bca..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ip_route.ref.diff +++ /dev/null @@ -1,192 +0,0 @@ ---- a/rt2/step3/show_ip_route.ref -+++ b/rt2/step4/show_ip_route.ref -@@ -15,36 +15,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050, -- 16010 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050, -- 16010 -- ] -- } - ] - } - ], -@@ -64,36 +38,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050, -- 16030 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050, -- 16030 -- ] -- } - ] - } - ], -@@ -115,9 +63,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - }, - { -@@ -128,9 +73,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -141,8 +83,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050, -- 16040 -+ 16050 - ] - } - ] -@@ -173,20 +114,14 @@ - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } -@@ -209,9 +144,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 16060 - ] - }, - { -@@ -222,9 +154,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 16060 - ] - } - ], -@@ -251,40 +180,12 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -+ "interfaceName":"eth-sw1" - }, - { - "ip":"10.0.1.3", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "interfaceName":"eth-sw1" - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..22bec0fa8c17 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ipv6_route.ref @@ -0,0 +1,162 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ipv6_route.ref.diff deleted file mode 100644 index 63731237ecb6..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_ipv6_route.ref.diff +++ /dev/null @@ -1,146 +0,0 @@ ---- a/rt2/step3/show_ipv6_route.ref -+++ b/rt2/step4/show_ipv6_route.ref -@@ -14,34 +14,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051, -- 16011 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051, -- 16011 -- ] -- } - ] - } - ], -@@ -60,34 +36,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051, -- 16031 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051, -- 16031 -- ] -- } - ] - } - ], -@@ -108,9 +60,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - }, - { -@@ -120,9 +69,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -132,8 +78,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16051, -- 16041 -+ 16051 - ] - } - ] -@@ -153,10 +98,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - }, - { - "fib":true, -@@ -171,10 +113,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } -@@ -196,9 +135,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 16061 - ] - }, - { -@@ -208,9 +144,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 16061 - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_mpls_table.ref new file mode 100644 index 000000000000..67f2b532b532 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_mpls_table.ref @@ -0,0 +1,142 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step4/show_mpls_table.ref.diff deleted file mode 100644 index 3872ce4980de..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step4/show_mpls_table.ref.diff +++ /dev/null @@ -1,200 +0,0 @@ ---- a/rt2/step3/show_mpls_table.ref -+++ b/rt2/step4/show_mpls_table.ref -@@ -7,23 +7,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.1.1" - } - ] - }, -@@ -35,23 +19,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-2" -+ "interface":"eth-sw1" - } - ] - }, -@@ -63,23 +31,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.3", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.1.3" - } - ] - }, -@@ -91,84 +43,6 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-2" -- } -- ] -- }, -- "16040":{ -- "inLabel":16040, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.3.4", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.2.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.1.3" -- } -- ] -- }, -- "16041":{ -- "inLabel":16041, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt4-2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt4-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, - "interface":"eth-sw1" - } - ] -@@ -181,18 +55,6 @@ - "type":"SR (IS-IS)", - "outLabel":16050, - "installed":true, -- "nexthop":"10.0.3.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, - "nexthop":"10.0.1.3" - } - ] -@@ -204,18 +66,6 @@ - { - "type":"SR (IS-IS)", - "outLabel":16051, -- "installed":true, -- "interface":"eth-rt4-2" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, - "installed":true, - "interface":"eth-sw1" - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ip_route.ref new file mode 100644 index 000000000000..7e1ccd10a2b7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16010 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16030 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050, + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ip_route.ref.diff deleted file mode 100644 index 4d5636436ca8..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ip_route.ref.diff +++ /dev/null @@ -1,192 +0,0 @@ ---- a/rt2/step4/show_ip_route.ref -+++ b/rt2/step5/show_ip_route.ref -@@ -15,10 +15,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16010 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16010 -+ ] -+ } - ] - } - ], -@@ -38,10 +64,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16030 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16030 -+ ] -+ } - ] - } - ], -@@ -63,6 +115,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - }, - { -@@ -73,6 +128,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -83,7 +141,8 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050 -+ 16050, -+ 16040 - ] - } - ] -@@ -114,14 +173,20 @@ - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -144,6 +209,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 16060 - ] - }, - { -@@ -154,6 +222,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 16060 - ] - } - ], -@@ -180,12 +251,40 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] - }, - { - "ip":"10.0.1.3", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..95432310fd4c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16031 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051, + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ipv6_route.ref.diff deleted file mode 100644 index f9e0276f85ae..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_ipv6_route.ref.diff +++ /dev/null @@ -1,146 +0,0 @@ ---- a/rt2/step4/show_ipv6_route.ref -+++ b/rt2/step5/show_ipv6_route.ref -@@ -14,10 +14,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16011 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16011 -+ ] -+ } - ] - } - ], -@@ -36,10 +60,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16031 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16031 -+ ] -+ } - ] - } - ], -@@ -60,6 +108,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - }, - { -@@ -69,6 +120,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -78,7 +132,8 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16051 -+ 16051, -+ 16041 - ] - } - ] -@@ -98,7 +153,10 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - }, - { - "fib":true, -@@ -113,7 +171,10 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } -@@ -135,6 +196,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 16061 - ] - }, - { -@@ -144,6 +208,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 16061 - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_mpls_table.ref new file mode 100644 index 000000000000..ecaaae18c031 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step5/show_mpls_table.ref.diff deleted file mode 100644 index 6aebbd6c82b6..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step5/show_mpls_table.ref.diff +++ /dev/null @@ -1,200 +0,0 @@ ---- a/rt2/step4/show_mpls_table.ref -+++ b/rt2/step5/show_mpls_table.ref -@@ -7,7 +7,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1" -+ "nexthop":"10.0.1.1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.3.4" - } - ] - }, -@@ -19,7 +35,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1" -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-2" - } - ] - }, -@@ -31,7 +63,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.3" -+ "nexthop":"10.0.1.3", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.3.4" - } - ] - }, -@@ -43,6 +91,84 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-2" -+ } -+ ] -+ }, -+ "16040":{ -+ "inLabel":16040, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.3.4", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.2.4", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.1.3" -+ } -+ ] -+ }, -+ "16041":{ -+ "inLabel":16041, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt4-2", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt4-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, - "interface":"eth-sw1" - } - ] -@@ -55,6 +181,18 @@ - "type":"SR (IS-IS)", - "outLabel":16050, - "installed":true, -+ "nexthop":"10.0.3.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "installed":true, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "installed":true, - "nexthop":"10.0.1.3" - } - ] -@@ -66,6 +204,18 @@ - { - "type":"SR (IS-IS)", - "outLabel":16051, -+ "installed":true, -+ "interface":"eth-rt4-2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "installed":true, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, - "installed":true, - "interface":"eth-sw1" - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ip_route.ref new file mode 100644 index 000000000000..7e1ccd10a2b7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16010 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16030 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050, + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..95432310fd4c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16031 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051, + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step6/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step6/show_mpls_table.ref new file mode 100644 index 000000000000..ecaaae18c031 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step6/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ip_route.ref new file mode 100644 index 000000000000..9459f2ebda17 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ip_route.ref @@ -0,0 +1,405 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1" + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ip_route.ref.diff deleted file mode 100644 index 5e73b978448d..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ip_route.ref.diff +++ /dev/null @@ -1,288 +0,0 @@ ---- a/rt2/step6/show_ip_route.ref -+++ b/rt2/step7/show_ip_route.ref -@@ -15,36 +15,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050, -- 16010 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050, -- 16010 -- ] -- } - ] - } - ], -@@ -64,36 +38,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050, -- 16030 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050, -- 16030 -- ] -- } - ] - } - ], -@@ -113,9 +61,6 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] -@@ -126,25 +71,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.3", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16050, -- 16040 -- ] -- } - ] - } - ], -@@ -163,30 +93,21 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } -@@ -251,40 +172,12 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -+ "interfaceName":"eth-sw1" - }, - { - "ip":"10.0.1.3", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.2.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16050 -- ] -- }, -- { -- "ip":"10.0.3.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "interfaceName":"eth-sw1" - } - ] - } -@@ -299,30 +192,13 @@ - { - "ip":"10.0.2.4", - "afi":"ipv4", -- "interfaceName":"eth-rt4-1", -- "backupIndex":[ -- 0 -- ] -+ "interfaceName":"eth-rt4-1" - }, - { - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.3", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } -@@ -338,29 +214,12 @@ - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "ip":"10.0.3.4", - "afi":"ipv4", -- "interfaceName":"eth-rt4-2", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.3", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "interfaceName":"eth-rt4-2" - } - ] - } -@@ -497,31 +356,14 @@ - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.3", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..a75e5850f0f9 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ipv6_route.ref @@ -0,0 +1,155 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ipv6_route.ref.diff deleted file mode 100644 index 5dc4e59151aa..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_ipv6_route.ref.diff +++ /dev/null @@ -1,139 +0,0 @@ ---- a/rt2/step6/show_ipv6_route.ref -+++ b/rt2/step7/show_ipv6_route.ref -@@ -14,34 +14,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051, -- 16011 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051, -- 16011 -- ] -- } - ] - } - ], -@@ -60,34 +36,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051, -- 16031 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051, -- 16031 -- ] -- } - ] - } - ], -@@ -106,9 +58,6 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] -@@ -118,24 +67,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16051, -- 16041 -- ] -- } - ] - } - ], -@@ -153,28 +88,19 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-1", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-2", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_mpls_table.ref new file mode 100644 index 000000000000..2c0139f8db32 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_mpls_table.ref @@ -0,0 +1,155 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step7/show_mpls_table.ref.diff deleted file mode 100644 index 6c0d7392f017..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step7/show_mpls_table.ref.diff +++ /dev/null @@ -1,207 +0,0 @@ ---- a/rt2/step6/show_mpls_table.ref -+++ b/rt2/step7/show_mpls_table.ref -@@ -7,23 +7,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.1.1" - } - ] - }, -@@ -35,23 +19,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-2" -+ "interface":"eth-sw1" - } - ] - }, -@@ -63,23 +31,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.3", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.1.3" - } - ] - }, -@@ -91,23 +43,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4-2" -+ "interface":"eth-sw1" - } - ] - }, -@@ -119,26 +55,13 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.3.4", -- "backupIndex":[ -- 0 -- ] -+ "nexthop":"10.0.3.4" - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.2.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.1.3" -+ "nexthop":"10.0.2.4" - } - ] - }, -@@ -150,74 +73,13 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt4-2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt4-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-sw1" -- } -- ] -- }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.3.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.1.3" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, - "interface":"eth-rt4-2" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":3, - "installed":true, - "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -- "interface":"eth-sw1" - } - ] - }, diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ip_route.ref new file mode 100644 index 000000000000..7e1ccd10a2b7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16010 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050, + 16030 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050, + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16050 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ip_route.ref.diff deleted file mode 100644 index f5df607613ed..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ip_route.ref.diff +++ /dev/null @@ -1,288 +0,0 @@ ---- a/rt2/step7/show_ip_route.ref -+++ b/rt2/step8/show_ip_route.ref -@@ -15,10 +15,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16010 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16010 -+ ] -+ } - ] - } - ], -@@ -38,10 +64,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16030 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16030 -+ ] -+ } - ] - } - ], -@@ -61,6 +113,9 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4-1", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] -@@ -71,10 +126,25 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4-2", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.3", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16050, -+ 16040 -+ ] -+ } - ] - } - ], -@@ -93,21 +163,30 @@ - "ip":"10.0.1.3", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - }, - { - "fib":true, - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -172,12 +251,40 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] - }, - { - "ip":"10.0.1.3", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.2.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] -+ }, -+ { -+ "ip":"10.0.3.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -192,13 +299,30 @@ - { - "ip":"10.0.2.4", - "afi":"ipv4", -- "interfaceName":"eth-rt4-1" -+ "interfaceName":"eth-rt4-1", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.3", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -214,12 +338,29 @@ - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.3.4", - "afi":"ipv4", -- "interfaceName":"eth-rt4-2" -+ "interfaceName":"eth-rt4-2", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.3", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -356,14 +497,31 @@ - "ip":"10.0.2.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.4", - "afi":"ipv4", - "interfaceName":"eth-rt4-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.3", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..95432310fd4c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051, + 16031 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051, + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16051 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ipv6_route.ref.diff deleted file mode 100644 index 125f36b1b449..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_ipv6_route.ref.diff +++ /dev/null @@ -1,139 +0,0 @@ ---- a/rt2/step7/show_ipv6_route.ref -+++ b/rt2/step8/show_ipv6_route.ref -@@ -14,10 +14,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16011 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16011 -+ ] -+ } - ] - } - ], -@@ -36,10 +60,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16031 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4-2", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16031 -+ ] -+ } - ] - } - ], -@@ -58,6 +106,9 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4-1", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] -@@ -67,10 +118,24 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4-2", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16051, -+ 16041 -+ ] -+ } - ] - } - ], -@@ -88,19 +153,28 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_mpls_table.ref new file mode 100644 index 000000000000..8580cb0e7c0c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16050, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16051, + "installed":true, + "interface":"eth-rt4-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step8/show_mpls_table.ref.diff deleted file mode 100644 index a1d5d795c552..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step8/show_mpls_table.ref.diff +++ /dev/null @@ -1,207 +0,0 @@ ---- a/rt2/step7/show_mpls_table.ref -+++ b/rt2/step8/show_mpls_table.ref -@@ -7,7 +7,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1" -+ "nexthop":"10.0.1.1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.3.4" - } - ] - }, -@@ -19,7 +35,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1" -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-2" - } - ] - }, -@@ -31,7 +63,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.3" -+ "nexthop":"10.0.1.3", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.3.4" - } - ] - }, -@@ -43,7 +91,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1" -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4-2" - } - ] - }, -@@ -55,13 +119,26 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.3.4" -+ "nexthop":"10.0.3.4", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.2.4" -+ "nexthop":"10.0.2.4", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.1.3" - } - ] - }, -@@ -73,13 +150,74 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt4-2" -+ "interface":"eth-rt4-2", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -+ "interface":"eth-rt4-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-sw1" -+ } -+ ] -+ }, -+ "16050":{ -+ "inLabel":16050, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "installed":true, -+ "nexthop":"10.0.3.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "installed":true, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "installed":true, -+ "nexthop":"10.0.1.3" -+ } -+ ] -+ }, -+ "16051":{ -+ "inLabel":16051, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "installed":true, -+ "interface":"eth-rt4-2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "installed":true, - "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "installed":true, -+ "interface":"eth-sw1" - } - ] - }, diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ip_route.ref new file mode 100644 index 000000000000..509615583362 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16500, + 16010 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16500, + 16010 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16500, + 16030 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16500, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16500, + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16500 + ] + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16500 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16500 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.3", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.2.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.4", + "afi":"ipv4", + "interfaceName":"eth-rt4-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ip_route.ref.diff deleted file mode 100644 index 2475c639c19a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ip_route.ref.diff +++ /dev/null @@ -1,119 +0,0 @@ ---- a/rt2/step8/show_ip_route.ref -+++ b/rt2/step9/show_ip_route.ref -@@ -31,7 +31,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16050, -+ 16500, - 16010 - ] - }, -@@ -41,7 +41,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16050, -+ 16500, - 16010 - ] - } -@@ -80,7 +80,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16050, -+ 16500, - 16030 - ] - }, -@@ -90,7 +90,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16050, -+ 16500, - 16030 - ] - } -@@ -141,7 +141,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050, -+ 16500, - 16040 - ] - } -@@ -165,7 +165,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - }, - { -@@ -175,7 +175,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - }, - { -@@ -185,7 +185,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] -@@ -274,7 +274,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - }, - { -@@ -283,7 +283,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] -@@ -321,7 +321,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] -@@ -359,7 +359,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] -@@ -520,7 +520,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..50e6a0a9f271 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16501, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16501, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16501, + 16031 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16501, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16501, + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16501 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "labels":[ + 16501 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "labels":[ + 16501 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ipv6_route.ref.diff deleted file mode 100644 index 2d21fbcde260..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_ipv6_route.ref.diff +++ /dev/null @@ -1,74 +0,0 @@ ---- a/rt2/step8/show_ipv6_route.ref -+++ b/rt2/step9/show_ipv6_route.ref -@@ -29,7 +29,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16051, -+ 16501, - 16011 - ] - }, -@@ -38,7 +38,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16051, -+ 16501, - 16011 - ] - } -@@ -75,7 +75,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16051, -+ 16501, - 16031 - ] - }, -@@ -84,7 +84,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16051, -+ 16501, - 16031 - ] - } -@@ -132,7 +132,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16051, -+ 16501, - 16041 - ] - } -@@ -155,7 +155,7 @@ - "interfaceName":"eth-rt4-1", - "active":true, - "labels":[ -- 16051 -+ 16501 - ] - }, - { -@@ -164,7 +164,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16051 -+ 16501 - ] - }, - { -@@ -173,7 +173,7 @@ - "interfaceName":"eth-rt4-2", - "active":true, - "labels":[ -- 16051 -+ 16501 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_mpls_table.ref new file mode 100644 index 000000000000..0bba1359484a --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-rt4-2" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-rt4-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-rt4-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + }, + "16500":{ + "inLabel":16500, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "installed":true, + "nexthop":"10.0.1.3", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16500, + "installed":true, + "nexthop":"10.0.3.4", + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16500, + "installed":true, + "nexthop":"10.0.2.4", + "interface":"eth-rt4-1" + } + ] + }, + "16501":{ + "inLabel":16501, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16501, + "installed":true, + "interface":"eth-rt4-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16501, + "installed":true, + "interface":"eth-rt4-1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step9/show_mpls_table.ref.diff deleted file mode 100644 index bc0ec3157ea2..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt2/step9/show_mpls_table.ref.diff +++ /dev/null @@ -1,182 +0,0 @@ ---- a/rt2/step8/show_mpls_table.ref -+++ b/rt2/step9/show_mpls_table.ref -@@ -17,12 +17,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":16500, - "nexthop":"10.0.2.4" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":16500, - "nexthop":"10.0.3.4" - } - ] -@@ -45,12 +45,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":16501, - "interface":"eth-rt4-1" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":16501, - "interface":"eth-rt4-2" - } - ] -@@ -73,12 +73,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":16500, - "nexthop":"10.0.2.4" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":16500, - "nexthop":"10.0.3.4" - } - ] -@@ -101,12 +101,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":16501, - "interface":"eth-rt4-1" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":16501, - "interface":"eth-rt4-2" - } - ] -@@ -137,7 +137,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":16500, - "nexthop":"10.0.1.3" - } - ] -@@ -168,55 +168,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-sw1" -- } -- ] -- }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.3.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.2.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "installed":true, -- "nexthop":"10.0.1.3" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -- "interface":"eth-rt4-2" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -- "interface":"eth-rt4-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "installed":true, -+ "outLabel":16501, - "interface":"eth-sw1" - } - ] -@@ -282,5 +234,53 @@ - "interface":"eth-sw1" - } - ] -+ }, -+ "16500":{ -+ "inLabel":16500, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16500, -+ "installed":true, -+ "nexthop":"10.0.3.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16500, -+ "installed":true, -+ "nexthop":"10.0.2.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16500, -+ "installed":true, -+ "nexthop":"10.0.1.3" -+ } -+ ] -+ }, -+ "16501":{ -+ "inLabel":16501, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16501, -+ "installed":true, -+ "interface":"eth-rt4-2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16501, -+ "installed":true, -+ "interface":"eth-rt4-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16501, -+ "installed":true, -+ "interface":"eth-sw1" -+ } -+ ] - } - } diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_ipv6_route.ref index 058d33609b89..45af4e067394 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_ipv6_route.ref +++ b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_ipv6_route.ref @@ -104,7 +104,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5-1", + "interfaceName":"eth-rt5-2", "active":true, "labels":[ 16041 @@ -113,7 +113,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-sw1", + "interfaceName":"eth-rt5-1", "active":true, "labels":[ 16041 @@ -122,7 +122,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5-2", + "interfaceName":"eth-sw1", "active":true, "labels":[ 16041 @@ -144,7 +144,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5-1", + "interfaceName":"eth-rt5-2", "active":true, "backupIndex":[ 0 @@ -156,7 +156,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5-2", + "interfaceName":"eth-rt5-1", "active":true, "backupIndex":[ 0 @@ -192,7 +192,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5-1", + "interfaceName":"eth-rt5-2", "active":true, "backupIndex":[ 0 @@ -204,7 +204,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5-2", + "interfaceName":"eth-rt5-1", "active":true, "backupIndex":[ 0 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_mpls_table.ref index 1912df3f050c..1b12d04f2daf 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_mpls_table.ref +++ b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_mpls_table.ref @@ -8,6 +8,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.1.1", + "interface":"eth-sw1", "backupIndex":[ 0, 1 @@ -18,12 +19,14 @@ { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.4.5" + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" }, { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.5.5" + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" } ] }, @@ -64,6 +67,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.1.2", + "interface":"eth-sw1", "backupIndex":[ 0, 1 @@ -74,12 +78,14 @@ { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.4.5" + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" }, { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.5.5" + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" } ] }, @@ -119,19 +125,22 @@ "type":"SR (IS-IS)", "outLabel":16040, "installed":true, - "nexthop":"10.0.5.5" + "nexthop":"10.0.1.2", + "interface":"eth-sw1" }, { "type":"SR (IS-IS)", "outLabel":16040, "installed":true, - "nexthop":"10.0.4.5" + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" }, { "type":"SR (IS-IS)", "outLabel":16040, "installed":true, - "nexthop":"10.0.1.2" + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" } ] }, @@ -143,19 +152,19 @@ "type":"SR (IS-IS)", "outLabel":16041, "installed":true, - "interface":"eth-rt5-2" + "interface":"eth-sw1" }, { "type":"SR (IS-IS)", "outLabel":16041, "installed":true, - "interface":"eth-rt5-1" + "interface":"eth-rt5-2" }, { "type":"SR (IS-IS)", "outLabel":16041, "installed":true, - "interface":"eth-sw1" + "interface":"eth-rt5-1" } ] }, @@ -168,6 +177,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", "backupIndex":[ 0 ] @@ -177,6 +187,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", "backupIndex":[ 0 ] @@ -186,7 +197,8 @@ { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.1.2" + "nexthop":"10.0.1.2", + "interface":"eth-sw1" } ] }, @@ -230,6 +242,7 @@ "outLabel":16060, "installed":true, "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", "backupIndex":[ 0 ] @@ -239,6 +252,7 @@ "outLabel":16060, "installed":true, "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", "backupIndex":[ 0 ] @@ -248,7 +262,8 @@ { "type":"SR (IS-IS)", "outLabel":16060, - "nexthop":"10.0.1.2" + "nexthop":"10.0.1.2", + "interface":"eth-sw1" } ] }, diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref index 777c74981970..2645827ec48f 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref +++ b/tests/topotests/isis_tilfa_topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref @@ -48,16 +48,16 @@ "adjacency": [ { "neighbor-sys-type": "level-1", - "neighbor-sysid": "0000.0000.0001", + "neighbor-sysid": "0000.0000.0002", "hold-timer": 10, - "neighbor-priority": 100, + "neighbor-priority": 64, "state": "up" }, { "neighbor-sys-type": "level-1", - "neighbor-sysid": "0000.0000.0002", + "neighbor-sysid": "0000.0000.0001", "hold-timer": 10, - "neighbor-priority": 64, + "neighbor-priority": 100, "state": "up" } ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff deleted file mode 100644 index 8695cf848f88..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff +++ /dev/null @@ -1,58 +0,0 @@ ---- a/rt3/step11/show_ip_route.ref -+++ b/rt3/step12/show_ip_route.ref -@@ -198,44 +198,37 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":30, -+ "metric":40, - "installed":true, - "nexthops":[ - { - "fib":true, -- "ip":"10.0.4.5", -+ "ip":"10.0.1.2", - "afi":"ipv4", -- "interfaceName":"eth-rt5-1", -+ "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ -- 30060 -+ 16060 - ] - }, - { - "fib":true, -- "ip":"10.0.5.5", -+ "ip":"10.0.4.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5-2", -+ "interfaceName":"eth-rt5-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 30060 - ] -- } -- ], -- "backupNexthops":[ -+ }, - { -- "ip":"10.0.1.2", -+ "fib":true, -+ "ip":"10.0.5.5", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -+ "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16060 -+ 30060 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff deleted file mode 100644 index 661d0fe75de3..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff +++ /dev/null @@ -1,45 +0,0 @@ ---- a/rt3/step11/show_ipv6_route.ref -+++ b/rt3/step12/show_ipv6_route.ref -@@ -186,7 +186,7 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":30, -+ "metric":40, - "installed":true, - "nexthops":[ - { -@@ -194,9 +194,6 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 30061 - ] -@@ -206,23 +203,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 30061 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16061 -- ] -- } - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff deleted file mode 100644 index 30941b398b7e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff +++ /dev/null @@ -1,60 +0,0 @@ ---- a/rt3/step11/show_mpls_table.ref -+++ b/rt3/step12/show_mpls_table.ref -@@ -165,27 +165,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30060, -- "installed":true, -- "nexthop":"10.0.5.5", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":30060, -- "installed":true, -- "nexthop":"10.0.4.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16060, -+ "installed":true, - "nexthop":"10.0.1.2" - } - ] -@@ -196,27 +177,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30061, -- "installed":true, -- "interface":"eth-rt5-2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":30061, -- "installed":true, -- "interface":"eth-rt5-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16061, -+ "installed":true, - "interface":"eth-sw1" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ip_route.ref new file mode 100644 index 000000000000..d70e9fe882e2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040, + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..45af4e067394 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041, + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step2/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_mpls_table.ref new file mode 100644 index 000000000000..1b12d04f2daf --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step2/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step2/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ip_route.ref new file mode 100644 index 000000000000..d70e9fe882e2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040, + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..45af4e067394 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041, + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step3/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_mpls_table.ref new file mode 100644 index 000000000000..1b12d04f2daf --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step3/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step3/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ip_route.ref new file mode 100644 index 000000000000..5f8779966fa9 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ip_route.ref @@ -0,0 +1,405 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1" + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1" + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1" + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ip_route.ref.diff deleted file mode 100644 index 9ba73b057a0e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ip_route.ref.diff +++ /dev/null @@ -1,288 +0,0 @@ ---- a/rt3/step3/show_ip_route.ref -+++ b/rt3/step4/show_ip_route.ref -@@ -15,36 +15,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.4.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16040, -- 16010 -- ] -- }, -- { -- "ip":"10.0.5.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16040, -- 16010 -- ] -- } - ] - } - ], -@@ -64,36 +38,10 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.4.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16040, -- 16020 -- ] -- }, -- { -- "ip":"10.0.5.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16040, -- 16020 -- ] -- } - ] - } - ], -@@ -112,30 +60,21 @@ - "ip":"10.0.1.2", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.4.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.5.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - } - ] - } -@@ -156,9 +95,6 @@ - "afi":"ipv4", - "interfaceName":"eth-rt5-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] -@@ -169,25 +105,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt5-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.2", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16040, -- 16050 -- ] -- } - ] - } - ], -@@ -251,40 +172,12 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -+ "interfaceName":"eth-sw1" - }, - { - "ip":"10.0.1.2", - "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.4.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16040 -- ] -- }, -- { -- "ip":"10.0.5.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "interfaceName":"eth-sw1" - } - ] - } -@@ -375,30 +268,13 @@ - { - "ip":"10.0.4.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5-1", -- "backupIndex":[ -- 0 -- ] -+ "interfaceName":"eth-rt5-1" - }, - { - "ip":"10.0.5.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.2", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - } - ] - } -@@ -414,29 +290,12 @@ - "ip":"10.0.4.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "ip":"10.0.5.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5-2", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.2", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "interfaceName":"eth-rt5-2" - } - ] - } -@@ -531,31 +390,14 @@ - "ip":"10.0.4.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.5.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.1.2", -- "afi":"ipv4", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..91426403e8e4 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ipv6_route.ref @@ -0,0 +1,155 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ipv6_route.ref.diff deleted file mode 100644 index 04f61c4eb40b..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_ipv6_route.ref.diff +++ /dev/null @@ -1,139 +0,0 @@ ---- a/rt3/step3/show_ipv6_route.ref -+++ b/rt3/step4/show_ipv6_route.ref -@@ -14,34 +14,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16041, -- 16011 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16041, -- 16011 -- ] -- } - ] - } - ], -@@ -60,34 +36,10 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -- "backupIndex":[ -- 0, -- 1 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16041, -- 16021 -- ] -- }, -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16041, -- 16021 -- ] -- } - ] - } - ], -@@ -105,28 +57,19 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5-1", -- "active":true, -- "labels":[ -- 16041 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16041 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5-2", -- "active":true, -- "labels":[ -- 16041 -- ] -+ "active":true - } - ] - } -@@ -146,9 +89,6 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] -@@ -158,24 +98,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-sw1", -- "active":true, -- "labels":[ -- 16041, -- 16051 -- ] -- } - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_mpls_table.ref new file mode 100644 index 000000000000..0a6e3169bf70 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_mpls_table.ref @@ -0,0 +1,155 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step4/show_mpls_table.ref.diff deleted file mode 100644 index b3588ca79132..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step4/show_mpls_table.ref.diff +++ /dev/null @@ -1,206 +0,0 @@ ---- a/rt3/step3/show_mpls_table.ref -+++ b/rt3/step4/show_mpls_table.ref -@@ -7,23 +7,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.4.5" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.5.5" -+ "nexthop":"10.0.1.1" - } - ] - }, -@@ -35,23 +19,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt5-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt5-2" -+ "interface":"eth-sw1" - } - ] - }, -@@ -63,23 +31,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.2", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.4.5" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.5.5" -+ "nexthop":"10.0.1.2" - } - ] - }, -@@ -91,70 +43,6 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1", -- "backupIndex":[ -- 0, -- 1 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt5-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt5-2" -- } -- ] -- }, -- "16040":{ -- "inLabel":16040, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "installed":true, -- "nexthop":"10.0.5.5" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "installed":true, -- "nexthop":"10.0.4.5" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "installed":true, -- "nexthop":"10.0.1.2" -- } -- ] -- }, -- "16041":{ -- "inLabel":16041, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "installed":true, -- "interface":"eth-rt5-2" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "installed":true, -- "interface":"eth-rt5-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "installed":true, - "interface":"eth-sw1" - } - ] -@@ -167,26 +55,13 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.5.5", -- "backupIndex":[ -- 0 -- ] -+ "nexthop":"10.0.5.5" - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.4.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.1.2" -+ "nexthop":"10.0.4.5" - } - ] - }, -@@ -198,26 +73,13 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt5-2", -- "backupIndex":[ -- 0 -- ] -+ "interface":"eth-rt5-2" - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt5-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-sw1" -+ "interface":"eth-rt5-1" - } - ] - }, diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ip_route.ref new file mode 100644 index 000000000000..d70e9fe882e2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040, + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ip_route.ref.diff deleted file mode 100644 index 1af024fc2e78..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ip_route.ref.diff +++ /dev/null @@ -1,288 +0,0 @@ ---- a/rt3/step4/show_ip_route.ref -+++ b/rt3/step5/show_ip_route.ref -@@ -15,10 +15,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.4.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5-1", -+ "active":true, -+ "labels":[ -+ 16040, -+ 16010 -+ ] -+ }, -+ { -+ "ip":"10.0.5.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5-2", -+ "active":true, -+ "labels":[ -+ 16040, -+ 16010 -+ ] -+ } - ] - } - ], -@@ -38,10 +64,36 @@ - "afi":"ipv4", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.4.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5-1", -+ "active":true, -+ "labels":[ -+ 16040, -+ 16020 -+ ] -+ }, -+ { -+ "ip":"10.0.5.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5-2", -+ "active":true, -+ "labels":[ -+ 16040, -+ 16020 -+ ] -+ } - ] - } - ], -@@ -60,21 +112,30 @@ - "ip":"10.0.1.2", - "afi":"ipv4", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - }, - { - "fib":true, - "ip":"10.0.4.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - }, - { - "fib":true, - "ip":"10.0.5.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } -@@ -95,6 +156,9 @@ - "afi":"ipv4", - "interfaceName":"eth-rt5-1", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] -@@ -105,10 +169,25 @@ - "afi":"ipv4", - "interfaceName":"eth-rt5-2", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16040, -+ 16050 -+ ] -+ } - ] - } - ], -@@ -172,12 +251,40 @@ - { - "ip":"10.0.1.1", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] - }, - { - "ip":"10.0.1.2", - "afi":"ipv4", -- "interfaceName":"eth-sw1" -+ "interfaceName":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.4.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5-1", -+ "active":true, -+ "labels":[ -+ 16040 -+ ] -+ }, -+ { -+ "ip":"10.0.5.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5-2", -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } -@@ -268,13 +375,30 @@ - { - "ip":"10.0.4.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5-1" -+ "interfaceName":"eth-rt5-1", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.5.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } -@@ -290,12 +414,29 @@ - "ip":"10.0.4.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.5.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5-2" -+ "interfaceName":"eth-rt5-2", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } -@@ -390,14 +531,31 @@ - "ip":"10.0.4.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "fib":true, - "ip":"10.0.5.5", - "afi":"ipv4", - "interfaceName":"eth-rt5-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.1.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..45af4e067394 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 16041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 16041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041, + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ipv6_route.ref.diff deleted file mode 100644 index 7cc79d0e5858..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_ipv6_route.ref.diff +++ /dev/null @@ -1,139 +0,0 @@ ---- a/rt3/step4/show_ipv6_route.ref -+++ b/rt3/step5/show_ipv6_route.ref -@@ -14,10 +14,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5-1", -+ "active":true, -+ "labels":[ -+ 16041, -+ 16011 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5-2", -+ "active":true, -+ "labels":[ -+ 16041, -+ 16011 -+ ] -+ } - ] - } - ], -@@ -36,10 +60,34 @@ - "afi":"ipv6", - "interfaceName":"eth-sw1", - "active":true, -+ "backupIndex":[ -+ 0, -+ 1 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5-1", -+ "active":true, -+ "labels":[ -+ 16041, -+ 16021 -+ ] -+ }, -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5-2", -+ "active":true, -+ "labels":[ -+ 16041, -+ 16021 -+ ] -+ } - ] - } - ], -@@ -57,19 +105,28 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16041 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-sw1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16041 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16041 -+ ] - } - ] - } -@@ -89,6 +146,9 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5-1", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] -@@ -98,10 +158,24 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5-2", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-sw1", -+ "active":true, -+ "labels":[ -+ 16041, -+ 16051 -+ ] -+ } - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_mpls_table.ref new file mode 100644 index 000000000000..1b12d04f2daf --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step5/show_mpls_table.ref.diff deleted file mode 100644 index 75a0f01f5514..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step5/show_mpls_table.ref.diff +++ /dev/null @@ -1,206 +0,0 @@ ---- a/rt3/step4/show_mpls_table.ref -+++ b/rt3/step5/show_mpls_table.ref -@@ -7,7 +7,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.1" -+ "nexthop":"10.0.1.1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.4.5" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.5.5" - } - ] - }, -@@ -19,7 +35,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-sw1" -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-rt5-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-rt5-2" - } - ] - }, -@@ -31,7 +63,23 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.1.2" -+ "nexthop":"10.0.1.2", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.4.5" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.5.5" - } - ] - }, -@@ -43,6 +91,70 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -+ "interface":"eth-sw1", -+ "backupIndex":[ -+ 0, -+ 1 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-rt5-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-rt5-2" -+ } -+ ] -+ }, -+ "16040":{ -+ "inLabel":16040, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "installed":true, -+ "nexthop":"10.0.5.5" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "installed":true, -+ "nexthop":"10.0.4.5" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "installed":true, -+ "nexthop":"10.0.1.2" -+ } -+ ] -+ }, -+ "16041":{ -+ "inLabel":16041, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "installed":true, -+ "interface":"eth-rt5-2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "installed":true, -+ "interface":"eth-rt5-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "installed":true, - "interface":"eth-sw1" - } - ] -@@ -55,13 +167,26 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.5.5" -+ "nexthop":"10.0.5.5", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.4.5" -+ "nexthop":"10.0.4.5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.1.2" - } - ] - }, -@@ -73,13 +198,26 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt5-2" -+ "interface":"eth-rt5-2", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt5-1" -+ "interface":"eth-rt5-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-sw1" - } - ] - }, diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ip_route.ref new file mode 100644 index 000000000000..e6d99e59e377 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040, + 30050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ip_route.ref.diff deleted file mode 100644 index c814a2876b4d..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ip_route.ref.diff +++ /dev/null @@ -1,101 +0,0 @@ ---- a/rt3/step5/show_ip_route.ref -+++ b/rt3/step6/show_ip_route.ref -@@ -31,7 +31,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16040, -+ 30040, - 16010 - ] - }, -@@ -41,7 +41,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16040, -+ 30040, - 16010 - ] - } -@@ -80,7 +80,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16040, -+ 30040, - 16020 - ] - }, -@@ -90,7 +90,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16040, -+ 30040, - 16020 - ] - } -@@ -124,7 +124,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16040 -+ 30040 - ] - }, - { -@@ -134,7 +134,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16040 -+ 30040 - ] - } - ] -@@ -185,7 +185,7 @@ - "active":true, - "labels":[ - 16040, -- 16050 -+ 30050 - ] - } - ] -@@ -211,7 +211,7 @@ - 0 - ], - "labels":[ -- 16060 -+ 30060 - ] - }, - { -@@ -224,7 +224,7 @@ - 0 - ], - "labels":[ -- 16060 -+ 30060 - ] - } - ], -@@ -274,7 +274,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16040 -+ 30040 - ] - }, - { -@@ -283,7 +283,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16040 -+ 30040 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..f844d5a49efa --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041, + 30051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ipv6_route.ref.diff deleted file mode 100644 index 6f9405f20ce9..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_ipv6_route.ref.diff +++ /dev/null @@ -1,83 +0,0 @@ ---- a/rt3/step5/show_ipv6_route.ref -+++ b/rt3/step6/show_ipv6_route.ref -@@ -29,7 +29,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16041, -+ 30041, - 16011 - ] - }, -@@ -38,7 +38,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16041, -+ 30041, - 16011 - ] - } -@@ -75,7 +75,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16041, -+ 30041, - 16021 - ] - }, -@@ -84,7 +84,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16041, -+ 30041, - 16021 - ] - } -@@ -107,7 +107,7 @@ - "interfaceName":"eth-rt5-1", - "active":true, - "labels":[ -- 16041 -+ 30041 - ] - }, - { -@@ -125,7 +125,7 @@ - "interfaceName":"eth-rt5-2", - "active":true, - "labels":[ -- 16041 -+ 30041 - ] - } - ] -@@ -173,7 +173,7 @@ - "active":true, - "labels":[ - 16041, -- 16051 -+ 30051 - ] - } - ] -@@ -198,7 +198,7 @@ - 0 - ], - "labels":[ -- 16061 -+ 30061 - ] - }, - { -@@ -210,7 +210,7 @@ - 0 - ], - "labels":[ -- 16061 -+ 30061 - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_mpls_table.ref new file mode 100644 index 000000000000..052a5a1cc198 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step6/show_mpls_table.ref.diff deleted file mode 100644 index d8c39685de7c..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step6/show_mpls_table.ref.diff +++ /dev/null @@ -1,130 +0,0 @@ ---- a/rt3/step5/show_mpls_table.ref -+++ b/rt3/step6/show_mpls_table.ref -@@ -17,12 +17,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "nexthop":"10.0.4.5" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "nexthop":"10.0.5.5" - } - ] -@@ -45,12 +45,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "interface":"eth-rt5-1" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "interface":"eth-rt5-2" - } - ] -@@ -73,12 +73,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "nexthop":"10.0.4.5" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "nexthop":"10.0.5.5" - } - ] -@@ -101,12 +101,12 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "interface":"eth-rt5-1" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "interface":"eth-rt5-2" - } - ] -@@ -117,13 +117,13 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "installed":true, - "nexthop":"10.0.5.5" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "installed":true, - "nexthop":"10.0.4.5" - }, -@@ -141,13 +141,13 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "installed":true, - "interface":"eth-rt5-2" - }, - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "installed":true, - "interface":"eth-rt5-1" - }, -@@ -227,7 +227,7 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16060, -+ "outLabel":30060, - "installed":true, - "nexthop":"10.0.5.5", - "backupIndex":[ -@@ -236,7 +236,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":16060, -+ "outLabel":30060, - "installed":true, - "nexthop":"10.0.4.5", - "backupIndex":[ -@@ -258,7 +258,7 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16061, -+ "outLabel":30061, - "installed":true, - "interface":"eth-rt5-2", - "backupIndex":[ -@@ -267,7 +267,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":16061, -+ "outLabel":30061, - "installed":true, - "interface":"eth-rt5-1", - "backupIndex":[ diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ip_route.ref new file mode 100644 index 000000000000..fd340ba96230 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ip_route.ref @@ -0,0 +1,556 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ip_route.ref.diff deleted file mode 100644 index c928fcdb4bf1..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ip_route.ref.diff +++ /dev/null @@ -1,32 +0,0 @@ ---- a/rt3/step6/show_ip_route.ref -+++ b/rt3/step7/show_ip_route.ref -@@ -158,9 +158,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - }, - { -@@ -171,9 +168,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -184,8 +178,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16040, -- 30050 -+ 16040 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..27be6929fb09 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ipv6_route.ref @@ -0,0 +1,222 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ipv6_route.ref.diff deleted file mode 100644 index 0170971781cf..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_ipv6_route.ref.diff +++ /dev/null @@ -1,32 +0,0 @@ ---- a/rt3/step6/show_ipv6_route.ref -+++ b/rt3/step7/show_ipv6_route.ref -@@ -148,9 +148,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - }, - { -@@ -160,9 +157,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -172,8 +166,7 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16041, -- 30051 -+ 16041 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_mpls_table.ref new file mode 100644 index 000000000000..1d8d1d0cb7f8 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_mpls_table.ref @@ -0,0 +1,236 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step7/show_mpls_table.ref.diff deleted file mode 100644 index d7a3ed978f36..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step7/show_mpls_table.ref.diff +++ /dev/null @@ -1,71 +0,0 @@ ---- a/rt3/step6/show_mpls_table.ref -+++ b/rt3/step7/show_mpls_table.ref -@@ -159,68 +159,6 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.5.5", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.4.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.1.2" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt5-2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt5-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-sw1" -- } -- ] -- }, - "16060":{ - "inLabel":16060, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ip_route.ref new file mode 100644 index 000000000000..e6d99e59e377 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040, + 30050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ip_route.ref.diff deleted file mode 100644 index 41a7ff32552e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ip_route.ref.diff +++ /dev/null @@ -1,32 +0,0 @@ ---- a/rt3/step7/show_ip_route.ref -+++ b/rt3/step8/show_ip_route.ref -@@ -158,6 +158,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - }, - { -@@ -168,6 +171,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -178,7 +184,8 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16040 -+ 16040, -+ 30050 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..f844d5a49efa --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041, + 30051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ipv6_route.ref.diff deleted file mode 100644 index bd49f8606ba8..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_ipv6_route.ref.diff +++ /dev/null @@ -1,32 +0,0 @@ ---- a/rt3/step7/show_ipv6_route.ref -+++ b/rt3/step8/show_ipv6_route.ref -@@ -148,6 +148,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - }, - { -@@ -157,6 +160,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -166,7 +172,8 @@ - "interfaceName":"eth-sw1", - "active":true, - "labels":[ -- 16041 -+ 16041, -+ 30051 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_mpls_table.ref new file mode 100644 index 000000000000..052a5a1cc198 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-sw1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step8/show_mpls_table.ref.diff deleted file mode 100644 index 4cc69b66f24d..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step8/show_mpls_table.ref.diff +++ /dev/null @@ -1,71 +0,0 @@ ---- a/rt3/step7/show_mpls_table.ref -+++ b/rt3/step8/show_mpls_table.ref -@@ -159,6 +159,68 @@ - } - ] - }, -+ "16050":{ -+ "inLabel":16050, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.5.5", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.4.5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.1.2" -+ } -+ ] -+ }, -+ "16051":{ -+ "inLabel":16051, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt5-2", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt5-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-sw1" -+ } -+ ] -+ }, - "16060":{ - "inLabel":16060, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ip_route.ref new file mode 100644 index 000000000000..a9590ee0fc94 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ip_route.ref @@ -0,0 +1,563 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16010 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040, + 16020 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040, + 16020 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040, + 30500 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30060 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.1.1", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + }, + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30040 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true + }, + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.5", + "afi":"ipv4", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.1.2", + "afi":"ipv4", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ip_route.ref.diff deleted file mode 100644 index cc0a482eee4e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ip_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt3/step8/show_ip_route.ref -+++ b/rt3/step9/show_ip_route.ref -@@ -185,7 +185,7 @@ - "active":true, - "labels":[ - 16040, -- 30050 -+ 30500 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..ce635407d5c9 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ipv6_route.ref @@ -0,0 +1,229 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16011 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "backupIndex":[ + 0, + 1 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041, + 16021 + ] + }, + { + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "labels":[ + 30041 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16041, + 30501 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30061 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-sw1", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ipv6_route.ref.diff deleted file mode 100644 index 650b982f0b62..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_ipv6_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt3/step8/show_ipv6_route.ref -+++ b/rt3/step9/show_ipv6_route.ref -@@ -173,7 +173,7 @@ - "active":true, - "labels":[ - 16041, -- 30051 -+ 30501 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_mpls_table.ref new file mode 100644 index 000000000000..a364c2e4caac --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.1", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-sw1", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5-2" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "installed":true, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30040, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "installed":true, + "interface":"eth-sw1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":30041, + "installed":true, + "interface":"eth-rt5-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30060, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":30061, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-sw1" + } + ] + }, + "16500":{ + "inLabel":16500, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.5", + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.5", + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.1.2", + "interface":"eth-sw1" + } + ] + }, + "16501":{ + "inLabel":16501, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-sw1" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step9/show_mpls_table.ref.diff deleted file mode 100644 index 8ce4f1d26610..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt3/step9/show_mpls_table.ref.diff +++ /dev/null @@ -1,133 +0,0 @@ ---- a/rt3/step8/show_mpls_table.ref -+++ b/rt3/step9/show_mpls_table.ref -@@ -159,13 +159,13 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -+ "16060":{ -+ "inLabel":16060, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":30060, - "installed":true, - "nexthop":"10.0.5.5", - "backupIndex":[ -@@ -174,7 +174,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":30060, - "installed":true, - "nexthop":"10.0.4.5", - "backupIndex":[ -@@ -185,18 +185,18 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":16060, - "nexthop":"10.0.1.2" - } - ] - }, -- "16051":{ -- "inLabel":16051, -+ "16061":{ -+ "inLabel":16061, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":30061, - "installed":true, - "interface":"eth-rt5-2", - "backupIndex":[ -@@ -205,7 +205,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":30061, - "installed":true, - "interface":"eth-rt5-1", - "backupIndex":[ -@@ -216,18 +216,18 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":16061, - "interface":"eth-sw1" - } - ] - }, -- "16060":{ -- "inLabel":16060, -+ "16500":{ -+ "inLabel":16500, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30060, -+ "outLabel":3, - "installed":true, - "nexthop":"10.0.5.5", - "backupIndex":[ -@@ -236,7 +236,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":30060, -+ "outLabel":3, - "installed":true, - "nexthop":"10.0.4.5", - "backupIndex":[ -@@ -247,18 +247,18 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16060, -+ "outLabel":16040, - "nexthop":"10.0.1.2" - } - ] - }, -- "16061":{ -- "inLabel":16061, -+ "16501":{ -+ "inLabel":16501, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30061, -+ "outLabel":3, - "installed":true, - "interface":"eth-rt5-2", - "backupIndex":[ -@@ -267,7 +267,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":30061, -+ "outLabel":3, - "installed":true, - "interface":"eth-rt5-1", - "backupIndex":[ -@@ -278,7 +278,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16061, -+ "outLabel":16041, - "interface":"eth-sw1" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step1/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step1/show_ipv6_route.ref index b640df30c1fb..c757031881e2 100644 --- a/tests/topotests/isis_tilfa_topo1/rt4/step1/show_ipv6_route.ref +++ b/tests/topotests/isis_tilfa_topo1/rt4/step1/show_ipv6_route.ref @@ -12,7 +12,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt2-2", + "interfaceName":"eth-rt2-1", "active":true, "backupIndex":[ 0 @@ -24,7 +24,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt2-1", + "interfaceName":"eth-rt2-2", "active":true, "backupIndex":[ 0 @@ -59,7 +59,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt2-2", + "interfaceName":"eth-rt2-1", "active":true, "backupIndex":[ 0 @@ -71,7 +71,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt2-1", + "interfaceName":"eth-rt2-2", "active":true, "backupIndex":[ 0 @@ -107,7 +107,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt2-2", + "interfaceName":"eth-rt2-1", "active":true, "labels":[ 16031 @@ -116,7 +116,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt2-1", + "interfaceName":"eth-rt2-2", "active":true, "labels":[ 16031 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step1/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step1/show_mpls_table.ref index f60937ccbcd7..2a709070e472 100644 --- a/tests/topotests/isis_tilfa_topo1/rt4/step1/show_mpls_table.ref +++ b/tests/topotests/isis_tilfa_topo1/rt4/step1/show_mpls_table.ref @@ -8,6 +8,7 @@ "outLabel":16010, "installed":true, "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", "backupIndex":[ 0 ] @@ -17,6 +18,7 @@ "outLabel":16010, "installed":true, "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", "backupIndex":[ 0 ] @@ -26,7 +28,8 @@ { "type":"SR (IS-IS)", "outLabel":16010, - "nexthop":"10.0.6.5" + "nexthop":"10.0.6.5", + "interface":"eth-rt5" } ] }, @@ -70,6 +73,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", "backupIndex":[ 0 ] @@ -79,6 +83,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", "backupIndex":[ 0 ] @@ -88,7 +93,8 @@ { "type":"SR (IS-IS)", "outLabel":16030, - "nexthop":"10.0.6.5" + "nexthop":"10.0.6.5", + "interface":"eth-rt5" } ] }, @@ -131,19 +137,22 @@ "type":"SR (IS-IS)", "outLabel":16030, "installed":true, - "nexthop":"10.0.3.2" + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" }, { "type":"SR (IS-IS)", "outLabel":16030, "installed":true, - "nexthop":"10.0.2.2" + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" }, { "type":"SR (IS-IS)", "outLabel":16030, "installed":true, - "nexthop":"10.0.6.5" + "nexthop":"10.0.6.5", + "interface":"eth-rt5" } ] }, @@ -180,6 +189,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.6.5", + "interface":"eth-rt5", "backupIndex":[ 0 ] @@ -189,7 +199,8 @@ { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.7.6" + "nexthop":"10.0.7.6", + "interface":"eth-rt6" } ] }, @@ -224,6 +235,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.7.6", + "interface":"eth-rt6", "backupIndex":[ 0 ] @@ -233,7 +245,8 @@ { "type":"SR (IS-IS)", "outLabel":16060, - "nexthop":"10.0.6.5" + "nexthop":"10.0.6.5", + "interface":"eth-rt5" } ] }, diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff deleted file mode 100644 index 2645c5945b51..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff +++ /dev/null @@ -1,144 +0,0 @@ ---- a/rt4/step11/show_ip_route.ref -+++ b/rt4/step12/show_ip_route.ref -@@ -160,23 +160,13 @@ - "interfaceName":"eth-rt5", - "active":true, - "backupIndex":[ -- 0 -+ 0, -+ 1 - ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16500 -- ] -- } - ] - } - ], -@@ -196,24 +186,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt6", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30060 -- ] -- } - ] - } - ], -@@ -352,19 +328,12 @@ - "active":true, - "backupIndex":[ - 0, -- 1, -- 2 -+ 1 - ] - } - ], - "backupNexthops":[ - { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- }, -- { - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -@@ -397,19 +366,12 @@ - "active":true, - "backupIndex":[ - 0, -- 1, -- 2 -+ 1 - ] - } - ], - "backupNexthops":[ - { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- }, -- { - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -@@ -439,14 +401,6 @@ - 0 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- } - ] - } - ], -@@ -460,18 +414,7 @@ - { - "ip":"10.0.7.6", - "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true -+ "interfaceName":"eth-rt6" - } - ] - } -@@ -492,13 +435,6 @@ - "afi":"ipv4", - "interfaceName":"eth-rt5", - "active":true -- }, -- { -- "fib":true, -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff deleted file mode 100644 index 37e3185ae034..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff +++ /dev/null @@ -1,50 +0,0 @@ ---- a/rt4/step11/show_ipv6_route.ref -+++ b/rt4/step12/show_ipv6_route.ref -@@ -149,23 +149,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt5", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16501 -- ] -- } - ] - } - ], -@@ -184,23 +171,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt6", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30061 -- ] -- } - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff deleted file mode 100644 index 186291adac06..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff +++ /dev/null @@ -1,78 +0,0 @@ ---- a/rt4/step11/show_mpls_table.ref -+++ b/rt4/step12/show_mpls_table.ref -@@ -179,17 +179,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.7.6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":30060, -- "nexthop":"10.0.6.5" -+ "nexthop":"10.0.7.6" - } - ] - }, -@@ -201,17 +191,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":30061, -- "interface":"eth-rt5" -+ "interface":"eth-rt6" - } - ] - }, -@@ -223,17 +203,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.6.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16500, -- "nexthop":"10.0.7.6" -+ "nexthop":"10.0.6.5" - } - ] - }, -@@ -245,17 +215,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16501, -- "interface":"eth-rt6" -+ "interface":"eth-rt5" - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ip_route.ref new file mode 100644 index 000000000000..0ef5d1bc3f82 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..c757031881e2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step2/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_mpls_table.ref new file mode 100644 index 000000000000..2a709070e472 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.6", + "interface":"eth-rt6" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step2/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step2/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ip_route.ref new file mode 100644 index 000000000000..0ef5d1bc3f82 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..c757031881e2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step3/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_mpls_table.ref new file mode 100644 index 000000000000..2a709070e472 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.6", + "interface":"eth-rt6" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step3/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step3/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ip_route.ref new file mode 100644 index 000000000000..0f26fa5d7aed --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ip_route.ref @@ -0,0 +1,296 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1" + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2" + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5" + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ip_route.ref.diff deleted file mode 100644 index a9418473c75c..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ip_route.ref.diff +++ /dev/null @@ -1,367 +0,0 @@ ---- a/rt4/step3/show_ip_route.ref -+++ b/rt4/step4/show_ip_route.ref -@@ -14,37 +14,14 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 16010 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 16010 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16010 -- ] -+ "active":true - } - ] - } -@@ -64,38 +41,14 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16030, -- 16020 -- ] -+ "active":true - } - ] - } -@@ -115,30 +68,21 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true, -- "labels":[ -- 16030 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true, -- "labels":[ -- 16030 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16030 -- ] -+ "active":true - } - ] - } -@@ -158,24 +102,7 @@ - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } -@@ -195,24 +122,7 @@ - "ip":"10.0.7.6", - "afi":"ipv4", - "interfaceName":"eth-rt6", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16060 -- ] -+ "active":true - } - ] - } -@@ -232,27 +142,13 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", - "active":true - } - ] -@@ -268,30 +164,13 @@ - { - "ip":"10.0.2.2", - "afi":"ipv4", -- "interfaceName":"eth-rt2-1", -- "backupIndex":[ -- 0 -- ] -+ "interfaceName":"eth-rt2-1" - }, - { - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16030 -- ] -+ "active":true - } - ] - } -@@ -307,29 +186,12 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "ip":"10.0.3.2", - "afi":"ipv4", -- "interfaceName":"eth-rt2-2", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16030 -- ] -+ "interfaceName":"eth-rt2-2" - } - ] - } -@@ -349,31 +211,6 @@ - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0, -- 1, -- 2 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- }, -- { -- "ip":"10.0.2.2", -- "afi":"ipv4", -- "interfaceName":"eth-rt2-1", -- "active":true -- }, -- { -- "ip":"10.0.3.2", -- "afi":"ipv4", -- "interfaceName":"eth-rt2-2", - "active":true - } - ] -@@ -394,31 +231,6 @@ - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0, -- 1, -- 2 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- }, -- { -- "ip":"10.0.2.2", -- "afi":"ipv4", -- "interfaceName":"eth-rt2-1", -- "active":true -- }, -- { -- "ip":"10.0.3.2", -- "afi":"ipv4", -- "interfaceName":"eth-rt2-2", - "active":true - } - ] -@@ -434,18 +246,7 @@ - { - "ip":"10.0.6.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.7.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -+ "interfaceName":"eth-rt5" - } - ] - } -@@ -460,18 +261,7 @@ - { - "ip":"10.0.7.6", - "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true -+ "interfaceName":"eth-rt6" - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..329fa39af910 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ipv6_route.ref @@ -0,0 +1,121 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ipv6_route.ref.diff deleted file mode 100644 index 991562ab9935..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_ipv6_route.ref.diff +++ /dev/null @@ -1,161 +0,0 @@ ---- a/rt4/step3/show_ipv6_route.ref -+++ b/rt4/step4/show_ipv6_route.ref -@@ -13,35 +13,13 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-2", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 16011 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-1", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 16011 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16011 -- ] -+ "active":true - } - ] - } -@@ -60,36 +38,13 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-2", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-1", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16031, -- 16021 -- ] -+ "active":true - } - ] - } -@@ -108,28 +63,19 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-2", -- "active":true, -- "labels":[ -- 16031 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-1", -- "active":true, -- "labels":[ -- 16031 -- ] -+ "active":true - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16031 -- ] -+ "active":true - } - ] - } -@@ -148,23 +94,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } -@@ -183,23 +113,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt6", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16061 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_mpls_table.ref new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_mpls_table.ref @@ -0,0 +1 @@ +{} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step4/show_mpls_table.ref.diff deleted file mode 100644 index 660d2fbde23f..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step4/show_mpls_table.ref.diff +++ /dev/null @@ -1,265 +0,0 @@ ---- a/rt4/step3/show_mpls_table.ref -+++ b/rt4/step4/show_mpls_table.ref -@@ -1,262 +1,2 @@ - { -- "16010":{ -- "inLabel":16010, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16010, -- "installed":true, -- "nexthop":"10.0.3.2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16010, -- "installed":true, -- "nexthop":"10.0.2.2", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16010, -- "nexthop":"10.0.6.5" -- } -- ] -- }, -- "16011":{ -- "inLabel":16011, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16011, -- "installed":true, -- "interface":"eth-rt2-2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16011, -- "installed":true, -- "interface":"eth-rt2-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16011, -- "interface":"eth-rt5" -- } -- ] -- }, -- "16020":{ -- "inLabel":16020, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.3.2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.2.2", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16030, -- "nexthop":"10.0.6.5" -- } -- ] -- }, -- "16021":{ -- "inLabel":16021, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt2-2", -- "backupIndex":[ -- 0 -- ] -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt2-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16031, -- "interface":"eth-rt5" -- } -- ] -- }, -- "16030":{ -- "inLabel":16030, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16030, -- "installed":true, -- "nexthop":"10.0.3.2" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16030, -- "installed":true, -- "nexthop":"10.0.2.2" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16030, -- "installed":true, -- "nexthop":"10.0.6.5" -- } -- ] -- }, -- "16031":{ -- "inLabel":16031, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16031, -- "installed":true, -- "interface":"eth-rt2-2" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16031, -- "installed":true, -- "interface":"eth-rt2-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16031, -- "installed":true, -- "interface":"eth-rt5" -- } -- ] -- }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.6.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.7.6" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt6" -- } -- ] -- }, -- "16060":{ -- "inLabel":16060, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.7.6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16060, -- "nexthop":"10.0.6.5" -- } -- ] -- }, -- "16061":{ -- "inLabel":16061, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16061, -- "interface":"eth-rt5" -- } -- ] -- } - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ip_route.ref new file mode 100644 index 000000000000..0ef5d1bc3f82 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ip_route.ref.diff deleted file mode 100644 index 4385df2c3666..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ip_route.ref.diff +++ /dev/null @@ -1,367 +0,0 @@ ---- a/rt4/step4/show_ip_route.ref -+++ b/rt4/step5/show_ip_route.ref -@@ -14,14 +14,37 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 16010 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 16010 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16010 -+ ] - } - ] - } -@@ -41,14 +64,38 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16030, -+ 16020 -+ ] - } - ] - } -@@ -68,21 +115,30 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16030 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16030 -+ ] - }, - { - "fib":true, - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true -+ "active":true, -+ "labels":[ -+ 16030 -+ ] - } - ] - } -@@ -102,7 +158,24 @@ - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.7.6", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt6", -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } -@@ -122,7 +195,24 @@ - "ip":"10.0.7.6", - "afi":"ipv4", - "interfaceName":"eth-rt6", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16060 -+ ] - } - ] - } -@@ -142,13 +232,27 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "fib":true, - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", - "active":true - } - ] -@@ -164,13 +268,30 @@ - { - "ip":"10.0.2.2", - "afi":"ipv4", -- "interfaceName":"eth-rt2-1" -+ "interfaceName":"eth-rt2-1", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.3.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16030 -+ ] - } - ] - } -@@ -186,12 +307,29 @@ - "ip":"10.0.2.2", - "afi":"ipv4", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.3.2", - "afi":"ipv4", -- "interfaceName":"eth-rt2-2" -+ "interfaceName":"eth-rt2-2", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16030 -+ ] - } - ] - } -@@ -211,6 +349,31 @@ - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -+ "active":true, -+ "backupIndex":[ -+ 0, -+ 1, -+ 2 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.7.6", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt6", -+ "active":true -+ }, -+ { -+ "ip":"10.0.2.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt2-1", -+ "active":true -+ }, -+ { -+ "ip":"10.0.3.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt2-2", - "active":true - } - ] -@@ -231,6 +394,31 @@ - "ip":"10.0.6.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -+ "active":true, -+ "backupIndex":[ -+ 0, -+ 1, -+ 2 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.7.6", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt6", -+ "active":true -+ }, -+ { -+ "ip":"10.0.2.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt2-1", -+ "active":true -+ }, -+ { -+ "ip":"10.0.3.2", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt2-2", - "active":true - } - ] -@@ -246,7 +434,18 @@ - { - "ip":"10.0.6.5", - "afi":"ipv4", -- "interfaceName":"eth-rt5" -+ "interfaceName":"eth-rt5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.7.6", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt6", -+ "active":true - } - ] - } -@@ -261,7 +460,18 @@ - { - "ip":"10.0.7.6", - "afi":"ipv4", -- "interfaceName":"eth-rt6" -+ "interfaceName":"eth-rt6", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.5", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt5", -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..c757031881e2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ipv6_route.ref.diff deleted file mode 100644 index 54a1dc23c510..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_ipv6_route.ref.diff +++ /dev/null @@ -1,161 +0,0 @@ ---- a/rt4/step4/show_ipv6_route.ref -+++ b/rt4/step5/show_ipv6_route.ref -@@ -13,13 +13,35 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 16011 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 16011 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16011 -+ ] - } - ] - } -@@ -38,13 +60,36 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16031, -+ 16021 -+ ] - } - ] - } -@@ -63,19 +108,28 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-2", -- "active":true -+ "active":true, -+ "labels":[ -+ 16031 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt2-1", -- "active":true -+ "active":true, -+ "labels":[ -+ 16031 -+ ] - }, - { - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5", -- "active":true -+ "active":true, -+ "labels":[ -+ 16031 -+ ] - } - ] - } -@@ -94,7 +148,23 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt5", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt6", -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } -@@ -113,7 +183,23 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt6", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ], -+ "labels":[ -+ 3 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt5", -+ "active":true, -+ "labels":[ -+ 16061 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_mpls_table.ref new file mode 100644 index 000000000000..2a709070e472 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.6", + "interface":"eth-rt6" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step5/show_mpls_table.ref.diff deleted file mode 100644 index fb6a1192813b..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step5/show_mpls_table.ref.diff +++ /dev/null @@ -1,265 +0,0 @@ ---- a/rt4/step4/show_mpls_table.ref -+++ b/rt4/step5/show_mpls_table.ref -@@ -1,2 +1,262 @@ - { -+ "16010":{ -+ "inLabel":16010, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16010, -+ "installed":true, -+ "nexthop":"10.0.3.2", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16010, -+ "installed":true, -+ "nexthop":"10.0.2.2", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16010, -+ "nexthop":"10.0.6.5" -+ } -+ ] -+ }, -+ "16011":{ -+ "inLabel":16011, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16011, -+ "installed":true, -+ "interface":"eth-rt2-2", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16011, -+ "installed":true, -+ "interface":"eth-rt2-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16011, -+ "interface":"eth-rt5" -+ } -+ ] -+ }, -+ "16020":{ -+ "inLabel":16020, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.3.2", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.2.2", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16030, -+ "nexthop":"10.0.6.5" -+ } -+ ] -+ }, -+ "16021":{ -+ "inLabel":16021, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt2-2", -+ "backupIndex":[ -+ 0 -+ ] -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt2-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16031, -+ "interface":"eth-rt5" -+ } -+ ] -+ }, -+ "16030":{ -+ "inLabel":16030, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16030, -+ "installed":true, -+ "nexthop":"10.0.3.2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16030, -+ "installed":true, -+ "nexthop":"10.0.2.2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16030, -+ "installed":true, -+ "nexthop":"10.0.6.5" -+ } -+ ] -+ }, -+ "16031":{ -+ "inLabel":16031, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16031, -+ "installed":true, -+ "interface":"eth-rt2-2" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16031, -+ "installed":true, -+ "interface":"eth-rt2-1" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16031, -+ "installed":true, -+ "interface":"eth-rt5" -+ } -+ ] -+ }, -+ "16050":{ -+ "inLabel":16050, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.6.5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.7.6" -+ } -+ ] -+ }, -+ "16051":{ -+ "inLabel":16051, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt6" -+ } -+ ] -+ }, -+ "16060":{ -+ "inLabel":16060, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.7.6", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16060, -+ "nexthop":"10.0.6.5" -+ } -+ ] -+ }, -+ "16061":{ -+ "inLabel":16061, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt6", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16061, -+ "interface":"eth-rt5" -+ } -+ ] -+ } - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ip_route.ref new file mode 100644 index 000000000000..89e556edd372 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ip_route.ref.diff deleted file mode 100644 index 9070414730e0..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ip_route.ref.diff +++ /dev/null @@ -1,56 +0,0 @@ ---- a/rt4/step5/show_ip_route.ref -+++ b/rt4/step6/show_ip_route.ref -@@ -43,7 +43,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16010 -+ 30010 - ] - } - ] -@@ -93,7 +93,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16030, -+ 30030, - 16020 - ] - } -@@ -137,7 +137,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16030 -+ 30030 - ] - } - ] -@@ -211,7 +211,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16060 -+ 30060 - ] - } - ] -@@ -290,7 +290,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16030 -+ 30030 - ] - } - ] -@@ -328,7 +328,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16030 -+ 30030 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..12479fadb8a4 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ipv6_route.ref.diff deleted file mode 100644 index 57a57647a17e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_ipv6_route.ref.diff +++ /dev/null @@ -1,38 +0,0 @@ ---- a/rt4/step5/show_ipv6_route.ref -+++ b/rt4/step6/show_ipv6_route.ref -@@ -40,7 +40,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16011 -+ 30011 - ] - } - ] -@@ -87,7 +87,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16031, -+ 30031, - 16021 - ] - } -@@ -128,7 +128,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16031 -+ 30031 - ] - } - ] -@@ -198,7 +198,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16061 -+ 30061 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_mpls_table.ref new file mode 100644 index 000000000000..6693de7666dd --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.6", + "interface":"eth-rt6" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step6/show_mpls_table.ref.diff deleted file mode 100644 index 94f87854d170..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step6/show_mpls_table.ref.diff +++ /dev/null @@ -1,74 +0,0 @@ ---- a/rt4/step5/show_mpls_table.ref -+++ b/rt4/step6/show_mpls_table.ref -@@ -25,7 +25,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16010, -+ "outLabel":30010, - "nexthop":"10.0.6.5" - } - ] -@@ -56,7 +56,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16011, -+ "outLabel":30011, - "interface":"eth-rt5" - } - ] -@@ -87,7 +87,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16030, -+ "outLabel":30030, - "nexthop":"10.0.6.5" - } - ] -@@ -118,7 +118,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16031, -+ "outLabel":30031, - "interface":"eth-rt5" - } - ] -@@ -141,7 +141,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":16030, -+ "outLabel":30030, - "installed":true, - "nexthop":"10.0.6.5" - } -@@ -165,7 +165,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":16031, -+ "outLabel":30031, - "installed":true, - "interface":"eth-rt5" - } -@@ -232,7 +232,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16060, -+ "outLabel":30060, - "nexthop":"10.0.6.5" - } - ] -@@ -254,7 +254,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16061, -+ "outLabel":30061, - "interface":"eth-rt5" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ip_route.ref new file mode 100644 index 000000000000..f90e7f4f57a2 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ip_route.ref @@ -0,0 +1,500 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ip_route.ref.diff deleted file mode 100644 index e54873d5ab59..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ip_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt4/step6/show_ip_route.ref -+++ b/rt4/step7/show_ip_route.ref -@@ -161,9 +161,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -172,10 +169,7 @@ - "ip":"10.0.7.6", - "afi":"ipv4", - "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..f55d6ba94966 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ipv6_route.ref @@ -0,0 +1,201 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ipv6_route.ref.diff deleted file mode 100644 index 92e08f99a065..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_ipv6_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt4/step6/show_ipv6_route.ref -+++ b/rt4/step7/show_ipv6_route.ref -@@ -151,9 +151,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -161,10 +158,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_mpls_table.ref new file mode 100644 index 000000000000..e6a73be2ef81 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_mpls_table.ref @@ -0,0 +1,229 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step7/show_mpls_table.ref.diff deleted file mode 100644 index fb614ebf6a8a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step7/show_mpls_table.ref.diff +++ /dev/null @@ -1,53 +0,0 @@ ---- a/rt4/step6/show_mpls_table.ref -+++ b/rt4/step7/show_mpls_table.ref -@@ -171,50 +171,6 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.6.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.7.6" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt6" -- } -- ] -- }, - "16060":{ - "inLabel":16060, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ip_route.ref new file mode 100644 index 000000000000..89e556edd372 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ip_route.ref.diff deleted file mode 100644 index 252da6e76417..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ip_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt4/step7/show_ip_route.ref -+++ b/rt4/step8/show_ip_route.ref -@@ -161,6 +161,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -169,7 +172,10 @@ - "ip":"10.0.7.6", - "afi":"ipv4", - "interfaceName":"eth-rt6", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..12479fadb8a4 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ipv6_route.ref.diff deleted file mode 100644 index 7057d2166a0c..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_ipv6_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt4/step7/show_ipv6_route.ref -+++ b/rt4/step8/show_ipv6_route.ref -@@ -151,6 +151,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -158,7 +161,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt6", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_mpls_table.ref new file mode 100644 index 000000000000..6693de7666dd --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.6", + "interface":"eth-rt6" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step8/show_mpls_table.ref.diff deleted file mode 100644 index 3dc4303b9b4d..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step8/show_mpls_table.ref.diff +++ /dev/null @@ -1,53 +0,0 @@ ---- a/rt4/step7/show_mpls_table.ref -+++ b/rt4/step8/show_mpls_table.ref -@@ -171,6 +171,50 @@ - } - ] - }, -+ "16050":{ -+ "inLabel":16050, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.6.5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.7.6" -+ } -+ ] -+ }, -+ "16051":{ -+ "inLabel":16051, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt6" -+ } -+ ] -+ }, - "16060":{ - "inLabel":16060, - "installed":true, diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ip_route.ref new file mode 100644 index 000000000000..1a084c77425a --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030, + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16030 + ] + }, + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30030 + ] + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.2.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-1", + "active":true + }, + { + "ip":"10.0.3.2", + "afi":"ipv4", + "interfaceName":"eth-rt2-2", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + }, + { + "fib":true, + "ip":"10.0.7.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ip_route.ref.diff deleted file mode 100644 index 56f9cc534f95..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ip_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt4/step8/show_ip_route.ref -+++ b/rt4/step9/show_ip_route.ref -@@ -174,7 +174,7 @@ - "interfaceName":"eth-rt6", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..1b08fde03ca7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031, + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-1", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt2-2", + "active":true, + "labels":[ + 16031 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30031 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16501 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ipv6_route.ref.diff deleted file mode 100644 index 41e552177a2f..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_ipv6_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt4/step8/show_ipv6_route.ref -+++ b/rt4/step9/show_ipv6_route.ref -@@ -163,7 +163,7 @@ - "interfaceName":"eth-rt6", - "active":true, - "labels":[ -- 16051 -+ 16501 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_mpls_table.ref new file mode 100644 index 000000000000..2c8ea080911a --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30010, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30011, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt2-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.3.2", + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.2.2", + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt2-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30060, + "nexthop":"10.0.6.5", + "interface":"eth-rt5" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30061, + "interface":"eth-rt5" + } + ] + }, + "16500":{ + "inLabel":16500, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.7.6", + "interface":"eth-rt6" + } + ] + }, + "16501":{ + "inLabel":16501, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-rt6" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step9/show_mpls_table.ref.diff deleted file mode 100644 index 627e292518fa..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt4/step9/show_mpls_table.ref.diff +++ /dev/null @@ -1,110 +0,0 @@ ---- a/rt4/step8/show_mpls_table.ref -+++ b/rt4/step9/show_mpls_table.ref -@@ -171,15 +171,15 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -+ "16060":{ -+ "inLabel":16060, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.6.5", -+ "nexthop":"10.0.7.6", - "backupIndex":[ - 0 - ] -@@ -188,20 +188,20 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.7.6" -+ "outLabel":30060, -+ "nexthop":"10.0.6.5" - } - ] - }, -- "16051":{ -- "inLabel":16051, -+ "16061":{ -+ "inLabel":16061, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt5", -+ "interface":"eth-rt6", - "backupIndex":[ - 0 - ] -@@ -210,20 +210,20 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt6" -+ "outLabel":30061, -+ "interface":"eth-rt5" - } - ] - }, -- "16060":{ -- "inLabel":16060, -+ "16500":{ -+ "inLabel":16500, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.7.6", -+ "nexthop":"10.0.6.5", - "backupIndex":[ - 0 - ] -@@ -232,20 +232,20 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30060, -- "nexthop":"10.0.6.5" -+ "outLabel":16500, -+ "nexthop":"10.0.7.6" - } - ] - }, -- "16061":{ -- "inLabel":16061, -+ "16501":{ -+ "inLabel":16501, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt6", -+ "interface":"eth-rt5", - "backupIndex":[ - 0 - ] -@@ -254,8 +254,8 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30061, -- "interface":"eth-rt5" -+ "outLabel":16501, -+ "interface":"eth-rt6" - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step1/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step1/show_ipv6_route.ref index 6dafa69adb8f..168828dcc40e 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/step1/show_ipv6_route.ref +++ b/tests/topotests/isis_tilfa_topo1/rt5/step1/show_ipv6_route.ref @@ -12,7 +12,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt3-2", + "interfaceName":"eth-rt3-1", "active":true, "backupIndex":[ 0 @@ -24,7 +24,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt3-1", + "interfaceName":"eth-rt3-2", "active":true, "backupIndex":[ 0 @@ -59,7 +59,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt4", + "interfaceName":"eth-rt3-1", "active":true, "labels":[ 16021 @@ -77,7 +77,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt3-1", + "interfaceName":"eth-rt4", "active":true, "labels":[ 16021 @@ -99,7 +99,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt3-2", + "interfaceName":"eth-rt3-1", "active":true, "backupIndex":[ 0 @@ -111,7 +111,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt3-1", + "interfaceName":"eth-rt3-2", "active":true, "backupIndex":[ 0 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step1/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step1/show_mpls_table.ref index 0c5861b5e89d..14de03d3f347 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/step1/show_mpls_table.ref +++ b/tests/topotests/isis_tilfa_topo1/rt5/step1/show_mpls_table.ref @@ -8,6 +8,7 @@ "outLabel":16010, "installed":true, "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", "backupIndex":[ 0 ] @@ -17,6 +18,7 @@ "outLabel":16010, "installed":true, "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", "backupIndex":[ 0 ] @@ -26,7 +28,8 @@ { "type":"SR (IS-IS)", "outLabel":16010, - "nexthop":"10.0.6.4" + "nexthop":"10.0.6.4", + "interface":"eth-rt4" } ] }, @@ -69,19 +72,22 @@ "type":"SR (IS-IS)", "outLabel":16020, "installed":true, - "nexthop":"10.0.5.3" + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" }, { "type":"SR (IS-IS)", "outLabel":16020, "installed":true, - "nexthop":"10.0.4.3" + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" }, { "type":"SR (IS-IS)", "outLabel":16020, "installed":true, - "nexthop":"10.0.6.4" + "nexthop":"10.0.6.4", + "interface":"eth-rt4" } ] }, @@ -118,6 +124,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", "backupIndex":[ 0 ] @@ -127,6 +134,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", "backupIndex":[ 0 ] @@ -136,7 +144,8 @@ { "type":"SR (IS-IS)", "outLabel":16020, - "nexthop":"10.0.6.4" + "nexthop":"10.0.6.4", + "interface":"eth-rt4" } ] }, @@ -180,6 +189,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.6.4", + "interface":"eth-rt4", "backupIndex":[ 0 ] @@ -189,7 +199,8 @@ { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.8.6" + "nexthop":"10.0.8.6", + "interface":"eth-rt6" } ] }, @@ -224,6 +235,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.8.6", + "interface":"eth-rt6", "backupIndex":[ 0 ] @@ -233,7 +245,8 @@ { "type":"SR (IS-IS)", "outLabel":16060, - "nexthop":"10.0.6.4" + "nexthop":"10.0.6.4", + "interface":"eth-rt4" } ] }, diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref new file mode 100644 index 000000000000..ff8ace25be5d --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref @@ -0,0 +1,485 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6" + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref new file mode 100644 index 000000000000..bc39e119b2b1 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref @@ -0,0 +1,194 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref new file mode 100644 index 000000000000..8a339e6e9a2a --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref @@ -0,0 +1,301 @@ +{ + "30010":{ + "inLabel":30010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30011":{ + "inLabel":30011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "30020":{ + "inLabel":30020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30021":{ + "inLabel":30021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "30030":{ + "inLabel":30030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30031":{ + "inLabel":30031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "30040":{ + "inLabel":30040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + } + ] + }, + "30041":{ + "inLabel":30041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt3-2" + } + ] + }, + "30060":{ + "inLabel":30060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + } + ] + }, + "30061":{ + "inLabel":30061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0, + 1 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt3-2" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff deleted file mode 100644 index 3d21c04297bb..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff +++ /dev/null @@ -1,151 +0,0 @@ ---- a/rt5/step11/show_ip_route.ref -+++ b/rt5/step12/show_ip_route.ref -@@ -159,24 +159,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16040 -- ] -- } - ] - } - ], -@@ -187,25 +173,11 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":20, -+ "metric":30, - "installed":true, - "nexthops":[ - { - "fib":true, -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -@@ -276,19 +248,12 @@ - "active":true, - "backupIndex":[ - 0, -- 1, -- 2 -+ 1 - ] - } - ], - "backupNexthops":[ - { -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- }, -- { - "ip":"10.0.4.3", - "afi":"ipv4", - "interfaceName":"eth-rt3-1", -@@ -321,19 +286,12 @@ - "active":true, - "backupIndex":[ - 0, -- 1, -- 2 -+ 1 - ] - } - ], - "backupNexthops":[ - { -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- }, -- { - "ip":"10.0.4.3", - "afi":"ipv4", - "interfaceName":"eth-rt3-1", -@@ -439,14 +397,6 @@ - 0 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- } - ] - } - ], -@@ -465,39 +415,6 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -- }, -- { -- "fib":true, -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "active":true -- } -- ] -- } -- ], -- "10.0.8.0\/24":[ -- { -- "prefix":"10.0.8.0\/24", -- "protocol":"isis", -- "distance":115, -- "metric":20, -- "nexthops":[ -- { -- "ip":"10.0.8.6", -- "afi":"ipv4", -- "interfaceName":"eth-rt6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4", - "active":true - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff deleted file mode 100644 index 66a9dace8b0b..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff +++ /dev/null @@ -1,53 +0,0 @@ ---- a/rt5/step11/show_ipv6_route.ref -+++ b/rt5/step12/show_ipv6_route.ref -@@ -149,23 +149,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16041 -- ] -- } - ] - } - ], -@@ -176,25 +163,12 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":20, -+ "metric":30, - "installed":true, - "nexthops":[ - { - "fib":true, - "afi":"ipv6", -- "interfaceName":"eth-rt6", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", - "interfaceName":"eth-rt4", - "active":true, - "labels":[ diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff deleted file mode 100644 index cdfc407f938b..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff +++ /dev/null @@ -1,80 +0,0 @@ ---- a/rt5/step11/show_mpls_table.ref -+++ b/rt5/step12/show_mpls_table.ref -@@ -179,17 +179,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.6.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.8.6" -+ "nexthop":"10.0.6.4" - } - ] - }, -@@ -201,17 +191,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt6" -+ "interface":"eth-rt4" - } - ] - }, -@@ -221,18 +201,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.8.6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16060, -+ "installed":true, - "nexthop":"10.0.6.4" - } - ] -@@ -243,18 +213,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt6", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16061, -+ "installed":true, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step2/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_mpls_table.ref new file mode 100644 index 000000000000..14de03d3f347 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step2/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step2/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step3/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_mpls_table.ref new file mode 100644 index 000000000000..14de03d3f347 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step3/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step3/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ip_route.ref new file mode 100644 index 000000000000..b5bd8c7a5c98 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ip_route.ref @@ -0,0 +1,439 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1" + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2" + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ip_route.ref.diff deleted file mode 100644 index 7545a31b9b05..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ip_route.ref.diff +++ /dev/null @@ -1,161 +0,0 @@ ---- a/rt5/step3/show_ip_route.ref -+++ b/rt5/step4/show_ip_route.ref -@@ -41,10 +41,7 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16010 -- ] -+ "active":true - } - ] - } -@@ -84,10 +81,7 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16020 -- ] -+ "active":true - } - ] - } -@@ -108,9 +102,6 @@ - "afi":"ipv4", - "interfaceName":"eth-rt3-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] -@@ -121,25 +112,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt3-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16020, -- 16030 -- ] -- } - ] - } - ], -@@ -161,9 +137,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -172,10 +145,7 @@ - "ip":"10.0.8.6", - "afi":"ipv4", - "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - } - ] - } -@@ -209,10 +179,7 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16060 -- ] -+ "active":true - } - ] - } -@@ -358,30 +325,13 @@ - { - "ip":"10.0.4.3", - "afi":"ipv4", -- "interfaceName":"eth-rt3-1", -- "backupIndex":[ -- 0 -- ] -+ "interfaceName":"eth-rt3-1" - }, - { - "ip":"10.0.5.3", - "afi":"ipv4", - "interfaceName":"eth-rt3-2", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16020 -- ] -+ "active":true - } - ] - } -@@ -397,29 +347,12 @@ - "ip":"10.0.4.3", - "afi":"ipv4", - "interfaceName":"eth-rt3-1", -- "active":true, -- "backupIndex":[ -- 0 -- ] -+ "active":true - }, - { - "ip":"10.0.5.3", - "afi":"ipv4", -- "interfaceName":"eth-rt3-2", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.6.4", -- "afi":"ipv4", -- "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16020 -- ] -+ "interfaceName":"eth-rt3-2" - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..647add85f51d --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ipv6_route.ref @@ -0,0 +1,175 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 3 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ipv6_route.ref.diff deleted file mode 100644 index 1de62bb58e18..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_ipv6_route.ref.diff +++ /dev/null @@ -1,95 +0,0 @@ ---- a/rt5/step3/show_ipv6_route.ref -+++ b/rt5/step4/show_ipv6_route.ref -@@ -38,10 +38,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16011 -- ] -+ "active":true - } - ] - } -@@ -60,10 +57,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16021 -- ] -+ "active":true - }, - { - "fib":true, -@@ -101,9 +95,6 @@ - "afi":"ipv6", - "interfaceName":"eth-rt3-2", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] -@@ -113,24 +104,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt3-1", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16021, -- 16031 -- ] -- } - ] - } - ], -@@ -151,9 +128,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -161,10 +135,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt6", -- "active":true, -- "labels":[ -- 16041 -- ] -+ "active":true - } - ] - } -@@ -196,10 +167,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16061 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_mpls_table.ref new file mode 100644 index 000000000000..cfb0bf2fd747 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_mpls_table.ref @@ -0,0 +1,189 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step4/show_mpls_table.ref.diff deleted file mode 100644 index b3d525243052..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step4/show_mpls_table.ref.diff +++ /dev/null @@ -1,166 +0,0 @@ ---- a/rt5/step3/show_mpls_table.ref -+++ b/rt5/step4/show_mpls_table.ref -@@ -25,7 +25,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16010, -+ "outLabel":3, - "nexthop":"10.0.6.4" - } - ] -@@ -56,7 +56,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16011, -+ "outLabel":3, - "interface":"eth-rt4" - } - ] -@@ -76,12 +76,6 @@ - "outLabel":16020, - "installed":true, - "nexthop":"10.0.4.3" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16020, -- "installed":true, -- "nexthop":"10.0.6.4" - } - ] - }, -@@ -100,12 +94,6 @@ - "outLabel":16021, - "installed":true, - "interface":"eth-rt3-1" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16021, -- "installed":true, -- "interface":"eth-rt4" - } - ] - }, -@@ -117,26 +105,13 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.5.3", -- "backupIndex":[ -- 0 -- ] -+ "nexthop":"10.0.5.3" - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.4.3", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16020, -- "nexthop":"10.0.6.4" -+ "nexthop":"10.0.4.3" - } - ] - }, -@@ -148,70 +123,13 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt3-2", -- "backupIndex":[ -- 0 -- ] -+ "interface":"eth-rt3-2" - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt3-1", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16021, -- "interface":"eth-rt4" -- } -- ] -- }, -- "16040":{ -- "inLabel":16040, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.6.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.8.6" -- } -- ] -- }, -- "16041":{ -- "inLabel":16041, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt6" -+ "interface":"eth-rt3-1" - } - ] - }, -@@ -232,7 +150,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16060, -+ "outLabel":3, - "nexthop":"10.0.6.4" - } - ] -@@ -254,7 +172,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16061, -+ "outLabel":3, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ip_route.ref.diff deleted file mode 100644 index be5d83f46357..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ip_route.ref.diff +++ /dev/null @@ -1,161 +0,0 @@ ---- a/rt5/step4/show_ip_route.ref -+++ b/rt5/step5/show_ip_route.ref -@@ -41,7 +41,10 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16010 -+ ] - } - ] - } -@@ -81,7 +84,10 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16020 -+ ] - } - ] - } -@@ -102,6 +108,9 @@ - "afi":"ipv4", - "interfaceName":"eth-rt3-1", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] -@@ -112,10 +121,25 @@ - "afi":"ipv4", - "interfaceName":"eth-rt3-2", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4", -+ "active":true, -+ "labels":[ -+ 16020, -+ 16030 -+ ] -+ } - ] - } - ], -@@ -137,6 +161,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -145,7 +172,10 @@ - "ip":"10.0.8.6", - "afi":"ipv4", - "interfaceName":"eth-rt6", -- "active":true -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } -@@ -179,7 +209,10 @@ - "ip":"10.0.6.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16060 -+ ] - } - ] - } -@@ -325,13 +358,30 @@ - { - "ip":"10.0.4.3", - "afi":"ipv4", -- "interfaceName":"eth-rt3-1" -+ "interfaceName":"eth-rt3-1", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.5.3", - "afi":"ipv4", - "interfaceName":"eth-rt3-2", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4", -+ "active":true, -+ "labels":[ -+ 16020 -+ ] - } - ] - } -@@ -347,12 +397,29 @@ - "ip":"10.0.4.3", - "afi":"ipv4", - "interfaceName":"eth-rt3-1", -- "active":true -+ "active":true, -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "ip":"10.0.5.3", - "afi":"ipv4", -- "interfaceName":"eth-rt3-2" -+ "interfaceName":"eth-rt3-2", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "ip":"10.0.6.4", -+ "afi":"ipv4", -+ "interfaceName":"eth-rt4", -+ "active":true, -+ "labels":[ -+ 16020 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ipv6_route.ref.diff deleted file mode 100644 index a856019622d4..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_ipv6_route.ref.diff +++ /dev/null @@ -1,95 +0,0 @@ ---- a/rt5/step4/show_ipv6_route.ref -+++ b/rt5/step5/show_ipv6_route.ref -@@ -38,7 +38,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16011 -+ ] - } - ] - } -@@ -57,7 +60,10 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16021 -+ ] - }, - { - "fib":true, -@@ -95,6 +101,9 @@ - "afi":"ipv6", - "interfaceName":"eth-rt3-2", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] -@@ -104,10 +113,24 @@ - "afi":"ipv6", - "interfaceName":"eth-rt3-1", - "active":true, -+ "backupIndex":[ -+ 0 -+ ], - "labels":[ - 3 - ] - } -+ ], -+ "backupNexthops":[ -+ { -+ "afi":"ipv6", -+ "interfaceName":"eth-rt4", -+ "active":true, -+ "labels":[ -+ 16021, -+ 16031 -+ ] -+ } - ] - } - ], -@@ -128,6 +151,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -135,7 +161,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt6", -- "active":true -+ "active":true, -+ "labels":[ -+ 16041 -+ ] - } - ] - } -@@ -167,7 +196,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16061 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_mpls_table.ref new file mode 100644 index 000000000000..d40be3d11e81 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "16060":{ + "inLabel":16060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "16061":{ + "inLabel":16061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step5/show_mpls_table.ref.diff deleted file mode 100644 index 74caa8620e61..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step5/show_mpls_table.ref.diff +++ /dev/null @@ -1,166 +0,0 @@ ---- a/rt5/step4/show_mpls_table.ref -+++ b/rt5/step5/show_mpls_table.ref -@@ -25,7 +25,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16010, - "nexthop":"10.0.6.4" - } - ] -@@ -56,7 +56,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16011, - "interface":"eth-rt4" - } - ] -@@ -69,6 +69,12 @@ - "type":"SR (IS-IS)", - "outLabel":16020, - "installed":true, -+ "nexthop":"10.0.6.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16020, -+ "installed":true, - "nexthop":"10.0.5.3" - }, - { -@@ -87,6 +93,12 @@ - "type":"SR (IS-IS)", - "outLabel":16021, - "installed":true, -+ "interface":"eth-rt4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16021, -+ "installed":true, - "interface":"eth-rt3-2" - }, - { -@@ -105,13 +117,26 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.5.3" -+ "nexthop":"10.0.5.3", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.4.3" -+ "nexthop":"10.0.4.3", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16020, -+ "nexthop":"10.0.6.4" - } - ] - }, -@@ -123,13 +148,70 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt3-2" -+ "interface":"eth-rt3-2", -+ "backupIndex":[ -+ 0 -+ ] - }, - { - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt3-1" -+ "interface":"eth-rt3-1", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16021, -+ "interface":"eth-rt4" -+ } -+ ] -+ }, -+ "16040":{ -+ "inLabel":16040, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.6.4", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.8.6" -+ } -+ ] -+ }, -+ "16041":{ -+ "inLabel":16041, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt4", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-rt6" - } - ] - }, -@@ -150,7 +232,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16060, - "nexthop":"10.0.6.4" - } - ] -@@ -172,7 +254,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16061, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_mpls_table.ref new file mode 100644 index 000000000000..a21038bf9d38 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "30010":{ + "inLabel":30010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30011":{ + "inLabel":30011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "30020":{ + "inLabel":30020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30021":{ + "inLabel":30021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "30030":{ + "inLabel":30030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30031":{ + "inLabel":30031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "30040":{ + "inLabel":30040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "30041":{ + "inLabel":30041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "30060":{ + "inLabel":30060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30061":{ + "inLabel":30061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step6/show_mpls_table.ref.diff deleted file mode 100644 index 2883c046fd50..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt5/step6/show_mpls_table.ref.diff +++ /dev/null @@ -1,146 +0,0 @@ ---- a/rt5/step5/show_mpls_table.ref -+++ b/rt5/step6/show_mpls_table.ref -@@ -1,6 +1,6 @@ - { -- "16010":{ -- "inLabel":16010, -+ "30010":{ -+ "inLabel":30010, - "installed":true, - "nexthops":[ - { -@@ -30,8 +30,8 @@ - } - ] - }, -- "16011":{ -- "inLabel":16011, -+ "30011":{ -+ "inLabel":30011, - "installed":true, - "nexthops":[ - { -@@ -61,56 +61,56 @@ - } - ] - }, -- "16020":{ -- "inLabel":16020, -+ "30020":{ -+ "inLabel":30020, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", - "outLabel":16020, - "installed":true, -- "nexthop":"10.0.6.4" -+ "nexthop":"10.0.5.3" - }, - { - "type":"SR (IS-IS)", - "outLabel":16020, - "installed":true, -- "nexthop":"10.0.5.3" -+ "nexthop":"10.0.4.3" - }, - { - "type":"SR (IS-IS)", - "outLabel":16020, - "installed":true, -- "nexthop":"10.0.4.3" -+ "nexthop":"10.0.6.4" - } - ] - }, -- "16021":{ -- "inLabel":16021, -+ "30021":{ -+ "inLabel":30021, - "installed":true, - "nexthops":[ - { - "type":"SR (IS-IS)", - "outLabel":16021, - "installed":true, -- "interface":"eth-rt4" -+ "interface":"eth-rt3-2" - }, - { - "type":"SR (IS-IS)", - "outLabel":16021, - "installed":true, -- "interface":"eth-rt3-2" -+ "interface":"eth-rt3-1" - }, - { - "type":"SR (IS-IS)", - "outLabel":16021, - "installed":true, -- "interface":"eth-rt3-1" -+ "interface":"eth-rt4" - } - ] - }, -- "16030":{ -- "inLabel":16030, -+ "30030":{ -+ "inLabel":30030, - "installed":true, - "nexthops":[ - { -@@ -140,8 +140,8 @@ - } - ] - }, -- "16031":{ -- "inLabel":16031, -+ "30031":{ -+ "inLabel":30031, - "installed":true, - "nexthops":[ - { -@@ -171,8 +171,8 @@ - } - ] - }, -- "16040":{ -- "inLabel":16040, -+ "30040":{ -+ "inLabel":30040, - "installed":true, - "nexthops":[ - { -@@ -193,8 +193,8 @@ - } - ] - }, -- "16041":{ -- "inLabel":16041, -+ "30041":{ -+ "inLabel":30041, - "installed":true, - "nexthops":[ - { -@@ -215,8 +215,8 @@ - } - ] - }, -- "16060":{ -- "inLabel":16060, -+ "30060":{ -+ "inLabel":30060, - "installed":true, - "nexthops":[ - { -@@ -237,8 +237,8 @@ - } - ] - }, -- "16061":{ -- "inLabel":16061, -+ "30061":{ -+ "inLabel":30061, - "installed":true, - "nexthops":[ - { diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step7/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_mpls_table.ref new file mode 100644 index 000000000000..a21038bf9d38 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "30010":{ + "inLabel":30010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30011":{ + "inLabel":30011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "30020":{ + "inLabel":30020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30021":{ + "inLabel":30021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "30030":{ + "inLabel":30030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30031":{ + "inLabel":30031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "30040":{ + "inLabel":30040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "30041":{ + "inLabel":30041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "30060":{ + "inLabel":30060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30061":{ + "inLabel":30061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step7/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step7/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step8/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_mpls_table.ref new file mode 100644 index 000000000000..a21038bf9d38 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "30010":{ + "inLabel":30010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30011":{ + "inLabel":30011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "30020":{ + "inLabel":30020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30021":{ + "inLabel":30021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "30030":{ + "inLabel":30030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30031":{ + "inLabel":30031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "30040":{ + "inLabel":30040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "30041":{ + "inLabel":30041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "30060":{ + "inLabel":30060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30061":{ + "inLabel":30061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step8/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step8/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ip_route.ref new file mode 100644 index 000000000000..93740e22e0c7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ip_route.ref @@ -0,0 +1,506 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16010 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16020 + ] + }, + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020, + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "6.6.6.6\/32":[ + { + "prefix":"6.6.6.6\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16060 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "fib":true, + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0, + 1, + 2 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + }, + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.4.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ] + }, + { + "ip":"10.0.5.3", + "afi":"ipv4", + "interfaceName":"eth-rt3-2", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.6", + "afi":"ipv4", + "interfaceName":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.6.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..168828dcc40e --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ipv6_route.ref @@ -0,0 +1,207 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16011 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "labels":[ + 16021 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-1", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt3-2", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16021, + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::6\/128":[ + { + "prefix":"2001:db8:1000::6\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt6", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16061 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step9/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_mpls_table.ref new file mode 100644 index 000000000000..a21038bf9d38 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_mpls_table.ref @@ -0,0 +1,275 @@ +{ + "30010":{ + "inLabel":30010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30011":{ + "inLabel":30011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "interface":"eth-rt4" + } + ] + }, + "30020":{ + "inLabel":30020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30021":{ + "inLabel":30021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-2" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt3-1" + }, + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "30030":{ + "inLabel":30030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.5.3", + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.4.3", + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30031":{ + "inLabel":30031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-2", + "backupIndex":[ + 0 + ] + }, + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt3-1", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt4" + } + ] + }, + "30040":{ + "inLabel":30040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.6.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.6", + "interface":"eth-rt6" + } + ] + }, + "30041":{ + "inLabel":30041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt6" + } + ] + }, + "30060":{ + "inLabel":30060, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.6", + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16060, + "nexthop":"10.0.6.4", + "interface":"eth-rt4" + } + ] + }, + "30061":{ + "inLabel":30061, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt6", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16061, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step9/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step9/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step1/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step1/show_ipv6_route.ref index 1b1942939ddc..de31816fe533 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/step1/show_ipv6_route.ref +++ b/tests/topotests/isis_tilfa_topo1/rt6/step1/show_ipv6_route.ref @@ -12,7 +12,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt4", + "interfaceName":"eth-rt5", "active":true, "labels":[ 16011 @@ -21,7 +21,7 @@ { "fib":true, "afi":"ipv6", - "interfaceName":"eth-rt5", + "interfaceName":"eth-rt4", "active":true, "labels":[ 16011 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step1/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step1/show_mpls_table.ref index 5b52a16f48df..4bd85c36b943 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/step1/show_mpls_table.ref +++ b/tests/topotests/isis_tilfa_topo1/rt6/step1/show_mpls_table.ref @@ -7,13 +7,15 @@ "type":"SR (IS-IS)", "outLabel":16010, "installed":true, - "nexthop":"10.0.8.5" + "nexthop":"10.0.8.5", + "interface":"eth-rt5" }, { "type":"SR (IS-IS)", "outLabel":16010, "installed":true, - "nexthop":"10.0.7.4" + "nexthop":"10.0.7.4", + "interface":"eth-rt4" } ] }, @@ -44,6 +46,7 @@ "outLabel":16020, "installed":true, "nexthop":"10.0.7.4", + "interface":"eth-rt4", "backupIndex":[ 0 ] @@ -53,7 +56,8 @@ { "type":"SR (IS-IS)", "outLabel":16020, - "nexthop":"10.0.8.5" + "nexthop":"10.0.8.5", + "interface":"eth-rt5" } ] }, @@ -88,6 +92,7 @@ "outLabel":16030, "installed":true, "nexthop":"10.0.8.5", + "interface":"eth-rt5", "backupIndex":[ 0 ] @@ -97,7 +102,8 @@ { "type":"SR (IS-IS)", "outLabel":16030, - "nexthop":"10.0.7.4" + "nexthop":"10.0.7.4", + "interface":"eth-rt4" } ] }, @@ -132,6 +138,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.7.4", + "interface":"eth-rt4", "backupIndex":[ 0 ] @@ -141,7 +148,8 @@ { "type":"SR (IS-IS)", "outLabel":16040, - "nexthop":"10.0.8.5" + "nexthop":"10.0.8.5", + "interface":"eth-rt5" } ] }, @@ -176,6 +184,7 @@ "outLabel":3, "installed":true, "nexthop":"10.0.8.5", + "interface":"eth-rt5", "backupIndex":[ 0 ] @@ -185,7 +194,8 @@ { "type":"SR (IS-IS)", "outLabel":16050, - "nexthop":"10.0.7.4" + "nexthop":"10.0.7.4", + "interface":"eth-rt4" } ] }, diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_bfd_peer_down.ref b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_bfd_peer_down.ref new file mode 100644 index 000000000000..2b573d077f62 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_bfd_peer_down.ref @@ -0,0 +1,6 @@ +{ + "multihop":false, + "peer":"10.0.8.5", + "interface":"eth-rt5", + "status":"down" +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_bfd_peer_up.ref b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_bfd_peer_up.ref new file mode 100644 index 000000000000..f536b36f15bd --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_bfd_peer_up.ref @@ -0,0 +1,6 @@ +{ + "multihop":false, + "peer":"10.0.8.5", + "interface":"eth-rt5", + "status":"up" +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref new file mode 100644 index 000000000000..822e24b3b0ca --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref @@ -0,0 +1,354 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":30, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref new file mode 100644 index 000000000000..7a87f447ccd7 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref @@ -0,0 +1,147 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16501 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref new file mode 100644 index 000000000000..6e4a783a6c57 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref @@ -0,0 +1,127 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16500":{ + "inLabel":16500, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16501":{ + "inLabel":16501, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "installed":true, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff deleted file mode 100644 index e477e87d1ed3..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff +++ /dev/null @@ -1,125 +0,0 @@ ---- a/rt6/step10/show_ip_route.ref -+++ b/rt6/step11/show_ip_route.ref -@@ -76,25 +76,11 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":30, -+ "metric":40, - "installed":true, - "nexthops":[ - { - "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 30030 -- ] -- } -- ], -- "backupNexthops":[ -- { - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -@@ -150,25 +136,11 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":20, -+ "metric":30, - "installed":true, - "nexthops":[ - { - "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -@@ -276,22 +248,11 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":20, -+ "metric":30, - "installed":true, - "nexthops":[ - { - "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -@@ -307,22 +268,11 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":20, -+ "metric":30, - "installed":true, - "nexthops":[ - { - "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -@@ -389,19 +339,9 @@ - "prefix":"10.0.8.0\/24", - "protocol":"isis", - "distance":115, -- "metric":20, -+ "metric":30, - "nexthops":[ - { -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff deleted file mode 100644 index 12e0b591d290..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff +++ /dev/null @@ -1,56 +0,0 @@ ---- a/rt6/step10/show_ipv6_route.ref -+++ b/rt6/step11/show_ipv6_route.ref -@@ -72,25 +72,12 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":30, -+ "metric":40, - "installed":true, - "nexthops":[ - { - "fib":true, - "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 30031 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", - "interfaceName":"eth-rt4", - "active":true, - "labels":[ -@@ -142,25 +129,12 @@ - "selected":true, - "destSelected":true, - "distance":115, -- "metric":20, -+ "metric":30, - "installed":true, - "nexthops":[ - { - "fib":true, - "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "backupIndex":[ -- 0 -- ], -- "labels":[ -- 3 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", - "interfaceName":"eth-rt4", - "active":true, - "labels":[ diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff deleted file mode 100644 index 387dcca3fe66..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff +++ /dev/null @@ -1,106 +0,0 @@ ---- a/rt6/step10/show_mpls_table.ref -+++ b/rt6/step11/show_mpls_table.ref -@@ -8,12 +8,6 @@ - "outLabel":16010, - "installed":true, - "nexthop":"10.0.7.4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":30010, -- "installed":true, -- "nexthop":"10.0.8.5" - } - ] - }, -@@ -26,12 +20,6 @@ - "outLabel":16011, - "installed":true, - "interface":"eth-rt4" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":30011, -- "installed":true, -- "interface":"eth-rt5" - } - ] - }, -@@ -85,18 +73,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30030, -- "installed":true, -- "nexthop":"10.0.8.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16030, -+ "installed":true, - "nexthop":"10.0.7.4" - } - ] -@@ -107,17 +85,6 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":30031, -- "installed":true, -- "interface":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16031, - "interface":"eth-rt4" - } -@@ -173,18 +140,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.8.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16500, -+ "installed":true, - "nexthop":"10.0.7.4" - } - ] -@@ -195,18 +152,8 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":16501, -+ "installed":true, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff deleted file mode 100644 index 1086b6e7060c..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff +++ /dev/null @@ -1,153 +0,0 @@ ---- a/rt6/step12/show_ip_route.ref -+++ b/rt6/step12/show_ip_route.ref -@@ -18,16 +18,6 @@ - "labels":[ - 16010 - ] -- }, -- { -- "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30010 -- ] - } - ] - } -@@ -48,24 +38,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 16020 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30020 -- ] -- } - ] - } - ], -@@ -108,24 +84,10 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30040 -- ] -- } - ] - } - ], -@@ -168,13 +130,6 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4", - "active":true -- }, -- { -- "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true - } - ] - } -@@ -194,17 +149,6 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", - "active":true - } - ] -@@ -225,17 +169,6 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", - "active":true - } - ] -@@ -297,13 +230,6 @@ - "afi":"ipv4", - "interfaceName":"eth-rt4", - "active":true -- }, -- { -- "fib":true, -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true - } - ] - } -@@ -318,18 +244,7 @@ - { - "ip":"10.0.7.4", - "afi":"ipv4", -- "interfaceName":"eth-rt4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "ip":"10.0.8.5", -- "afi":"ipv4", -- "interfaceName":"eth-rt5", -- "active":true -+ "interfaceName":"eth-rt4" - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff deleted file mode 100644 index 571c66fb6503..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff +++ /dev/null @@ -1,66 +0,0 @@ ---- a/rt6/step12/show_ipv6_route.ref -+++ b/rt6/step12/show_ipv6_route.ref -@@ -17,15 +17,6 @@ - "labels":[ - 16011 - ] -- }, -- { -- "fib":true, -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30011 -- ] - } - ] - } -@@ -45,23 +36,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 16021 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30021 -- ] -- } - ] - } - ], -@@ -102,23 +80,10 @@ - "afi":"ipv6", - "interfaceName":"eth-rt4", - "active":true, -- "backupIndex":[ -- 0 -- ], - "labels":[ - 3 - ] - } -- ], -- "backupNexthops":[ -- { -- "afi":"ipv6", -- "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 30041 -- ] -- } - ] - } - ], diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff deleted file mode 100644 index 18322f18a1ed..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff +++ /dev/null @@ -1,78 +0,0 @@ ---- a/rt6/step12/show_mpls_table.ref -+++ b/rt6/step12/show_mpls_table.ref -@@ -31,17 +31,7 @@ - "type":"SR (IS-IS)", - "outLabel":16020, - "installed":true, -- "nexthop":"10.0.7.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":30020, -- "nexthop":"10.0.8.5" -+ "nexthop":"10.0.7.4" - } - ] - }, -@@ -53,17 +43,7 @@ - "type":"SR (IS-IS)", - "outLabel":16021, - "installed":true, -- "interface":"eth-rt4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":30021, -- "interface":"eth-rt5" -+ "interface":"eth-rt4" - } - ] - }, -@@ -98,17 +78,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "nexthop":"10.0.7.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":30040, -- "nexthop":"10.0.8.5" -+ "nexthop":"10.0.7.4" - } - ] - }, -@@ -120,17 +90,7 @@ - "type":"SR (IS-IS)", - "outLabel":3, - "installed":true, -- "interface":"eth-rt4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":30041, -- "interface":"eth-rt5" -+ "interface":"eth-rt4" - } - ] - }, \ No newline at end of file diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ip_route.ref new file mode 100644 index 000000000000..b9b43c413927 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ip_route.ref @@ -0,0 +1,413 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ipv6_route.ref new file mode 100644 index 000000000000..de31816fe533 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ipv6_route.ref @@ -0,0 +1,173 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step2/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_mpls_table.ref new file mode 100644 index 000000000000..4bd85c36b943 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_mpls_table.ref @@ -0,0 +1,224 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt5" + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step2/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step2/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ip_route.ref new file mode 100644 index 000000000000..b9b43c413927 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ip_route.ref @@ -0,0 +1,413 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ip_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ipv6_route.ref new file mode 100644 index 000000000000..de31816fe533 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ipv6_route.ref @@ -0,0 +1,173 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_ipv6_route.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step3/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_mpls_table.ref new file mode 100644 index 000000000000..4bd85c36b943 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_mpls_table.ref @@ -0,0 +1,224 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt5" + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step3/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step3/show_mpls_table.ref.diff deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ip_route.ref new file mode 100644 index 000000000000..d34a28ee0f00 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ip_route.ref @@ -0,0 +1,395 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ip_route.ref.diff deleted file mode 100644 index 7c2f00419ab0..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ip_route.ref.diff +++ /dev/null @@ -1,70 +0,0 @@ ---- a/rt6/step3/show_ip_route.ref -+++ b/rt6/step4/show_ip_route.ref -@@ -14,10 +14,7 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16010 -- ] -+ "active":true - }, - { - "fib":true, -@@ -50,9 +47,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 16020 - ] - } - ], -@@ -98,10 +92,7 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16030 -- ] -+ "active":true - } - ] - } -@@ -124,9 +115,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -135,10 +123,7 @@ - "ip":"10.0.8.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16040 -- ] -+ "active":true - } - ] - } -@@ -172,10 +157,7 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ipv6_route.ref new file mode 100644 index 000000000000..2527c85bf862 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ipv6_route.ref @@ -0,0 +1,155 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ipv6_route.ref.diff deleted file mode 100644 index 70f872e9de36..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_ipv6_route.ref.diff +++ /dev/null @@ -1,70 +0,0 @@ ---- a/rt6/step3/show_ipv6_route.ref -+++ b/rt6/step4/show_ipv6_route.ref -@@ -13,10 +13,7 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16011 -- ] -+ "active":true - }, - { - "fib":true, -@@ -47,9 +44,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 16021 - ] - } - ], -@@ -92,10 +86,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16031 -- ] -+ "active":true - } - ] - } -@@ -117,9 +108,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -127,10 +115,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt5", -- "active":true, -- "labels":[ -- 16041 -- ] -+ "active":true - } - ] - } -@@ -162,10 +147,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_mpls_table.ref new file mode 100644 index 000000000000..5cac9257053b --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_mpls_table.ref @@ -0,0 +1,165 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "interface":"eth-rt4" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step4/show_mpls_table.ref.diff deleted file mode 100644 index c191763a73f7..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step4/show_mpls_table.ref.diff +++ /dev/null @@ -1,109 +0,0 @@ ---- a/rt6/step3/show_mpls_table.ref -+++ b/rt6/step4/show_mpls_table.ref -@@ -8,12 +8,6 @@ - "outLabel":16010, - "installed":true, - "nexthop":"10.0.8.5" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16010, -- "installed":true, -- "nexthop":"10.0.7.4" - } - ] - }, -@@ -26,12 +20,6 @@ - "outLabel":16011, - "installed":true, - "interface":"eth-rt5" -- }, -- { -- "type":"SR (IS-IS)", -- "outLabel":16011, -- "installed":true, -- "interface":"eth-rt4" - } - ] - }, -@@ -96,7 +84,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16030, -+ "outLabel":3, - "nexthop":"10.0.7.4" - } - ] -@@ -118,52 +106,8 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16031, -- "interface":"eth-rt4" -- } -- ] -- }, -- "16040":{ -- "inLabel":16040, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.7.4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16040, -- "nexthop":"10.0.8.5" -- } -- ] -- }, -- "16041":{ -- "inLabel":16041, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", - "outLabel":3, -- "installed":true, -- "interface":"eth-rt4", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16041, -- "interface":"eth-rt5" -+ "interface":"eth-rt4" - } - ] - }, -@@ -184,7 +128,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":3, - "nexthop":"10.0.7.4" - } - ] -@@ -206,7 +150,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":3, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ip_route.ref new file mode 100644 index 000000000000..b9b43c413927 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ip_route.ref @@ -0,0 +1,413 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ip_route.ref.diff deleted file mode 100644 index 9f017d24925b..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ip_route.ref.diff +++ /dev/null @@ -1,70 +0,0 @@ ---- a/rt6/step4/show_ip_route.ref -+++ b/rt6/step5/show_ip_route.ref -@@ -14,7 +14,10 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16010 -+ ] - }, - { - "fib":true, -@@ -47,6 +50,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 16020 - ] - } - ], -@@ -92,7 +98,10 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16030 -+ ] - } - ] - } -@@ -115,6 +124,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -123,7 +135,10 @@ - "ip":"10.0.8.5", - "afi":"ipv4", - "interfaceName":"eth-rt5", -- "active":true -+ "active":true, -+ "labels":[ -+ 16040 -+ ] - } - ] - } -@@ -157,7 +172,10 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ipv6_route.ref new file mode 100644 index 000000000000..de31816fe533 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ipv6_route.ref @@ -0,0 +1,173 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 16041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ipv6_route.ref.diff deleted file mode 100644 index 1209504e9425..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_ipv6_route.ref.diff +++ /dev/null @@ -1,70 +0,0 @@ ---- a/rt6/step4/show_ipv6_route.ref -+++ b/rt6/step5/show_ipv6_route.ref -@@ -13,7 +13,10 @@ - "fib":true, - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16011 -+ ] - }, - { - "fib":true, -@@ -44,6 +47,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 16021 - ] - } - ], -@@ -86,7 +92,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16031 -+ ] - } - ] - } -@@ -108,6 +117,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -115,7 +127,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt5", -- "active":true -+ "active":true, -+ "labels":[ -+ 16041 -+ ] - } - ] - } -@@ -147,7 +162,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_mpls_table.ref new file mode 100644 index 000000000000..ef2310f03f9c --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_mpls_table.ref @@ -0,0 +1,224 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16041, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step5/show_mpls_table.ref.diff deleted file mode 100644 index abf7c2a32d73..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step5/show_mpls_table.ref.diff +++ /dev/null @@ -1,112 +0,0 @@ ---- a/rt6/step4/show_mpls_table.ref -+++ b/rt6/step5/show_mpls_table.ref -@@ -7,6 +7,12 @@ - "type":"SR (IS-IS)", - "outLabel":16010, - "installed":true, -+ "nexthop":"10.0.7.4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16010, -+ "installed":true, - "nexthop":"10.0.8.5" - } - ] -@@ -19,6 +25,12 @@ - "type":"SR (IS-IS)", - "outLabel":16011, - "installed":true, -+ "interface":"eth-rt4" -+ }, -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16011, -+ "installed":true, - "interface":"eth-rt5" - } - ] -@@ -84,7 +96,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16030, - "nexthop":"10.0.7.4" - } - ] -@@ -106,11 +118,55 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16031, - "interface":"eth-rt4" - } - ] - }, -+ "16040":{ -+ "inLabel":16040, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.7.4", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16040, -+ "nexthop":"10.0.8.5" -+ } -+ ] -+ }, -+ "16041":{ -+ "inLabel":16041, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt4", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16041, -+ "interface":"eth-rt5" -+ } -+ ] -+ }, - "16050":{ - "inLabel":16050, - "installed":true, -@@ -128,7 +184,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16050, - "nexthop":"10.0.7.4" - } - ] -@@ -150,7 +206,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":3, -+ "outLabel":16051, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ip_route.ref new file mode 100644 index 000000000000..ca39251e4ac1 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ip_route.ref @@ -0,0 +1,413 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ip_route.ref.diff deleted file mode 100644 index f318f95e212b..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ip_route.ref.diff +++ /dev/null @@ -1,38 +0,0 @@ ---- a/rt6/step5/show_ip_route.ref -+++ b/rt6/step6/show_ip_route.ref -@@ -26,7 +26,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16010 -+ 30010 - ] - } - ] -@@ -63,7 +63,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16020 -+ 30020 - ] - } - ] -@@ -89,7 +89,7 @@ - 0 - ], - "labels":[ -- 16030 -+ 30030 - ] - } - ], -@@ -137,7 +137,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16040 -+ 30040 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ipv6_route.ref new file mode 100644 index 000000000000..4a42ec9df83f --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ipv6_route.ref @@ -0,0 +1,173 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ipv6_route.ref.diff deleted file mode 100644 index 9208491fc824..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_ipv6_route.ref.diff +++ /dev/null @@ -1,38 +0,0 @@ ---- a/rt6/step5/show_ipv6_route.ref -+++ b/rt6/step6/show_ipv6_route.ref -@@ -24,7 +24,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16011 -+ 30011 - ] - } - ] -@@ -59,7 +59,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16021 -+ 30021 - ] - } - ] -@@ -84,7 +84,7 @@ - 0 - ], - "labels":[ -- 16031 -+ 30031 - ] - } - ], -@@ -129,7 +129,7 @@ - "interfaceName":"eth-rt5", - "active":true, - "labels":[ -- 16041 -+ 30041 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_mpls_table.ref new file mode 100644 index 000000000000..edbe78aa98ab --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_mpls_table.ref @@ -0,0 +1,224 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30011, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step6/show_mpls_table.ref.diff deleted file mode 100644 index aee8969deddc..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step6/show_mpls_table.ref.diff +++ /dev/null @@ -1,74 +0,0 @@ ---- a/rt6/step5/show_mpls_table.ref -+++ b/rt6/step6/show_mpls_table.ref -@@ -11,7 +11,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":16010, -+ "outLabel":30010, - "installed":true, - "nexthop":"10.0.8.5" - } -@@ -29,7 +29,7 @@ - }, - { - "type":"SR (IS-IS)", -- "outLabel":16011, -+ "outLabel":30011, - "installed":true, - "interface":"eth-rt5" - } -@@ -52,7 +52,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16020, -+ "outLabel":30020, - "nexthop":"10.0.8.5" - } - ] -@@ -74,7 +74,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16021, -+ "outLabel":30021, - "interface":"eth-rt5" - } - ] -@@ -85,7 +85,7 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16030, -+ "outLabel":30030, - "installed":true, - "nexthop":"10.0.8.5", - "backupIndex":[ -@@ -107,7 +107,7 @@ - "nexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16031, -+ "outLabel":30031, - "installed":true, - "interface":"eth-rt5", - "backupIndex":[ -@@ -140,7 +140,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16040, -+ "outLabel":30040, - "nexthop":"10.0.8.5" - } - ] -@@ -162,7 +162,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16041, -+ "outLabel":30041, - "interface":"eth-rt5" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ip_route.ref new file mode 100644 index 000000000000..ee47c1aa9305 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ip_route.ref @@ -0,0 +1,407 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ip_route.ref.diff deleted file mode 100644 index 0e6c3ff5cd54..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ip_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt6/step6/show_ip_route.ref -+++ b/rt6/step7/show_ip_route.ref -@@ -161,9 +161,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -172,10 +169,7 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16050 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ipv6_route.ref new file mode 100644 index 000000000000..c5ef607aeb64 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ipv6_route.ref @@ -0,0 +1,167 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ipv6_route.ref.diff deleted file mode 100644 index 2fe46c82658a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_ipv6_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt6/step6/show_ipv6_route.ref -+++ b/rt6/step7/show_ipv6_route.ref -@@ -152,9 +152,6 @@ - "active":true, - "backupIndex":[ - 0 -- ], -- "labels":[ -- 3 - ] - } - ], -@@ -162,10 +159,7 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true, -- "labels":[ -- 16051 -- ] -+ "active":true - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_mpls_table.ref new file mode 100644 index 000000000000..ad965cee679b --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_mpls_table.ref @@ -0,0 +1,178 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30011, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step7/show_mpls_table.ref.diff deleted file mode 100644 index 179a4f460b2a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step7/show_mpls_table.ref.diff +++ /dev/null @@ -1,52 +0,0 @@ ---- a/rt6/step6/show_mpls_table.ref -+++ b/rt6/step7/show_mpls_table.ref -@@ -166,49 +166,5 @@ - "interface":"eth-rt5" - } - ] -- }, -- "16050":{ -- "inLabel":16050, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "nexthop":"10.0.8.5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16050, -- "nexthop":"10.0.7.4" -- } -- ] -- }, -- "16051":{ -- "inLabel":16051, -- "installed":true, -- "nexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":3, -- "installed":true, -- "interface":"eth-rt5", -- "backupIndex":[ -- 0 -- ] -- } -- ], -- "backupNexthops":[ -- { -- "type":"SR (IS-IS)", -- "outLabel":16051, -- "interface":"eth-rt4" -- } -- ] - } - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ip_route.ref new file mode 100644 index 000000000000..ca39251e4ac1 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ip_route.ref @@ -0,0 +1,413 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16050 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ip_route.ref.diff deleted file mode 100644 index 9d5c440a2215..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ip_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt6/step7/show_ip_route.ref -+++ b/rt6/step8/show_ip_route.ref -@@ -161,6 +161,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -169,7 +172,10 @@ - "ip":"10.0.7.4", - "afi":"ipv4", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16050 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ipv6_route.ref new file mode 100644 index 000000000000..4a42ec9df83f --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ipv6_route.ref @@ -0,0 +1,173 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16051 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ipv6_route.ref.diff deleted file mode 100644 index 21cab20a470a..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_ipv6_route.ref.diff +++ /dev/null @@ -1,24 +0,0 @@ ---- a/rt6/step7/show_ipv6_route.ref -+++ b/rt6/step8/show_ipv6_route.ref -@@ -152,6 +152,9 @@ - "active":true, - "backupIndex":[ - 0 -+ ], -+ "labels":[ -+ 3 - ] - } - ], -@@ -159,7 +162,10 @@ - { - "afi":"ipv6", - "interfaceName":"eth-rt4", -- "active":true -+ "active":true, -+ "labels":[ -+ 16051 -+ ] - } - ] - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_mpls_table.ref new file mode 100644 index 000000000000..edbe78aa98ab --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_mpls_table.ref @@ -0,0 +1,224 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30011, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5" + } + ] + }, + "16050":{ + "inLabel":16050, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16050, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16051":{ + "inLabel":16051, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16051, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step8/show_mpls_table.ref.diff deleted file mode 100644 index 760c5542cb7e..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step8/show_mpls_table.ref.diff +++ /dev/null @@ -1,52 +0,0 @@ ---- a/rt6/step7/show_mpls_table.ref -+++ b/rt6/step8/show_mpls_table.ref -@@ -166,5 +166,49 @@ - "interface":"eth-rt5" - } - ] -+ }, -+ "16050":{ -+ "inLabel":16050, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "nexthop":"10.0.8.5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16050, -+ "nexthop":"10.0.7.4" -+ } -+ ] -+ }, -+ "16051":{ -+ "inLabel":16051, -+ "installed":true, -+ "nexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":3, -+ "installed":true, -+ "interface":"eth-rt5", -+ "backupIndex":[ -+ 0 -+ ] -+ } -+ ], -+ "backupNexthops":[ -+ { -+ "type":"SR (IS-IS)", -+ "outLabel":16051, -+ "interface":"eth-rt4" -+ } -+ ] - } - } diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ip_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ip_route.ref new file mode 100644 index 000000000000..879d595c884b --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ip_route.ref @@ -0,0 +1,413 @@ +{ + "1.1.1.1\/32":[ + { + "prefix":"1.1.1.1\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16010 + ] + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30010 + ] + } + ] + } + ], + "2.2.2.2\/32":[ + { + "prefix":"2.2.2.2\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16020 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30020 + ] + } + ] + } + ], + "3.3.3.3\/32":[ + { + "prefix":"3.3.3.3\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30030 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16030 + ] + } + ] + } + ], + "4.4.4.4\/32":[ + { + "prefix":"4.4.4.4\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30040 + ] + } + ] + } + ], + "5.5.5.5\/32":[ + { + "prefix":"5.5.5.5\/32", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16500 + ] + } + ] + } + ], + "10.0.1.0\/24":[ + { + "prefix":"10.0.1.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.2.0\/24":[ + { + "prefix":"10.0.2.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.3.0\/24":[ + { + "prefix":"10.0.3.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.4.0\/24":[ + { + "prefix":"10.0.4.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.5.0\/24":[ + { + "prefix":"10.0.5.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ], + "10.0.6.0\/24":[ + { + "prefix":"10.0.6.0\/24", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + }, + { + "fib":true, + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.7.0\/24":[ + { + "prefix":"10.0.7.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "active":true + } + ] + } + ], + "10.0.8.0\/24":[ + { + "prefix":"10.0.8.0\/24", + "protocol":"isis", + "distance":115, + "metric":20, + "nexthops":[ + { + "ip":"10.0.8.5", + "afi":"ipv4", + "interfaceName":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "ip":"10.0.7.4", + "afi":"ipv4", + "interfaceName":"eth-rt4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ip_route.ref.diff deleted file mode 100644 index ee296470c0cc..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ip_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt6/step8/show_ip_route.ref -+++ b/rt6/step9/show_ip_route.ref -@@ -174,7 +174,7 @@ - "interfaceName":"eth-rt4", - "active":true, - "labels":[ -- 16050 -+ 16500 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ipv6_route.ref b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ipv6_route.ref new file mode 100644 index 000000000000..e8a72001d195 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ipv6_route.ref @@ -0,0 +1,173 @@ +{ + "2001:db8:1000::1\/128":[ + { + "prefix":"2001:db8:1000::1\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":40, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30011 + ] + }, + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16011 + ] + } + ] + } + ], + "2001:db8:1000::2\/128":[ + { + "prefix":"2001:db8:1000::2\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 16021 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30021 + ] + } + ] + } + ], + "2001:db8:1000::3\/128":[ + { + "prefix":"2001:db8:1000::3\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":30, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 30031 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16031 + ] + } + ] + } + ], + "2001:db8:1000::4\/128":[ + { + "prefix":"2001:db8:1000::4\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "labels":[ + 30041 + ] + } + ] + } + ], + "2001:db8:1000::5\/128":[ + { + "prefix":"2001:db8:1000::5\/128", + "protocol":"isis", + "selected":true, + "destSelected":true, + "distance":115, + "metric":20, + "installed":true, + "nexthops":[ + { + "fib":true, + "afi":"ipv6", + "interfaceName":"eth-rt5", + "active":true, + "backupIndex":[ + 0 + ], + "labels":[ + 3 + ] + } + ], + "backupNexthops":[ + { + "afi":"ipv6", + "interfaceName":"eth-rt4", + "active":true, + "labels":[ + 16501 + ] + } + ] + } + ] +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ipv6_route.ref.diff deleted file mode 100644 index bebca4dcf189..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_ipv6_route.ref.diff +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rt6/step8/show_ipv6_route.ref -+++ b/rt6/step9/show_ipv6_route.ref -@@ -164,7 +164,7 @@ - "interfaceName":"eth-rt4", - "active":true, - "labels":[ -- 16051 -+ 16501 - ] - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_mpls_table.ref b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_mpls_table.ref new file mode 100644 index 000000000000..4b6c4eebfea9 --- /dev/null +++ b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_mpls_table.ref @@ -0,0 +1,224 @@ +{ + "16010":{ + "inLabel":16010, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16010, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30010, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16011":{ + "inLabel":16011, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16011, + "installed":true, + "interface":"eth-rt4" + }, + { + "type":"SR (IS-IS)", + "outLabel":30011, + "installed":true, + "interface":"eth-rt5" + } + ] + }, + "16020":{ + "inLabel":16020, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16020, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30020, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16021":{ + "inLabel":16021, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16021, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30021, + "interface":"eth-rt5" + } + ] + }, + "16030":{ + "inLabel":16030, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30030, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16030, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16031":{ + "inLabel":16031, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30031, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16031, + "interface":"eth-rt4" + } + ] + }, + "16040":{ + "inLabel":16040, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.7.4", + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30040, + "nexthop":"10.0.8.5", + "interface":"eth-rt5" + } + ] + }, + "16041":{ + "inLabel":16041, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt4", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":30041, + "interface":"eth-rt5" + } + ] + }, + "16500":{ + "inLabel":16500, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "nexthop":"10.0.8.5", + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16500, + "nexthop":"10.0.7.4", + "interface":"eth-rt4" + } + ] + }, + "16501":{ + "inLabel":16501, + "installed":true, + "nexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":3, + "installed":true, + "interface":"eth-rt5", + "backupIndex":[ + 0 + ] + } + ], + "backupNexthops":[ + { + "type":"SR (IS-IS)", + "outLabel":16501, + "interface":"eth-rt4" + } + ] + } +} diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step9/show_mpls_table.ref.diff deleted file mode 100644 index 57347d15beed..000000000000 --- a/tests/topotests/isis_tilfa_topo1/rt6/step9/show_mpls_table.ref.diff +++ /dev/null @@ -1,39 +0,0 @@ ---- a/rt6/step8/show_mpls_table.ref -+++ b/rt6/step9/show_mpls_table.ref -@@ -167,8 +167,8 @@ - } - ] - }, -- "16050":{ -- "inLabel":16050, -+ "16500":{ -+ "inLabel":16500, - "installed":true, - "nexthops":[ - { -@@ -184,13 +184,13 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16050, -+ "outLabel":16500, - "nexthop":"10.0.7.4" - } - ] - }, -- "16051":{ -- "inLabel":16051, -+ "16501":{ -+ "inLabel":16501, - "installed":true, - "nexthops":[ - { -@@ -206,7 +206,7 @@ - "backupNexthops":[ - { - "type":"SR (IS-IS)", -- "outLabel":16051, -+ "outLabel":16501, - "interface":"eth-rt4" - } - ] diff --git a/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf index 94fed46cca19..c765996237ec 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf @@ -16,6 +16,7 @@ interface eth-rt4 ! interface eth-rt5 ip address 10.0.8.6/24 + no link-detect ! ip forwarding ! diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py index e2bbf4588c39..c8e66befa5c0 100755 --- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py @@ -54,8 +54,8 @@ import sys import pytest import json -import tempfile from functools import partial +from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -120,45 +120,6 @@ def build_topo(tgen): switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6") switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5") - # - # Populate multi-dimensional dictionary containing all expected outputs - # - files = [ - "show_ip_route.ref", - "show_ipv6_route.ref", - "show_mpls_table.ref", - "show_yang_interface_isis_adjacencies.ref", - ] - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - outputs[rname] = {} - for step in range(1, 12 + 1): - outputs[rname][step] = {} - for file in files: - if step == 1: - # Get snapshots relative to the expected initial network convergence - filename = "{}/{}/step{}/{}".format(CWD, rname, step, file) - outputs[rname][step][file] = open(filename).read() - else: - if file == "show_yang_interface_isis_adjacencies.ref": - continue - - # Get diff relative to the previous step - filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file) - - # Create temporary files in order to apply the diff - f_in = tempfile.NamedTemporaryFile(mode="w") - f_in.write(outputs[rname][step - 1][file]) - f_in.flush() - f_out = tempfile.NamedTemporaryFile(mode="r") - os.system( - "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename) - ) - - # Store the updated snapshot and remove the temporary files - outputs[rname][step][file] = open(f_out.name).read() - f_in.close() - f_out.close() - def setup_module(mod): "Sets up the pytest environment" @@ -176,13 +137,13 @@ def setup_module(mod): TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) ) router.load_config( - TopoRouter.RD_BFD, os.path.join(CWD, "/dev/null".format(rname)) + TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) ) tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -190,12 +151,174 @@ def teardown_module(mod): tgen.stop_topology() -def router_compare_json_output(rname, command, reference, count=120, wait=0.5): +def filter_json(data, keys_to_keep): + """ + Filters a dictionary, keeping only the specified keys. + """ + return {k: v for k, v in data.items() if k in keys_to_keep} + + +def regen_data(rname, command, step, file, wait): + """ + Regenerates reference data. + """ + # Sleep enough time to ensure the protocol has converged + if rname == "rt1": + sleep(wait) + if step == 10: + sleep(10) + + # Get and parse JSON output + tgen = get_topogen() + output = json.loads(tgen.gears[rname].vtysh_cmd(command)) + + # Default JSON separators + separators = (",", ":") + + # Process JSON output based on the specified file + if file == "show_yang_interface_isis_adjacencies.ref": + # Filter out the loopback interface + output["frr-interface:lib"]["interface"] = [ + interface + for interface in output["frr-interface:lib"]["interface"] + if interface["name"] != "lo" + ] + + # Filter out unwanted fields + for interface in output["frr-interface:lib"]["interface"]: + keys_to_keep = {"name", "vrf", "state"} + filtered_interface = filter_json(interface, keys_to_keep) + interface.clear() + interface.update(filtered_interface) + + keys_to_keep = {"frr-isisd:isis"} + filtered_state = filter_json(interface["state"], keys_to_keep) + interface["state"].clear() + interface["state"].update(filtered_state) + + keys_to_keep = {"adjacencies"} + filtered_isis = filter_json( + interface["state"]["frr-isisd:isis"], keys_to_keep + ) + interface["state"]["frr-isisd:isis"].clear() + interface["state"]["frr-isisd:isis"].update(filtered_isis) + if "adjacencies" in interface["state"]["frr-isisd:isis"]: + for adjacency in interface["state"]["frr-isisd:isis"]["adjacencies"][ + "adjacency" + ]: + keys_to_keep = { + "neighbor-sys-type", + "neighbor-sysid", + "hold-timer", + "neighbor-priority", + "state", + } + filtered_adjacency = filter_json(adjacency, keys_to_keep) + adjacency.clear() + adjacency.update(filtered_adjacency) + # Adjust separators to match libyang's output. + separators = (",", ": ") + + elif file == "show_ip_route.ref" or file == "show_ipv6_route.ref": + # Filter out unwanted fields + keys_to_keep_route = { + "prefix", + "protocol", + "selected", + "destSelected", + "distance", + "metric", + "installed", + "nexthops", + "backupNexthops", + } + keys_to_keep_nh = { + "fib", + "ip", + "afi", + "interfaceName", + "active", + "backupIndex", + "labels", + } + for prefix_key, prefix_value in output.items(): + filtered_routes = [] + for route in prefix_value: + if "nexthops" in route: + filtered_nhs = [] + for nh in route["nexthops"]: + if nh["ip"].startswith("fe80"): + del nh["ip"] + filtered_nhs.append(filter_json(nh, keys_to_keep_nh)) + route["nexthops"] = filtered_nhs + if "backupNexthops" in route: + filtered_nhs = [] + for nh in route["backupNexthops"]: + if nh["ip"].startswith("fe80"): + del nh["ip"] + filtered_nhs.append(filter_json(nh, keys_to_keep_nh)) + route["backupNexthops"] = filtered_nhs + filtered_routes.append(filter_json(route, keys_to_keep_route)) + output[prefix_key] = filtered_routes + + elif file == "show_mpls_table.ref": + # Filter out Adj-SID labels + output = {int(key): value for key, value in output.items() if int(key) >= 16000} + + # Filter out unwanted fields + keys_to_keep_label = { + "inLabel", + "installed", + "nexthops", + "backupNexthops", + } + keys_to_keep_nh = { + "type", + "outLabel", + "installed", + "interface", + "nexthop", + "backupIndex", + } + for label_key, label_value in output.items(): + if "nexthops" in label_value: + filtered_nhs = [] + for nh in label_value["nexthops"]: + if nh["nexthop"].startswith("fe80"): + del nh["nexthop"] + filtered_nhs.append(filter_json(nh, keys_to_keep_nh)) + label_value["nexthops"] = filtered_nhs + if "backupNexthops" in label_value: + filtered_nhs = [] + for nh in label_value["backupNexthops"]: + if nh["nexthop"].startswith("fe80"): + del nh["nexthop"] + filtered_nhs.append(filter_json(nh, keys_to_keep_nh)) + label_value["backupNexthops"] = filtered_nhs + output[label_key] = filter_json(label_value, keys_to_keep_label) + + elif file.startswith("show_bfd_peer"): + keys_to_keep = ["multihop", "peer", "interface", "status"] + output = filter_json(output, keys_to_keep) + + # Save the processed output to a file + filename = "{}/{}/step{}/{}".format(CWD, rname, step, file) + output = json.dumps(output, separators=separators, indent=2).replace("/", "\\/") + with open(filename, "w", encoding="ascii") as file: + file.write(output + "\n") + + +def router_compare_json_output(rname, command, step, file, count=120, wait=0.5): "Compare router JSON output" - logger.info('Comparing router "%s" "%s" output', rname, command) + # Regenerate reference data when the REGEN_DATA environment variable is set + if os.environ.get("REGEN_DATA") is not None: + regen_data(rname, command, step, file, count * wait) + return tgen = get_topogen() + logger.info('Comparing router "%s" "%s" output', rname, command) + reference = open("{}/{}/step{}/{}".format(CWD, rname, step, file)).read() expected = json.loads(reference) # Run test function until we get an result. Wait at most 60 seconds. @@ -222,7 +345,8 @@ def test_isis_adjacencies_step1(): router_compare_json_output( rname, "show yang operational-data /frr-interface:lib isisd", - outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"], + 1, + "show_yang_interface_isis_adjacencies.ref", ) @@ -236,7 +360,7 @@ def test_rib_ipv4_step1(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"] + rname, "show ip route isis json", 1, "show_ip_route.ref" ) @@ -250,7 +374,7 @@ def test_rib_ipv6_step1(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 1, "show_ipv6_route.ref" ) @@ -264,7 +388,7 @@ def test_mpls_lib_step1(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][1]["show_mpls_table.ref"] + rname, "show mpls table json", 1, "show_mpls_table.ref" ) @@ -292,7 +416,7 @@ def test_rib_ipv4_step2(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"] + rname, "show ip route isis json", 2, "show_ip_route.ref" ) @@ -306,7 +430,7 @@ def test_rib_ipv6_step2(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 2, "show_ipv6_route.ref" ) @@ -320,7 +444,7 @@ def test_mpls_lib_step2(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][2]["show_mpls_table.ref"] + rname, "show mpls table json", 2, "show_mpls_table.ref" ) @@ -348,7 +472,7 @@ def test_rib_ipv4_step3(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"] + rname, "show ip route isis json", 3, "show_ip_route.ref" ) @@ -362,7 +486,7 @@ def test_rib_ipv6_step3(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 3, "show_ipv6_route.ref" ) @@ -376,7 +500,7 @@ def test_mpls_lib_step3(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][3]["show_mpls_table.ref"] + rname, "show mpls table json", 3, "show_mpls_table.ref" ) @@ -409,7 +533,7 @@ def test_rib_ipv4_step4(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"] + rname, "show ip route isis json", 4, "show_ip_route.ref" ) @@ -423,7 +547,7 @@ def test_rib_ipv6_step4(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 4, "show_ipv6_route.ref" ) @@ -437,7 +561,7 @@ def test_mpls_lib_step4(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][4]["show_mpls_table.ref"] + rname, "show mpls table json", 4, "show_mpls_table.ref" ) @@ -463,7 +587,7 @@ def test_rib_ipv4_step5(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"] + rname, "show ip route isis json", 5, "show_ip_route.ref" ) @@ -477,7 +601,7 @@ def test_rib_ipv6_step5(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 5, "show_ipv6_route.ref" ) @@ -491,7 +615,7 @@ def test_mpls_lib_step5(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][5]["show_mpls_table.ref"] + rname, "show mpls table json", 5, "show_mpls_table.ref" ) @@ -519,7 +643,7 @@ def test_rib_ipv4_step6(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"] + rname, "show ip route isis json", 6, "show_ip_route.ref" ) @@ -533,7 +657,7 @@ def test_rib_ipv6_step6(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 6, "show_ipv6_route.ref" ) @@ -547,7 +671,7 @@ def test_mpls_lib_step6(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][6]["show_mpls_table.ref"] + rname, "show mpls table json", 6, "show_mpls_table.ref" ) @@ -579,7 +703,7 @@ def test_rib_ipv4_step7(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"] + rname, "show ip route isis json", 7, "show_ip_route.ref" ) @@ -593,7 +717,7 @@ def test_rib_ipv6_step7(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 7, "show_ipv6_route.ref" ) @@ -607,7 +731,7 @@ def test_mpls_lib_step7(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][7]["show_mpls_table.ref"] + rname, "show mpls table json", 7, "show_mpls_table.ref" ) @@ -638,7 +762,7 @@ def test_rib_ipv4_step8(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"] + rname, "show ip route isis json", 8, "show_ip_route.ref" ) @@ -652,7 +776,7 @@ def test_rib_ipv6_step8(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 8, "show_ipv6_route.ref" ) @@ -666,7 +790,7 @@ def test_mpls_lib_step8(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][8]["show_mpls_table.ref"] + rname, "show mpls table json", 8, "show_mpls_table.ref" ) @@ -698,7 +822,7 @@ def test_rib_ipv4_step9(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"] + rname, "show ip route isis json", 9, "show_ip_route.ref" ) @@ -712,7 +836,7 @@ def test_rib_ipv6_step9(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"] + rname, "show ipv6 route isis json", 9, "show_ipv6_route.ref" ) @@ -726,7 +850,7 @@ def test_mpls_lib_step9(): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: router_compare_json_output( - rname, "show mpls table json", outputs[rname][9]["show_mpls_table.ref"] + rname, "show mpls table json", 9, "show_mpls_table.ref" ) @@ -734,11 +858,17 @@ def test_mpls_lib_step9(): # Step 10 # # Action(s): -# - Setting spf-delay-ietf init-delay of 15s +# - Enable ISIS BFD between rt5 and rt6 +# - Verify that the BFD session is up +# - Configure an SPF delay-ietf initial delay of 60 seconds on both rt5 and rt6 +# - Shut down the eth-rt5 interface on rt6 from the switch side to test fast-reroute # # Expected changes: -# - No routing table change -# - At the end of test, SPF reacts to a failure in 15s +# - Verify that the BFD session is down +# - Routes should switch over to use alternate paths +# - On rt5, the switchover should be triggered by the link down event +# - On rt6, the switchover should be triggered by the BFD down event, since it has +# link-detect disabled on the eth-rt5 interface # def test_rib_ipv4_step10(): logger.info("Test (step 10): verify IPv4 RIB") @@ -748,353 +878,69 @@ def test_rib_ipv4_step10(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info("Setting spf-delay-ietf init-delay of 15s") - tgen.net["rt6"].cmd( - 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"' - ) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"] - ) - - -def test_rib_ipv6_step10(): - logger.info("Test (step 10): verify IPv6 RIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, - "show ipv6 route isis json", - outputs[rname][10]["show_ipv6_route.ref"], - ) - - -def test_mpls_lib_step10(): - logger.info("Test (step 10): verify MPLS LIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, "show mpls table json", outputs[rname][10]["show_mpls_table.ref"] - ) - - -# -# Step 11 -# -# Action(s): -# - shut the eth-rt5 interface on rt6 -# -# Expected changes: -# - Route switchover of routes via eth-rt5 -# -def test_rt6_step11(): - logger.info( - "Test (step 11): Check IPv4/6 RIB and MPLS table after a LFA switchover" - ) - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info( - "Shut a rt6 interface to rt5 from the switch side and check fast-reroute" - ) - tgen.net.cmd_raises("ip link set %s down" % tgen.net["s8"].intfs[1]) - - rname = "rt6" - router_compare_json_output( - rname, - "show ip route isis json", - outputs[rname][11]["show_ip_route.ref"], - count=20, - ) - router_compare_json_output( - rname, - "show ipv6 route isis json", - outputs[rname][11]["show_ipv6_route.ref"], - count=20, - ) - router_compare_json_output( - rname, - "show mpls table json", - outputs[rname][11]["show_mpls_table.ref"], - count=20, - ) - - -# -# Step 12 -# -# Action(s): wait for the convergence and SPF computation on rt6 -# -# Expected changes: -# - convergence of IPv4/6 RIB and MPLS table -# -def test_rib_ipv4_step12(): - logger.info("Test (step 12): verify IPv4 RIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info("Check SPF convergence") - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, - "show ip route isis json", - outputs[rname][12]["show_ip_route.ref"], - ) - - -def test_rib_ipv6_step12(): - logger.info("Test (step 12): verify IPv6 RIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, - "show ipv6 route isis json", - outputs[rname][12]["show_ipv6_route.ref"], - ) - - -def test_mpls_lib_step12(): - logger.info("Test (step 12): verify MPLS LIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, - "show mpls table json", - outputs[rname][12]["show_mpls_table.ref"], - ) - - -# -# Step 13 -# -# Action(s): -# - unshut the rt6 to rt5 interface -# - Setup BFD -# -# Expected changes: -# - All route tables go back to previous state situation -# - At the end of test, next SPF is scheduled in approximatively 15s -# -def test_rib_ipv4_step13(): - logger.info("Test (step 13): verify IPv4 RIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info("Unsetting spf-delay-ietf init-delay of 15s") - tgen.net["rt6"].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf-delay-ietf"') - - logger.info( - "Unshut the rt6 interface to rt5 from the switch side and check fast-reroute" - ) - tgen.net.cmd_raises("ip link set %s up" % tgen.net["s8"].intfs[1]) - - logger.info("Setup BFD on rt5 and rt6") - for rname in ["rt5", "rt6"]: - conf_file = os.path.join(CWD, "{}/bfdd.conf".format(rname)) - tgen.net[rname].cmd("vtysh -f {}".format(conf_file)) - - expect = ( - '[{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"up"}]' - ) - router_compare_json_output("rt6", "show bfd peers json", expect) - - # Unset link detection. We want zebra to consider linkdow as operationaly up - # in order that BFD triggers LFA instead of the interface down - - # reset spf-interval - logger.info("Set spf-interval to 15s") - tgen.net["rt6"].cmd( - 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"' - ) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"] - ) - - logger.info("Set ISIS BFD") + logger.info("Enabling ISIS BFD between rt5 and rt6") tgen.net["rt5"].cmd('vtysh -c "conf t" -c "int eth-rt6" -c "isis bfd"') tgen.net["rt6"].cmd('vtysh -c "conf t" -c "int eth-rt5" -c "isis bfd"') - expect = ( - '[{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"up"}]' - ) + logger.info("Checking if the BFD session is up") + expect = '{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"up"}' router_compare_json_output( - rname, - "show bfd peers json", - expect, + "rt6", "show bfd peer 10.0.8.5 json", 10, "show_bfd_peer_up.ref" ) - -def test_rib_ipv6_step13(): - logger.info("Test (step 13): verify IPv6 RIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, - "show ipv6 route isis json", - outputs[rname][10]["show_ipv6_route.ref"], - ) - - -def test_mpls_lib_step13(): - logger.info("Test (step 13): verify MPLS LIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: - router_compare_json_output( - rname, "show mpls table json", outputs[rname][10]["show_mpls_table.ref"] + logger.info("Setting SPF delay-ietf initial delay to 60 seconds") + for rname in ["rt5", "rt6"]: + tgen.net[rname].cmd( + 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 60000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"' ) - -# -# Step 14 -# -# Action(s): -# - drop traffic between rt5 and rt6 by shutting down the bridge between -# the routers. Interfaces on rt5 and rt6 stay up. -# -# Expected changes: -# - Route switchover of routes via eth-rt5 -# -def test_rt6_step14(): - logger.info("Test (step 14): verify IPv4/6 RIB and MPLS table") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info("Drop traffic between rt5 and rt6") - tgen.net.cmd_raises("ip link set s8 down") - - rname = "rt6" - - expect = ( - '[{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"down"}]' - ) - router_compare_json_output( - rname, - "show bfd peers json", - expect, - count=40, - wait=0.5, + logger.info( + "Shutting down rt5 interface to rt6 from the switch side to test fast-reroute" ) + tgen.net.cmd_raises("ip link set %s down" % tgen.net["s8"].intfs[0]) - router_compare_json_output( - rname, - "show ip route isis json", - outputs[rname][11]["show_ip_route.ref"], - count=20, - ) - router_compare_json_output( - rname, - "show ipv6 route isis json", - outputs[rname][11]["show_ipv6_route.ref"], - count=20, - wait=2, + logger.info("Verifying if the BFD session is down") + expect = ( + '{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"down"}' ) router_compare_json_output( - rname, - "show mpls table json", - outputs[rname][11]["show_mpls_table.ref"], - count=20, + "rt6", "show bfd peer 10.0.8.5 json", 10, "show_bfd_peer_down.ref" ) - -# -# Step 15 -# -# Action(s): wait for the convergence and SPF computation on rt6 -# -# Expected changes: -# - convergence of IPv4/6 RIB and MPLS table -# -def test_rib_ipv4_step15(): - logger.info("Test (step 15): verify IPv4 RIB") - tgen = get_topogen() - - # Skip if previous fatal error condition is raised - if tgen.routers_have_failure(): - pytest.skip(tgen.errors) - - logger.info("Check SPF convergence") - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + for rname in ["rt5", "rt6"]: router_compare_json_output( - rname, - "show ip route isis json", - outputs[rname][12]["show_ip_route.ref"], + rname, "show ip route isis json", 10, "show_ip_route.ref" ) -def test_rib_ipv6_step15(): - logger.info("Test (step 15): verify IPv6 RIB") +def test_rib_ipv6_step10(): + logger.info("Test (step 10): verify IPv6 RIB") tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + for rname in ["rt5", "rt6"]: router_compare_json_output( rname, "show ipv6 route isis json", - outputs[rname][12]["show_ipv6_route.ref"], + 10, + "show_ipv6_route.ref", ) -def test_mpls_lib_step15(): - logger.info("Test (step 15): verify MPLS LIB") +def test_mpls_lib_step10(): + logger.info("Test (step 10): verify MPLS LIB") tgen = get_topogen() # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) - for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]: + for rname in ["rt5", "rt6"]: router_compare_json_output( - rname, - "show mpls table json", - outputs[rname][12]["show_mpls_table.ref"], + rname, "show mpls table json", 10, "show_mpls_table.ref" ) diff --git a/tests/topotests/isis_topo1/r1/r1_topology.json b/tests/topotests/isis_topo1/r1/r1_topology.json index 337d6bf5ef08..6b3374cc4d6f 100644 --- a/tests/topotests/isis_topo1/r1/r1_topology.json +++ b/tests/topotests/isis_topo1/r1/r1_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r2/r2_topology.json b/tests/topotests/isis_topo1/r2/r2_topology.json index de90fb5a32d0..8720bc1cac2c 100644 --- a/tests/topotests/isis_topo1/r2/r2_topology.json +++ b/tests/topotests/isis_topo1/r2/r2_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r3/r3_topology.json b/tests/topotests/isis_topo1/r3/r3_topology.json index 2d36f9b427aa..568b6dfeede8 100644 --- a/tests/topotests/isis_topo1/r3/r3_topology.json +++ b/tests/topotests/isis_topo1/r3/r3_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.254.0.1/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "metric": "10", - "interface": "r3-eth0", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::1/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.254.0.1/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "metric": 10, + "interface": "r3-eth0", + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::1/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r4/r4_topology.json b/tests/topotests/isis_topo1/r4/r4_topology.json index e7d78419127b..9a53955cc969 100644 --- a/tests/topotests/isis_topo1/r4/r4_topology.json +++ b/tests/topotests/isis_topo1/r4/r4_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.254.0.2/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "metric": "10", - "interface": "r4-eth0", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::2/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.254.0.2/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "metric": 10, + "interface": "r4-eth0", + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::2/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r5/r5_topology.json b/tests/topotests/isis_topo1/r5/r5_topology.json index 3d887b7cea69..64590d8eb267 100644 --- a/tests/topotests/isis_topo1/r5/r5_topology.json +++ b/tests/topotests/isis_topo1/r5/r5_topology.json @@ -1,156 +1,154 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index 48e9d5336fdf..a574f43d8913 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -104,7 +104,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -120,19 +120,13 @@ def test_isis_convergence(): pytest.skip(tgen.errors) logger.info("waiting for ISIS protocol to converge") - # Code to generate the json files. - # for rname, router in tgen.routers().items(): - # open('/tmp/{}_topology.json'.format(rname), 'w').write( - # json.dumps(show_isis_topology(router), indent=2, sort_keys=True) - # ) - for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_topology.json".format(CWD, rname) expected = json.loads(open(filename).read()) def compare_isis_topology(router, expected): "Helper function to test ISIS topology convergence." - actual = show_isis_topology(router) + actual = json.loads(router.vtysh_cmd("show isis topology json")) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -160,7 +154,7 @@ def compare_isis_installed_routes(router, expected): return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_installed_routes, router, expected) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -205,7 +199,7 @@ def compare_isis_v6_installed_routes(router, expected): test_func = functools.partial( compare_isis_v6_installed_routes, router, expected ) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -237,7 +231,7 @@ def test_isis_summary_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis summary json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True) assertmsg = "Test isis summary json failed in '{}' data '{}'".format( @@ -257,7 +251,7 @@ def test_isis_interface_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis interface json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis interface json", isjson=True @@ -294,7 +288,7 @@ def test_isis_neighbor_json(): # tgen.mininet_cli() logger.info("Checking 'show isis neighbor json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis neighbor json", isjson=True @@ -330,7 +324,7 @@ def test_isis_database_json(): # tgen.mininet_cli() logger.info("Checking 'show isis database json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis database json", isjson=True @@ -685,7 +679,10 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): ) database_json = json.loads(isis_database_output) - att_p_ol = database_json["areas"][0]["levels"][1]["att-p-ol"] + if "lsps" not in database_json["areas"][0]["levels"][1]: + return "The LSP of {} has not been synchronized yet ".format(router.name) + + att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"] if att_p_ol == att_p_ol_expected: return True return "{} peer with expected att_p_ol {} got {} ".format( @@ -708,9 +705,9 @@ def _check_overload_timer(router, timer_expected): tgen = get_topogen() router = tgen.gears[router] - thread_output = router.vtysh_cmd("show thread timers") + output = router.vtysh_cmd("show event timers") - timer_running = "set_overload_on_start_timer" in thread_output + timer_running = "set_overload_on_start_timer" in output if timer_running == timer_expected: return True return "Expected timer running status: {}".format(timer_expected) @@ -755,7 +752,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: @@ -845,52 +842,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-1") - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-2") - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json index 666fa52b19a2..da537c552bfa 100644 --- a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json +++ b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json index c26ad1ee37e4..bf965659bea5 100644 --- a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json +++ b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 044a6c0438aa..94592b50a72a 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json index d40008aa3013..b8295e87b9cc 100644 --- a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json +++ b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + } + ] }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json index 2a088cae3061..8b5159cbfbd2 100644 --- a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json +++ b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json @@ -1,124 +1,122 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index 032319c446a1..afc6864b98c9 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -118,7 +118,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # move back rx-eth0 to default VRF @@ -141,8 +141,9 @@ def test_isis_convergence(): def compare_isis_topology(router, expected): "Helper function to test ISIS vrf topology convergence." - actual = show_isis_topology(router) - + actual = json.loads( + router.vtysh_cmd(f"show isis vrf {router.name}-cust1 topology json") + ) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -287,7 +288,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: @@ -377,52 +378,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS vrf topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name)) - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name)) - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/key_sendaccept/r1/frr.conf b/tests/topotests/key_sendaccept/r1/frr.conf new file mode 100644 index 000000000000..d23163478d69 --- /dev/null +++ b/tests/topotests/key_sendaccept/r1/frr.conf @@ -0,0 +1,31 @@ +log timestamp precision 6 +log file frr.log debug + +! debug northbound libyang + +debug northbound notifications +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 + + ip ospf hello-interval 2 + ip ospf dead-interval 10 +exit + +router ospf + ospf router-id 1.1.1.1 + network 1.1.1.0/24 area 0 +exit + +router rip + network 1.1.1.0/24 + network r1-eth0 +exit + +!ip route 250.0.0.1/32 Null0 \ No newline at end of file diff --git a/tests/topotests/key_sendaccept/r2/frr.conf b/tests/topotests/key_sendaccept/r2/frr.conf new file mode 100644 index 000000000000..95bb6e2ee109 --- /dev/null +++ b/tests/topotests/key_sendaccept/r2/frr.conf @@ -0,0 +1,20 @@ +log timestamp precision 6 +log file frr.log debug + +interface r2-eth0 + ip address 1.1.1.2/24 + + ip ospf hello-interval 2 + ip ospf dead-interval 10 +exit + +router ospf + ospf router-id 2.2.2.2 + network 1.1.1.0/24 area 0 +exit + +router rip + network 1.1.1.0/24 +exit + +ip route 250.0.0.2/32 Null0 \ No newline at end of file diff --git a/tests/topotests/key_sendaccept/test_keychain.py b/tests/topotests/key_sendaccept/test_keychain.py new file mode 100644 index 000000000000..1d24c170042f --- /dev/null +++ b/tests/topotests/key_sendaccept/test_keychain.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# March 4 2024, Christian Hopps +# +# Copyright (c) 2024, LabN Consulting, L.L.C. +# +""" +Test static route functionality +""" +import json + +import pytest +from lib.topogen import Topogen + +pytestmark = [pytest.mark.ripd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1", "r2")} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for _, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +DIR_SEND = 0 +DIR_ACCEPT = 1 + + +def is_key_active(router, keychain, keyid, direction): + dstr = "send" if direction == DIR_SEND else "accept" + node = f"{dstr}-lifetime-active" + output = router.net.cmd_raises( + "vtysh -c 'show mgmt get-data " + f'/ietf-key-chain:key-chains/key-chain[name="{keychain}"]' + f'/key[key-id="{keyid}"]/{node} json' + "'" + ) + jd = json.loads(output) + return jd["ietf-key-chain:key-chains"]["key-chain"][0]["key"][0][node] + + +def test_send_accept(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + conf = """conf t +key chain kc + key 1 + key-string theSecret + cryptographic-algorithm hmac-sha-256 + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert is_key_active(r1, "kc", 1, DIR_SEND) + assert is_key_active(r1, "kc", 1, DIR_ACCEPT) + + conf = """conf t +key chain kc + key 1 + key-string theSecret + cryptographic-algorithm hmac-sha-256 + send-lifetime 00:00:00 Jan 1 2024 infinite + accept-lifetime 00:00:00 Jan 1 2024 infinite + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert is_key_active(r1, "kc", 1, DIR_SEND) + assert is_key_active(r1, "kc", 1, DIR_ACCEPT) + + conf = """conf t +key chain kc + key 1 + send-lifetime 00:00:00 Jan 1 2035 infinite + accept-lifetime 00:00:00 Jan 1 2035 infinite + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert not is_key_active(r1, "kc", 1, DIR_SEND) + assert not is_key_active(r1, "kc", 1, DIR_ACCEPT) + + secs_in_10_years = 60 * 60 * 24 * 365 * 10 + conf = f"""conf t +key chain kc + key 2 + key-string theSecret + cryptographic-algorithm hmac-sha-256 + send-lifetime 00:00:00 Jan 1 2024 duration {secs_in_10_years} + accept-lifetime 00:00:00 Jan 1 2024 duration {secs_in_10_years} + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert is_key_active(r1, "kc", 2, DIR_SEND) + assert is_key_active(r1, "kc", 2, DIR_ACCEPT) + + conf = f"""conf t +key chain kc + key 2 + send-lifetime 00:00:00 Jan 1 2000 duration 10 + accept-lifetime 00:00:00 Jan 1 2000 duration 10 + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert not is_key_active(r1, "kc", 2, DIR_SEND) + assert not is_key_active(r1, "kc", 2, DIR_ACCEPT) + + conf = """conf t +key chain kc + key 3 + key-string theSecret + cryptographic-algorithm hmac-sha-256 + send-lifetime 00:00:00 Jan 1 2024 23:59:59 Dec 31 2034 + accept-lifetime 00:00:00 Jan 1 2024 23:59:59 Dec 31 2034 + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert is_key_active(r1, "kc", 3, DIR_SEND) + assert is_key_active(r1, "kc", 3, DIR_ACCEPT) + + conf = """conf t +key chain kc + key 3 + send-lifetime 00:00:00 Dec 1 2035 23:59:59 Dec 31 2034 + accept-lifetime 00:00:00 Dec 1 2035 23:59:59 Dec 31 2034 + exit +exit +""" + r1.vtysh_multicmd(conf.split("\n"), pretty_output=True) + assert not is_key_active(r1, "kc", 3, DIR_SEND) + assert not is_key_active(r1, "kc", 3, DIR_ACCEPT) diff --git a/tests/topotests/kinds.yaml b/tests/topotests/kinds.yaml index 127790ed07d8..5f4b61d4b7a5 100644 --- a/tests/topotests/kinds.yaml +++ b/tests/topotests/kinds.yaml @@ -12,6 +12,7 @@ kinds: - "./%NAME%:/etc/frr" - "%RUNDIR%/var.log.frr:/var/log/frr" - "%RUNDIR%/var.run.frr:/var/run/frr" + - "%RUNDIR%/var.lib.frr:/var/lib/frr" cap-add: - SYS_ADMIN - AUDIT_WRITE diff --git a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py index c2bcaa84ceb2..8123e0498260 100644 --- a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py +++ b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py @@ -117,7 +117,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py index 387fd89c20d3..bfb93d55889a 100644 --- a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py +++ b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py @@ -116,7 +116,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py index 52a67d8bb8da..ea404beae4fa 100644 --- a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py +++ b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py index cb6b784d6d36..f2c41ebe301f 100644 --- a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py +++ b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref index 6c27a1042760..846be5b849c9 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync.ref @@ -5,8 +5,8 @@ "ldpIgpSyncState":"Sync achieved" }, "r2-eth2":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" } } diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref index 889f69ed7f40..ad3b8b5ca442 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref @@ -5,8 +5,8 @@ "ldpIgpSyncState":"Holding down until Sync" }, "r2-eth2":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" } } diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref index d9036e124bca..d5e4b88d07cd 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref @@ -1,7 +1,7 @@ { "r2-eth2":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" } } diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref index b417ab040ab5..5b9542d5a996 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync.ref @@ -1,8 +1,8 @@ { "r3-eth1":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" }, "r3-eth2":{ "ldpIgpSyncEnabled":true, diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref index b417ab040ab5..5b9542d5a996 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref @@ -1,8 +1,8 @@ { "r3-eth1":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" }, "r3-eth2":{ "ldpIgpSyncEnabled":true, diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref index b417ab040ab5..5b9542d5a996 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref @@ -1,8 +1,8 @@ { "r3-eth1":{ - "ldpIgpSyncEnabled":false, + "ldpIgpSyncEnabled":true, "holdDownTimeInSec":50, - "ldpIgpSyncState":"Sync not required" + "ldpIgpSyncState":"Sync achieved" }, "r3-eth2":{ "ldpIgpSyncEnabled":true, diff --git a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py index 760b4e3df566..9e41e06c6a85 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py +++ b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py @@ -128,7 +128,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py index 1f4a4b5fd595..c14c79e6d4f2 100644 --- a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 3a16ed5a090d..bcd1c748120f 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -333,7 +333,7 @@ def __create_bgp_global(tgen, input_dict, router, build=False): else: del_action = False - for rs_timer, value in timer.items(): + for rs_timer, _ in timer.items(): rs_timer_value = timer.setdefault(rs_timer, None) if rs_timer_value and rs_timer != "delete": @@ -1229,7 +1229,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict): # Copy bgp config file to /etc/frr for dut in input_dict.keys(): router_list = tgen.routers() - for router, rnode in router_list.items(): + for router, _ in router_list.items(): if router != dut: continue @@ -1750,7 +1750,7 @@ def verify_as_numbers(tgen, topo, input_dict, expected=True): for bgp_neighbor, peer_data in bgp_neighbors.items(): remote_as = input_dict[bgp_neighbor]["bgp"]["local_as"] - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): neighbor_ip = None data = topo["routers"][bgp_neighbor]["links"] @@ -1833,7 +1833,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True): return errormsg for vrf, addr_family_data in show_bgp_json.items(): - for address_family, neighborship_data in addr_family_data.items(): + for _, neighborship_data in addr_family_data.items(): total_peer = 0 no_of_peer = 0 @@ -1980,7 +1980,7 @@ def clear_bgp_and_verify(tgen, topo, router, rid=None): bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] for bgp_neighbor, peer_data in bgp_neighbors.items(): - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3231,7 +3231,7 @@ def verify_graceful_restart( if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3266,27 +3266,43 @@ def verify_graceful_restart( lmode = None rmode = None + # Local GR mode - if "address_family" in input_dict[dut]["bgp"]: - bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][peer]["dest_link"] + if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]: + if ( + "graceful-restart" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart"] + ): + lmode = "Restart*" + elif ( + "graceful-restart-disable" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart-disable"] + ): + lmode = "Disable*" + else: + lmode = "Helper*" - for dest_link, data in bgp_neighbors.items(): - if ( - "graceful-restart-helper" in data - and data["graceful-restart-helper"] - ): - lmode = "Helper" - elif "graceful-restart" in data and data["graceful-restart"]: - lmode = "Restart" - elif ( - "graceful-restart-disable" in data - and data["graceful-restart-disable"] - ): - lmode = "Disable" - else: - lmode = None + if lmode is None: + if "address_family" in input_dict[dut]["bgp"]: + bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ + "unicast" + ]["neighbor"][peer]["dest_link"] + + for dest_link, data in bgp_neighbors.items(): + if ( + "graceful-restart-helper" in data + and data["graceful-restart-helper"] + ): + lmode = "Helper" + elif "graceful-restart" in data and data["graceful-restart"]: + lmode = "Restart" + elif ( + "graceful-restart-disable" in data + and data["graceful-restart-disable"] + ): + lmode = "Disable" + else: + lmode = None if lmode is None: if "graceful-restart" in input_dict[dut]["bgp"]: @@ -3314,7 +3330,11 @@ def verify_graceful_restart( return True # Remote GR mode - if "address_family" in input_dict[peer]["bgp"]: + + if ( + "bgp" in input_dict[peer] + and "address_family" in input_dict[peer]["bgp"] + ): bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][ "unicast" ]["neighbor"][dut]["dest_link"] @@ -3336,7 +3356,10 @@ def verify_graceful_restart( rmode = None if rmode is None: - if "graceful-restart" in input_dict[peer]["bgp"]: + if ( + "bgp" in input_dict[peer] + and "graceful-restart" in input_dict[peer]["bgp"] + ): if ( "graceful-restart" in input_dict[peer]["bgp"]["graceful-restart"] @@ -3355,6 +3378,27 @@ def verify_graceful_restart( rmode = "Disable" else: rmode = "Helper" + + if rmode is None: + if ( + "bgp" not in input_dict[peer] + and "graceful-restart" in input_dict[peer] + ): + if ( + "graceful-restart" in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"]["graceful-restart"] + ): + rmode = "Restart" + elif ( + "graceful-restart-disable" + in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"][ + "graceful-restart-disable" + ] + ): + rmode = "Disable" + else: + rmode = "Helper" else: rmode = "Helper" @@ -3479,7 +3523,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3597,7 +3641,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3762,7 +3806,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3890,7 +3934,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer) if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: diff --git a/tests/topotests/lib/bgpcheck.py b/tests/topotests/lib/bgpcheck.py new file mode 100644 index 000000000000..5ca35a50a46b --- /dev/null +++ b/tests/topotests/lib/bgpcheck.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0-or-later + +# Copyright 2023, 6wind +import json + +from lib import topotest + + +def check_show_bgp_vpn_prefix_not_found(router, ipversion, prefix, rd, label=None): + """ + Check if a given vpn prefix is not present in the BGP RIB + * 'router': the router to check BGP VPN RIB + * 'ipversion': The ip version to check: ipv4 or ipv6 + * 'prefix': the IP prefix to check + * 'rd': the route distinguisher to check + * 'label: the label to check + """ + output = json.loads( + router.vtysh_cmd("show bgp {} vpn {} json".format(ipversion, prefix)) + ) + if label: + expected = {rd: {"prefix": prefix, "paths": [{"remoteLabel": label}]}} + else: + expected = {rd: {"prefix": prefix}} + ret = topotest.json_cmp(output, expected) + if ret is None: + return "not good" + return None + + +def check_show_bgp_vpn_prefix_found( + router, ipversion, prefix, rd, label=None, nexthop=None +): + """ + Check if a given vpn prefix is present in the BGP RIB + * 'router': the router to check BGP VPN RIB + * 'ipversion': The ip version to check: ipv4 or ipv6 + * 'prefix': the IP prefix to check + * 'rd': the route distinguisher to check + * 'label: the label to check + """ + output = json.loads( + router.vtysh_cmd("show bgp {} vpn {} json".format(ipversion, prefix)) + ) + if label: + if nexthop: + expected = { + rd: { + "prefix": prefix, + "paths": [{"remoteLabel": label, "nexthops": [{"ip": nexthop}]}], + } + } + else: + expected = {rd: {"prefix": prefix, "paths": [{"remoteLabel": label}]}} + else: + if nexthop: + expected = { + rd: {"prefix": prefix, "paths": [{"nexthops": [{"ip": nexthop}]}]} + } + else: + expected = {rd: {"prefix": prefix}} + return topotest.json_cmp(output, expected) diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index 699c7a4da612..f01a440b9e3b 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -64,10 +64,9 @@ def routes_include_wanted(self, pfxtbl, want, debug): self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"]) return 0 - def RequireVpnRoutes(self, target, title, wantroutes, debug=0): + def RequireVpnRoutesOne(self, target, title, wantroutes, debug=0): import json - logstr = "RequireVpnRoutes " + str(wantroutes) # non json form for humans luCommand( target, @@ -86,11 +85,18 @@ def RequireVpnRoutes(self, target, title, wantroutes, debug=0): if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True rib = json.loads(ret) - rds = rib["routes"]["routeDistinguishers"] + try: + rds = rib["routes"]["routeDistinguishers"] + except KeyError as err: + # KeyError: 'routes' probably means missing/bad VRF + # This error also happens if we are too quick and the routing + # table has not been fully populated yet. + if debug: + self.log("KeyError, no routes") + return False for want in wantroutes: found = 0 if debug: @@ -105,11 +111,39 @@ def RequireVpnRoutes(self, target, title, wantroutes, debug=0): found = 1 break if not found: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True + + def RequireVpnRoutes( + self, target, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireVpnRoutes " + str(wantroutes) + found = False + n = 0 + startt = time.time() + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found = self.RequireVpnRoutesOne(target, title, wantroutes, debug) + if found is not False: + break - def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title, logstr) + return found + + def RequireUnicastRoutesOne(self, target, afi, vrf, title, wantroutes, debug=0): logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": @@ -129,9 +163,8 @@ def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" rib = json.loads(ret) try: table = rib["routes"] @@ -141,25 +174,60 @@ def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) else: errstr = "-script ERROR: check if vrf missing" - luResult(target, False, title + errstr, logstr) - return + self.log(errstr) + return False, errstr # if debug: # self.log("table=%s" % table) for want in wantroutes: if debug: self.log("want=%s" % want) if not self.routes_include_wanted(table, want, debug): - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" + + def RequireUnicastRoutes( + self, target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireUnicastRoutes %s" % str(wantroutes) + found = False + n = 0 + startt = time.time() + errstr = "" + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found, errstr = self.RequireUnicastRoutesOne( + target, afi, vrf, title, wantroutes, debug + ) + if found is not False: + break + + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title + errstr, logstr) + return found BgpRib = BgpRib() -def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0): - BgpRib.RequireVpnRoutes(target, title, wantroutes, debug) +def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0, wait=10, wait_time=0.5): + BgpRib.RequireVpnRoutes(target, title, wantroutes, debug, wait, wait_time) -def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0): - BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug) +def bgpribRequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 +): + BgpRib.RequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug, wait, wait_time + ) diff --git a/tests/topotests/lib/bmp_collector/bgp/open/__init__.py b/tests/topotests/lib/bmp_collector/bgp/open/__init__.py index 6c814ee9aaca..e1e6b51f6429 100644 --- a/tests/topotests/lib/bmp_collector/bgp/open/__init__.py +++ b/tests/topotests/lib/bmp_collector/bgp/open/__init__.py @@ -8,27 +8,29 @@ class BGPOpen: - UNPACK_STR = '!16sHBBHH4sB' + UNPACK_STR = "!16sHBBHH4sB" @classmethod def dissect(cls, data): - (marker, - length, - open_type, - version, - my_as, - hold_time, - bgp_id, - optional_params_len) = struct.unpack_from(cls.UNPACK_STR, data) + ( + marker, + length, + open_type, + version, + my_as, + hold_time, + bgp_id, + optional_params_len, + ) = struct.unpack_from(cls.UNPACK_STR, data) - data = data[struct.calcsize(cls.UNPACK_STR) + optional_params_len:] + data = data[struct.calcsize(cls.UNPACK_STR) + optional_params_len :] # XXX: parse optional parameters return data, { - 'version': version, - 'my_as': my_as, - 'hold_time': hold_time, - 'bgp_id': ipaddress.ip_address(bgp_id), - 'optional_params_len': optional_params_len, + "version": version, + "my_as": my_as, + "hold_time": hold_time, + "bgp_id": ipaddress.ip_address(bgp_id), + "optional_params_len": optional_params_len, } diff --git a/tests/topotests/lib/bmp_collector/bgp/update/__init__.py b/tests/topotests/lib/bmp_collector/bgp/update/__init__.py index d079b3511363..629e1753646d 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/__init__.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/__init__.py @@ -10,45 +10,47 @@ from .path_attributes import PathAttribute -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BGPUpdate: - UNPACK_STR = '!16sHBH' + UNPACK_STR = "!16sHBH" STATIC_SIZE = 23 @classmethod def dissect(cls, data): - msg = {'bmp_log_type': 'update'} + msg = {"bmp_log_type": "update"} common_size = struct.calcsize(cls.UNPACK_STR) - (marker, - length, - update_type, - withdrawn_routes_len) = struct.unpack_from(cls.UNPACK_STR, data) + (marker, length, update_type, withdrawn_routes_len) = struct.unpack_from( + cls.UNPACK_STR, data + ) # get withdrawn routes - withdrawn_routes = '' + withdrawn_routes = "" if withdrawn_routes_len: withdrawn_routes = NlriIPv4Unicast.parse( - data[common_size:common_size + withdrawn_routes_len] + data[common_size : common_size + withdrawn_routes_len] ) - msg['bmp_log_type'] = 'withdraw' + msg["bmp_log_type"] = "withdraw" msg.update(withdrawn_routes) # get path attributes (total_path_attrs_len,) = struct.unpack_from( - '!H', data[common_size+withdrawn_routes_len:]) + "!H", data[common_size + withdrawn_routes_len :] + ) if total_path_attrs_len: offset = cls.STATIC_SIZE + withdrawn_routes_len - path_attrs_data = data[offset:offset + total_path_attrs_len] + path_attrs_data = data[offset : offset + total_path_attrs_len] while path_attrs_data: path_attrs_data, pattr = PathAttribute.dissect(path_attrs_data) if pattr: msg = {**msg, **pattr} # get nlri - nlri_len = length - cls.STATIC_SIZE - withdrawn_routes_len - total_path_attrs_len + nlri_len = ( + length - cls.STATIC_SIZE - withdrawn_routes_len - total_path_attrs_len + ) if nlri_len > 0: - nlri = NlriIPv4Unicast.parse(data[length - nlri_len:length]) + nlri = NlriIPv4Unicast.parse(data[length - nlri_len : length]) msg.update(nlri) return data[length:], msg diff --git a/tests/topotests/lib/bmp_collector/bgp/update/af.py b/tests/topotests/lib/bmp_collector/bgp/update/af.py index 01af1ae2be57..200b15a05d83 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/af.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/af.py @@ -19,7 +19,7 @@ SAFI_VPN_FLOWSPEC = 134 -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class AddressFamily: def __init__(self, afi, safi): self.afi = afi @@ -31,13 +31,13 @@ def __eq__(self, other): return (self.afi, self.safi) == (other.afi, other.safi) def __str__(self): - return f'afi: {self.afi}, safi: {self.safi}' + return f"afi: {self.afi}, safi: {self.safi}" def __hash__(self): return hash((self.afi, self.safi)) -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class AF: IPv4_UNICAST = AddressFamily(AFI_IP, SAFI_UNICAST) IPv6_UNICAST = AddressFamily(AFI_IP6, SAFI_UNICAST) diff --git a/tests/topotests/lib/bmp_collector/bgp/update/nlri.py b/tests/topotests/lib/bmp_collector/bgp/update/nlri.py index c1720f126cc1..b3625201f4d9 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/nlri.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/nlri.py @@ -13,7 +13,8 @@ def decode_label(label): # from frr # frr encode just one label - return (label[0] << 12) | (label[1] << 4) | (label[2] & 0xf0) >> 4 + return (label[0] << 12) | (label[1] << 4) | (label[2] & 0xF0) >> 4 + def padding(databin, len_): """ @@ -23,7 +24,8 @@ def padding(databin, len_): """ if len(databin) >= len_: return databin - return databin + b'\0' * (len_ - len(databin)) + return databin + b"\0" * (len_ - len(databin)) + def dissect_nlri(nlri_data, afi, safi): """ @@ -37,35 +39,34 @@ def dissect_nlri(nlri_data, afi, safi): elif addr_family == AF.IPv6_UNICAST: return NlriIPv6Unicast.parse(nlri_data) - return {'ip_prefix': 'Unknown'} + return {"ip_prefix": "Unknown"} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv4Unicast: - @staticmethod def parse(data): """parses prefixes from withdrawn_routes or nrli data""" - (prefix_len,) = struct.unpack_from('!B', data) + (prefix_len,) = struct.unpack_from("!B", data) prefix = padding(data[1:], 4) - return {'ip_prefix': f'{ipaddress.IPv4Address(prefix)}/{prefix_len}'} + return {"ip_prefix": f"{ipaddress.IPv4Address(prefix)}/{prefix_len}"} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv6Unicast: @staticmethod def parse(data): """parses prefixes from withdrawn_routes or nrli data""" - (prefix_len,) = struct.unpack_from('!B', data) + (prefix_len,) = struct.unpack_from("!B", data) prefix = padding(data[1:], 16) - return {'ip_prefix': f'{ipaddress.IPv6Address(prefix)}/{prefix_len}'} + return {"ip_prefix": f"{ipaddress.IPv6Address(prefix)}/{prefix_len}"} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv4Vpn: - UNPACK_STR = '!B3s8s' + UNPACK_STR = "!B3s8s" @classmethod def parse(cls, data): @@ -74,17 +75,17 @@ def parse(cls, data): ipv4 = padding(data[offset:], 4) # prefix_len = total_bits_len - label_bits_len - rd_bits_len - prefix_len = bit_len - 3*8 - 8*8 + prefix_len = bit_len - 3 * 8 - 8 * 8 return { - 'label': decode_label(label), - 'rd': str(RouteDistinguisher(rd)), - 'ip_prefix': f'{ipaddress.IPv4Address(ipv4)}/{prefix_len}', + "label": decode_label(label), + "rd": str(RouteDistinguisher(rd)), + "ip_prefix": f"{ipaddress.IPv4Address(ipv4)}/{prefix_len}", } -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv6Vpn: - UNPACK_STR = '!B3s8s' + UNPACK_STR = "!B3s8s" @classmethod def parse(cls, data): @@ -93,48 +94,49 @@ def parse(cls, data): offset = struct.calcsize(cls.UNPACK_STR) ipv6 = padding(data[offset:], 16) - prefix_len = bit_len - 3*8 - 8*8 + prefix_len = bit_len - 3 * 8 - 8 * 8 return { - 'label': decode_label(label), - 'rd': str(RouteDistinguisher(rd)), - 'ip_prefix': f'{ipaddress.IPv6Address(ipv6)}/{prefix_len}', + "label": decode_label(label), + "rd": str(RouteDistinguisher(rd)), + "ip_prefix": f"{ipaddress.IPv6Address(ipv6)}/{prefix_len}", } -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv4Mpls: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv6Mpls: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv4FlowSpec: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriIPv6FlowSpec: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriVpn4FlowSpec: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriVpn6FlowSpec: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class NlriL2EVPN: pass -#------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ class NlriL2VPNFlowSpec: pass diff --git a/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py b/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py index 6e82e9c1701c..3694cb4fe3df 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/path_attributes.py @@ -38,17 +38,18 @@ ORIGIN_INCOMPLETE = 0x02 -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttribute: PATH_ATTRS = {} UNKNOWN_ATTR = None - UNPACK_STR = '!BB' + UNPACK_STR = "!BB" @classmethod def register_path_attr(cls, path_attr): def _register_path_attr(subcls): cls.PATH_ATTRS[path_attr] = subcls return subcls + return _register_path_attr @classmethod @@ -61,7 +62,7 @@ def dissect(cls, data): offset = struct.calcsize(cls.UNPACK_STR) # get attribute length - attr_len_str = '!H' if (flags & PATH_ATTR_FLAG_EXTENDED_LENGTH) else '!B' + attr_len_str = "!H" if (flags & PATH_ATTR_FLAG_EXTENDED_LENGTH) else "!B" (attr_len,) = struct.unpack_from(attr_len_str, data[offset:]) @@ -69,32 +70,34 @@ def dissect(cls, data): path_attr_cls = cls.lookup_path_attr(type_code) if path_attr_cls == cls.UNKNOWN_ATTR: - return data[offset + attr_len:], None + return data[offset + attr_len :], None - return data[offset+attr_len:], path_attr_cls.dissect(data[offset:offset+attr_len]) + return data[offset + attr_len :], path_attr_cls.dissect( + data[offset : offset + attr_len] + ) -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @PathAttribute.register_path_attr(PATH_ATTR_TYPE_ORIGIN) class PathAttrOrigin: ORIGIN_STR = { - ORIGIN_IGP: 'IGP', - ORIGIN_EGP: 'EGP', - ORIGIN_INCOMPLETE: 'INCOMPLETE', + ORIGIN_IGP: "IGP", + ORIGIN_EGP: "EGP", + ORIGIN_INCOMPLETE: "INCOMPLETE", } @classmethod def dissect(cls, data): - (origin,) = struct.unpack_from('!B', data) + (origin,) = struct.unpack_from("!B", data) - return {'origin': cls.ORIGIN_STR.get(origin, 'UNKNOWN')} + return {"origin": cls.ORIGIN_STR.get(origin, "UNKNOWN")} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @PathAttribute.register_path_attr(PATH_ATTR_TYPE_AS_PATH) class PathAttrAsPath: AS_PATH_TYPE_SET = 0x01 - AS_PATH_TYPE_SEQUENCE= 0x02 + AS_PATH_TYPE_SEQUENCE = 0x02 @staticmethod def get_asn_len(asns): @@ -103,34 +106,34 @@ def get_asn_len(asns): @classmethod def dissect(cls, data): - (_type, _len) = struct.unpack_from('!BB', data) + (_type, _len) = struct.unpack_from("!BB", data) data = data[2:] - _type_str = 'Ordred' if _type == cls.AS_PATH_TYPE_SEQUENCE else 'Raw' + _type_str = "Ordred" if _type == cls.AS_PATH_TYPE_SEQUENCE else "Raw" segment = [] while data: - (asn,) = struct.unpack_from('!I', data) + (asn,) = struct.unpack_from("!I", data) segment.append(asn) data = data[4:] - return {'as_path': ' '.join(str(a) for a in segment)} + return {"as_path": " ".join(str(a) for a in segment)} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @PathAttribute.register_path_attr(PATH_ATTR_TYPE_NEXT_HOP) class PathAttrNextHop: @classmethod def dissect(cls, data): - (nexthop,) = struct.unpack_from('!4s', data) - return {'bgp_nexthop': str(ipaddress.IPv4Address(nexthop))} + (nexthop,) = struct.unpack_from("!4s", data) + return {"bgp_nexthop": str(ipaddress.IPv4Address(nexthop))} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrMultiExitDisc: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @PathAttribute.register_path_attr(PATH_ATTR_TYPE_MP_REACH_NLRI) class PathAttrMpReachNLRI: """ @@ -162,7 +165,8 @@ class PathAttrMpReachNLRI: | Network Layer Reachability Information (variable) | +---------------------------------------------------------+ """ - UNPACK_STR = '!HBB' + + UNPACK_STR = "!HBB" NLRI_RESERVED_LEN = 1 @staticmethod @@ -170,35 +174,35 @@ def dissect_nexthop(nexthop_data, nexthop_len): msg = {} if nexthop_len == 4: # IPv4 - (ipv4,) = struct.unpack_from('!4s', nexthop_data) - msg['nxhp_ip'] = str(ipaddress.IPv4Address(ipv4)) + (ipv4,) = struct.unpack_from("!4s", nexthop_data) + msg["nxhp_ip"] = str(ipaddress.IPv4Address(ipv4)) elif nexthop_len == 12: # RD + IPv4 - (rd, ipv4) = struct.unpack_from('!8s4s', nexthop_data) - msg['nxhp_ip'] = str(ipaddress.IPv4Address(ipv4)) - msg['nxhp_rd'] = str(RouteDistinguisher(rd)) + (rd, ipv4) = struct.unpack_from("!8s4s", nexthop_data) + msg["nxhp_ip"] = str(ipaddress.IPv4Address(ipv4)) + msg["nxhp_rd"] = str(RouteDistinguisher(rd)) elif nexthop_len == 16: # IPv6 - (ipv6,) = struct.unpack_from('!16s', nexthop_data) - msg['nxhp_ip'] = str(ipaddress.IPv6Address(ipv6)) + (ipv6,) = struct.unpack_from("!16s", nexthop_data) + msg["nxhp_ip"] = str(ipaddress.IPv6Address(ipv6)) elif nexthop_len == 24: # RD + IPv6 - (rd, ipv6) = struct.unpack_from('!8s16s', nexthop_data) - msg['nxhp_ip'] = str(ipaddress.IPv6Address(ipv6)) - msg['nxhp_rd'] = str(RouteDistinguisher(rd)) + (rd, ipv6) = struct.unpack_from("!8s16s", nexthop_data) + msg["nxhp_ip"] = str(ipaddress.IPv6Address(ipv6)) + msg["nxhp_rd"] = str(RouteDistinguisher(rd)) elif nexthop_len == 32: # IPv6 + IPv6 link-local - (ipv6, link_local)= struct.unpack_from('!16s16s', nexthop_data) - msg['nxhp_ip'] = str(ipaddress.IPv6Address(ipv6)) - msg['nxhp_link-local'] = str(ipaddress.IPv6Address(link_local)) + (ipv6, link_local) = struct.unpack_from("!16s16s", nexthop_data) + msg["nxhp_ip"] = str(ipaddress.IPv6Address(ipv6)) + msg["nxhp_link-local"] = str(ipaddress.IPv6Address(link_local)) elif nexthop_len == 48: # RD + IPv6 + RD + IPv6 link-local - u_str = '!8s16s8s16s' - (rd1, ipv6, rd2, link_local)= struct.unpack_from(u_str, nexthop_data) - msg['nxhp_rd1'] = str(RouteDistinguisher(rd1)) - msg['nxhp_ip'] = str(ipaddress.IPv6Address(ipv6)) - msg['nxhp_rd2'] = str(RouteDistinguisher(rd2)) - msg['nxhp_link-local'] = str(ipaddress.IPv6Address(link_local)) + u_str = "!8s16s8s16s" + (rd1, ipv6, rd2, link_local) = struct.unpack_from(u_str, nexthop_data) + msg["nxhp_rd1"] = str(RouteDistinguisher(rd1)) + msg["nxhp_ip"] = str(ipaddress.IPv6Address(ipv6)) + msg["nxhp_rd2"] = str(RouteDistinguisher(rd2)) + msg["nxhp_link-local"] = str(ipaddress.IPv6Address(link_local)) return msg @@ -210,10 +214,10 @@ def dissect_snpa(snpa_data): def dissect(cls, data): (afi, safi, nexthop_len) = struct.unpack_from(cls.UNPACK_STR, data) offset = struct.calcsize(cls.UNPACK_STR) - msg = {'afi': afi, 'safi': safi} + msg = {"afi": afi, "safi": safi} # dissect nexthop - nexthop_data = data[offset: offset + nexthop_len] + nexthop_data = data[offset : offset + nexthop_len] nexthop = cls.dissect_nexthop(nexthop_data, nexthop_len) msg.update(nexthop) @@ -227,7 +231,7 @@ def dissect(cls, data): return msg -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @PathAttribute.register_path_attr(PATH_ATTR_TYPE_MP_UNREACH_NLRI) class PathAttrMpUnReachNLRI: """ @@ -239,13 +243,14 @@ class PathAttrMpUnReachNLRI: | Withdrawn Routes (variable) | +---------------------------------------------------------+ """ - UNPACK_STR = '!HB' + + UNPACK_STR = "!HB" @classmethod def dissect(cls, data): (afi, safi) = struct.unpack_from(cls.UNPACK_STR, data) offset = struct.calcsize(cls.UNPACK_STR) - msg = {'bmp_log_type': 'withdraw','afi': afi, 'safi': safi} + msg = {"bmp_log_type": "withdraw", "afi": afi, "safi": safi} if data[offset:]: # dissect withdrawn_routes @@ -254,51 +259,51 @@ def dissect(cls, data): return msg -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrLocalPref: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrAtomicAgregate: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrAggregator: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrCommunities: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrOriginatorID: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrClusterList: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrExtendedCommunities: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrPMSITunnel: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrLinkState: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class PathAttrLargeCommunities: pass diff --git a/tests/topotests/lib/bmp_collector/bgp/update/rd.py b/tests/topotests/lib/bmp_collector/bgp/update/rd.py index c382fa834020..3f08de5ae9f0 100644 --- a/tests/topotests/lib/bmp_collector/bgp/update/rd.py +++ b/tests/topotests/lib/bmp_collector/bgp/update/rd.py @@ -7,7 +7,7 @@ import struct -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class RouteDistinguisher: """ type 0: @@ -28,32 +28,32 @@ class RouteDistinguisher: + | 4-bytes AS number (4 bytes)| Service Provider 2 bytes)| +-------------------------------------------------------------------------+ """ + def __init__(self, rd): self.rd = rd self.as_number = None self.admin_ipv4 = None self.four_bytes_as = None self.assigned_sp = None - self.repr_str = '' + self.repr_str = "" self.dissect() def dissect(self): - (rd_type,) = struct.unpack_from('!H', self.rd) + (rd_type,) = struct.unpack_from("!H", self.rd) if rd_type == 0: - (self.as_number, - self.assigned_sp) = struct.unpack_from('!HI', self.rd[2:]) - self.repr_str = f'{self.as_number}:{self.assigned_sp}' + (self.as_number, self.assigned_sp) = struct.unpack_from("!HI", self.rd[2:]) + self.repr_str = f"{self.as_number}:{self.assigned_sp}" elif rd_type == 1: - (self.admin_ipv4, - self.assigned_sp) = struct.unpack_from('!IH', self.rd[2:]) + (self.admin_ipv4, self.assigned_sp) = struct.unpack_from("!IH", self.rd[2:]) ipv4 = str(ipaddress.IPv4Address(self.admin_ipv4)) - self.repr_str = f'{self.as_number}:{self.assigned_sp}' + self.repr_str = f"{self.as_number}:{self.assigned_sp}" elif rd_type == 2: - (self.four_bytes_as, - self.assigned_sp) = struct.unpack_from('!IH', self.rd[2:]) - self.repr_str = f'{self.four_bytes_as}:{self.assigned_sp}' + (self.four_bytes_as, self.assigned_sp) = struct.unpack_from( + "!IH", self.rd[2:] + ) + self.repr_str = f"{self.four_bytes_as}:{self.assigned_sp}" def __str__(self): return self.repr_str diff --git a/tests/topotests/lib/bmp_collector/bmp.py b/tests/topotests/lib/bmp_collector/bmp.py index b07329cd523f..237decdd5ecb 100644 --- a/tests/topotests/lib/bmp_collector/bmp.py +++ b/tests/topotests/lib/bmp_collector/bmp.py @@ -33,30 +33,33 @@ if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) + def bin2str_ipaddress(ip_bytes, is_ipv6=False): if is_ipv6: return str(ipaddress.IPv6Address(ip_bytes)) return str(ipaddress.IPv4Address(ip_bytes[-4:])) -def log2file(logs): + +def log2file(logs, log_file): """ XXX: extract the useful information and save it in a flat dictionnary """ - with open(LOG_FILE, 'a') as f: + with open(log_file, "a") as f: f.write(json.dumps(logs) + "\n") -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPCodes: """ XXX: complete the list, provide RFCs. """ + VERSION = 0x3 BMP_MSG_TYPE_ROUTE_MONITORING = 0x00 BMP_MSG_TYPE_STATISTICS_REPORT = 0x01 - BMP_MSG_TYPE_PEER_DOWN_NOTIFICATION = 0x02 - BMP_MSG_TYPE_PEER_UP_NOTIFICATION = 0x03 + BMP_MSG_TYPE_PEER_DOWN_NOTIFICATION = 0x02 + BMP_MSG_TYPE_PEER_UP_NOTIFICATION = 0x03 BMP_MSG_TYPE_INITIATION = 0x04 BMP_MSG_TYPE_TERMINATION = 0x05 BMP_MSG_TYPE_ROUTE_MIRRORING = 0x06 @@ -107,15 +110,15 @@ class BMPCodes: # peer down reason code BMP_PEER_DOWN_LOCAL_NOTIFY = 0x01 - BMP_PEER_DOWN_LOCAL_NO_NOTIFY = 0X02 - BMP_PEER_DOWN_REMOTE_NOTIFY = 0X03 - BMP_PEER_DOWN_REMOTE_NO_NOTIFY = 0X04 + BMP_PEER_DOWN_LOCAL_NO_NOTIFY = 0x02 + BMP_PEER_DOWN_REMOTE_NOTIFY = 0x03 + BMP_PEER_DOWN_REMOTE_NO_NOTIFY = 0x04 BMP_PEER_DOWN_INFO_NO_LONGER = 0x05 - BMP_PEER_DOWN_SYSTEM_CLOSED = 0X06 + BMP_PEER_DOWN_SYSTEM_CLOSED = 0x06 # termincation message types BMP_TERM_TYPE_STRING = 0x00 - BMP_TERM_TYPE_REASON = 0X01 + BMP_TERM_TYPE_REASON = 0x01 # termination reason code BMP_TERM_REASON_ADMIN_CLOSE = 0x00 @@ -126,31 +129,32 @@ class BMPCodes: # policy route tlv BMP_ROUTE_POLICY_TLV_VRF = 0x00 - BMP_ROUTE_POLICY_TLV_POLICY= 0x01 + BMP_ROUTE_POLICY_TLV_POLICY = 0x01 BMP_ROUTE_POLICY_TLV_PRE_POLICY = 0x02 BMP_ROUTE_POLICY_TLV_POST_POLICY = 0x03 BMP_ROUTE_POLICY_TLV_STRING = 0x04 -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPMsg: """ XXX: should we move register_msg_type and look_msg_type to generic Type class. """ + TYPES = {} UNKNOWN_TYPE = None - HDR_STR = '!BIB' + HDR_STR = "!BIB" MIN_LEN = struct.calcsize(HDR_STR) TYPES_STR = { - BMPCodes.BMP_MSG_TYPE_INITIATION: 'initiation', - BMPCodes.BMP_MSG_TYPE_PEER_DOWN_NOTIFICATION: 'peer down notification', - BMPCodes.BMP_MSG_TYPE_PEER_UP_NOTIFICATION: 'peer up notification', - BMPCodes.BMP_MSG_TYPE_ROUTE_MONITORING: 'route monitoring', - BMPCodes.BMP_MSG_TYPE_STATISTICS_REPORT: 'statistics report', - BMPCodes.BMP_MSG_TYPE_TERMINATION: 'termination', - BMPCodes.BMP_MSG_TYPE_ROUTE_MIRRORING: 'route mirroring', - BMPCodes.BMP_MSG_TYPE_ROUTE_POLICY: 'route policy', + BMPCodes.BMP_MSG_TYPE_INITIATION: "initiation", + BMPCodes.BMP_MSG_TYPE_PEER_DOWN_NOTIFICATION: "peer down notification", + BMPCodes.BMP_MSG_TYPE_PEER_UP_NOTIFICATION: "peer up notification", + BMPCodes.BMP_MSG_TYPE_ROUTE_MONITORING: "route monitoring", + BMPCodes.BMP_MSG_TYPE_STATISTICS_REPORT: "statistics report", + BMPCodes.BMP_MSG_TYPE_TERMINATION: "termination", + BMPCodes.BMP_MSG_TYPE_ROUTE_MIRRORING: "route mirroring", + BMPCodes.BMP_MSG_TYPE_ROUTE_POLICY: "route policy", } @classmethod @@ -158,6 +162,7 @@ def register_msg_type(cls, msgtype): def _register_type(subcls): cls.TYPES[msgtype] = subcls return subcls + return _register_type @classmethod @@ -179,15 +184,15 @@ def dissect_header(cls, data): if len(data) < cls.MIN_LEN: pass else: - _version, _len, _type = struct.unpack(cls.HDR_STR, data[0:cls.MIN_LEN]) + _version, _len, _type = struct.unpack(cls.HDR_STR, data[0 : cls.MIN_LEN]) return _version, _len, _type @classmethod - def dissect(cls, data): + def dissect(cls, data, log_file=None): global SEQ version, msglen, msgtype = cls.dissect_header(data) - msg_data = data[cls.MIN_LEN:msglen] + msg_data = data[cls.MIN_LEN : msglen] data = data[msglen:] if version != BMPCodes.VERSION: @@ -202,13 +207,13 @@ def dissect(cls, data): msg_cls.MSG_LEN = msglen - cls.MIN_LEN logs = msg_cls.dissect(msg_data) logs["seq"] = SEQ - log2file(logs) + log2file(logs, log_file if log_file else LOG_FILE) SEQ += 1 return data -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPPerPeerMessage: """ 0 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 @@ -229,29 +234,33 @@ class BMPPerPeerMessage: | Timestamp (microseconds) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ - PEER_UNPACK_STR = '!BB8s16sI4sII' + + PEER_UNPACK_STR = "!BB8s16sI4sII" PEER_TYPE_STR = { - BMPCodes.BMP_PEER_GLOBAL_INSTANCE: 'global instance', - BMPCodes.BMP_PEER_RD_INSTANCE: 'route distinguisher instance', - BMPCodes.BMP_PEER_LOCAL_INSTANCE: 'local instance', - BMPCodes.BMP_PEER_LOC_RIB_INSTANCE: 'loc-rib instance', + BMPCodes.BMP_PEER_GLOBAL_INSTANCE: "global instance", + BMPCodes.BMP_PEER_RD_INSTANCE: "route distinguisher instance", + BMPCodes.BMP_PEER_LOCAL_INSTANCE: "local instance", + BMPCodes.BMP_PEER_LOC_RIB_INSTANCE: "loc-rib instance", } @classmethod def dissect(cls, data): - (peer_type, - peer_flags, - peer_distinguisher, - peer_address, - peer_asn, - peer_bgp_id, - timestamp_secs, - timestamp_microsecs) = struct.unpack_from(cls.PEER_UNPACK_STR, data) - - msg = {'peer_type': cls.PEER_TYPE_STR[peer_type]} + ( + peer_type, + peer_flags, + peer_distinguisher, + peer_address, + peer_asn, + peer_bgp_id, + timestamp_secs, + timestamp_microsecs, + ) = struct.unpack_from(cls.PEER_UNPACK_STR, data) + + msg = {"peer_type": cls.PEER_TYPE_STR[peer_type]} if peer_type == 0x03: - msg['is_filtered'] = bool(peer_flags & IS_FILTERED) + msg["is_filtered"] = bool(peer_flags & IS_FILTERED) + msg["policy"] = "loc-rib" else: # peer_flags = 0x0000 0000 # ipv6, post-policy, as-path, adj-rib-out, reserverdx4 @@ -259,29 +268,29 @@ def dissect(cls, data): is_as_path = bool(peer_flags & IS_AS_PATH) is_post_policy = bool(peer_flags & IS_POST_POLICY) is_ipv6 = bool(peer_flags & IS_IPV6) - msg['post_policy'] = is_post_policy - msg['ipv6'] = is_ipv6 - msg['peer_ip'] = bin2str_ipaddress(peer_address, is_ipv6) - + msg["policy"] = "post-policy" if is_post_policy else "pre-policy" + msg["ipv6"] = is_ipv6 + msg["peer_ip"] = bin2str_ipaddress(peer_address, is_ipv6) peer_bgp_id = bin2str_ipaddress(peer_bgp_id) - timestamp = float(timestamp_secs) + timestamp_microsecs * (10 ** -6) - - data = data[struct.calcsize(cls.PEER_UNPACK_STR):] - msg.update({ - 'peer_distinguisher': str(RouteDistinguisher(peer_distinguisher)), - 'peer_asn': peer_asn, - 'peer_bgp_id': peer_bgp_id, - 'timestamp': str(datetime.datetime.fromtimestamp(timestamp)), - }) + timestamp = float(timestamp_secs) + timestamp_microsecs * (10**-6) + + data = data[struct.calcsize(cls.PEER_UNPACK_STR) :] + msg.update( + { + "peer_distinguisher": str(RouteDistinguisher(peer_distinguisher)), + "peer_asn": peer_asn, + "peer_bgp_id": peer_bgp_id, + "timestamp": str(datetime.datetime.fromtimestamp(timestamp)), + } + ) return data, msg -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @BMPMsg.register_msg_type(BMPCodes.BMP_MSG_TYPE_ROUTE_MONITORING) class BMPRouteMonitoring(BMPPerPeerMessage): - @classmethod def dissect(cls, data): data, peer_msg = super().dissect(data) @@ -289,7 +298,7 @@ def dissect(cls, data): return {**peer_msg, **update_msg} -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPStatisticsReport: """ 0 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 @@ -302,10 +311,11 @@ class BMPStatisticsReport: ~ ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ + pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPPeerDownNotification: """ 0 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 @@ -315,10 +325,11 @@ class BMPPeerDownNotification: | Data (present if Reason = 1, 2 or 3) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ + pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @BMPMsg.register_msg_type(BMPCodes.BMP_MSG_TYPE_PEER_UP_NOTIFICATION) class BMPPeerUpNotification(BMPPerPeerMessage): """ @@ -335,7 +346,8 @@ class BMPPeerUpNotification(BMPPerPeerMessage): ~ ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ - UNPACK_STR = '!16sHH' + + UNPACK_STR = "!16sHH" MIN_LEN = struct.calcsize(UNPACK_STR) MSG_LEN = None @@ -343,16 +355,14 @@ class BMPPeerUpNotification(BMPPerPeerMessage): def dissect(cls, data): data, peer_msg = super().dissect(data) - (local_addr, - local_port, - remote_port) = struct.unpack_from(cls.UNPACK_STR, data) + (local_addr, local_port, remote_port) = struct.unpack_from(cls.UNPACK_STR, data) msg = { **peer_msg, **{ - 'local_ip': bin2str_ipaddress(local_addr, peer_msg.get('ipv6')), - 'local_port': int(local_port), - 'remote_port': int(remote_port), + "local_ip": bin2str_ipaddress(local_addr, peer_msg.get("ipv6")), + "local_port": int(local_port), + "remote_port": int(remote_port), }, } @@ -361,7 +371,7 @@ def dissect(cls, data): return msg -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ @BMPMsg.register_msg_type(BMPCodes.BMP_MSG_TYPE_INITIATION) class BMPInitiation: """ @@ -373,30 +383,31 @@ class BMPInitiation: ~ ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ - TLV_STR = '!HH' + + TLV_STR = "!HH" MIN_LEN = struct.calcsize(TLV_STR) FIELD_TO_STR = { - BMPCodes.BMP_INIT_INFO_STRING: 'information', - BMPCodes.BMP_INIT_ADMIN_LABEL: 'admin_label', - BMPCodes.BMP_INIT_SYSTEM_DESCRIPTION: 'system_description', - BMPCodes.BMP_INIT_SYSTEM_NAME: 'system_name', - BMPCodes.BMP_INIT_VRF_TABLE_NAME: 'vrf_table_name', + BMPCodes.BMP_INIT_INFO_STRING: "information", + BMPCodes.BMP_INIT_ADMIN_LABEL: "admin_label", + BMPCodes.BMP_INIT_SYSTEM_DESCRIPTION: "system_description", + BMPCodes.BMP_INIT_SYSTEM_NAME: "system_name", + BMPCodes.BMP_INIT_VRF_TABLE_NAME: "vrf_table_name", } @classmethod def dissect(cls, data): msg = {} while len(data) > cls.MIN_LEN: - _type, _len = struct.unpack_from(cls.TLV_STR, data[0:cls.MIN_LEN]) - _value = data[cls.MIN_LEN: cls.MIN_LEN + _len].decode() + _type, _len = struct.unpack_from(cls.TLV_STR, data[0 : cls.MIN_LEN]) + _value = data[cls.MIN_LEN : cls.MIN_LEN + _len].decode() msg[cls.FIELD_TO_STR[_type]] = _value - data = data[cls.MIN_LEN + _len:] + data = data[cls.MIN_LEN + _len :] return msg -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPTermination: """ 0 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 @@ -407,14 +418,15 @@ class BMPTermination: ~ ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ + pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPRouteMirroring: pass -#------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ class BMPRoutePolicy: pass diff --git a/tests/topotests/lib/bmp_collector/bmpserver b/tests/topotests/lib/bmp_collector/bmpserver index 25b4a52c5eb1..5257df7530b6 100755 --- a/tests/topotests/lib/bmp_collector/bmpserver +++ b/tests/topotests/lib/bmp_collector/bmpserver @@ -16,10 +16,12 @@ BGP_MAX_SIZE = 4096 parser = argparse.ArgumentParser() parser.add_argument("-a", "--address", type=str, default="0.0.0.0") parser.add_argument("-p", "--port", type=int, default=1789) +parser.add_argument("-l", "--logfile", type=str, default="/var/log/bmp.log") def main(): args = parser.parse_args() ADDRESS, PORT = args.address, args.port + LOG_FILE = args.logfile with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -31,7 +33,7 @@ def main(): while True: data = connection.recv(BGP_MAX_SIZE) while len(data) > BMPMsg.MIN_LEN: - data = BMPMsg.dissect(data) + data = BMPMsg.dissect(data, log_file=LOG_FILE) except Exception as e: # XXX: do something pass diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py index aaa6164dd45f..aa95f45b2967 100644 --- a/tests/topotests/lib/checkping.py +++ b/tests/topotests/lib/checkping.py @@ -8,7 +8,7 @@ from lib import topotest -def check_ping(name, dest_addr, expect_connected, count, wait): +def check_ping(name, dest_addr, expect_connected, count, wait, source_addr=None): """ Assert that ping to dest_addr is expected * 'name': the router to set the ping from @@ -18,9 +18,13 @@ def check_ping(name, dest_addr, expect_connected, count, wait): * 'wait': how long ping should wait to receive all replies """ - def _check(name, dest_addr, match): + def _check(name, dest_addr, source_addr, match): tgen = get_topogen() - output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr)) + cmd = "ping {}".format(dest_addr) + if source_addr: + cmd += " -I {}".format(source_addr) + cmd += " -c 1 -w 1" + output = tgen.gears[name].run(cmd) logger.info(output) if match not in output: return "ping fail" @@ -28,6 +32,6 @@ def _check(name, dest_addr, match): match = ", {} packet loss".format("0%" if expect_connected else "100%") logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() - func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=count, wait=wait) + func = functools.partial(_check, name, dest_addr, source_addr, match) + _, result = topotest.run_and_expect(func, None, count=count, wait=wait) assert result is None, "Failed" diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py new file mode 100644 index 000000000000..19f02dbadc9f --- /dev/null +++ b/tests/topotests/lib/common_check.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# common_check.py +# +# Copyright 2024 6WIND S.A. + +# +import json +from lib import topotest + + +def ip_check_path_selection( + router, ipaddr_str, expected, vrf_name=None, check_fib=False +): + if vrf_name: + cmdstr = f"show ip route vrf {vrf_name} {ipaddr_str} json" + else: + cmdstr = f"show ip route {ipaddr_str} json" + try: + output = json.loads(router.vtysh_cmd(cmdstr)) + except: + output = {} + + ret = topotest.json_cmp(output, expected) + if ret is None: + num_nh_expected = len(expected[ipaddr_str][0]["nexthops"]) + num_nh_observed = len(output[ipaddr_str][0]["nexthops"]) + if num_nh_expected == num_nh_observed: + if check_fib: + # special case: when fib flag is unset, + # an extra test should be done to check that the flag is really unset + for nh_output, nh_expected in zip( + output[ipaddr_str][0]["nexthops"], + expected[ipaddr_str][0]["nexthops"], + ): + if ( + "fib" in nh_output.keys() + and nh_output["fib"] + and ("fib" not in nh_expected.keys() or not nh_expected["fib"]) + ): + return "{}, prefix {} nexthop {} has the fib flag set, whereas it is not expected".format( + router.name, ipaddr_str, nh_output["ip"] + ) + return ret + return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format( + router.name, ipaddr_str, num_nh_observed, num_nh_expected + ) + return ret + + +def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): + if not topotest.iproute2_is_json_capable(): + return None + + if vrf_name: + cmdstr = f"ip -json route show vrf {vrf_name} {ipaddr_str}" + else: + cmdstr = f"ip -json route show {ipaddr_str}" + try: + output = json.loads(cmdstr) + except: + output = [] + + return topotest.json_cmp(output, expected) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index e19d96f918ec..e856c23d3632 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -7,13 +7,13 @@ import functools import ipaddress -import json import os import platform import socket import subprocess import sys import traceback +import configparser from collections import OrderedDict from copy import deepcopy from datetime import datetime, timedelta @@ -21,12 +21,6 @@ from re import search as re_search from time import sleep -try: - # Imports from python2 - import ConfigParser as configparser -except ImportError: - # Imports from python3 - import configparser from lib.micronet import comm_error from lib.topogen import TopoRouter, get_topogen @@ -447,7 +441,7 @@ def check_router_status(tgen): try: router_list = tgen.routers() - for router, rnode in router_list.items(): + for _, rnode in router_list.items(): result = rnode.check_router_running() if result != "": daemons = [] @@ -691,7 +685,7 @@ def prep_load_config_to_routers(tgen, *config_name_list): """ routers = tgen.routers() - for rname, router in routers.items(): + for rname, _ in routers.items(): destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_FILE) wmode = "w" for cfbase in config_name_list: @@ -876,7 +870,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): """ router_list = tgen.routers() - for rname, rnode in router_list.items(): + for rname, _ in router_list.items(): if rname != router: continue @@ -892,7 +886,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): cmd = "show interface vrf {}".format(vrf) else: cmd = "show interface" - for chk_ll in range(0, 60): + for _ in range(0, 60): sleep(1 / 4) ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd)) # Fix newlines (make them all the same) @@ -941,14 +935,26 @@ def generate_support_bundle(): """ tgen = get_topogen() + if tgen is None: + logger.warn( + "Support bundle attempted to be generated, but topogen is not being used" + ) + return True + router_list = tgen.routers() test_name = os.environ.get("PYTEST_CURRENT_TEST").split(":")[-1].split(" ")[0] bundle_procs = {} for rname, rnode in router_list.items(): logger.info("Spawn collection of support bundle for %s", rname) - dst_bundle = "{}/{}/support_bundles/{}".format(tgen.logdir, rname, test_name) - rnode.run("mkdir -p " + dst_bundle) + try: + dst_bundle = "{}/{}/support_bundles/{}".format( + tgen.logdir, rname, test_name + ) + rnode.run("mkdir -p " + dst_bundle) + except Exception as err: + logger.error("Generation of Support bundle failed {}".format(err)) + return True gen_sup_cmd = [ "/usr/lib/frr/generate_support_bundle.py", @@ -3088,7 +3094,7 @@ def configure_brctl(tgen, topo, input_dict): "{} dev {} master {}".format(ip_cmd, brctl_name, vrf) ) - for intf_name, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "vrf" not in data: continue @@ -4935,7 +4941,7 @@ def scapy_send_raw_packet(tgen, topo, senderRouter, intf, packet=None): sender_interface = intf rnode = tgen.routers()[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py new file mode 100755 index 000000000000..784f7d17eb29 --- /dev/null +++ b/tests/topotests/lib/fe_client.py @@ -0,0 +1,457 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: GPL-2.0-or-later +# +# November 27 2023, Christian Hopps +# +# Copyright (c) 2023, LabN Consulting, L.L.C. +# +# noqa: E501 +# +import argparse +import logging +import os +import socket +import struct +import sys +import time +from pathlib import Path + +from munet.base import Timeout + +CWD = os.path.dirname(os.path.realpath(__file__)) + +# This is painful but works if you have installed protobuf would be better if we +# actually built and installed these but ... python packaging. +try: + sys.path.append(os.path.dirname(CWD)) + from munet.base import commander + + commander.cmd_raises(f"protoc --python_out={CWD} -I {CWD}/../../../lib mgmt.proto") +except Exception as error: + logging.error("can't create protobuf definition modules %s", error) + raise + +try: + sys.path[0:0] = "." + import mgmt_pb2 +except Exception as error: + logging.error("can't import proto definition modules %s", error) + raise + +CANDIDATE_DS = mgmt_pb2.DatastoreId.CANDIDATE_DS +OPERATIONAL_DS = mgmt_pb2.DatastoreId.OPERATIONAL_DS +RUNNING_DS = mgmt_pb2.DatastoreId.RUNNING_DS +STARTUP_DS = mgmt_pb2.DatastoreId.STARTUP_DS + +# ===================== +# Native message values +# ===================== + +MGMT_MSG_MARKER_PROTOBUF = b"\000###" +MGMT_MSG_MARKER_NATIVE = b"\001###" + +# +# Native message formats +# +MSG_HDR_FMT = "=H2xIQQ" +HDR_FIELD_CODE = 0 +HDR_FIELD_VSPLIT = 1 +HDR_FIELD_SESS_ID = 2 +HDR_FIELD_REQ_ID = 3 + +MSG_ERROR_FMT = "=h6x" +ERROR_FIELD_ERROR = 0 + +# MSG_GET_TREE_FMT = "=B7x" +# GET_TREE_FIELD_RESULT_TYPE = 0 + +MSG_TREE_DATA_FMT = "=bBB5x" +TREE_DATA_FIELD_PARTIAL_ERROR = 0 +TREE_DATA_FIELD_RESULT_TYPE = 1 +TREE_DATA_FIELD_MORE = 2 + +MSG_GET_DATA_FMT = "=BB6x" +GET_DATA_FIELD_RESULT_TYPE = 0 +GET_DATA_FIELD_FLAGS = 1 +GET_DATA_FLAG_STATE = 0x1 +GET_DATA_FLAG_CONFIG = 0x2 +GET_DATA_FLAG_EXACT = 0x4 + +MSG_NOTIFY_FMT = "=B7x" +NOTIFY_FIELD_RESULT_TYPE = 0 + +MSG_NOTIFY_SELECT_FMT = "=B7x" + +MSG_SESSION_REQ_FMT = "=8x" + +MSG_SESSION_REPLY_FMT = "=B7x" +SESSION_REPLY_FIELD_CREATED = 0 + +# +# Native message codes +# +MSG_CODE_ERROR = 0 +# MSG_CODE_GET_TREE = 1 +MSG_CODE_TREE_DATA = 2 +MSG_CODE_GET_DATA = 3 +MSG_CODE_NOTIFY = 4 +MSG_CODE_NOTIFY_SELECT = 9 +MSG_CODE_SESSION_REQ = 10 +MSG_CODE_SESSION_REPLY = 11 + +msg_native_formats = { + MSG_CODE_ERROR: MSG_ERROR_FMT, + # MSG_CODE_GET_TREE: MSG_GET_TREE_FMT, + MSG_CODE_TREE_DATA: MSG_TREE_DATA_FMT, + MSG_CODE_GET_DATA: MSG_GET_DATA_FMT, + MSG_CODE_NOTIFY: MSG_NOTIFY_FMT, + MSG_CODE_NOTIFY_SELECT: MSG_NOTIFY_SELECT_FMT, + MSG_CODE_SESSION_REQ: MSG_SESSION_REQ_FMT, + MSG_CODE_SESSION_REPLY: MSG_SESSION_REPLY_FMT, +} + + +# Result formats +MSG_FORMAT_XML = 1 +MSG_FORMAT_JSON = 2 +MSG_FORMAT_LYB = 3 + + +def cstr(mdata): + assert mdata[-1] == 0 + return mdata[:-1] + + +class FEClientError(Exception): + pass + + +class PBMessageError(FEClientError): + def __init__(self, msg, errstr): + self.msg = msg + # self.sess_id = mhdr[HDR_FIELD_SESS_ID] + # self.req_id = mhdr[HDR_FIELD_REQ_ID] + self.error = -1 + self.errstr = errstr + super().__init__(f"PBMessageError: {self.errstr}: {msg}") + + +class NativeMessageError(FEClientError): + def __init__(self, mhdr, mfixed, mdata): + self.mhdr = mhdr + self.sess_id = mhdr[HDR_FIELD_SESS_ID] + self.req_id = mhdr[HDR_FIELD_REQ_ID] + self.error = mfixed[0] + self.errstr = cstr(mdata) + super().__init__( + "NativeMessageError: " + f"session {self.sess_id} reqid {self.req_id} " + f"error {self.error}: {self.errstr}" + ) + + +# +# Low-level socket functions +# + + +def recv_wait(sock, size): + """Receive a fixed number of bytes from a stream socket.""" + data = b"" + while len(data) < size: + newdata = sock.recv(size - len(data)) + if not newdata: + raise Exception("Socket closed") + data += newdata + return data + + +def recv_msg(sock): + marker = recv_wait(sock, 4) + assert marker in (MGMT_MSG_MARKER_PROTOBUF, MGMT_MSG_MARKER_NATIVE) + + msize = int.from_bytes(recv_wait(sock, 4), byteorder=sys.byteorder) + assert msize >= 8 + mdata = recv_wait(sock, msize - 8) if msize > 8 else b"" + + return mdata, marker == MGMT_MSG_MARKER_NATIVE + + +def send_msg(sock, marker, mdata): + """Send a mgmtd native message to a stream socket.""" + msize = int.to_bytes(len(mdata) + 8, byteorder=sys.byteorder, length=4) + sock.send(marker) + sock.send(msize) + sock.send(mdata) + + +class Session: + """A session to the mgmtd server.""" + + client_id = 1 + + def __init__(self, sock, use_protobuf): + self.sock = sock + self.next_req_id = 1 + + if use_protobuf: + req = mgmt_pb2.FeMessage() + req.register_req.client_name = "test-client" + self.send_pb_msg(req) + logging.debug("Sent FeRegisterReq: %s", req) + + req = mgmt_pb2.FeMessage() + req.session_req.create = 1 + req.session_req.client_conn_id = Session.client_id + Session.client_id += 1 + self.send_pb_msg(req) + logging.debug("Sent FeSessionReq: %s", req) + + reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) + logging.debug("Received FeSessionReply: %s", repr(reply)) + + assert reply.session_reply.success + self.sess_id = reply.session_reply.session_id + else: + self.sess_id = 0 + mdata, _ = self.get_native_msg_header(MSG_CODE_SESSION_REQ) + mdata += struct.pack(MSG_SESSION_REQ_FMT) + mdata += "test-client".encode("utf-8") + b"\x00" + + self.send_native_msg(mdata) + logging.debug("Sent native SESSION-REQ") + + mhdr, mfixed, mdata = self.recv_native_msg() + if mhdr[HDR_FIELD_CODE] == MSG_CODE_SESSION_REPLY: + logging.debug("Recv native SESSION-REQ Message: %s: %s", mfixed, mdata) + else: + raise Exception(f"Recv NON-SESSION-REPLY Message: {mfixed}: {mdata}") + assert mfixed[0] + self.sess_id = mhdr[HDR_FIELD_SESS_ID] + + def close(self, clean=True): + if clean: + req = mgmt_pb2.FeMessage() + req.session_req.create = 0 + req.session_req.sess_id = self.sess_id + self.send_pb_msg(req) + self.sock.close() + self.sock = None + + def get_next_req_id(self): + req_id = self.next_req_id + self.next_req_id += 1 + return req_id + + # -------------------------- + # Protobuf message functions + # -------------------------- + + def recv_pb_msg(self, msg): + """Receive a protobuf message.""" + mdata, native = recv_msg(self.sock) + assert not native + + msg.ParseFromString(mdata) + + req = getattr(msg, msg.WhichOneof("message")) + if req.HasField("success"): + if not req.success: + raise PBMessageError(msg, req.error_if_any) + + return msg + + def send_pb_msg(self, msg): + """Send a protobuf message.""" + mdata = msg.SerializeToString() + return send_msg(self.sock, MGMT_MSG_MARKER_PROTOBUF, mdata) + + # ------------------------ + # Native message functions + # ------------------------ + + def recv_native_msg(self): + """Send a native message.""" + mdata, native = recv_msg(self.sock) + assert native + + hlen = struct.calcsize(MSG_HDR_FMT) + hdata = mdata[:hlen] + mhdr = struct.unpack(MSG_HDR_FMT, hdata) + code = mhdr[0] + + if code not in msg_native_formats: + raise Exception(f"Unknown native msg code {code} rcvd") + + mfmt = msg_native_formats[code] + flen = struct.calcsize(mfmt) + fdata = mdata[hlen : hlen + flen] + mfixed = struct.unpack(mfmt, fdata) + mdata = mdata[hlen + flen :] + + if code == MSG_ERROR_FMT: + raise NativeMessageError(mhdr, mfixed, mdata) + + return mhdr, mfixed, mdata + + def send_native_msg(self, mdata): + """Send a native message.""" + return send_msg(self.sock, MGMT_MSG_MARKER_NATIVE, mdata) + + def get_native_msg_header(self, msg_code): + req_id = self.get_next_req_id() + hdata = struct.pack(MSG_HDR_FMT, msg_code, 0, self.sess_id, req_id) + return hdata, req_id + + # ----------------------- + # Front-end API Fountains + # ----------------------- + + def lock(self, lock=True, ds_id=mgmt_pb2.CANDIDATE_DS): + req = mgmt_pb2.FeMessage() + req.lockds_req.session_id = self.sess_id + req.lockds_req.req_id = self.get_next_req_id() + req.lockds_req.ds_id = ds_id + req.lockds_req.lock = lock + self.send_pb_msg(req) + logging.debug("Sent LockDsReq: %s", req) + + reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) + logging.debug("Received Reply: %s", repr(reply)) + assert reply.lockds_reply.success + + def get_data(self, query, data=True, config=False): + # Create the message + mdata, _ = self.get_native_msg_header(MSG_CODE_GET_DATA) + flags = GET_DATA_FLAG_STATE if data else 0 + flags |= GET_DATA_FLAG_CONFIG if config else 0 + mdata += struct.pack(MSG_GET_DATA_FMT, MSG_FORMAT_JSON, flags) + mdata += query.encode("utf-8") + b"\x00" + + self.send_native_msg(mdata) + logging.debug("Sent GET-TREE") + + _, mfixed, mdata = self.recv_native_msg() + assert mdata[-1] == 0 + result = mdata[:-1].decode("utf-8") + + logging.debug("Received GET: %s: %s", mfixed, mdata) + return result + + def add_notify_select(self, replace, notif_xpaths): + # Create the message + mdata, _ = self.get_native_msg_header(MSG_CODE_NOTIFY_SELECT) + mdata += struct.pack(MSG_NOTIFY_SELECT_FMT, replace) + + for xpath in notif_xpaths: + mdata += xpath.encode("utf-8") + b"\x00" + + self.send_native_msg(mdata) + logging.debug("Sent NOTIFY_SELECT") + + def recv_notify(self, xpaths=None): + if xpaths: + self.add_notify_select(True, xpaths) + + for _ in Timeout(60): + logging.debug("Waiting for Notify Message") + mhdr, mfixed, mdata = self.recv_native_msg() + if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY: + logging.debug("Received Notify Message: %s: %s", mfixed, mdata) + else: + raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}") + + vsplit = mhdr[HDR_FIELD_VSPLIT] + assert mdata[vsplit - 1] == 0 + assert mdata[-1] == 0 + # xpath = mdata[: vsplit - 1].decode("utf-8") + return mdata[vsplit:-1].decode("utf-8") + else: + raise TimeoutError("Timeout waiting for notifications") + + +def __parse_args(): + MPATH = "/var/run/frr/mgmtd_fe.sock" + parser = argparse.ArgumentParser() + parser.add_argument( + "-l", "--listen", nargs="*", metavar="XPATH", help="xpath[s] to listen for" + ) + parser.add_argument( + "--notify-count", + type=int, + default=1, + help="Number of notifications to listen for 0 for infinite", + ) + parser.add_argument( + "-b", "--both", action="store_true", help="return both config and data" + ) + parser.add_argument( + "-c", "--config-only", action="store_true", help="return config only" + ) + parser.add_argument( + "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query" + ) + parser.add_argument("-s", "--server", default=MPATH, help="path to server socket") + parser.add_argument( + "--use-protobuf", action="store_true", help="Use protobuf when there's a choice" + ) + parser.add_argument("-v", "--verbose", action="store_true", help="Be verbose") + args = parser.parse_args() + + level = logging.DEBUG if args.verbose else logging.INFO + logging.basicConfig(level=level, format="%(asctime)s %(levelname)s: %(message)s") + + return args + + +def __server_connect(spath): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + logging.debug("Connecting to server on %s", spath) + while ec := sock.connect_ex(str(spath)): + logging.warn("retry server connection in .5s (%s)", os.strerror(ec)) + time.sleep(0.5) + logging.info("Connected to server on %s", spath) + # Set a timeout of 5 minutes for socket operations. + sock.settimeout(60 * 5) + return sock + + +def __main(): + args = __parse_args() + sock = __server_connect(Path(args.server)) + sess = Session(sock, use_protobuf=args.use_protobuf) + + if args.query: + # Performa an xpath query + # query = "/frr-interface:lib/interface/state/mtu" + for query in args.query: + logging.info("Sending query: %s", query) + result = sess.get_data( + query, data=not args.config_only, config=(args.both or args.config_only) + ) + print(result) + + if args.listen is not None: + i = args.notify_count + while i > 0 or args.notify_count == 0: + notif = sess.recv_notify(args.listen) + print(notif) + i -= 1 + + +def main(): + try: + __main() + except KeyboardInterrupt: + logging.info("Exiting") + except TimeoutError as error: + logging.error("Timeout: %s", error) + sys.exit(2) + except Exception as error: + logging.error("Unexpected error exiting: %s", error, exc_info=True) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/topotests/lib/grpc-query.py b/tests/topotests/lib/grpc-query.py index 8c4701c24390..cc7b1ad207a7 100755 --- a/tests/topotests/lib/grpc-query.py +++ b/tests/topotests/lib/grpc-query.py @@ -10,35 +10,45 @@ import logging import os import sys +import tempfile import pytest CWD = os.path.dirname(os.path.realpath(__file__)) -# This is painful but works if you have installed grpc and grpc_tools would be *way* -# better if we actually built and installed these but ... python packaging. try: - import grpc - import grpc_tools - - sys.path.append(os.path.dirname(CWD)) - from munet.base import commander - - commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .") - commander.cmd_raises( - f"python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto" - ) -except Exception as error: - logging.error("can't create proto definition modules %s", error) - raise - -try: - sys.path[0:0] = "." - import frr_northbound_pb2 - import frr_northbound_pb2_grpc -except Exception as error: - logging.error("can't import proto definition modules %s", error) - raise + # Make sure we don't run-into ourselves in parallel operating environment + tmpdir = tempfile.mkdtemp(prefix="grpc-client-") + + # This is painful but works if you have installed grpc and grpc_tools would be *way* + # better if we actually built and installed these but ... python packaging. + try: + import grpc_tools + from munet.base import commander + + import grpc + + commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .") + commander.cmd_raises( + "python3 -m grpc_tools.protoc" + f" --python_out={tmpdir} --grpc_python_out={tmpdir}" + f" -I {CWD}/../../../grpc frr-northbound.proto" + ) + except Exception as error: + logging.error("can't create proto definition modules %s", error) + raise + + try: + sys.path[0:0] = [tmpdir] + import frr_northbound_pb2 + import frr_northbound_pb2_grpc + + sys.path = sys.path[1:] + except Exception as error: + logging.error("can't import proto definition modules %s", error) + raise +finally: + commander.cmd_nostatus(f"rm -rf {tmpdir}") class GRPCClient: @@ -57,16 +67,16 @@ def get_capabilities(self): logging.debug("GRPC Capabilities: %s", response) return response - def get(self, xpath): + def get(self, xpath, encoding, gtype): request = frr_northbound_pb2.GetRequest() request.path.append(xpath) - request.type = frr_northbound_pb2.GetRequest.ALL - request.encoding = frr_northbound_pb2.XML - xml = "" + request.type = gtype + request.encoding = encoding + result = "" for r in self.stub.Get(request): - logging.info('GRPC Get path: "%s" value: %s', request.path, r) - xml += str(r.data.data) - return xml + logging.debug('GRPC Get path: "%s" value: %s', request.path, r) + result += str(r.data.data) + return result def next_action(action_list=None): @@ -95,6 +105,7 @@ def main(*args): ) parser.add_argument("-v", "--verbose", action="store_true", help="be verbose") parser.add_argument("--check", action="store_true", help="check runable") + parser.add_argument("--xml", action="store_true", help="encode XML instead of JSON") parser.add_argument("actions", nargs="*", help="GETCAP|GET,xpath") args = parser.parse_args(*args) @@ -107,20 +118,32 @@ def main(*args): if args.check: sys.exit(0) + encoding = frr_northbound_pb2.XML if args.xml else frr_northbound_pb2.JSON + c = GRPCClient(args.server, args.port) for action in next_action(args.actions): action = action.casefold() - logging.info("GOT ACTION: %s", action) + logging.debug("GOT ACTION: %s", action) if action == "getcap": caps = c.get_capabilities() - print("Capabilities:", caps) + print(caps) elif action.startswith("get,"): - # Print Interface State and Config + # Get and print config and state + _, xpath = action.split(",", 1) + logging.debug("Get XPath: %s", xpath) + print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.ALL)) + elif action.startswith("get-config,"): + # Get and print config + _, xpath = action.split(",", 1) + logging.debug("Get Config XPath: %s", xpath) + print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.CONFIG)) + # for _ in range(0, 1): + elif action.startswith("get-state,"): + # Get and print state _, xpath = action.split(",", 1) - print("Get XPath: ", xpath) - xml = c.get(xpath) - print("{}: {}".format(xpath, xml)) + logging.debug("Get State XPath: %s", xpath) + print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.STATE)) # for _ in range(0, 1): diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 5b18f8b679ce..2c876e198926 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -1545,7 +1545,7 @@ def verify_ospf_database( ) return errormsg if ospf_external_lsa: - for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items(): + for ospf_ext_lsa, _ in ospf_external_lsa.items(): if ospf_ext_lsa in show_ospf_json["AS External Link States"]: logger.info( "[DUT: %s] OSPF LSDB:External LSA %s", router, ospf_ext_lsa @@ -2509,7 +2509,7 @@ def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None): raise ValueError(errormsg) return errormsg - for ospf_gr, gr_data in input_dict.items(): + for ospf_gr, _ in input_dict.items(): try: if input_dict[ospf_gr] == show_ospf_json[ospf_gr]: logger.info( diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index f7440efd6d57..71e36b62295f 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -149,7 +149,7 @@ def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict): # At least one interface must be enabled for PIM on the router pim_if_enabled = False pim6_if_enabled = False - for destLink, data in topo[dut]["links"].items(): + for _, data in topo[dut]["links"].items(): if "pim" in data: pim_if_enabled = True if "pim6" in data: @@ -332,6 +332,13 @@ def create_igmp_config(tgen, topo, input_dict=None, build=False): cmd = "no {}".format(cmd) config_data.append(cmd) + if attribute == "static-group": + for group in data: + cmd = "ip {} {} {}".format(protocol, attribute, group) + if del_attr: + cmd = "no {}".format(cmd) + config_data.append(cmd) + if attribute == "query": for query, value in data.items(): if query != "delete": @@ -603,7 +610,7 @@ def find_rp_details(tgen, topo): # ip address of RP rp_addr = rp_dict["rp_addr"] - for link, data in topo["routers"][router]["links"].items(): + for _, data in topo["routers"][router]["links"].items(): if data["ipv4"].split("/")[0] == rp_addr: rp_details[router] = rp_addr @@ -2089,7 +2096,7 @@ def verify_pim_interface( ) return True else: - for destLink, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2292,7 +2299,7 @@ def clear_pim_interfaces(tgen, dut): # Waiting for maximum 60 sec fail_intf = [] - for retry in range(1, 13): + for _ in range(1, 13): sleep(5) logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut) run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True) @@ -2368,7 +2375,7 @@ def clear_igmp_interfaces(tgen, dut): total_groups_before_clear = igmp_json["totalGroups"] - for key, value in igmp_json.items(): + for _, value in igmp_json.items(): if type(value) is not dict: continue @@ -2381,7 +2388,7 @@ def clear_igmp_interfaces(tgen, dut): result = run_frr_cmd(rnode, "clear ip igmp interfaces") # Waiting for maximum 60 sec - for retry in range(1, 13): + for _ in range(1, 13): logger.info( "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", dut ) @@ -2460,7 +2467,7 @@ def clear_mroute_verify(tgen, dut, expected=True): # RFC 3376: 8.2. Query Interval - Default: 125 seconds # So waiting for maximum 130 sec to get the igmp report - for retry in range(1, 26): + for _ in range(1, 26): logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut) sleep(5) keys_json1 = mroute_json_1.keys() @@ -2671,7 +2678,7 @@ def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping): try: config_data = [] - for group, rp_list in rp_mapping.items(): + for _, rp_list in rp_mapping.items(): for _rp in rp_list: config_data.append("interface {}".format(interface)) config_data.append("ip address {}".format(_rp)) @@ -2720,7 +2727,7 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N script_path = os.path.join(CWD, "send_bsr_packet.py") node = tgen.net[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2795,12 +2802,12 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None): # RP with lowest priority if len(priority_dict) != 1: - rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0] + rp_p, _ = sorted(rp_priority.items(), key=lambda x: x[1])[0] rp_details[group] = rp_p # RP with highest hash value if len(priority_dict) == 1: - rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1] + rp_h, _ = sorted(rp_hash.items(), key=lambda x: x[1])[-1] rp_details[group] = rp_h # RP with highest IP address @@ -3239,7 +3246,7 @@ def verify_pim_join( interface_json = show_pim_join_json[interface] grp_addr = grp_addr.split("/")[0] - for source, data in interface_json[grp_addr].items(): + for _, data in interface_json[grp_addr].items(): # Verify pim join if pim_join: if data["group"] == grp_addr and data["channelJoinName"] == "JOIN": @@ -4253,6 +4260,75 @@ def verify_local_igmp_groups(tgen, dut, interface, group_addresses): logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True +@retry(retry_timeout=62) +def verify_static_groups(tgen, dut, interface, group_addresses): + """ + Verify static groups are received from an intended interface + by running "show ip igmp static-group json" command + + Parameters + ---------- + * `tgen`: topogen object + * `dut`: device under test + * `interface`: interface, from which IGMP groups are configured + * `group_addresses`: IGMP group address + + Usage + ----- + dut = "r1" + interface = "r1-r0-eth0" + group_address = "225.1.1.1" + result = verify_static_groups(tgen, dut, interface, group_address) + + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + + if dut not in tgen.routers(): + return False + + rnode = tgen.routers()[dut] + + logger.info("[DUT: %s]: Verifying static groups received:", dut) + show_static_group_json = run_frr_cmd(rnode, "show ip igmp static-group json", isjson=True) + + if type(group_addresses) is not list: + group_addresses = [group_addresses] + + if interface not in show_static_group_json: + errormsg = ( + "[DUT %s]: Verifying static group received" + " from interface %s [FAILED]!! " % (dut, interface) + ) + return errormsg + + for grp_addr in group_addresses: + found = False + for index in show_static_group_json[interface]["groups"]: + if index["group"] == grp_addr: + found = True + break + if not found: + errormsg = ( + "[DUT %s]: Verifying static group received" + " from interface %s [FAILED]!! " + " Expected: %s " % (dut, interface, grp_addr) + ) + return errormsg + + logger.info( + "[DUT %s]: Verifying static group %s received " + "from interface %s [PASSED]!! ", + dut, + grp_addr, + interface, + ) + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return True def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"): """ diff --git a/tests/topotests/lib/snmptest.py b/tests/topotests/lib/snmptest.py index e7cd657b2027..8e2e76d154b4 100644 --- a/tests/topotests/lib/snmptest.py +++ b/tests/topotests/lib/snmptest.py @@ -18,6 +18,7 @@ """ from lib.topolog import logger +import re class SnmpTester(object): @@ -72,16 +73,6 @@ def _get_snmp_oid(snmp_output): # third token onwards is the value of the object return tokens[0].split(".", 1)[1] - @staticmethod - def _get_snmp_oid(snmp_output): - tokens = snmp_output.strip().split() - - # if len(tokens) > 5: - # return None - - # third token is the value of the object - return tokens[0].split(".", 1)[1] - def _parse_multiline(self, snmp_output): results = snmp_output.strip().split("\n") @@ -94,15 +85,18 @@ def _parse_multiline(self, snmp_output): return out_dict, out_list def get(self, oid): - cmd = "snmpget {0} {1}".format(self._snmp_config(), oid) - + cmd = "snmpget {0} {1} 2>&1 | grep -v SNMPv2-PDU".format( + self._snmp_config(), oid + ) result = self.router.cmd(cmd) if "not found" in result: return None return self._get_snmp_value(result) def get_next(self, oid): - cmd = "snmpgetnext {0} {1}".format(self._snmp_config(), oid) + cmd = "snmpgetnext {0} {1} 2>&1 | grep -v SNMPv2-PDU".format( + self._snmp_config(), oid + ) result = self.router.cmd(cmd) print("get_next: {}".format(result)) @@ -111,11 +105,158 @@ def get_next(self, oid): return self._get_snmp_value(result) def walk(self, oid): - cmd = "snmpwalk {0} {1}".format(self._snmp_config(), oid) + cmd = "snmpwalk {0} {1} 2>&1 | grep -v SNMPv2-PDU".format( + self._snmp_config(), oid + ) result = self.router.cmd(cmd) return self._parse_multiline(result) + def parse_notif_ipv4(self, notif): + # normalise values + notif = re.sub(":", "", notif) + notif = re.sub('"([0-9]{2}) ([0-9]{2}) "', r"\1\2", notif) + notif = re.sub('"([0-9]{2}) "', r"\1", notif) + elems = re.findall(r"([0-9,\.]+) = ([0-9,\.]+)", notif) + + # remove common part + elems = elems[1:] + return elems + + def is_notif_bgp4_valid(self, output_list, address): + oid_notif_type = ".1.3.6.1.6.3.1.1.4.1.0" + peer_notif_established = ".1.3.6.1.2.1.15.0.1" + peer_notif_backward = ".1.3.6.1.2.1.15.0.2" + oid_peer_last_error = ".1.3.6.1.2.1.15.3.1.14" + oid_peer_remote_addr = ".1.3.6.1.2.1.15.3.1.7" + oid_peer_state = ".1.3.6.1.2.1.15.3.1.2" + + nb_notif = len(output_list) + for nb in range(0, nb_notif - 1): + # identify type of notification + # established or BackwardTransition + + if output_list[nb][0][0] != "{}".format(oid_notif_type): + return False + + if output_list[nb][0][1] == "{}".format(peer_notif_established): + logger.info("Established notification") + elif output_list[nb][0][1] == "{}".format(peer_notif_backward): + logger.info("Backward transition notification") + else: + return False + + # same behavior for 2 notification type in bgp4 + if output_list[nb][1][0] != "{}.{}".format(oid_peer_remote_addr, address): + return False + + if output_list[nb][2][0] != "{}.{}".format(oid_peer_last_error, address): + return False + if output_list[nb][3][0] != "{}.{}".format(oid_peer_state, address): + return False + + return True + + def is_notif_bgp4v2_valid(self, output_list, address, type_requested): + oid_notif_type = ".1.3.6.1.6.3.1.1.4.1.0" + peer_notif_established = ".1.3.6.1.3.5.1.0.1" + peer_notif_backward = ".1.3.6.1.3.5.1.0.2" + oid_peer_state = ".1.3.6.1.3.5.1.1.2.1.13" + oid_peer_local_port = ".1.3.6.1.3.5.1.1.2.1.6" + oid_peer_remote_port = ".1.3.6.1.3.5.1.1.2.1.9" + oid_peer_err_code_recv = ".1.3.6.1.3.5.1.1.3.1.1" + oid_peer_err_sub_code_recv = ".1.3.6.1.3.5.1.1.3.1.2" + oid_peer_err_recv_text = ".1.3.6.1.3.5.1.1.3.1.4" + + nb_notif = len(output_list) + for nb in range(nb_notif): + if output_list[nb][0][0] != "{}".format(oid_notif_type): + return False + + if output_list[nb][0][1] == "{}".format(peer_notif_established): + logger.info("Established notification") + notif_type = "Estab" + + elif output_list[nb][0][1] == "{}".format(peer_notif_backward): + logger.info("Backward transition notification") + notif_type = "Backward" + else: + return False + + if notif_type != type_requested: + continue + + if output_list[nb][1][0] != "{}.1.{}".format(oid_peer_state, address): + continue + + if output_list[nb][2][0] != "{}.1.{}".format(oid_peer_local_port, address): + return False + + if output_list[nb][3][0] != "{}.1.{}".format(oid_peer_remote_port, address): + return False + + if notif_type == "Estab": + return True + + if output_list[nb][4][0] != "{}.1.{}".format( + oid_peer_err_code_recv, address + ): + return False + + if output_list[nb][5][0] != "{}.1.{}".format( + oid_peer_err_sub_code_recv, address + ): + return False + + if output_list[nb][6][0] != "{}.1.{}".format( + oid_peer_err_recv_text, address + ): + return False + + return True + + return False + + def get_notif_bgp4(self, output_file): + notifs = [] + notif_list = [] + whitecleanfile = re.sub("\t", " ", output_file) + results = whitecleanfile.strip().split("\n") + + # don't consider additional SNMP or application messages + for result in results: + if re.search(r"(\.([0-9]+))+\s", result): + notifs.append(result) + + oid_v4 = r"1\.3\.6\.1\.2\.1\.15" + for one_notif in notifs: + is_ipv4_notif = re.search(oid_v4, one_notif) + if is_ipv4_notif != None: + formated_notif = self.parse_notif_ipv4(one_notif) + notif_list.append(formated_notif) + + return notif_list + + def get_notif_bgp4v2(self, output_file): + notifs = [] + notif_list = [] + whitecleanfile = re.sub("\t", " ", output_file) + results = whitecleanfile.strip().split("\n") + + # don't consider additional SNMP or application messages + for result in results: + if re.search(r"(\.([0-9]+))+\s", result): + notifs.append(result) + + oid_v6 = r"1\.3\.6\.1\.3\.5\.1" + for one_notif in notifs: + is_ipv6_notif = re.search(oid_v6, one_notif) + if is_ipv6_notif != None: + formated_notif = self.parse_notif_ipv4(one_notif) + notif_list.append(formated_notif) + + return notif_list + def test_oid(self, oid, value): print("oid: {}".format(self.get_next(oid))) return self.get_next(oid) == value diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 4d935b9538c5..f49e30ea5f9c 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -81,20 +81,22 @@ def is_string(value): def get_exabgp_cmd(commander=None): - """Return the command to use for ExaBGP version < 4.""" + """Return the command to use for ExaBGP version >= 4.2.11""" if commander is None: commander = Commander("exabgp", logger=logging.getLogger("exabgp")) def exacmd_version_ok(exacmd): - logger.debug("checking %s for exabgp < version 4", exacmd) + logger.debug("checking %s for exabgp version >= 4.2.11", exacmd) _, stdout, _ = commander.cmd_status(exacmd + " -v", warn=False) m = re.search(r"ExaBGP\s*:\s*((\d+)\.(\d+)(?:\.(\d+))?)", stdout) if not m: return False version = m.group(1) - if topotest.version_cmp(version, "4") >= 0: - logging.debug("found exabgp version >= 4 in %s will keep looking", exacmd) + if topotest.version_cmp(version, "4.2.11") < 0: + logging.debug( + "found exabgp version < 4.2.11 in %s will keep looking", exacmd + ) return False logger.info("Using ExaBGP version %s in %s", version, exacmd) return True @@ -102,14 +104,14 @@ def exacmd_version_ok(exacmd): exacmd = commander.get_exec_path("exabgp") if exacmd and exacmd_version_ok(exacmd): return exacmd - py2_path = commander.get_exec_path("python2") - if py2_path: - exacmd = py2_path + " -m exabgp" + py3_path = commander.get_exec_path("python3") + if py3_path: + exacmd = py3_path + " -m exabgp" if exacmd_version_ok(exacmd): return exacmd - py2_path = commander.get_exec_path("python") - if py2_path: - exacmd = py2_path + " -m exabgp" + py3_path = commander.get_exec_path("python") + if py3_path: + exacmd = py3_path + " -m exabgp" if exacmd_version_ok(exacmd): return exacmd return None @@ -719,6 +721,7 @@ class TopoRouter(TopoGear): "/etc/frr", "/etc/snmp", "/var/run/frr", + "/var/lib/frr", "/var/log", ] @@ -744,6 +747,8 @@ class TopoRouter(TopoGear): RD_SNMP = 18 RD_PIM6 = 19 RD_MGMTD = 20 + RD_TRAP = 21 + RD_FPM_LISTENER = 22 RD = { RD_FRR: "frr", RD_ZEBRA: "zebra", @@ -766,6 +771,8 @@ class TopoRouter(TopoGear): RD_PATH: "pathd", RD_SNMP: "snmpd", RD_MGMTD: "mgmtd", + RD_TRAP: "snmptrapd", + RD_FPM_LISTENER: "fpm_listener", } def __init__(self, tgen, cls, name, **params): @@ -842,7 +849,8 @@ def load_config(self, daemon, source=None, param=None): TopoRouter.RD_RIPNG, TopoRouter.RD_OSPF, TopoRouter.RD_OSPF6, TopoRouter.RD_ISIS, TopoRouter.RD_BGP, TopoRouter.RD_LDP, TopoRouter.RD_PIM, TopoRouter.RD_PIM6, TopoRouter.RD_PBR, - TopoRouter.RD_SNMP, TopoRouter.RD_MGMTD. + TopoRouter.RD_SNMP, TopoRouter.RD_MGMTD, TopoRouter.RD_TRAP, + TopoRouter.RD_FPM_LISTENER. Possible `source` values are `None` for an empty config file, a path name which is used directly, or a file name with no path components which is first looked for @@ -880,7 +888,12 @@ def start(self): # Enable all daemon command logging, logging files # and set them to the start dir. for daemon, enabled in nrouter.daemons.items(): - if enabled and daemon != "snmpd": + if ( + enabled + and daemon != "snmpd" + and daemon != "snmptrapd" + and daemon != "fpm_listener" + ): self.vtysh_cmd( "\n".join( [ @@ -930,7 +943,7 @@ def startDaemons(self, daemons): # and set them to the start dir. for daemon in daemons: enabled = nrouter.daemons[daemon] - if enabled and daemon != "snmpd": + if enabled and daemon != "snmpd" and daemon != "fpm_listener": self.vtysh_cmd( "\n".join( [ @@ -1196,7 +1209,7 @@ def start(self, peer_dir, env_file=None): * Run ExaBGP with env file `env_file` and configuration peer*/exabgp.cfg """ exacmd = self.tgen.get_exabgp_cmd() - assert exacmd, "Can't find a usabel ExaBGP (must be < version 4)" + assert exacmd, "Can't find a usable ExaBGP (must be version >= 4.2.11)" self.run("mkdir -p /etc/exabgp") self.run("chmod 755 /etc/exabgp") @@ -1207,8 +1220,22 @@ def start(self, peer_dir, env_file=None): self.run("chmod 644 /etc/exabgp/*") self.run("chmod a+x /etc/exabgp/*.py") self.run("chown -R exabgp:exabgp /etc/exabgp") + self.run("[ -p /var/run/exabgp.in ] || mkfifo /var/run/exabgp.in") + self.run("[ -p /var/run/exabgp.out ] || mkfifo /var/run/exabgp.out") + self.run("chown exabgp:exabgp /var/run/exabgp.{in,out}") + self.run("chmod 600 /var/run/exabgp.{in,out}") + + log_dir = os.path.join(self.logdir, self.name) + self.run("chmod 777 {}".format(log_dir)) + + log_file = os.path.join(log_dir, "exabgp.log") - output = self.run(exacmd + " -e /etc/exabgp/exabgp.env /etc/exabgp/exabgp.cfg") + env_cmd = "env exabgp.log.level=INFO " + env_cmd += "exabgp.log.destination={} ".format(log_file) + + output = self.run( + env_cmd + exacmd + " -e /etc/exabgp/exabgp.env /etc/exabgp/exabgp.cfg " + ) if output is None or len(output) == 0: output = "" @@ -1236,9 +1263,12 @@ def __str__(self): gear += " TopoBMPCollector<>".format() return gear - def start(self): + def start(self, log_file=None): + log_arg = "-l {}".format(log_file) if log_file else "" self.run( - "{}/bmp_collector/bmpserver -a {} -p {}&".format(CWD, self.ip, self.port), + "{}/bmp_collector/bmpserver -a {} -p {} {}&".format( + CWD, self.ip, self.port, log_arg + ), stdout=None, ) @@ -1369,7 +1399,7 @@ def diagnose_env_linux(rundir): logger.info("LDPd tests will not run (missing mpls-iptunnel kernel module)") if not get_exabgp_cmd(): - logger.warning("Failed to find exabgp < 4") + logger.warning("Failed to find exabgp >= 4.2.11") logger.removeHandler(fhandler) fhandler.close() diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index 901e4f623a16..148fb04fe5f1 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -227,13 +227,17 @@ def build_topo_from_json(tgen, topo=None): topo["routers"][destRouter]["links"][curSwitch][ "interface" ] = "{}-{}-eth{}".format( - destRouter, curSwitch, topo["routers"][destRouter]["nextIfname"] + destRouter, + curSwitch, + topo["routers"][destRouter]["nextIfname"], ) topo["switches"][curSwitch]["links"][destRouter][ "interface" ] = "{}-{}-eth{}".format( - curSwitch, destRouter, topo["routers"][destRouter]["nextIfname"] + curSwitch, + destRouter, + topo["routers"][destRouter]["nextIfname"], ) topo["routers"][destRouter]["nextIfname"] += 1 diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index c220bcfed1b8..5a8c2e5964a6 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -27,11 +27,13 @@ import logging from collections.abc import Mapping from copy import deepcopy +from pathlib import Path import lib.topolog as topolog from lib.micronet_compat import Node from lib.topolog import logger -from munet.base import Timeout +from munet.base import commander, get_exec_path_host, Timeout +from munet.testing.util import retry from lib import micronet @@ -600,6 +602,30 @@ def is_linux(): return False +def iproute2_is_json_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling JSON outputss + + Returns True if capability can be detected, returns False otherwise. + """ + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "-json", "route", "show"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def iproute2_is_vrf_capable(): """ Checks if the iproute2 version installed on the system is capable of @@ -1261,8 +1287,8 @@ def rlimit_atleast(rname, min_value, raises=False): def fix_netns_limits(ns): # Maximum read and write socket buffer sizes - sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2 ** 20]) - sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2 ** 20]) + sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2**20]) + sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2**20]) sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0) sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0) @@ -1294,6 +1320,8 @@ def fix_netns_limits(ns): sysctl_assure(ns, "net.ipv4.conf.all.ignore_routes_with_linkdown", 1) sysctl_assure(ns, "net.ipv6.conf.all.ignore_routes_with_linkdown", 1) + sysctl_assure(ns, "net.ipv4.conf.default.ignore_routes_with_linkdown", 1) + sysctl_assure(ns, "net.ipv6.conf.default.ignore_routes_with_linkdown", 1) # igmp sysctl_atleast(ns, "net.ipv4.igmp_max_memberships", 1000) @@ -1321,8 +1349,8 @@ def fix_host_limits(): sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024) # Maximum read and write socket buffer sizes - sysctl_atleast(None, "net.core.rmem_max", 16 * 2 ** 20) - sysctl_atleast(None, "net.core.wmem_max", 16 * 2 ** 20) + sysctl_atleast(None, "net.core.rmem_max", 16 * 2**20) + sysctl_atleast(None, "net.core.wmem_max", 16 * 2**20) # Garbage Collection Settings for ARP and Neighbors sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024) @@ -1363,6 +1391,8 @@ def setup_node_tmpdir(logdir, name): class Router(Node): "A Node with IPv4/IPv6 forwarding enabled" + gdb_emacs_router = None + def __init__(self, name, *posargs, **params): # Backward compatibility: # Load configuration defaults like topogen. @@ -1380,6 +1410,8 @@ def __init__(self, name, *posargs, **params): ) self.perf_daemons = {} + self.rr_daemons = {} + self.valgrind_gdb_daemons = {} # If this topology is using old API and doesn't have logdir # specified, then attempt to generate an unique logdir. @@ -1398,7 +1430,7 @@ def __init__(self, name, *posargs, **params): self.daemondir = None self.hasmpls = False self.routertype = "frr" - self.unified_config = None + self.unified_config = False self.daemons = { "zebra": 0, "ripd": 0, @@ -1420,6 +1452,8 @@ def __init__(self, name, *posargs, **params): "pathd": 0, "snmpd": 0, "mgmtd": 0, + "snmptrapd": 0, + "fpm_listener": 0, } self.daemons_options = {"zebra": ""} self.reportCores = True @@ -1516,7 +1550,7 @@ def listDaemons(self): pass return ret - def stopRouter(self, assertOnError=True, minErrorVersion="5.1"): + def stopRouter(self, assertOnError=True): # Stop Running FRR Daemons running = self.listDaemons() if not running: @@ -1563,9 +1597,6 @@ def stopRouter(self, assertOnError=True, minErrorVersion="5.1"): ) errors = self.checkRouterCores(reportOnce=True) - if self.checkRouterVersion("<", minErrorVersion): - # ignore errors in old versions - errors = "" if assertOnError and (errors is not None) and len(errors) > 0: assert "Errors found - details follow:" == 0, errors return errors @@ -1622,7 +1653,7 @@ def loadConf(self, daemon, source=None, param=None): # print "Daemons before:", self.daemons if daemon in self.daemons.keys() or daemon == "frr": if daemon == "frr": - self.unified_config = 1 + self.unified_config = True else: self.daemons[daemon] = 1 if param is not None: @@ -1796,10 +1827,17 @@ def startRouterDaemons(self, daemons=None, tgen=None): "Starts FRR daemons for this router." asan_abort = bool(g_pytest_config.option.asan_abort) + cov_option = bool(g_pytest_config.option.cov_topotest) + cov_dir = Path(g_pytest_config.option.rundir) / "gcda" gdb_breakpoints = g_pytest_config.get_option_list("--gdb-breakpoints") gdb_daemons = g_pytest_config.get_option_list("--gdb-daemons") gdb_routers = g_pytest_config.get_option_list("--gdb-routers") + gdb_use_emacs = bool(g_pytest_config.option.gdb_use_emacs) + rr_daemons = g_pytest_config.get_option_list("--rr-daemons") + rr_routers = g_pytest_config.get_option_list("--rr-routers") + rr_options = g_pytest_config.get_option("--rr-options", "") valgrind_extra = bool(g_pytest_config.option.valgrind_extra) + valgrind_leak_kinds = g_pytest_config.option.valgrind_leak_kinds valgrind_memleaks = bool(g_pytest_config.option.valgrind_memleaks) strace_daemons = g_pytest_config.get_option_list("--strace-daemons") @@ -1824,13 +1862,6 @@ def startRouterDaemons(self, daemons=None, tgen=None): # Re-enable to allow for report per run self.reportCores = True - # XXX: glue code forward ported from removed function. - if self.version is None: - self.version = self.cmd( - os.path.join(self.daemondir, "bgpd") + " -v" - ).split()[2] - logger.info("{}: running version: {}".format(self.name, self.version)) - perfds = {} perf_options = g_pytest_config.get_option("--perf-options", "-g") for perf in g_pytest_config.get_option("--perf", []): @@ -1875,14 +1906,36 @@ def start_daemon(daemon, extra_opts=None): # do not since apparently presence of the pidfile impacts BGP GR self.cmd_status("rm -f {0}.pid {0}.vty".format(runbase)) + def do_gdb_or_rr(gdb): + routers = gdb_routers if gdb else rr_routers + daemons = gdb_daemons if gdb else rr_daemons + return ( + (routers or daemons) + and (not routers or self.name in routers or "all" in routers) + and (not daemons or daemon in daemons or "all" in daemons) + ) + rediropt = " > {0}.out 2> {0}.err".format(daemon) - if daemon == "snmpd": + if daemon == "fpm_listener": + binary = "/usr/lib/frr/fpm_listener" + cmdenv = "" + cmdopt = "-d {}".format(daemon_opts) + elif daemon == "snmpd": binary = "/usr/sbin/snmpd" cmdenv = "" cmdopt = "{} -C -c /etc/frr/snmpd.conf -p ".format( daemon_opts ) + "{}.pid -x /etc/frr/agentx".format(runbase) # check_daemon_files.append(runbase + ".pid") + elif daemon == "snmptrapd": + binary = "/usr/sbin/snmptrapd" + cmdenv = "" + cmdopt = ( + "{} ".format(daemon_opts) + + "-C -c /etc/{}/snmptrapd.conf".format(self.routertype) + + " -p {}.pid".format(runbase) + + " -LF 6-7 {}/{}/snmptrapd.log".format(self.logdir, self.name) + ) else: binary = os.path.join(self.daemondir, daemon) check_daemon_files.extend([runbase + ".pid", runbase + ".vty"]) @@ -1894,6 +1947,10 @@ def start_daemon(daemon, extra_opts=None): self.logdir, self.name, daemon ) + if cov_option: + scount = os.environ["GCOV_PREFIX_STRIP"] + cmdenv += f"GCOV_PREFIX_STRIP={scount} GCOV_PREFIX={cov_dir}" + if valgrind_memleaks: this_dir = os.path.dirname( os.path.abspath(os.path.realpath(__file__)) @@ -1901,13 +1958,23 @@ def start_daemon(daemon, extra_opts=None): supp_file = os.path.abspath( os.path.join(this_dir, "../../../tools/valgrind.supp") ) - cmdenv += " /usr/bin/valgrind --num-callers=50 --log-file={1}/{2}.valgrind.{0}.%p --leak-check=full --suppressions={3}".format( - daemon, self.logdir, self.name, supp_file + + valgrind_logbase = f"{self.logdir}/{self.name}.valgrind.{daemon}" + if do_gdb_or_rr(True): + cmdenv += " exec" + cmdenv += ( + " /usr/bin/valgrind --num-callers=50" + f" --log-file={valgrind_logbase}.%p" + f" --leak-check=full --suppressions={supp_file}" ) + if valgrind_leak_kinds: + cmdenv += f" --show-leak-kinds={valgrind_leak_kinds}" if valgrind_extra: cmdenv += ( " --gen-suppressions=all --expensive-definedness-checks=yes" ) + if do_gdb_or_rr(True): + cmdenv += " --vgdb-error=0" elif daemon in strace_daemons or "all" in strace_daemons: cmdenv = "strace -f -D -o {1}/{2}.strace.{0} ".format( daemon, self.logdir, self.name @@ -1922,16 +1989,22 @@ def start_daemon(daemon, extra_opts=None): tail_log_files.append( "{}/{}/{}.log".format(self.logdir, self.name, daemon) ) + if extra_opts: cmdopt += " " + extra_opts + if do_gdb_or_rr(True) and do_gdb_or_rr(False): + logger.warning("cant' use gdb and rr at same time") + if ( - (gdb_routers or gdb_daemons) - and ( - not gdb_routers or self.name in gdb_routers or "all" in gdb_routers - ) - and (not gdb_daemons or daemon in gdb_daemons or "all" in gdb_daemons) - ): + not gdb_use_emacs or Router.gdb_emacs_router or valgrind_memleaks + ) and do_gdb_or_rr(True): + if Router.gdb_emacs_router is not None: + logger.warning( + "--gdb-use-emacs can only run a single router and daemon, using" + " new window" + ) + if daemon == "snmpd": cmdopt += " -f " @@ -1941,9 +2014,133 @@ def start_daemon(daemon, extra_opts=None): gdbcmd += " -ex 'set breakpoint pending on'" for bp in gdb_breakpoints: gdbcmd += " -ex 'b {}'".format(bp) - gdbcmd += " -ex 'run {}'".format(cmdopt) - self.run_in_window(gdbcmd, daemon) + if not valgrind_memleaks: + gdbcmd += " -ex 'run {}'".format(cmdopt) + self.run_in_window(gdbcmd, daemon) + + logger.info( + "%s: %s %s launched in gdb window", + self, + self.routertype, + daemon, + ) + + else: + cmd = " ".join([cmdenv, binary, cmdopt]) + p = self.popen(cmd) + self.valgrind_gdb_daemons[daemon] = p + if p.poll() and p.returncode: + self.logger.error( + '%s: Failed to launch "%s" (%s) with perf using: %s', + self, + daemon, + p.returncode, + cmd, + ) + assert False, "Faled to launch valgrind with gdb" + logger.debug( + "%s: %s %s started with perf", self, self.routertype, daemon + ) + # Now read the erorr log file until we ae given launch priority + timeout = Timeout(30) + vpid = None + for remaining in timeout: + try: + fname = f"{valgrind_logbase}.{p.pid}" + logging.info("Checking %s for valgrind launch info", fname) + o = open(fname, encoding="ascii").read() + except FileNotFoundError: + logging.info("%s not present yet", fname) + else: + m = re.search(r"target remote \| (.*vgdb) --pid=(\d+)", o) + if m: + vgdb_cmd = m.group(0) + break + time.sleep(1) + else: + assert False, "Faled to get launch info for valgrind with gdb" + + gdbcmd += f" -ex '{vgdb_cmd}'" + gdbcmd += " -ex 'c'" + self.run_in_window(gdbcmd, daemon) + + logger.info( + "%s: %s %s launched in gdb window", + self, + self.routertype, + daemon, + ) + elif gdb_use_emacs and do_gdb_or_rr(True): + assert Router.gdb_emacs_router is None + Router.gdb_emacs_router = self + + assert not valgrind_memleaks, "vagrind gdb in emacs not supported yet" + + if daemon == "snmpd": + cmdopt += " -f " + cmdopt += rediropt + + sudo_path = get_exec_path_host("sudo") + ecbin = [ + sudo_path, + "-Eu", + os.environ["SUDO_USER"], + get_exec_path_host("emacsclient"), + ] + pre_cmd = self._get_pre_cmd(True, False, ns_only=True, root_level=True) + # why fail:? gdb -i=mi -iex='set debuginfod enabled off' {binary} " + gdbcmd = f"{sudo_path} {pre_cmd} gdb -i=mi {binary} " + + commander.cmd_raises( + ecbin + + [ + "--eval", + f'(gdb "{gdbcmd}"))', + ] + ) + + elcheck = ( + '(ignore-errors (with-current-buffer "*gud-nsenter*"' + " (and (string-match-p" + ' "(gdb) "' + " (buffer-substring-no-properties " + ' (- (point-max) 10) (point-max))) "ready")))' + ) + + @retry(10) + def emacs_gdb_ready(): + check = commander.cmd_nostatus(ecbin + ["--eval", elcheck]) + return None if "ready" in check else False + + emacs_gdb_ready() + + # target gdb commands + cmd = "set breakpoint pending on" + self.cmd_raises( + ecbin + + [ + "--eval", + f'(gud-gdb-run-command-fetch-lines "{cmd}" "*gud-gdb*")', + ] + ) + # gdb breakpoints + for bp in gdb_breakpoints: + self.cmd_raises( + ecbin + + [ + "--eval", + f'(gud-gdb-run-command-fetch-lines "br {bp}" "*gud-gdb*")', + ] + ) + + self.cmd_raises( + ecbin + + [ + "--eval", + f'(gud-gdb-run-command-fetch-lines "run {cmdopt}" "*gud-gdb*")', + ] + ) logger.info( "%s: %s %s launched in gdb window", self, self.routertype, daemon @@ -1969,8 +2166,35 @@ def start_daemon(daemon, extra_opts=None): logger.debug( "%s: %s %s started with perf", self, self.routertype, daemon ) + elif do_gdb_or_rr(False): + cmdopt += rediropt + cmd = " ".join( + [ + "rr record -o {} {} --".format(self.rundir / "rr", rr_options), + binary, + cmdopt, + ] + ) + p = self.popen(cmd) + self.rr_daemons[daemon] = p + if p.poll() and p.returncode: + self.logger.error( + '%s: Failed to launch "%s" (%s) with rr using: %s', + self, + daemon, + p.returncode, + cmd, + ) + else: + logger.debug( + "%s: %s %s started with rr", self, self.routertype, daemon + ) else: - if daemon != "snmpd": + if ( + daemon != "snmpd" + and daemon != "snmptrapd" + and daemon != "fpm_listener" + ): cmdopt += " -d " cmdopt += rediropt @@ -1983,12 +2207,16 @@ def start_daemon(daemon, extra_opts=None): daemon, error.returncode, error.cmd, - '\n:stdout: "{}"'.format(error.stdout.strip()) - if error.stdout - else "", - '\n:stderr: "{}"'.format(error.stderr.strip()) - if error.stderr - else "", + ( + '\n:stdout: "{}"'.format(error.stdout.strip()) + if error.stdout + else "" + ), + ( + '\n:stderr: "{}"'.format(error.stderr.strip()) + if error.stderr + else "" + ), ) else: logger.debug("%s: %s %s started", self, self.routertype, daemon) @@ -2020,6 +2248,11 @@ def start_daemon(daemon, extra_opts=None): while "snmpd" in daemons_list: daemons_list.remove("snmpd") + if "fpm_listener" in daemons_list: + start_daemon("fpm_listener") + while "fpm_listener" in daemons_list: + daemons_list.remove("fpm_listener") + # Now start all the other daemons for daemon in daemons_list: if self.daemons[daemon] == 0: @@ -2071,9 +2304,7 @@ def pid_exists(self, pid): rc, o, e = self.cmd_status("kill -0 " + str(pid), warn=False) return rc == 0 or "No such process" not in e - def killRouterDaemons( - self, daemons, wait=True, assertOnError=True, minErrorVersion="5.1" - ): + def killRouterDaemons(self, daemons, wait=True, assertOnError=True): # Kill Running FRR # Daemons(user specified daemon only) using SIGKILL rundaemons = self.cmd("ls -1 /var/run/%s/*.pid" % self.routertype) @@ -2133,9 +2364,6 @@ def killRouterDaemons( self.cmd("rm -- {}".format(daemonpidfile)) if wait: errors = self.checkRouterCores(reportOnce=True) - if self.checkRouterVersion("<", minErrorVersion): - # ignore errors in old versions - errors = "" if assertOnError and len(errors) > 0: assert "Errors found - details follow:" == 0, errors else: @@ -2213,6 +2441,10 @@ def checkRouterRunning(self): for daemon in self.daemons: if daemon == "snmpd": continue + if daemon == "snmptrapd": + continue + if daemon == "fpm_listener": + continue if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning): sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon)) if daemon == "staticd": diff --git a/tests/topotests/mgmt_config/test_config.py b/tests/topotests/mgmt_config/test_config.py index b07ed8f7fde4..1d732223fff8 100644 --- a/tests/topotests/mgmt_config/test_config.py +++ b/tests/topotests/mgmt_config/test_config.py @@ -61,8 +61,7 @@ from lib.common_config import retry, step from lib.topogen import Topogen, TopoRouter -# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] @retry(retry_timeout=1, initial_wait=0.1) diff --git a/tests/topotests/mgmt_config/test_regression.py b/tests/topotests/mgmt_config/test_regression.py index 00c3e01724fe..928151a23afa 100644 --- a/tests/topotests/mgmt_config/test_regression.py +++ b/tests/topotests/mgmt_config/test_regression.py @@ -12,7 +12,7 @@ import pytest from lib.topogen import Topogen -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] @pytest.fixture(scope="module") @@ -51,3 +51,23 @@ def test_regression_issue_13920(tgen): ) output = r1.net.checkRouterCores() assert not output.strip() + + +def test_regression_pullreq_15423(tgen): + r1 = tgen.gears["r1"] + r1.vtysh_multicmd( + """ + conf t + access-list test seq 1 permit ip any 10.10.10.0 0.0.0.255 + """ + ) + + output = r1.vtysh_multicmd( + """ + conf terminal file-lock + mgmt delete-config /frr-filter:lib/access-list[name='test'][type='ipv4']/entry[sequence='1']/destination-network + mgmt commit apply + end + """ + ) + assert "No changes found" not in output diff --git a/tests/topotests/mgmt_debug_flags/r1/frr.conf b/tests/topotests/mgmt_debug_flags/r1/frr.conf new file mode 100644 index 000000000000..ba95b8d49328 --- /dev/null +++ b/tests/topotests/mgmt_debug_flags/r1/frr.conf @@ -0,0 +1,11 @@ +log timestamp precision 6 +log file frr.log + +! debug mgmt backend datastore frontend transaction +! debug mgmt client frontend +! debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 +exit +ip route 11.11.11.11/32 1.1.1.2 \ No newline at end of file diff --git a/tests/topotests/mgmt_debug_flags/test_debug.py b/tests/topotests/mgmt_debug_flags/test_debug.py new file mode 100644 index 000000000000..fe659e54cabb --- /dev/null +++ b/tests/topotests/mgmt_debug_flags/test_debug.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis +# +# noqa: E501 +# +""" +Test static route functionality +""" +import pytest +from lib.common_config import step +from lib.topogen import Topogen +from munet.watchlog import WatchLog + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",)} + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + for _, router in tgen.routers().items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_client_debug_enable(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + # Start watching log files + watch_mgmtd_log = WatchLog(r1.net.rundir / "mgmtd.log") + watch_staticd_log = WatchLog(r1.net.rundir / "staticd.log") + + def __test_debug(r1, on): + watch_mgmtd_log.snapshot() + watch_staticd_log.snapshot() + + # Add ip route and remove look for debug. + r1.vtysh_cmd("conf t\nip route 11.11.11.11/32 1.1.1.2") + r1.vtysh_cmd("conf t\nno ip route 11.11.11.11/32 1.1.1.2") + + new_mgmt_logs = watch_mgmtd_log.snapshot() + new_be_logs = watch_staticd_log.snapshot() + + fe_cl_msg = "Sending SET_CONFIG_REQ" + fe_ad_msg = "Got SETCFG_REQ" + be_ad_msg = "Sending CFGDATA_CREATE_REQ" + be_cl_msg = "Got CFG_APPLY_REQ" + + if on: + assert fe_cl_msg in new_mgmt_logs + assert fe_ad_msg in new_mgmt_logs + assert be_ad_msg in new_mgmt_logs + assert be_cl_msg in new_be_logs + else: + assert fe_cl_msg not in new_mgmt_logs + assert fe_ad_msg not in new_mgmt_logs + assert be_ad_msg not in new_mgmt_logs + assert be_cl_msg not in new_be_logs + + step("test debug off") + __test_debug(r1, False) + + # Turn it on + step("tests debug on") + r1.vtysh_cmd("debug mgmt client frontend") + r1.vtysh_cmd("debug mgmt client backend") + r1.vtysh_cmd("debug mgmt backend frontend") + __test_debug(r1, True) + + # Turn it off + step("tests debug off") + r1.vtysh_cmd("no debug mgmt client frontend") + r1.vtysh_cmd("no debug mgmt client backend") + r1.vtysh_cmd("no debug mgmt backend frontend") + __test_debug(r1, False) + + # Configure it on + step("tests debug on") + r1.vtysh_cmd("conf t\ndebug mgmt client frontend") + r1.vtysh_cmd("conf t\ndebug mgmt client backend") + r1.vtysh_cmd("conf t\ndebug mgmt backend frontend") + __test_debug(r1, True) + + # Configure it off + step("tests debug off") + r1.vtysh_cmd("conf t\nno debug mgmt client frontend") + r1.vtysh_cmd("conf t\nno debug mgmt client backend") + r1.vtysh_cmd("conf t\nno debug mgmt backend frontend") + __test_debug(r1, False) + + # Turn it on + step("tests debug on") + r1.vtysh_cmd("debug mgmt client frontend") + r1.vtysh_cmd("debug mgmt client backend") + r1.vtysh_cmd("debug mgmt backend frontend") + __test_debug(r1, True) + # Configure it on + step("tests debug on") + r1.vtysh_cmd("conf t\ndebug mgmt client frontend") + r1.vtysh_cmd("conf t\ndebug mgmt client backend") + r1.vtysh_cmd("conf t\ndebug mgmt backend frontend") + __test_debug(r1, True) + # Turn it off + step("tests debug on") + r1.vtysh_cmd("no debug mgmt client frontend") + r1.vtysh_cmd("no debug mgmt client backend") + r1.vtysh_cmd("no debug mgmt backend frontend") + __test_debug(r1, True) + # Configure it off + step("tests debug off") + r1.vtysh_cmd("conf t\nno debug mgmt client frontend") + r1.vtysh_cmd("conf t\nno debug mgmt client backend") + r1.vtysh_cmd("conf t\nno debug mgmt backend frontend") + __test_debug(r1, False) diff --git a/tests/topotests/mgmt_fe_client/mgmt_pb2.py b/tests/topotests/mgmt_fe_client/mgmt_pb2.py new file mode 100644 index 000000000000..44dd2f66887d --- /dev/null +++ b/tests/topotests/mgmt_fe_client/mgmt_pb2.py @@ -0,0 +1,3469 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: mgmt.proto + +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database + +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +DESCRIPTOR = _descriptor.FileDescriptor( + name="mgmt.proto", + package="mgmtd", + syntax="proto2", + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\nmgmt.proto\x12\x05mgmtd"\x1e\n\rYangDataXPath\x12\r\n\x05xpath\x18\x01 \x02(\t"3\n\rYangDataValue\x12\x19\n\x0f\x65ncoded_str_val\x18\x64 \x01(\tH\x00\x42\x07\n\x05value">\n\x08YangData\x12\r\n\x05xpath\x18\x01 \x02(\t\x12#\n\x05value\x18\x02 \x01(\x0b\x32\x14.mgmtd.YangDataValue"X\n\x0eYangCfgDataReq\x12\x1d\n\x04\x64\x61ta\x18\x01 \x02(\x0b\x32\x0f.mgmtd.YangData\x12\'\n\x08req_type\x18\x02 \x02(\x0e\x32\x15.mgmtd.CfgDataReqType"B\n\x0eYangGetDataReq\x12\x1d\n\x04\x64\x61ta\x18\x01 \x02(\x0b\x32\x0f.mgmtd.YangData\x12\x11\n\tnext_indx\x18\x02 \x02(\x03"R\n\x0e\x42\x65SubscribeReq\x12\x13\n\x0b\x63lient_name\x18\x01 \x02(\t\x12\x18\n\x10subscribe_xpaths\x18\x02 \x02(\x08\x12\x11\n\txpath_reg\x18\x03 \x03(\t"#\n\x10\x42\x65SubscribeReply\x12\x0f\n\x07success\x18\x01 \x02(\x08"*\n\x08\x42\x65TxnReq\x12\x0e\n\x06txn_id\x18\x01 \x02(\x04\x12\x0e\n\x06\x63reate\x18\x02 \x02(\x08"=\n\nBeTxnReply\x12\x0e\n\x06txn_id\x18\x01 \x02(\x04\x12\x0e\n\x06\x63reate\x18\x02 \x02(\x08\x12\x0f\n\x07success\x18\x03 \x02(\x08"b\n\x12\x42\x65\x43\x66gDataCreateReq\x12\x0e\n\x06txn_id\x18\x01 \x02(\x04\x12\'\n\x08\x64\x61ta_req\x18\x02 \x03(\x0b\x32\x15.mgmtd.YangCfgDataReq\x12\x13\n\x0b\x65nd_of_data\x18\x03 \x02(\x08"M\n\x14\x42\x65\x43\x66gDataCreateReply\x12\x0e\n\x06txn_id\x18\x01 \x02(\x04\x12\x0f\n\x07success\x18\x02 \x02(\x08\x12\x14\n\x0c\x65rror_if_any\x18\x03 \x01(\t"#\n\x11\x42\x65\x43\x66gDataApplyReq\x12\x0e\n\x06txn_id\x18\x01 \x02(\x04"L\n\x13\x42\x65\x43\x66gDataApplyReply\x12\x0e\n\x06txn_id\x18\x01 \x02(\x04\x12\x0f\n\x07success\x18\x02 \x02(\x08\x12\x14\n\x0c\x65rror_if_any\x18\x03 \x01(\t"A\n\rYangDataReply\x12\x1d\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x0f.mgmtd.YangData\x12\x11\n\tnext_indx\x18\x02 \x02(\x03"\x94\x03\n\tBeMessage\x12+\n\nsubscr_req\x18\x02 \x01(\x0b\x32\x15.mgmtd.BeSubscribeReqH\x00\x12/\n\x0csubscr_reply\x18\x03 \x01(\x0b\x32\x17.mgmtd.BeSubscribeReplyH\x00\x12"\n\x07txn_req\x18\x04 \x01(\x0b\x32\x0f.mgmtd.BeTxnReqH\x00\x12&\n\ttxn_reply\x18\x05 \x01(\x0b\x32\x11.mgmtd.BeTxnReplyH\x00\x12\x31\n\x0c\x63\x66g_data_req\x18\x06 \x01(\x0b\x32\x19.mgmtd.BeCfgDataCreateReqH\x00\x12\x35\n\x0e\x63\x66g_data_reply\x18\x07 \x01(\x0b\x32\x1b.mgmtd.BeCfgDataCreateReplyH\x00\x12\x31\n\rcfg_apply_req\x18\x08 \x01(\x0b\x32\x18.mgmtd.BeCfgDataApplyReqH\x00\x12\x35\n\x0f\x63\x66g_apply_reply\x18\t \x01(\x0b\x32\x1a.mgmtd.BeCfgDataApplyReplyH\x00\x42\t\n\x07message"$\n\rFeRegisterReq\x12\x13\n\x0b\x63lient_name\x18\x01 \x02(\t"T\n\x0c\x46\x65SessionReq\x12\x0e\n\x06\x63reate\x18\x01 \x02(\x08\x12\x18\n\x0e\x63lient_conn_id\x18\x02 \x01(\x04H\x00\x12\x14\n\nsession_id\x18\x03 \x01(\x04H\x00\x42\x04\n\x02id"]\n\x0e\x46\x65SessionReply\x12\x0e\n\x06\x63reate\x18\x01 \x02(\x08\x12\x0f\n\x07success\x18\x02 \x02(\x08\x12\x16\n\x0e\x63lient_conn_id\x18\x03 \x01(\x04\x12\x12\n\nsession_id\x18\x04 \x02(\x04"b\n\x0b\x46\x65LockDsReq\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12\x0e\n\x06req_id\x18\x02 \x02(\x04\x12!\n\x05\x64s_id\x18\x03 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0c\n\x04lock\x18\x04 \x02(\x08"\x8b\x01\n\rFeLockDsReply\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12\x0e\n\x06req_id\x18\x02 \x02(\x04\x12!\n\x05\x64s_id\x18\x03 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0c\n\x04lock\x18\x04 \x02(\x08\x12\x0f\n\x07success\x18\x05 \x02(\x08\x12\x14\n\x0c\x65rror_if_any\x18\x06 \x01(\t"\xbf\x01\n\x0e\x46\x65SetConfigReq\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12!\n\x05\x64s_id\x18\x02 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0e\n\x06req_id\x18\x03 \x02(\x04\x12#\n\x04\x64\x61ta\x18\x04 \x03(\x0b\x32\x15.mgmtd.YangCfgDataReq\x12\x17\n\x0fimplicit_commit\x18\x05 \x02(\x08\x12(\n\x0c\x63ommit_ds_id\x18\x06 \x02(\x0e\x32\x12.mgmtd.DatastoreId"\x99\x01\n\x10\x46\x65SetConfigReply\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12!\n\x05\x64s_id\x18\x02 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0e\n\x06req_id\x18\x03 \x02(\x04\x12\x0f\n\x07success\x18\x04 \x02(\x08\x12\x17\n\x0fimplicit_commit\x18\x05 \x02(\x08\x12\x14\n\x0c\x65rror_if_any\x18\x06 \x01(\t"\xab\x01\n\x11\x46\x65\x43ommitConfigReq\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12%\n\tsrc_ds_id\x18\x02 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12%\n\tdst_ds_id\x18\x03 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0e\n\x06req_id\x18\x04 \x02(\x04\x12\x15\n\rvalidate_only\x18\x05 \x02(\x08\x12\r\n\x05\x61\x62ort\x18\x06 \x02(\x08"\xd4\x01\n\x13\x46\x65\x43ommitConfigReply\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12%\n\tsrc_ds_id\x18\x02 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12%\n\tdst_ds_id\x18\x03 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0e\n\x06req_id\x18\x04 \x02(\x04\x12\x15\n\rvalidate_only\x18\x05 \x02(\x08\x12\x0f\n\x07success\x18\x06 \x02(\x08\x12\r\n\x05\x61\x62ort\x18\x07 \x02(\x08\x12\x14\n\x0c\x65rror_if_any\x18\x08 \x01(\t"\x86\x01\n\x08\x46\x65GetReq\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12\x0e\n\x06\x63onfig\x18\x02 \x02(\x08\x12!\n\x05\x64s_id\x18\x03 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0e\n\x06req_id\x18\x04 \x02(\x04\x12#\n\x04\x64\x61ta\x18\x05 \x03(\x0b\x32\x15.mgmtd.YangGetDataReq"\xae\x01\n\nFeGetReply\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12\x0e\n\x06\x63onfig\x18\x02 \x02(\x08\x12!\n\x05\x64s_id\x18\x03 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x0e\n\x06req_id\x18\x04 \x02(\x04\x12\x0f\n\x07success\x18\x05 \x02(\x08\x12\x14\n\x0c\x65rror_if_any\x18\x06 \x01(\t\x12"\n\x04\x64\x61ta\x18\x07 \x01(\x0b\x32\x14.mgmtd.YangDataReply"0\n\x0f\x46\x65NotifyDataReq\x12\x1d\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x0f.mgmtd.YangData"\x9c\x01\n\x13\x46\x65RegisterNotifyReq\x12\x12\n\nsession_id\x18\x01 \x02(\x04\x12!\n\x05\x64s_id\x18\x02 \x02(\x0e\x32\x12.mgmtd.DatastoreId\x12\x14\n\x0cregister_req\x18\x03 \x02(\x08\x12\x0e\n\x06req_id\x18\x04 \x02(\x04\x12(\n\ndata_xpath\x18\x05 \x03(\x0b\x32\x14.mgmtd.YangDataXPath"\xf0\x04\n\tFeMessage\x12,\n\x0cregister_req\x18\x02 \x01(\x0b\x32\x14.mgmtd.FeRegisterReqH\x00\x12*\n\x0bsession_req\x18\x03 \x01(\x0b\x32\x13.mgmtd.FeSessionReqH\x00\x12.\n\rsession_reply\x18\x04 \x01(\x0b\x32\x15.mgmtd.FeSessionReplyH\x00\x12(\n\nlockds_req\x18\x05 \x01(\x0b\x32\x12.mgmtd.FeLockDsReqH\x00\x12,\n\x0clockds_reply\x18\x06 \x01(\x0b\x32\x14.mgmtd.FeLockDsReplyH\x00\x12+\n\nsetcfg_req\x18\x07 \x01(\x0b\x32\x15.mgmtd.FeSetConfigReqH\x00\x12/\n\x0csetcfg_reply\x18\x08 \x01(\x0b\x32\x17.mgmtd.FeSetConfigReplyH\x00\x12/\n\x0b\x63ommcfg_req\x18\t \x01(\x0b\x32\x18.mgmtd.FeCommitConfigReqH\x00\x12\x33\n\rcommcfg_reply\x18\n \x01(\x0b\x32\x1a.mgmtd.FeCommitConfigReplyH\x00\x12"\n\x07get_req\x18\x0b \x01(\x0b\x32\x0f.mgmtd.FeGetReqH\x00\x12&\n\tget_reply\x18\x0c \x01(\x0b\x32\x11.mgmtd.FeGetReplyH\x00\x12\x31\n\x0fnotify_data_req\x18\x0f \x01(\x0b\x32\x16.mgmtd.FeNotifyDataReqH\x00\x12\x33\n\rregnotify_req\x18\x10 \x01(\x0b\x32\x1a.mgmtd.FeRegisterNotifyReqH\x00\x42\t\n\x07message*B\n\x0e\x43\x66gDataReqType\x12\x11\n\rREQ_TYPE_NONE\x10\x00\x12\x0c\n\x08SET_DATA\x10\x01\x12\x0f\n\x0b\x44\x45LETE_DATA\x10\x02*`\n\x0b\x44\x61tastoreId\x12\x0b\n\x07\x44S_NONE\x10\x00\x12\x0e\n\nRUNNING_DS\x10\x01\x12\x10\n\x0c\x43\x41NDIDATE_DS\x10\x02\x12\x12\n\x0eOPERATIONAL_DS\x10\x03\x12\x0e\n\nSTARTUP_DS\x10\x04', +) + +_CFGDATAREQTYPE = _descriptor.EnumDescriptor( + name="CfgDataReqType", + full_name="mgmtd.CfgDataReqType", + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name="REQ_TYPE_NONE", + index=0, + number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.EnumValueDescriptor( + name="SET_DATA", + index=1, + number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.EnumValueDescriptor( + name="DELETE_DATA", + index=2, + number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=3674, + serialized_end=3740, +) +_sym_db.RegisterEnumDescriptor(_CFGDATAREQTYPE) + +CfgDataReqType = enum_type_wrapper.EnumTypeWrapper(_CFGDATAREQTYPE) +_DATASTOREID = _descriptor.EnumDescriptor( + name="DatastoreId", + full_name="mgmtd.DatastoreId", + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name="DS_NONE", + index=0, + number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.EnumValueDescriptor( + name="RUNNING_DS", + index=1, + number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.EnumValueDescriptor( + name="CANDIDATE_DS", + index=2, + number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.EnumValueDescriptor( + name="OPERATIONAL_DS", + index=3, + number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.EnumValueDescriptor( + name="STARTUP_DS", + index=4, + number=4, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key, + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=3742, + serialized_end=3838, +) +_sym_db.RegisterEnumDescriptor(_DATASTOREID) + +DatastoreId = enum_type_wrapper.EnumTypeWrapper(_DATASTOREID) +REQ_TYPE_NONE = 0 +SET_DATA = 1 +DELETE_DATA = 2 +DS_NONE = 0 +RUNNING_DS = 1 +CANDIDATE_DS = 2 +OPERATIONAL_DS = 3 +STARTUP_DS = 4 + + +_YANGDATAXPATH = _descriptor.Descriptor( + name="YangDataXPath", + full_name="mgmtd.YangDataXPath", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="xpath", + full_name="mgmtd.YangDataXPath.xpath", + index=0, + number=1, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=21, + serialized_end=51, +) + + +_YANGDATAVALUE = _descriptor.Descriptor( + name="YangDataValue", + full_name="mgmtd.YangDataValue", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="encoded_str_val", + full_name="mgmtd.YangDataValue.encoded_str_val", + index=0, + number=100, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="value", + full_name="mgmtd.YangDataValue.value", + index=0, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + ), + ], + serialized_start=53, + serialized_end=104, +) + + +_YANGDATA = _descriptor.Descriptor( + name="YangData", + full_name="mgmtd.YangData", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="xpath", + full_name="mgmtd.YangData.xpath", + index=0, + number=1, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="value", + full_name="mgmtd.YangData.value", + index=1, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=106, + serialized_end=168, +) + + +_YANGCFGDATAREQ = _descriptor.Descriptor( + name="YangCfgDataReq", + full_name="mgmtd.YangCfgDataReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.YangCfgDataReq.data", + index=0, + number=1, + type=11, + cpp_type=10, + label=2, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_type", + full_name="mgmtd.YangCfgDataReq.req_type", + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=170, + serialized_end=258, +) + + +_YANGGETDATAREQ = _descriptor.Descriptor( + name="YangGetDataReq", + full_name="mgmtd.YangGetDataReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.YangGetDataReq.data", + index=0, + number=1, + type=11, + cpp_type=10, + label=2, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="next_indx", + full_name="mgmtd.YangGetDataReq.next_indx", + index=1, + number=2, + type=3, + cpp_type=2, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=260, + serialized_end=326, +) + + +_BESUBSCRIBEREQ = _descriptor.Descriptor( + name="BeSubscribeReq", + full_name="mgmtd.BeSubscribeReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="client_name", + full_name="mgmtd.BeSubscribeReq.client_name", + index=0, + number=1, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="subscribe_xpaths", + full_name="mgmtd.BeSubscribeReq.subscribe_xpaths", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="xpath_reg", + full_name="mgmtd.BeSubscribeReq.xpath_reg", + index=2, + number=3, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=328, + serialized_end=410, +) + + +_BESUBSCRIBEREPLY = _descriptor.Descriptor( + name="BeSubscribeReply", + full_name="mgmtd.BeSubscribeReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.BeSubscribeReply.success", + index=0, + number=1, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=412, + serialized_end=447, +) + + +_BETXNREQ = _descriptor.Descriptor( + name="BeTxnReq", + full_name="mgmtd.BeTxnReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="txn_id", + full_name="mgmtd.BeTxnReq.txn_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="create", + full_name="mgmtd.BeTxnReq.create", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=449, + serialized_end=491, +) + + +_BETXNREPLY = _descriptor.Descriptor( + name="BeTxnReply", + full_name="mgmtd.BeTxnReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="txn_id", + full_name="mgmtd.BeTxnReply.txn_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="create", + full_name="mgmtd.BeTxnReply.create", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.BeTxnReply.success", + index=2, + number=3, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=493, + serialized_end=554, +) + + +_BECFGDATACREATEREQ = _descriptor.Descriptor( + name="BeCfgDataCreateReq", + full_name="mgmtd.BeCfgDataCreateReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="txn_id", + full_name="mgmtd.BeCfgDataCreateReq.txn_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="data_req", + full_name="mgmtd.BeCfgDataCreateReq.data_req", + index=1, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="end_of_data", + full_name="mgmtd.BeCfgDataCreateReq.end_of_data", + index=2, + number=3, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=556, + serialized_end=654, +) + + +_BECFGDATACREATEREPLY = _descriptor.Descriptor( + name="BeCfgDataCreateReply", + full_name="mgmtd.BeCfgDataCreateReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="txn_id", + full_name="mgmtd.BeCfgDataCreateReply.txn_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.BeCfgDataCreateReply.success", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="error_if_any", + full_name="mgmtd.BeCfgDataCreateReply.error_if_any", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=656, + serialized_end=733, +) + + +_BECFGDATAAPPLYREQ = _descriptor.Descriptor( + name="BeCfgDataApplyReq", + full_name="mgmtd.BeCfgDataApplyReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="txn_id", + full_name="mgmtd.BeCfgDataApplyReq.txn_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=735, + serialized_end=770, +) + + +_BECFGDATAAPPLYREPLY = _descriptor.Descriptor( + name="BeCfgDataApplyReply", + full_name="mgmtd.BeCfgDataApplyReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="txn_id", + full_name="mgmtd.BeCfgDataApplyReply.txn_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.BeCfgDataApplyReply.success", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="error_if_any", + full_name="mgmtd.BeCfgDataApplyReply.error_if_any", + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=772, + serialized_end=848, +) + + +_YANGDATAREPLY = _descriptor.Descriptor( + name="YangDataReply", + full_name="mgmtd.YangDataReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.YangDataReply.data", + index=0, + number=1, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="next_indx", + full_name="mgmtd.YangDataReply.next_indx", + index=1, + number=2, + type=3, + cpp_type=2, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=850, + serialized_end=915, +) + + +_BEMESSAGE = _descriptor.Descriptor( + name="BeMessage", + full_name="mgmtd.BeMessage", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="subscr_req", + full_name="mgmtd.BeMessage.subscr_req", + index=0, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="subscr_reply", + full_name="mgmtd.BeMessage.subscr_reply", + index=1, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="txn_req", + full_name="mgmtd.BeMessage.txn_req", + index=2, + number=4, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="txn_reply", + full_name="mgmtd.BeMessage.txn_reply", + index=3, + number=5, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="cfg_data_req", + full_name="mgmtd.BeMessage.cfg_data_req", + index=4, + number=6, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="cfg_data_reply", + full_name="mgmtd.BeMessage.cfg_data_reply", + index=5, + number=7, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="cfg_apply_req", + full_name="mgmtd.BeMessage.cfg_apply_req", + index=6, + number=8, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="cfg_apply_reply", + full_name="mgmtd.BeMessage.cfg_apply_reply", + index=7, + number=9, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="message", + full_name="mgmtd.BeMessage.message", + index=0, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + ), + ], + serialized_start=918, + serialized_end=1322, +) + + +_FEREGISTERREQ = _descriptor.Descriptor( + name="FeRegisterReq", + full_name="mgmtd.FeRegisterReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="client_name", + full_name="mgmtd.FeRegisterReq.client_name", + index=0, + number=1, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=1324, + serialized_end=1360, +) + + +_FESESSIONREQ = _descriptor.Descriptor( + name="FeSessionReq", + full_name="mgmtd.FeSessionReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="create", + full_name="mgmtd.FeSessionReq.create", + index=0, + number=1, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="client_conn_id", + full_name="mgmtd.FeSessionReq.client_conn_id", + index=1, + number=2, + type=4, + cpp_type=4, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeSessionReq.session_id", + index=2, + number=3, + type=4, + cpp_type=4, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="id", + full_name="mgmtd.FeSessionReq.id", + index=0, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + ), + ], + serialized_start=1362, + serialized_end=1446, +) + + +_FESESSIONREPLY = _descriptor.Descriptor( + name="FeSessionReply", + full_name="mgmtd.FeSessionReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="create", + full_name="mgmtd.FeSessionReply.create", + index=0, + number=1, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.FeSessionReply.success", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="client_conn_id", + full_name="mgmtd.FeSessionReply.client_conn_id", + index=2, + number=3, + type=4, + cpp_type=4, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeSessionReply.session_id", + index=3, + number=4, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=1448, + serialized_end=1541, +) + + +_FELOCKDSREQ = _descriptor.Descriptor( + name="FeLockDsReq", + full_name="mgmtd.FeLockDsReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeLockDsReq.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeLockDsReq.req_id", + index=1, + number=2, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeLockDsReq.ds_id", + index=2, + number=3, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="lock", + full_name="mgmtd.FeLockDsReq.lock", + index=3, + number=4, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=1543, + serialized_end=1641, +) + + +_FELOCKDSREPLY = _descriptor.Descriptor( + name="FeLockDsReply", + full_name="mgmtd.FeLockDsReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeLockDsReply.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeLockDsReply.req_id", + index=1, + number=2, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeLockDsReply.ds_id", + index=2, + number=3, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="lock", + full_name="mgmtd.FeLockDsReply.lock", + index=3, + number=4, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.FeLockDsReply.success", + index=4, + number=5, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="error_if_any", + full_name="mgmtd.FeLockDsReply.error_if_any", + index=5, + number=6, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=1644, + serialized_end=1783, +) + + +_FESETCONFIGREQ = _descriptor.Descriptor( + name="FeSetConfigReq", + full_name="mgmtd.FeSetConfigReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeSetConfigReq.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeSetConfigReq.ds_id", + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeSetConfigReq.req_id", + index=2, + number=3, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.FeSetConfigReq.data", + index=3, + number=4, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="implicit_commit", + full_name="mgmtd.FeSetConfigReq.implicit_commit", + index=4, + number=5, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="commit_ds_id", + full_name="mgmtd.FeSetConfigReq.commit_ds_id", + index=5, + number=6, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=1786, + serialized_end=1977, +) + + +_FESETCONFIGREPLY = _descriptor.Descriptor( + name="FeSetConfigReply", + full_name="mgmtd.FeSetConfigReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeSetConfigReply.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeSetConfigReply.ds_id", + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeSetConfigReply.req_id", + index=2, + number=3, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.FeSetConfigReply.success", + index=3, + number=4, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="implicit_commit", + full_name="mgmtd.FeSetConfigReply.implicit_commit", + index=4, + number=5, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="error_if_any", + full_name="mgmtd.FeSetConfigReply.error_if_any", + index=5, + number=6, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=1980, + serialized_end=2133, +) + + +_FECOMMITCONFIGREQ = _descriptor.Descriptor( + name="FeCommitConfigReq", + full_name="mgmtd.FeCommitConfigReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeCommitConfigReq.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="src_ds_id", + full_name="mgmtd.FeCommitConfigReq.src_ds_id", + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="dst_ds_id", + full_name="mgmtd.FeCommitConfigReq.dst_ds_id", + index=2, + number=3, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeCommitConfigReq.req_id", + index=3, + number=4, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="validate_only", + full_name="mgmtd.FeCommitConfigReq.validate_only", + index=4, + number=5, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="abort", + full_name="mgmtd.FeCommitConfigReq.abort", + index=5, + number=6, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=2136, + serialized_end=2307, +) + + +_FECOMMITCONFIGREPLY = _descriptor.Descriptor( + name="FeCommitConfigReply", + full_name="mgmtd.FeCommitConfigReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeCommitConfigReply.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="src_ds_id", + full_name="mgmtd.FeCommitConfigReply.src_ds_id", + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="dst_ds_id", + full_name="mgmtd.FeCommitConfigReply.dst_ds_id", + index=2, + number=3, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeCommitConfigReply.req_id", + index=3, + number=4, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="validate_only", + full_name="mgmtd.FeCommitConfigReply.validate_only", + index=4, + number=5, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.FeCommitConfigReply.success", + index=5, + number=6, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="abort", + full_name="mgmtd.FeCommitConfigReply.abort", + index=6, + number=7, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="error_if_any", + full_name="mgmtd.FeCommitConfigReply.error_if_any", + index=7, + number=8, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=2310, + serialized_end=2522, +) + + +_FEGETREQ = _descriptor.Descriptor( + name="FeGetReq", + full_name="mgmtd.FeGetReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeGetReq.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="config", + full_name="mgmtd.FeGetReq.config", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeGetReq.ds_id", + index=2, + number=3, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeGetReq.req_id", + index=3, + number=4, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.FeGetReq.data", + index=4, + number=5, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=2525, + serialized_end=2659, +) + + +_FEGETREPLY = _descriptor.Descriptor( + name="FeGetReply", + full_name="mgmtd.FeGetReply", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeGetReply.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="config", + full_name="mgmtd.FeGetReply.config", + index=1, + number=2, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeGetReply.ds_id", + index=2, + number=3, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeGetReply.req_id", + index=3, + number=4, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="success", + full_name="mgmtd.FeGetReply.success", + index=4, + number=5, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="error_if_any", + full_name="mgmtd.FeGetReply.error_if_any", + index=5, + number=6, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=b"".decode("utf-8"), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.FeGetReply.data", + index=6, + number=7, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=2662, + serialized_end=2836, +) + + +_FENOTIFYDATAREQ = _descriptor.Descriptor( + name="FeNotifyDataReq", + full_name="mgmtd.FeNotifyDataReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="data", + full_name="mgmtd.FeNotifyDataReq.data", + index=0, + number=1, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=2838, + serialized_end=2886, +) + + +_FEREGISTERNOTIFYREQ = _descriptor.Descriptor( + name="FeRegisterNotifyReq", + full_name="mgmtd.FeRegisterNotifyReq", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="session_id", + full_name="mgmtd.FeRegisterNotifyReq.session_id", + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="ds_id", + full_name="mgmtd.FeRegisterNotifyReq.ds_id", + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="register_req", + full_name="mgmtd.FeRegisterNotifyReq.register_req", + index=2, + number=3, + type=8, + cpp_type=7, + label=2, + has_default_value=False, + default_value=False, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="req_id", + full_name="mgmtd.FeRegisterNotifyReq.req_id", + index=3, + number=4, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="data_xpath", + full_name="mgmtd.FeRegisterNotifyReq.data_xpath", + index=4, + number=5, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[], + serialized_start=2889, + serialized_end=3045, +) + + +_FEMESSAGE = _descriptor.Descriptor( + name="FeMessage", + full_name="mgmtd.FeMessage", + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name="register_req", + full_name="mgmtd.FeMessage.register_req", + index=0, + number=2, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="session_req", + full_name="mgmtd.FeMessage.session_req", + index=1, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="session_reply", + full_name="mgmtd.FeMessage.session_reply", + index=2, + number=4, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="lockds_req", + full_name="mgmtd.FeMessage.lockds_req", + index=3, + number=5, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="lockds_reply", + full_name="mgmtd.FeMessage.lockds_reply", + index=4, + number=6, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="setcfg_req", + full_name="mgmtd.FeMessage.setcfg_req", + index=5, + number=7, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="setcfg_reply", + full_name="mgmtd.FeMessage.setcfg_reply", + index=6, + number=8, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="commcfg_req", + full_name="mgmtd.FeMessage.commcfg_req", + index=7, + number=9, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="commcfg_reply", + full_name="mgmtd.FeMessage.commcfg_reply", + index=8, + number=10, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="get_req", + full_name="mgmtd.FeMessage.get_req", + index=9, + number=11, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="get_reply", + full_name="mgmtd.FeMessage.get_reply", + index=10, + number=12, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="notify_data_req", + full_name="mgmtd.FeMessage.notify_data_req", + index=11, + number=15, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + _descriptor.FieldDescriptor( + name="regnotify_req", + full_name="mgmtd.FeMessage.regnotify_req", + index=12, + number=16, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax="proto2", + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name="message", + full_name="mgmtd.FeMessage.message", + index=0, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[], + ), + ], + serialized_start=3048, + serialized_end=3672, +) + +_YANGDATAVALUE.oneofs_by_name["value"].fields.append( + _YANGDATAVALUE.fields_by_name["encoded_str_val"] +) +_YANGDATAVALUE.fields_by_name[ + "encoded_str_val" +].containing_oneof = _YANGDATAVALUE.oneofs_by_name["value"] +_YANGDATA.fields_by_name["value"].message_type = _YANGDATAVALUE +_YANGCFGDATAREQ.fields_by_name["data"].message_type = _YANGDATA +_YANGCFGDATAREQ.fields_by_name["req_type"].enum_type = _CFGDATAREQTYPE +_YANGGETDATAREQ.fields_by_name["data"].message_type = _YANGDATA +_BECFGDATACREATEREQ.fields_by_name["data_req"].message_type = _YANGCFGDATAREQ +_YANGDATAREPLY.fields_by_name["data"].message_type = _YANGDATA +_BEMESSAGE.fields_by_name["subscr_req"].message_type = _BESUBSCRIBEREQ +_BEMESSAGE.fields_by_name["subscr_reply"].message_type = _BESUBSCRIBEREPLY +_BEMESSAGE.fields_by_name["txn_req"].message_type = _BETXNREQ +_BEMESSAGE.fields_by_name["txn_reply"].message_type = _BETXNREPLY +_BEMESSAGE.fields_by_name["cfg_data_req"].message_type = _BECFGDATACREATEREQ +_BEMESSAGE.fields_by_name["cfg_data_reply"].message_type = _BECFGDATACREATEREPLY +_BEMESSAGE.fields_by_name["cfg_apply_req"].message_type = _BECFGDATAAPPLYREQ +_BEMESSAGE.fields_by_name["cfg_apply_reply"].message_type = _BECFGDATAAPPLYREPLY +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["subscr_req"] +) +_BEMESSAGE.fields_by_name["subscr_req"].containing_oneof = _BEMESSAGE.oneofs_by_name[ + "message" +] +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["subscr_reply"] +) +_BEMESSAGE.fields_by_name["subscr_reply"].containing_oneof = _BEMESSAGE.oneofs_by_name[ + "message" +] +_BEMESSAGE.oneofs_by_name["message"].fields.append(_BEMESSAGE.fields_by_name["txn_req"]) +_BEMESSAGE.fields_by_name["txn_req"].containing_oneof = _BEMESSAGE.oneofs_by_name[ + "message" +] +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["txn_reply"] +) +_BEMESSAGE.fields_by_name["txn_reply"].containing_oneof = _BEMESSAGE.oneofs_by_name[ + "message" +] +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["cfg_data_req"] +) +_BEMESSAGE.fields_by_name["cfg_data_req"].containing_oneof = _BEMESSAGE.oneofs_by_name[ + "message" +] +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["cfg_data_reply"] +) +_BEMESSAGE.fields_by_name[ + "cfg_data_reply" +].containing_oneof = _BEMESSAGE.oneofs_by_name["message"] +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["cfg_apply_req"] +) +_BEMESSAGE.fields_by_name["cfg_apply_req"].containing_oneof = _BEMESSAGE.oneofs_by_name[ + "message" +] +_BEMESSAGE.oneofs_by_name["message"].fields.append( + _BEMESSAGE.fields_by_name["cfg_apply_reply"] +) +_BEMESSAGE.fields_by_name[ + "cfg_apply_reply" +].containing_oneof = _BEMESSAGE.oneofs_by_name["message"] +_FESESSIONREQ.oneofs_by_name["id"].fields.append( + _FESESSIONREQ.fields_by_name["client_conn_id"] +) +_FESESSIONREQ.fields_by_name[ + "client_conn_id" +].containing_oneof = _FESESSIONREQ.oneofs_by_name["id"] +_FESESSIONREQ.oneofs_by_name["id"].fields.append( + _FESESSIONREQ.fields_by_name["session_id"] +) +_FESESSIONREQ.fields_by_name[ + "session_id" +].containing_oneof = _FESESSIONREQ.oneofs_by_name["id"] +_FELOCKDSREQ.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FELOCKDSREPLY.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FESETCONFIGREQ.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FESETCONFIGREQ.fields_by_name["data"].message_type = _YANGCFGDATAREQ +_FESETCONFIGREQ.fields_by_name["commit_ds_id"].enum_type = _DATASTOREID +_FESETCONFIGREPLY.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FECOMMITCONFIGREQ.fields_by_name["src_ds_id"].enum_type = _DATASTOREID +_FECOMMITCONFIGREQ.fields_by_name["dst_ds_id"].enum_type = _DATASTOREID +_FECOMMITCONFIGREPLY.fields_by_name["src_ds_id"].enum_type = _DATASTOREID +_FECOMMITCONFIGREPLY.fields_by_name["dst_ds_id"].enum_type = _DATASTOREID +_FEGETREQ.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FEGETREQ.fields_by_name["data"].message_type = _YANGGETDATAREQ +_FEGETREPLY.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FEGETREPLY.fields_by_name["data"].message_type = _YANGDATAREPLY +_FENOTIFYDATAREQ.fields_by_name["data"].message_type = _YANGDATA +_FEREGISTERNOTIFYREQ.fields_by_name["ds_id"].enum_type = _DATASTOREID +_FEREGISTERNOTIFYREQ.fields_by_name["data_xpath"].message_type = _YANGDATAXPATH +_FEMESSAGE.fields_by_name["register_req"].message_type = _FEREGISTERREQ +_FEMESSAGE.fields_by_name["session_req"].message_type = _FESESSIONREQ +_FEMESSAGE.fields_by_name["session_reply"].message_type = _FESESSIONREPLY +_FEMESSAGE.fields_by_name["lockds_req"].message_type = _FELOCKDSREQ +_FEMESSAGE.fields_by_name["lockds_reply"].message_type = _FELOCKDSREPLY +_FEMESSAGE.fields_by_name["setcfg_req"].message_type = _FESETCONFIGREQ +_FEMESSAGE.fields_by_name["setcfg_reply"].message_type = _FESETCONFIGREPLY +_FEMESSAGE.fields_by_name["commcfg_req"].message_type = _FECOMMITCONFIGREQ +_FEMESSAGE.fields_by_name["commcfg_reply"].message_type = _FECOMMITCONFIGREPLY +_FEMESSAGE.fields_by_name["get_req"].message_type = _FEGETREQ +_FEMESSAGE.fields_by_name["get_reply"].message_type = _FEGETREPLY +_FEMESSAGE.fields_by_name["notify_data_req"].message_type = _FENOTIFYDATAREQ +_FEMESSAGE.fields_by_name["regnotify_req"].message_type = _FEREGISTERNOTIFYREQ +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["register_req"] +) +_FEMESSAGE.fields_by_name["register_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["session_req"] +) +_FEMESSAGE.fields_by_name["session_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["session_reply"] +) +_FEMESSAGE.fields_by_name["session_reply"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["lockds_req"] +) +_FEMESSAGE.fields_by_name["lockds_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["lockds_reply"] +) +_FEMESSAGE.fields_by_name["lockds_reply"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["setcfg_req"] +) +_FEMESSAGE.fields_by_name["setcfg_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["setcfg_reply"] +) +_FEMESSAGE.fields_by_name["setcfg_reply"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["commcfg_req"] +) +_FEMESSAGE.fields_by_name["commcfg_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["commcfg_reply"] +) +_FEMESSAGE.fields_by_name["commcfg_reply"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append(_FEMESSAGE.fields_by_name["get_req"]) +_FEMESSAGE.fields_by_name["get_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["get_reply"] +) +_FEMESSAGE.fields_by_name["get_reply"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["notify_data_req"] +) +_FEMESSAGE.fields_by_name[ + "notify_data_req" +].containing_oneof = _FEMESSAGE.oneofs_by_name["message"] +_FEMESSAGE.oneofs_by_name["message"].fields.append( + _FEMESSAGE.fields_by_name["regnotify_req"] +) +_FEMESSAGE.fields_by_name["regnotify_req"].containing_oneof = _FEMESSAGE.oneofs_by_name[ + "message" +] +DESCRIPTOR.message_types_by_name["YangDataXPath"] = _YANGDATAXPATH +DESCRIPTOR.message_types_by_name["YangDataValue"] = _YANGDATAVALUE +DESCRIPTOR.message_types_by_name["YangData"] = _YANGDATA +DESCRIPTOR.message_types_by_name["YangCfgDataReq"] = _YANGCFGDATAREQ +DESCRIPTOR.message_types_by_name["YangGetDataReq"] = _YANGGETDATAREQ +DESCRIPTOR.message_types_by_name["BeSubscribeReq"] = _BESUBSCRIBEREQ +DESCRIPTOR.message_types_by_name["BeSubscribeReply"] = _BESUBSCRIBEREPLY +DESCRIPTOR.message_types_by_name["BeTxnReq"] = _BETXNREQ +DESCRIPTOR.message_types_by_name["BeTxnReply"] = _BETXNREPLY +DESCRIPTOR.message_types_by_name["BeCfgDataCreateReq"] = _BECFGDATACREATEREQ +DESCRIPTOR.message_types_by_name["BeCfgDataCreateReply"] = _BECFGDATACREATEREPLY +DESCRIPTOR.message_types_by_name["BeCfgDataApplyReq"] = _BECFGDATAAPPLYREQ +DESCRIPTOR.message_types_by_name["BeCfgDataApplyReply"] = _BECFGDATAAPPLYREPLY +DESCRIPTOR.message_types_by_name["YangDataReply"] = _YANGDATAREPLY +DESCRIPTOR.message_types_by_name["BeMessage"] = _BEMESSAGE +DESCRIPTOR.message_types_by_name["FeRegisterReq"] = _FEREGISTERREQ +DESCRIPTOR.message_types_by_name["FeSessionReq"] = _FESESSIONREQ +DESCRIPTOR.message_types_by_name["FeSessionReply"] = _FESESSIONREPLY +DESCRIPTOR.message_types_by_name["FeLockDsReq"] = _FELOCKDSREQ +DESCRIPTOR.message_types_by_name["FeLockDsReply"] = _FELOCKDSREPLY +DESCRIPTOR.message_types_by_name["FeSetConfigReq"] = _FESETCONFIGREQ +DESCRIPTOR.message_types_by_name["FeSetConfigReply"] = _FESETCONFIGREPLY +DESCRIPTOR.message_types_by_name["FeCommitConfigReq"] = _FECOMMITCONFIGREQ +DESCRIPTOR.message_types_by_name["FeCommitConfigReply"] = _FECOMMITCONFIGREPLY +DESCRIPTOR.message_types_by_name["FeGetReq"] = _FEGETREQ +DESCRIPTOR.message_types_by_name["FeGetReply"] = _FEGETREPLY +DESCRIPTOR.message_types_by_name["FeNotifyDataReq"] = _FENOTIFYDATAREQ +DESCRIPTOR.message_types_by_name["FeRegisterNotifyReq"] = _FEREGISTERNOTIFYREQ +DESCRIPTOR.message_types_by_name["FeMessage"] = _FEMESSAGE +DESCRIPTOR.enum_types_by_name["CfgDataReqType"] = _CFGDATAREQTYPE +DESCRIPTOR.enum_types_by_name["DatastoreId"] = _DATASTOREID +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +YangDataXPath = _reflection.GeneratedProtocolMessageType( + "YangDataXPath", + (_message.Message,), + { + "DESCRIPTOR": _YANGDATAXPATH, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.YangDataXPath) + }, +) +_sym_db.RegisterMessage(YangDataXPath) + +YangDataValue = _reflection.GeneratedProtocolMessageType( + "YangDataValue", + (_message.Message,), + { + "DESCRIPTOR": _YANGDATAVALUE, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.YangDataValue) + }, +) +_sym_db.RegisterMessage(YangDataValue) + +YangData = _reflection.GeneratedProtocolMessageType( + "YangData", + (_message.Message,), + { + "DESCRIPTOR": _YANGDATA, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.YangData) + }, +) +_sym_db.RegisterMessage(YangData) + +YangCfgDataReq = _reflection.GeneratedProtocolMessageType( + "YangCfgDataReq", + (_message.Message,), + { + "DESCRIPTOR": _YANGCFGDATAREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.YangCfgDataReq) + }, +) +_sym_db.RegisterMessage(YangCfgDataReq) + +YangGetDataReq = _reflection.GeneratedProtocolMessageType( + "YangGetDataReq", + (_message.Message,), + { + "DESCRIPTOR": _YANGGETDATAREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.YangGetDataReq) + }, +) +_sym_db.RegisterMessage(YangGetDataReq) + +BeSubscribeReq = _reflection.GeneratedProtocolMessageType( + "BeSubscribeReq", + (_message.Message,), + { + "DESCRIPTOR": _BESUBSCRIBEREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeSubscribeReq) + }, +) +_sym_db.RegisterMessage(BeSubscribeReq) + +BeSubscribeReply = _reflection.GeneratedProtocolMessageType( + "BeSubscribeReply", + (_message.Message,), + { + "DESCRIPTOR": _BESUBSCRIBEREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeSubscribeReply) + }, +) +_sym_db.RegisterMessage(BeSubscribeReply) + +BeTxnReq = _reflection.GeneratedProtocolMessageType( + "BeTxnReq", + (_message.Message,), + { + "DESCRIPTOR": _BETXNREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeTxnReq) + }, +) +_sym_db.RegisterMessage(BeTxnReq) + +BeTxnReply = _reflection.GeneratedProtocolMessageType( + "BeTxnReply", + (_message.Message,), + { + "DESCRIPTOR": _BETXNREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeTxnReply) + }, +) +_sym_db.RegisterMessage(BeTxnReply) + +BeCfgDataCreateReq = _reflection.GeneratedProtocolMessageType( + "BeCfgDataCreateReq", + (_message.Message,), + { + "DESCRIPTOR": _BECFGDATACREATEREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeCfgDataCreateReq) + }, +) +_sym_db.RegisterMessage(BeCfgDataCreateReq) + +BeCfgDataCreateReply = _reflection.GeneratedProtocolMessageType( + "BeCfgDataCreateReply", + (_message.Message,), + { + "DESCRIPTOR": _BECFGDATACREATEREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeCfgDataCreateReply) + }, +) +_sym_db.RegisterMessage(BeCfgDataCreateReply) + +BeCfgDataApplyReq = _reflection.GeneratedProtocolMessageType( + "BeCfgDataApplyReq", + (_message.Message,), + { + "DESCRIPTOR": _BECFGDATAAPPLYREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeCfgDataApplyReq) + }, +) +_sym_db.RegisterMessage(BeCfgDataApplyReq) + +BeCfgDataApplyReply = _reflection.GeneratedProtocolMessageType( + "BeCfgDataApplyReply", + (_message.Message,), + { + "DESCRIPTOR": _BECFGDATAAPPLYREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeCfgDataApplyReply) + }, +) +_sym_db.RegisterMessage(BeCfgDataApplyReply) + +YangDataReply = _reflection.GeneratedProtocolMessageType( + "YangDataReply", + (_message.Message,), + { + "DESCRIPTOR": _YANGDATAREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.YangDataReply) + }, +) +_sym_db.RegisterMessage(YangDataReply) + +BeMessage = _reflection.GeneratedProtocolMessageType( + "BeMessage", + (_message.Message,), + { + "DESCRIPTOR": _BEMESSAGE, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.BeMessage) + }, +) +_sym_db.RegisterMessage(BeMessage) + +FeRegisterReq = _reflection.GeneratedProtocolMessageType( + "FeRegisterReq", + (_message.Message,), + { + "DESCRIPTOR": _FEREGISTERREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeRegisterReq) + }, +) +_sym_db.RegisterMessage(FeRegisterReq) + +FeSessionReq = _reflection.GeneratedProtocolMessageType( + "FeSessionReq", + (_message.Message,), + { + "DESCRIPTOR": _FESESSIONREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeSessionReq) + }, +) +_sym_db.RegisterMessage(FeSessionReq) + +FeSessionReply = _reflection.GeneratedProtocolMessageType( + "FeSessionReply", + (_message.Message,), + { + "DESCRIPTOR": _FESESSIONREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeSessionReply) + }, +) +_sym_db.RegisterMessage(FeSessionReply) + +FeLockDsReq = _reflection.GeneratedProtocolMessageType( + "FeLockDsReq", + (_message.Message,), + { + "DESCRIPTOR": _FELOCKDSREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeLockDsReq) + }, +) +_sym_db.RegisterMessage(FeLockDsReq) + +FeLockDsReply = _reflection.GeneratedProtocolMessageType( + "FeLockDsReply", + (_message.Message,), + { + "DESCRIPTOR": _FELOCKDSREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeLockDsReply) + }, +) +_sym_db.RegisterMessage(FeLockDsReply) + +FeSetConfigReq = _reflection.GeneratedProtocolMessageType( + "FeSetConfigReq", + (_message.Message,), + { + "DESCRIPTOR": _FESETCONFIGREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeSetConfigReq) + }, +) +_sym_db.RegisterMessage(FeSetConfigReq) + +FeSetConfigReply = _reflection.GeneratedProtocolMessageType( + "FeSetConfigReply", + (_message.Message,), + { + "DESCRIPTOR": _FESETCONFIGREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeSetConfigReply) + }, +) +_sym_db.RegisterMessage(FeSetConfigReply) + +FeCommitConfigReq = _reflection.GeneratedProtocolMessageType( + "FeCommitConfigReq", + (_message.Message,), + { + "DESCRIPTOR": _FECOMMITCONFIGREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeCommitConfigReq) + }, +) +_sym_db.RegisterMessage(FeCommitConfigReq) + +FeCommitConfigReply = _reflection.GeneratedProtocolMessageType( + "FeCommitConfigReply", + (_message.Message,), + { + "DESCRIPTOR": _FECOMMITCONFIGREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeCommitConfigReply) + }, +) +_sym_db.RegisterMessage(FeCommitConfigReply) + +FeGetReq = _reflection.GeneratedProtocolMessageType( + "FeGetReq", + (_message.Message,), + { + "DESCRIPTOR": _FEGETREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeGetReq) + }, +) +_sym_db.RegisterMessage(FeGetReq) + +FeGetReply = _reflection.GeneratedProtocolMessageType( + "FeGetReply", + (_message.Message,), + { + "DESCRIPTOR": _FEGETREPLY, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeGetReply) + }, +) +_sym_db.RegisterMessage(FeGetReply) + +FeNotifyDataReq = _reflection.GeneratedProtocolMessageType( + "FeNotifyDataReq", + (_message.Message,), + { + "DESCRIPTOR": _FENOTIFYDATAREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeNotifyDataReq) + }, +) +_sym_db.RegisterMessage(FeNotifyDataReq) + +FeRegisterNotifyReq = _reflection.GeneratedProtocolMessageType( + "FeRegisterNotifyReq", + (_message.Message,), + { + "DESCRIPTOR": _FEREGISTERNOTIFYREQ, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeRegisterNotifyReq) + }, +) +_sym_db.RegisterMessage(FeRegisterNotifyReq) + +FeMessage = _reflection.GeneratedProtocolMessageType( + "FeMessage", + (_message.Message,), + { + "DESCRIPTOR": _FEMESSAGE, + "__module__": "mgmt_pb2", + # @@protoc_insertion_point(class_scope:mgmtd.FeMessage) + }, +) +_sym_db.RegisterMessage(FeMessage) + + +# @@protoc_insertion_point(module_scope) diff --git a/tests/topotests/mgmt_fe_client/oper.py b/tests/topotests/mgmt_fe_client/oper.py new file mode 120000 index 000000000000..924439251ad9 --- /dev/null +++ b/tests/topotests/mgmt_fe_client/oper.py @@ -0,0 +1 @@ +../mgmt_oper/oper.py \ No newline at end of file diff --git a/tests/topotests/mgmt_fe_client/r1/frr.conf b/tests/topotests/mgmt_fe_client/r1/frr.conf new file mode 100644 index 000000000000..cf8ba160f4b7 --- /dev/null +++ b/tests/topotests/mgmt_fe_client/r1/frr.conf @@ -0,0 +1,23 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 +exit + +interface r1-eth1 vrf red + ip address 3.3.3.1/24 +exit +ip route 11.11.11.11/32 1.1.1.2 +!ip route 13.13.13.13/32 3.3.3.2 vrf red \ No newline at end of file diff --git a/tests/topotests/mgmt_fe_client/test_client.py b/tests/topotests/mgmt_fe_client/test_client.py new file mode 100644 index 000000000000..b5a74c60acd8 --- /dev/null +++ b/tests/topotests/mgmt_fe_client/test_client.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis +# +# noqa: E501 +# +""" +Test static route functionality +""" +import pytest +from lib.topogen import Topogen +from oper import check_kernel_32 + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth1", "red") + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_oper_simple(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"].net + check_kernel_32(r1, "11.11.11.11", 1, "") diff --git a/tests/topotests/mgmt_notif/oper.py b/tests/topotests/mgmt_notif/oper.py new file mode 120000 index 000000000000..924439251ad9 --- /dev/null +++ b/tests/topotests/mgmt_notif/oper.py @@ -0,0 +1 @@ +../mgmt_oper/oper.py \ No newline at end of file diff --git a/tests/topotests/mgmt_notif/r1/frr.conf b/tests/topotests/mgmt_notif/r1/frr.conf new file mode 100644 index 000000000000..47e73956cfe8 --- /dev/null +++ b/tests/topotests/mgmt_notif/r1/frr.conf @@ -0,0 +1,27 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +ip route 11.11.11.11/32 lo + +interface r1-eth0 + ip address 1.1.1.1/24 + ip rip authentication string foo + ip rip authentication mode text +exit + +router rip + network 1.1.1.0/24 + timers basic 5 15 10 + redistribute static +exit diff --git a/tests/topotests/mgmt_notif/r2/frr.conf b/tests/topotests/mgmt_notif/r2/frr.conf new file mode 100644 index 000000000000..cd052011e057 --- /dev/null +++ b/tests/topotests/mgmt_notif/r2/frr.conf @@ -0,0 +1,27 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +ip route 22.22.22.22/32 lo + +interface r2-eth0 + ip address 1.1.1.2/24 + ip rip authentication string bar + ip rip authentication mode text +exit + +router rip + network 1.1.1.0/24 + timers basic 5 15 10 + redistribute static +exit \ No newline at end of file diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py new file mode 100644 index 000000000000..e5286faae208 --- /dev/null +++ b/tests/topotests/mgmt_notif/test_notif.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# January 23 2024, Christian Hopps +# +# Copyright (c) 2024, LabN Consulting, L.L.C. +# + +""" +Test YANG Notifications +""" +import json +import os + +import pytest +from lib.topogen import Topogen +from lib.topotest import json_cmp +from oper import check_kernel_32 + +pytestmark = [pytest.mark.ripd, pytest.mark.staticd, pytest.mark.mgmtd] + +CWD = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = { + "s1": ("r1", "r2"), + } + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for _, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_frontend_notification(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"].net + + check_kernel_32(r1, "11.11.11.11", 1, "") + + fe_client_path = CWD + "/../lib/fe_client.py --verbose" + rc, _, _ = r1.cmd_status(fe_client_path + " --help") + + if rc: + pytest.skip("No protoc or present cannot run test") + + # The first notifications is a frr-ripd:authentication-type-failure + # So we filter to avoid that, all the rest are frr-ripd:authentication-failure + # making our test deterministic + output = r1.cmd_raises( + fe_client_path + " --listen /frr-ripd:authentication-failure" + ) + jsout = json.loads(output) + + expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}} + result = json_cmp(jsout, expected) + assert result is None + + output = r1.cmd_raises(fe_client_path + " --use-protobuf --listen") + jsout = json.loads(output) + + expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}} + result = json_cmp(jsout, expected) + assert result is None + + +def test_backend_notification(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"].net + + check_kernel_32(r1, "11.11.11.11", 1, "") + + be_client_path = "/usr/lib/frr/mgmtd_testc" + rc, _, _ = r1.cmd_status(be_client_path + " --help") + + if rc: + pytest.skip("No mgmtd_testc") + + output = r1.cmd_raises( + be_client_path + " --timeout 20 --log file:mgmt_testc.log --listen /frr-ripd" + ) + + jsout = json.loads(output) + + expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}} + result = json_cmp(jsout, expected) + assert result is None diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json new file mode 100644 index 000000000000..948f4e6c23b4 --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-default.json @@ -0,0 +1,591 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json new file mode 100644 index 000000000000..30daecf16ebc --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-nokey.json @@ -0,0 +1,1177 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + }, + { + "name": "red", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "13.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "13.13.13.13/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "3.3.3.2", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "14.14.14.14/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "4.4.4.2", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2003:333::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2003:333::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2003:333::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2003:333::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json new file mode 100644 index 000000000000..cfabd49c45d3 --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-red.json @@ -0,0 +1,576 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "red", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "13.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "13.13.13.13/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "3.3.3.2", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "14.14.14.14/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "4.4.4.2", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2003:333::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "2003:333::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2003:333::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "2003:333::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null] + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json new file mode 100644 index 000000000000..b1124bd7bb55 --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra-ribs.json @@ -0,0 +1,588 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json new file mode 100644 index 000000000000..70c8798b31fe --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-lib-vrf-zebra.json @@ -0,0 +1,588 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper-results/result-lib.json b/tests/topotests/mgmt_oper/oper-results/result-lib.json new file mode 100644 index 000000000000..0b2a9fa4270a --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-lib.json @@ -0,0 +1,1177 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + } + ] + } + } + }, + { + "name": "red", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "13.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "13.13.13.13/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "3.3.3.2", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "14.14.14.14/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "4.4.4.2", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "4.4.4.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2003:333::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2003:333::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2003:333::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2003:333::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth2", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2004:4444::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth3", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json new file mode 100644 index 000000000000..769c1f73a579 --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-ipv4-unicast.json @@ -0,0 +1,229 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json new file mode 100644 index 000000000000..c740f592f7bc --- /dev/null +++ b/tests/topotests/mgmt_oper/oper-results/result-ribs-rib-nokeys.json @@ -0,0 +1,588 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "11.0.0.0/8", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "blackhole", + "vrf": "rubout", + "gateway": "", + "interface": " ", + "bh-type": "null", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "12.12.12.12/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "2.2.2.2", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2.2.2.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + }, + { + "prefix": "2001:1111::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2001:1111::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::/64", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + }, + { + "prefix": "2002:2222::1/128", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/oper.py b/tests/topotests/mgmt_oper/oper.py new file mode 100644 index 000000000000..9fc504569d50 --- /dev/null +++ b/tests/topotests/mgmt_oper/oper.py @@ -0,0 +1,267 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# October 29 2023, Christian Hopps +# +# Copyright (c) 2023, LabN Consulting, L.L.C. +# + +import datetime +import ipaddress +import json +import logging +import math +import os +import pprint +import re + +from lib.common_config import retry, step +from lib.topolog import logger +from lib.topotest import json_cmp as tt_json_cmp + +try: + from deepdiff import DeepDiff as dd_json_cmp +except ImportError: + dd_json_cmp = None + + +def json_cmp(got, expect, exact_match): + if dd_json_cmp: + if exact_match: + deep_diff = dd_json_cmp(expect, got) + # Convert DeepDiff completely into dicts or lists at all levels + json_diff = json.loads(deep_diff.to_json()) + else: + json_diff = dd_json_cmp(expect, got, ignore_order=True) + # Convert DeepDiff completely into dicts or lists at all levels + # json_diff = json.loads(deep_diff.to_json()) + # Remove new fields in json object from diff + if json_diff.get("dictionary_item_added") is not None: + del json_diff["dictionary_item_added"] + # Remove new json objects in json array from diff + if (new_items := json_diff.get("iterable_item_added")) is not None: + new_item_paths = list(new_items.keys()) + for path in new_item_paths: + if type(new_items[path]) is dict: + del new_items[path] + if len(new_items) == 0: + del json_diff["iterable_item_added"] + if not json_diff: + json_diff = None + else: + json_diff = tt_json_cmp(got, expect, exact_match) + json_diff = str(json_diff) + return json_diff + + +def enable_debug(router): + router.vtysh_cmd("debug northbound callbacks configuration") + + +def disable_debug(router): + router.vtysh_cmd("no debug northbound callbacks configuration") + + +@retry(retry_timeout=30, initial_wait=1) +def _do_oper_test(tgen, qr): + r1 = tgen.gears["r1"].net + + qcmd = ( + r"vtysh -c 'show mgmt get-data {} {}' " + r"""| sed -e 's/"phy-address": ".*"/"phy-address": "rubout"/'""" + r"""| sed -e 's/"uptime": ".*"/"uptime": "rubout"/'""" + r"""| sed -e 's/"vrf": "[0-9]*"/"vrf": "rubout"/'""" + r"""| sed -e 's/"if-index": [0-9][0-9]*/"if-index": "rubout"/'""" + r"""| sed -e 's/"id": [0-9][0-9]*/"id": "rubout"/'""" + ) + # Don't use this for now. + dd_json_cmp = None + + expected = open(qr[1], encoding="ascii").read() + output = r1.cmd_nostatus(qcmd.format(qr[0], qr[2] if len(qr) > 2 else "")) + + try: + ojson = json.loads(output) + except json.decoder.JSONDecodeError as error: + logging.error("Error decoding json: %s\noutput:\n%s", error, output) + raise + + try: + ejson = json.loads(expected) + except json.decoder.JSONDecodeError as error: + logging.error( + "Error decoding json exp result: %s\noutput:\n%s", error, expected + ) + logging.warning("FILE: {}".format(qr[1])) + raise + + if dd_json_cmp: + cmpout = json_cmp(ojson, ejson, exact_match=True) + if cmpout: + logging.warning( + "-------DIFF---------\n%s\n---------DIFF----------", + pprint.pformat(cmpout), + ) + else: + cmpout = tt_json_cmp(ojson, ejson, exact=True) + if cmpout: + logging.warning( + "-------EXPECT--------\n%s\n------END-EXPECT------", + json.dumps(ejson, indent=4), + ) + logging.warning( + "--------GOT----------\n%s\n-------END-GOT--------", + json.dumps(ojson, indent=4), + ) + logging.warning("----diff---\n{}".format(cmpout)) + logging.warning("Command: {}".format(qcmd.format(qr[0], qr[2] if len(qr) > 2 else ""))) + logging.warning("File: {}".format(qr[1])) + assert cmpout is None + + +def do_oper_test(tgen, query_results): + reset = True + for qr in query_results: + step(f"Perform query '{qr[0]}'", reset=reset) + if reset: + reset = False + _do_oper_test(tgen, qr) + + +def get_ip_networks(super_prefix, count): + count_log2 = math.log(count, 2) + if count_log2 != int(count_log2): + count_log2 = int(count_log2) + 1 + else: + count_log2 = int(count_log2) + network = ipaddress.ip_network(super_prefix) + return tuple(network.subnets(count_log2))[0:count] + + +@retry(retry_timeout=30, initial_wait=0.1) +def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): + network = ipaddress.ip_network(super_prefix) + vrfstr = f" vrf {vrf}" if vrf else "" + if network.version == 6: + kernel = r1.cmd_raises(f"ip -6 route show{vrfstr}") + else: + kernel = r1.cmd_raises(f"ip -4 route show{vrfstr}") + + # logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) + + for _, net in enumerate(get_ip_networks(super_prefix, count)): + if not add: + assert str(net) not in kernel + continue + + if is_blackhole: + route = f"blackhole {str(net)} proto (static|196) metric 20" + else: + route = ( + f"{str(net)}(?: nhid [0-9]+)? {matchvia} " + "proto (static|196) metric 20" + ) + assert re.search(route, kernel), f"Failed to find \n'{route}'\n in \n'{kernel}'" + + +def addrgen(a, count, step=1): + for _ in range(0, count, step): + yield a + a += step + + +@retry(retry_timeout=30, initial_wait=0.1) +def check_kernel_32(r1, start_addr, count, vrf, step=1): + start = ipaddress.ip_address(start_addr) + vrfstr = f" vrf {vrf}" if vrf else "" + if start.version == 6: + kernel = r1.cmd_raises(f"ip -6 route show{vrfstr}") + else: + kernel = r1.cmd_raises(f"ip -4 route show{vrfstr}") + + nentries = len(re.findall("\n", kernel)) + logging.info("checking kernel routing table%s: (%s entries)", vrfstr, nentries) + + for addr in addrgen(start, count, step): + assert str(addr) in kernel, f"Failed to find '{addr}' in {nentries} entries" + + +def do_config( + r1, + count, + add=True, + do_ipv6=False, + via=None, + vrf=None, + use_cli=False, +): + optype = "adding" if add else "removing" + iptype = "IPv6" if do_ipv6 else "IPv4" + + # + # Set the route details + # + + if vrf: + super_prefix = "2111::/48" if do_ipv6 else "111.0.0.0/8" + else: + super_prefix = "2055::/48" if do_ipv6 else "55.0.0.0/8" + + matchvia = "" + if via == "blackhole": + pass + elif via: + matchvia = f"dev {via}" + else: + if vrf: + via = "2102::2" if do_ipv6 else "3.3.3.2" + matchvia = f"via {via} dev r1-eth1" + else: + via = "2101::2" if do_ipv6 else "1.1.1.2" + matchvia = f"via {via} dev r1-eth0" + + vrfdbg = " in vrf {}".format(vrf) if vrf else "" + logger.debug("{} {} static {} routes{}".format(optype, count, iptype, vrfdbg)) + + # + # Generate config file in a retrievable place + # + + config_file = os.path.join( + r1.logdir, r1.name, "{}-routes-{}.conf".format(iptype.lower(), optype) + ) + with open(config_file, "w") as f: + if use_cli: + f.write("configure terminal\n") + if vrf: + f.write("vrf {}\n".format(vrf)) + + for _, net in enumerate(get_ip_networks(super_prefix, count)): + if add: + f.write("ip route {} {}\n".format(net, via)) + else: + f.write("no ip route {} {}\n".format(net, via)) + + # + # Load config file. + # + + if use_cli: + load_command = 'vtysh < "{}"'.format(config_file) + else: + load_command = 'vtysh -f "{}"'.format(config_file) + tstamp = datetime.datetime.now() + output = r1.cmd_raises(load_command) + delta = (datetime.datetime.now() - tstamp).total_seconds() + + # + # Verify the results are in the kernel + # + check_kernel(r1, super_prefix, count, add, via == "blackhole", vrf, matchvia) + + optyped = "added" if add else "removed" + logger.debug( + "{} {} {} static routes under {}{} in {}s".format( + optyped, count, iptype.lower(), super_prefix, vrfdbg, delta + ) + ) diff --git a/tests/topotests/mgmt_oper/r1/frr-scale.conf b/tests/topotests/mgmt_oper/r1/frr-scale.conf new file mode 100644 index 000000000000..237d013aecf5 --- /dev/null +++ b/tests/topotests/mgmt_oper/r1/frr-scale.conf @@ -0,0 +1,25 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +! debug northbound libyang +! debug northbound callbacks + +debug northbound notifications +debug northbound events + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 +exit + +interface r1-eth1 vrf red + ip address 3.3.3.1/24 +exit + +ip route 11.11.11.11/32 1.1.1.2 +ip route 13.13.13.13/32 3.3.3.2 vrf red \ No newline at end of file diff --git a/tests/topotests/mgmt_oper/r1/frr-simple.conf b/tests/topotests/mgmt_oper/r1/frr-simple.conf new file mode 100644 index 000000000000..73df6b97b2bb --- /dev/null +++ b/tests/topotests/mgmt_oper/r1/frr-simple.conf @@ -0,0 +1,26 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 + description r1-eth0-desc + evpn mh es-df-pref 32767 +exit + +interface r1-eth1 vrf red + ip address 3.3.3.1/24 + description r1-eth1-desc +exit +ip route 11.11.11.11/32 1.1.1.2 +!ip route 13.13.13.13/32 3.3.3.2 vrf red diff --git a/tests/topotests/mgmt_oper/r1/frr.conf b/tests/topotests/mgmt_oper/r1/frr.conf new file mode 100644 index 000000000000..72a67bf020e7 --- /dev/null +++ b/tests/topotests/mgmt_oper/r1/frr.conf @@ -0,0 +1,41 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + +interface r1-eth0 + ip address 1.1.1.1/24 + ipv6 address 2001:1111::1/64 +exit + +interface r1-eth1 + ip address 2.2.2.1/24 + ipv6 address 2002:2222::1/64 +exit + +interface r1-eth2 vrf red + ip address 3.3.3.1/24 + ipv6 address 2003:333::1/64 +exit + +interface r1-eth3 vrf red + ip address 4.4.4.1/24 + ipv6 address 2004:4444::1/64 +exit + +ip route 11.0.0.0/8 Null0 +ip route 11.11.11.11/32 1.1.1.2 +ip route 12.12.12.12/32 2.2.2.2 + +ip route 13.0.0.0/8 Null0 vrf red +ip route 13.13.13.13/32 3.3.3.2 vrf red +ip route 14.14.14.14/32 4.4.4.2 vrf red \ No newline at end of file diff --git a/tests/topotests/mgmt_oper/simple-results/result-empty.json b/tests/topotests/mgmt_oper/simple-results/result-empty.json new file mode 100644 index 000000000000..2c63c0851048 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-empty.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-description.json b/tests/topotests/mgmt_oper/simple-results/result-intf-description.json new file mode 100644 index 000000000000..8f8092ec1a55 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-description.json @@ -0,0 +1,14 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "description": "r1-eth0-desc" + }, + { + "name": "r1-eth1", + "description": "r1-eth1-desc" + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-description-exact.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-description-exact.json new file mode 100644 index 000000000000..e00f23c3ddee --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-description-exact.json @@ -0,0 +1,3 @@ +{ + "frr-interface:description": "r1-eth0-desc" +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json new file mode 100644 index 000000000000..04591b6e2984 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-exact.json @@ -0,0 +1,23 @@ +{ + "frr-interface:interface": [ + { + "name": "r1-eth0", + "vrf": "default", + "state": { + "if-index": "rubout", + "mtu": 1500, + "mtu6": 1500, + "speed": 10000, + "metric": 0, + "phy-address": "rubout" + }, + "frr-zebra:zebra": { + "state": { + "up-count": 0, + "down-count": 0, + "zif-type": "zif-veth" + } + } + } + ] +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-name.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-name.json new file mode 100644 index 000000000000..3988204bb83b --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-name.json @@ -0,0 +1,9 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0" + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json new file mode 100644 index 000000000000..e48002e672a1 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json @@ -0,0 +1,21 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "description": "r1-eth0-desc", + "frr-zebra:zebra": { + "ipv4-addrs": [ + { + "ip": "1.1.1.1", + "prefix-length": 24 + } + ], + "evpn-mh": { + "df-preference": 32767 + } + } + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-vrf.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-vrf.json new file mode 100644 index 000000000000..3a6eeb853d6b --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-vrf.json @@ -0,0 +1,10 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "vrf": "default" + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json new file mode 100644 index 000000000000..caee164468a0 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json @@ -0,0 +1,13 @@ +{ + "frr-zebra:evpn-mh": { + "df-preference": 32767, + "bypass": false, + "@bypass": { + "ietf-netconf-with-defaults:default": true + }, + "uplink": false, + "@uplink": { + "ietf-netconf-with-defaults:default": true + } + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json new file mode 100644 index 000000000000..07ba53b8bcc4 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json @@ -0,0 +1,7 @@ +{ + "frr-zebra:evpn-mh": { + "df-preference": 32767, + "bypass": false, + "uplink": false + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json new file mode 100644 index 000000000000..1779d1cd4ea0 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json @@ -0,0 +1,5 @@ +{ + "frr-zebra:evpn-mh": { + "df-preference": 32767 + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json new file mode 100644 index 000000000000..efd7e8c684c0 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json @@ -0,0 +1,3 @@ +{ + "frr-zebra:evpn-mh": {} +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json new file mode 100644 index 000000000000..c770db49b17d --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json @@ -0,0 +1,35 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "vrf": "default", + "description": "r1-eth0-desc", + "state": { + "if-index": "rubout", + "mtu": 1500, + "mtu6": 1500, + "speed": 10000, + "metric": 0, + "phy-address": "rubout" + }, + "frr-zebra:zebra": { + "ipv4-addrs": [ + { + "ip": "1.1.1.1", + "prefix-length": 24 + } + ], + "evpn-mh": { + "df-preference": 32767 + }, + "state": { + "up-count": 0, + "down-count": 0, + "zif-type": "zif-veth" + } + } + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-name.json b/tests/topotests/mgmt_oper/simple-results/result-intf-name.json new file mode 100644 index 000000000000..9d8ea759b9c2 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-name.json @@ -0,0 +1,21 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "lo" + }, + { + "name": "r1-eth0" + }, + { + "name": "lo-red" + }, + { + "name": "r1-eth1" + }, + { + "name": "red" + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json b/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json new file mode 100644 index 000000000000..018ed99f4011 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-state-mtu.json @@ -0,0 +1,13 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "state": { + "mtu": 1500 + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-state.json b/tests/topotests/mgmt_oper/simple-results/result-intf-state.json new file mode 100644 index 000000000000..35669fd5715d --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-intf-state.json @@ -0,0 +1,18 @@ +{ + "frr-interface:lib": { + "interface": [ + { + "name": "r1-eth0", + "state": { + "if-index": "rubout", + "mtu": 1500, + "mtu6": 1500, + "speed": 10000, + "metric": 0, + "phy-address": "rubout" + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json new file mode 100644 index 000000000000..f85b163bd6bb --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-default.json @@ -0,0 +1,197 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json new file mode 100644 index 000000000000..e2cfec972443 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-nokey.json @@ -0,0 +1,358 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + }, + { + "name": "red", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json new file mode 100644 index 000000000000..3567f35a349b --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-red.json @@ -0,0 +1,168 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "red", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json new file mode 100644 index 000000000000..d9ca58d25d91 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra-ribs.json @@ -0,0 +1,193 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json new file mode 100644 index 000000000000..d9ca58d25d91 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-lib-vrf-zebra.json @@ -0,0 +1,193 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-lib.json b/tests/topotests/mgmt_oper/simple-results/result-lib.json new file mode 100644 index 000000000000..e2cfec972443 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-lib.json @@ -0,0 +1,358 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + }, + { + "name": "red", + "state": { + "id": "rubout", + "active": true + }, + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 10, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "3.3.3.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "3.3.3.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth1", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 10, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json new file mode 100644 index 000000000000..11766ce9c1ea --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-ipv4-unicast.json @@ -0,0 +1,112 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json new file mode 100644 index 000000000000..d9ca58d25d91 --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-nokeys.json @@ -0,0 +1,193 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv4-multicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "internal-flags": 8, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-unicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + }, + { + "afi-safi-name": "frr-routing:ipv6-multicast", + "table-id": 254, + "route": [ + { + "prefix": "::/0" + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json new file mode 100644 index 000000000000..11766ce9c1ea --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-nokey.json @@ -0,0 +1,112 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "0.0.0.0/0" + }, + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "1.1.1.1/32", + "route-entry": [ + { + "protocol": "local", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + }, + { + "prefix": "11.11.11.11/32", + "route-entry": [ + { + "protocol": "static", + "distance": 1, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 73, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ip4-ifindex", + "vrf": "rubout", + "gateway": "1.1.1.2", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight": 1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json new file mode 100644 index 000000000000..ef4a4ab1313f --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-ribs-rib-route-prefix.json @@ -0,0 +1,51 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "distance": 0, + "metric": 0, + "selected": [null], + "installed": [null], + "internal-flags": 8, + "internal-status": 16, + "uptime": "rubout", + "nexthop-group": { + "id": "rubout", + "nexthop": [ + { + "nh-type": "ifindex", + "vrf": "rubout", + "gateway": "", + "interface": "r1-eth0", + "active": [null], + "fib": [null], + "weight":1 + } + ] + } + } + ] + } + ] + } + ] + } + } + } + ] + } +} + diff --git a/tests/topotests/mgmt_oper/simple-results/result-singleton-metric.json b/tests/topotests/mgmt_oper/simple-results/result-singleton-metric.json new file mode 100644 index 000000000000..b3a7df54eaaf --- /dev/null +++ b/tests/topotests/mgmt_oper/simple-results/result-singleton-metric.json @@ -0,0 +1,30 @@ +{ + "frr-vrf:lib": { + "vrf": [ + { + "name": "default", + "frr-zebra:zebra": { + "ribs": { + "rib": [ + { + "afi-safi-name": "frr-routing:ipv4-unicast", + "table-id": 254, + "route": [ + { + "prefix": "1.1.1.0/24", + "route-entry": [ + { + "protocol": "connected", + "metric": 0 + } + ] + } + ] + } + ] + } + } + } + ] + } +} diff --git a/tests/topotests/mgmt_oper/test_oper.py b/tests/topotests/mgmt_oper/test_oper.py new file mode 100644 index 000000000000..e4ceabf35275 --- /dev/null +++ b/tests/topotests/mgmt_oper/test_oper.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis +# +""" +Test static route functionality +""" + +import ipaddress +import math + +import pytest +from lib.topogen import Topogen +from oper import check_kernel_32, do_oper_test + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",), "s3": ("r1",), "s4": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth2", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth3", "red") + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def get_ip_networks(super_prefix, count): + count_log2 = math.log(count, 2) + if count_log2 != int(count_log2): + count_log2 = int(count_log2) + 1 + else: + count_log2 = int(count_log2) + network = ipaddress.ip_network(super_prefix) + return tuple(network.subnets(count_log2))[0:count] + + +def test_oper(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + query_results = [ + ("/frr-vrf:lib", "oper-results/result-lib.json"), + ("/frr-vrf:lib/vrf", "oper-results/result-lib-vrf-nokey.json"), + ( + '/frr-vrf:lib/vrf[name="default"]', + "oper-results/result-lib-vrf-default.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra', + "oper-results/result-lib-vrf-zebra.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs', + "oper-results/result-lib-vrf-zebra-ribs.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib', + "oper-results/result-ribs-rib-nokeys.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]', + "oper-results/result-ribs-rib-ipv4-unicast.json", + ), + ] + + r1 = tgen.gears["r1"].net + check_kernel_32(r1, "11.11.11.11", 1, "") + check_kernel_32(r1, "12.12.12.12", 1, "") + check_kernel_32(r1, "13.13.13.13", 1, "red") + check_kernel_32(r1, "14.14.14.14", 1, "red") + do_oper_test(tgen, query_results) + + +to_gen_new_results = """ +scriptdir=~chopps/w/frr/tests/topotests/mgmt_oper +resdir=${scriptdir}/oper-results +vtysh -c 'show mgmt get-data /frr-vrf:lib' > ${resdir}/result-lib.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf' > ${resdir}/result-lib-vrf-nokey.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]' > ${resdir}/result-lib-vrf-default.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="red"]' > ${resdir}/result-lib-vrf-red.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra' > ${resdir}/result-lib-vrf-zebra.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs' > ${resdir}/result-lib-vrf-zebra-ribs.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib' > ${resdir}/result-ribs-rib-nokeys.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]' > ${resdir}/result-ribs-rib-ipv4-unicast.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/route' > ${resdir}/result-ribs-rib-route-nokey.json + +for f in ${resdir}/result-*; do + sed -i -e 's/"uptime": ".*"/"uptime": "rubout"/;s/"id": [0-9][0-9]*/"id": "rubout"/' $f + sed -i -e 's/"if-index": [0-9][0-9]*/"if-index": "rubout"/' $f + sed -i -e 's,"vrf": "[0-9]*","vrf": "rubout",' $f +done +""" # noqa: 501 +# should not differ +# diff result-lib.json result-lib-vrf-nokey.json +# diff result-lib-vrf-zebra.json result-lib-vrf-zebra-ribs.json diff --git a/tests/topotests/mgmt_oper/test_querying.py b/tests/topotests/mgmt_oper/test_querying.py new file mode 100644 index 000000000000..086a87b5e650 --- /dev/null +++ b/tests/topotests/mgmt_oper/test_querying.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis +# +# noqa: E501 +# +""" +Test various query types +""" +import json +import logging + +import pytest +from lib.common_config import step +from lib.topogen import Topogen +from oper import check_kernel_32 + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth1", "red") + router.load_frr_config("frr-simple.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_oper_simple(tgen): + """This test is useful for doing manual testing""" + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + query_results = [ + # Non-key specific query with function filtering selector + '/frr-interface:lib/interface[contains(name,"eth")]/vrf', + # Non-key specific query with child value filtering selector + '/frr-interface:lib/interface[vrf="red"]/vrf', + '/frr-interface:lib/interface[./vrf="red"]/vrf', + # Container query with function filtering selector + '/frr-interface:lib/interface[contains(name,"eth")]/state', + # Multi list elemenet with function filtering selector + '/frr-interface:lib/interface[contains(name,"eth")]', + # + # Specific list entry after non-specific lists + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route/route-entry[protocol="connected"]', + # crashes: All specific until the end, then walk + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route[prefix="1.1.1.0/24"]/route-entry[protocol="connected"]', + # Does nothing: Root level query + "//metric", + # specific leaf after non-specific lists + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + "route/route-entry/metric", + # All specific until the end generic. + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route[prefix="1.1.1.0/24"]/route-entry', + # All specific until the penultimate generic with a specific leaf child. + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route[prefix="1.1.1.0/24"]/route-entry/metric', + # All generic until the end (middle) specific with unspecified + # children below to walk. + '/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route[prefix="1.1.1.0/24"]', + # All generic until the end which is a specific leaf. + "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/metric", + ] + # query_results = [ + # '/frr-interface:lib/frr-interface:interface/frr-zebra:zebra/ip-addrs[frr-rt:address-family="frr-rt:ipv4"][prefix="1.1.1.1/24"]' + # ] + + r1 = tgen.gears["r1"].net + check_kernel_32(r1, "11.11.11.11", 1, "") + + step("Oper test start", reset=True) + + for qr in query_results: + step(f"Perform query '{qr}'") + try: + output = r1.cmd_nostatus(f"vtysh -c 'show mgmt get-data {qr}'") + except Exception as error: + logging.error("Error sending query: %s: %s", qr, error) + continue + + try: + ojson = json.loads(output) + logging.info("'%s': generates:\n%s", qr, ojson) + except json.decoder.JSONDecodeError as error: + logging.error("Error decoding json: %s\noutput:\n%s", error, output) diff --git a/tests/topotests/mgmt_oper/test_scale.py b/tests/topotests/mgmt_oper/test_scale.py new file mode 100644 index 000000000000..87794d7d6686 --- /dev/null +++ b/tests/topotests/mgmt_oper/test_scale.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis +# +# noqa: E501 +# +""" +Test static route functionality +""" +import re +import time + +import pytest +from lib.common_config import step +from lib.topogen import Topogen, TopoRouter +from oper import check_kernel_32 + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth1", "red") + router.load_frr_config("frr-scale.conf") + router.load_config(TopoRouter.RD_SHARP, "") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_oper_simple(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"].net + + count = 20 * 1000 + + vrf = None # "red" + check_kernel_32(r1, "11.11.11.11", 1, vrf) + + step("Found 11.11.11.11 in kernel adding sharpd routes") + r1.cmd_raises(f"vtysh -c 'sharp install routes 20.0.0.0 nexthop 1.1.1.2 {count}'") + check_kernel_32(r1, "20.0.0.0", count, vrf, 1000) + + step(f"All {count} routes installed in kernel, continuing") + # output = r1.cmd_raises("vtysh -c 'show mgmt get-data /frr-vrf:lib'") + # step(f"Got output: {output[0:1024]}") + + query = '/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route[contains(prefix,"20.0.0.12")]/prefix' + output = r1.cmd_raises(f"vtysh -c 'show mgmt get-data {query}'") + matches = re.findall(r'"prefix":', output) + # 20.0.0.12 + 20.0.0.12{0,1,2,3,4,5,6,7,8,9} + assert len(matches) == 11 diff --git a/tests/topotests/mgmt_oper/test_simple.py b/tests/topotests/mgmt_oper/test_simple.py new file mode 100644 index 000000000000..2b3d6ff6a52a --- /dev/null +++ b/tests/topotests/mgmt_oper/test_simple.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2021, LabN Consulting, L.L.C. +# Copyright (c) 2019-2020 by +# Donatas Abraitis +# +# noqa: E501 +# +""" +Test static route functionality +""" +import pytest +from lib.topogen import Topogen +from oper import check_kernel_32, do_oper_test + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.add_loop("lo-red") + router.net.attach_iface_to_l3vrf("lo-red", "red") + router.net.attach_iface_to_l3vrf(rname + "-eth1", "red") + router.load_frr_config("frr-simple.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_oper_simple(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + query_results = [ + ( + # Non-key query with key specific selection + '/frr-interface:lib/interface[name="r1-eth0"]/vrf', + "simple-results/result-intf-eth0-vrf.json", + ), + # Test machines will have different sets of interfaces so the test results will + # vary and need to be generated dynamically before this test is re-enabled + # ( + # # Key query on generic list + # "/frr-interface:lib/interface/name", + # "simple-results/result-intf-name.json", + # ), + ( + # Key query with key specific selection + '/frr-interface:lib/interface[name="r1-eth0"]/name', + "simple-results/result-intf-eth0-name.json", + ), + ("/frr-vrf:lib", "simple-results/result-lib.json"), + ("/frr-vrf:lib/vrf", "simple-results/result-lib-vrf-nokey.json"), + ( + '/frr-vrf:lib/vrf[name="default"]', + "simple-results/result-lib-vrf-default.json", + ), + ('/frr-vrf:lib/vrf[name="red"]', "simple-results/result-lib-vrf-red.json"), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra', + "simple-results/result-lib-vrf-zebra.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs', + "simple-results/result-lib-vrf-zebra-ribs.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib', + "simple-results/result-ribs-rib-nokeys.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]', + "simple-results/result-ribs-rib-ipv4-unicast.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/route', + "simple-results/result-ribs-rib-route-nokey.json", + ), + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route[prefix="1.1.1.0/24"]', + "simple-results/result-ribs-rib-route-prefix.json", + ), + # Missing entry + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route[prefix="1.1.0.0/24"]', + "simple-results/result-empty.json", + ), + # Leaf reference + ( + '/frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/' + 'rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/' + 'route[prefix="1.1.1.0/24"]/route-entry[protocol="connected"]/metric', + "simple-results/result-singleton-metric.json", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]', + "simple-results/result-intf-eth0-with-config.json", + "with-config", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]', + "simple-results/result-intf-eth0-only-config.json", + "only-config", + ), + ( + "/frr-interface:lib/interface/description", + "simple-results/result-intf-description.json", + "with-config", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]', + "simple-results/result-intf-eth0-exact.json", + "exact", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]/description', + "simple-results/result-intf-eth0-description-exact.json", + "with-config exact", + ), + # Interface state + ( + '/frr-interface:lib/interface[name="r1-eth0"]/state', + "simple-results/result-intf-state.json", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]/state/mtu', + "simple-results/result-intf-state-mtu.json", + ), + # with-defaults + ( + '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh', + "simple-results/result-intf-eth0-wd-explicit.json", + "with-config exact", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh', + "simple-results/result-intf-eth0-wd-trim.json", + "with-config exact with-defaults trim", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh', + "simple-results/result-intf-eth0-wd-all.json", + "with-config exact with-defaults all", + ), + ( + '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh', + "simple-results/result-intf-eth0-wd-all-tag.json", + "with-config exact with-defaults all-tag", + ), + ] + + r1 = tgen.gears["r1"].net + check_kernel_32(r1, "11.11.11.11", 1, "") + do_oper_test(tgen, query_results) + + +to_gen_new_results = """ +scriptdir=~chopps/w/frr/tests/topotests/mgmt_oper +resdir=${scriptdir}/simple-results +vtysh -c 'show mgmt get-data /frr-vrf:lib' > ${resdir}/result-lib.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf' > ${resdir}/result-lib-vrf-nokey.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]' > ${resdir}/result-lib-vrf-default.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="red"]' > ${resdir}/result-lib-vrf-red.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra' > ${resdir}/result-lib-vrf-ebra.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs' > ${resdir}/result-lib-vrf-zebra-ribs.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib' > ${resdir}/result-ribs-rib-nokeys.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]' > ${resdir}/result-ribs-rib-ipv4-unicast.json +vtysh -c 'show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/route' > ${resdir}/result-ribs-rib-route-nokey.json + +vtysh -c 'show mgmt get-data /frr-interface:lib/interface[name="r1-eth0"]/state' > ${resdir}/result-intf-state.json +vtysh -c 'show mgmt get-data /frr-interface:lib/interface[name="r1-eth0"]/state/mtu' > ${resdir}/result-intf-state-mtu.json + +for f in ${resdir}/result-*; do + sed -i -e 's/"uptime": ".*"/"uptime": "rubout"/;s/"id": [0-9][0-9]*/"id": "rubout"/' $f + sed -i -e 's/"phy-address": ".*"/"phy-address": "rubout"/' $f + sed -i -e 's/"if-index": [0-9][0-9]*/"if-index": "rubout"/' $f + sed -i -e 's,"vrf": "[0-9]*","vrf": "rubout",' $f +done +""" # noqa: 501 + +# Example commands: +# show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/route[prefix="1.1.0.0/24"] # noqa: E501 +# show mgmt get-data /frr-vrf:lib/vrf[name="default"]/frr-zebra:zebra/ribs/rib[afi-safi-name="frr-routing:ipv4-unicast"][table-id="254"]/route[prefix="1.1.1.0/24"] # noqa: E501 diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff b/tests/topotests/mgmt_rpc/r1/frr.conf similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff rename to tests/topotests/mgmt_rpc/r1/frr.conf diff --git a/tests/topotests/mgmt_rpc/test_rpc.py b/tests/topotests/mgmt_rpc/test_rpc.py new file mode 100644 index 000000000000..4d073fd0c9b3 --- /dev/null +++ b/tests/topotests/mgmt_rpc/test_rpc.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# March 21 2024, Igor Ryzhov +# +# Copyright (c) 2024, NFWare Inc. +# + +""" +Test YANG Notifications +""" +import json +import os +import threading + +import pytest +from lib.common_config import retry +from lib.topogen import Topogen +from lib.topotest import json_cmp + +pytestmark = [pytest.mark.ripd, pytest.mark.mgmtd] + +CWD = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for _, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +# Verify the backend test client has connected +@retry(retry_timeout=10) +def check_client_connect(r1): + out = r1.vtysh_cmd("show mgmt backend-adapter all") + assert "mgmtd-testc" in out + + +def test_backend_rpc(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + # Run the backend test client which registers to handle the `clear ip rip` command. + be_client_path = "/usr/lib/frr/mgmtd_testc" + rc, _, _ = r1.net.cmd_status(be_client_path + " --help") + + if rc: + pytest.skip("No mgmtd_testc") + + out = [] + + def run_testc(): + output = r1.net.cmd_raises( + be_client_path + " --timeout 10 --log file:mgmt_testc.log" + ) + out.append(json.loads(output)) + + t = threading.Thread(target=run_testc) + t.start() + + # We need to wait for mgmtd_testc to connect before issuing the command. + res = check_client_connect(r1) + assert res is None + + r1.vtysh_cmd("clear ip rip vrf testname") + + t.join() + + jsout = out[0] + + expected = {"frr-ripd:clear-rip-route": {"vrf": "testname"}} + result = json_cmp(jsout, expected) + assert result is None diff --git a/tests/topotests/mgmt_startup/test_bigconf.py b/tests/topotests/mgmt_startup/test_bigconf.py index 4f46c8fabdca..1c08fe6ca387 100644 --- a/tests/topotests/mgmt_startup/test_bigconf.py +++ b/tests/topotests/mgmt_startup/test_bigconf.py @@ -21,8 +21,7 @@ CWD = os.path.dirname(os.path.realpath(__file__)) -# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] track = Timeout(0) diff --git a/tests/topotests/mgmt_startup/test_cfgfile_var.py b/tests/topotests/mgmt_startup/test_cfgfile_var.py index 6a54f7191011..8203ae57ff99 100644 --- a/tests/topotests/mgmt_startup/test_cfgfile_var.py +++ b/tests/topotests/mgmt_startup/test_cfgfile_var.py @@ -31,8 +31,7 @@ from lib.topogen import Topogen, TopoRouter from util import check_kernel -# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] @pytest.fixture(scope="module") diff --git a/tests/topotests/mgmt_startup/test_late_bigconf.py b/tests/topotests/mgmt_startup/test_late_bigconf.py index 0b5bf38d1047..5bf345732bcd 100644 --- a/tests/topotests/mgmt_startup/test_late_bigconf.py +++ b/tests/topotests/mgmt_startup/test_late_bigconf.py @@ -22,8 +22,7 @@ CWD = os.path.dirname(os.path.realpath(__file__)) -# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] track = Timeout(0) ROUTE_COUNT = 2500 diff --git a/tests/topotests/mgmt_startup/test_late_uniconf.py b/tests/topotests/mgmt_startup/test_late_uniconf.py index d4e7e07ad633..380c2eb20b6f 100644 --- a/tests/topotests/mgmt_startup/test_late_uniconf.py +++ b/tests/topotests/mgmt_startup/test_late_uniconf.py @@ -14,8 +14,7 @@ from lib.topogen import Topogen from util import _test_staticd_late_start -# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] @pytest.fixture(scope="module") diff --git a/tests/topotests/mgmt_startup/test_latestart.py b/tests/topotests/mgmt_startup/test_latestart.py index 1c97b9dd0fca..c0c0121d0545 100644 --- a/tests/topotests/mgmt_startup/test_latestart.py +++ b/tests/topotests/mgmt_startup/test_latestart.py @@ -14,8 +14,7 @@ from lib.topogen import Topogen, TopoRouter from util import _test_staticd_late_start -# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] -pytestmark = [pytest.mark.staticd] +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] @pytest.fixture(scope="module") diff --git a/tests/topotests/mgmt_tests/test_yang_mgmt.py b/tests/topotests/mgmt_tests/test_yang_mgmt.py index 921b4e622cb8..52f6ba4db745 100644 --- a/tests/topotests/mgmt_tests/test_yang_mgmt.py +++ b/tests/topotests/mgmt_tests/test_yang_mgmt.py @@ -36,6 +36,7 @@ import os import pytest import platform +import json # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -45,7 +46,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp +from lib.topotest import version_cmp, router_json_cmp # Import topoJson from lib, to create topology and initial configuration from lib.common_config import ( @@ -65,10 +66,9 @@ start_router_daemons, ) from lib.topolog import logger -from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib from lib.topojson import build_config_from_json -pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd, pytest.mark.mgmtd] # Global variables ADDR_TYPES = check_address_types() @@ -401,6 +401,242 @@ def test_mgmt_delete_config(request): write_test_footer(tc_name) +def test_mgmt_edit_config(request): + """ + Verify mgmt edit config. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + r1 = tgen.gears["r1"] + + # check "create" operation + data = {"frr-interface:interface": [{"name": "eth0", "description": "eth0-desc"}]} + r1.vtysh_cmd( + f"conf\nmgmt edit create /frr-interface:lib lock commit {json.dumps(data, separators=(',', ':'))}" + ) + data_out = data + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-interface:lib/interface[name='eth0'] only-config exact", + data_out, + exact=True, + ) + == None + ) + + # check error on "create" for an existing object + data = {"frr-interface:interface": [{"name": "eth0", "description": "eth0-desc"}]} + ret = r1.vtysh_cmd( + f"conf\nmgmt edit create /frr-interface:lib lock commit {json.dumps(data, separators=(',', ':'))}" + ) + assert "Data already exists" in ret + + # check adding a leaf to an existing object using "merge" + data = { + "frr-interface:interface": [ + {"name": "eth0", "frr-zebra:zebra": {"bandwidth": 100}} + ] + } + r1.vtysh_cmd( + f"conf\nmgmt edit merge /frr-interface:lib/interface[name='eth0'] lock commit {json.dumps(data, separators=(',', ':'))}" + ) + data_out = { + "frr-interface:interface": [ + { + "name": "eth0", + "description": "eth0-desc", + "frr-zebra:zebra": {"bandwidth": 100}, + } + ] + } + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-interface:lib/interface[name='eth0'] only-config exact", + data_out, + exact=True, + ) + == None + ) + + # check replacing an existing object using "replace" + data = { + "frr-interface:interface": [{"name": "eth0", "description": "eth0-desc-new"}] + } + r1.vtysh_cmd( + f"conf\nmgmt edit replace /frr-interface:lib/interface[name='eth0'] lock commit {json.dumps(data, separators=(',', ':'))}" + ) + data_out = data + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-interface:lib/interface[name='eth0'] only-config exact", + data_out, + exact=True, + ) + == None + ) + + # check error on "replace" when keys in xpath and data are different + data = { + "frr-interface:interface": [{"name": "eth1", "description": "eth0-desc-new"}] + } + ret = r1.vtysh_cmd( + f"conf\nmgmt edit replace /frr-interface:lib/interface[name='eth0'] lock commit {json.dumps(data, separators=(',', ':'))}" + ) + assert "List keys in xpath and data tree are different" in ret + + # check deleting an existing object using "delete" + r1.vtysh_cmd( + f"conf\nmgmt edit delete /frr-interface:lib/interface[name='eth0'] lock commit" + ) + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-interface:lib/interface[name='eth0'] only-config exact", + {}, + exact=True, + ) + == None + ) + + # check error on "delete" for a non-existing object + ret = r1.vtysh_cmd( + f"conf\nmgmt edit delete /frr-interface:lib/interface[name='eth0'] lock commit" + ) + assert "Data missing" in ret + + # check no error on "remove" for a non-existing object + ret = r1.vtysh_cmd( + f"conf\nmgmt edit remove /frr-interface:lib/interface[name='eth0'] lock commit" + ) + assert "Data missing" not in ret + + # check "remove" for an existing object + data = {"frr-interface:interface": [{"name": "eth0", "description": "eth0-desc"}]} + r1.vtysh_cmd( + f"conf\nmgmt edit create /frr-interface:lib lock commit {json.dumps(data, separators=(',', ':'))}" + ) + r1.vtysh_cmd( + f"conf\nmgmt edit remove /frr-interface:lib/interface[name='eth0'] lock commit" + ) + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-interface:lib/interface[name='eth0'] only-config exact", + {}, + exact=True, + ) + == None + ) + + # check "create" of a top-level node + data = {"frr-vrf:lib": {"vrf": [{"name": "vrf1"}]}} + r1.vtysh_cmd( + f"conf\nmgmt edit create / lock commit {json.dumps(data, separators=(',', ':'))}" + ) + data_out = data + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-vrf:lib only-config exact", + data_out, + exact=True, + ) + == None + ) + + # check "replace" of a top-level node + data = {"frr-vrf:lib": {"vrf": [{"name": "vrf2"}]}} + r1.vtysh_cmd( + f"conf\nmgmt edit replace /frr-vrf:lib lock commit {json.dumps(data, separators=(',', ':'))}" + ) + data_out = data + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-vrf:lib only-config exact", + data_out, + exact=True, + ) + == None + ) + + # check "delete" of a top-level node + r1.vtysh_cmd(f"conf\nmgmt edit delete /frr-vrf:lib lock commit") + assert ( + router_json_cmp( + r1, "show mgmt get-data /frr-vrf:lib only-config exact", {}, exact=True + ) + == None + ) + + # check replace of the whole config + # this test won't work at the moment, because we don't allow to delete + # interfaces from the config if they are present in the system + # another problem is that we don't allow "/" as an xpath in get-data command + # therefore, commenting it out for now + # data = { + # "frr-interface:lib": { + # "interface": [{"name": "eth1", "description": "eth1-desc"}] + # }, + # "frr-vrf:lib": {"vrf": [{"name": "vrf3"}]}, + # } + # r1.vtysh_cmd( + # f"conf\nmgmt edit replace / lock commit {json.dumps(data, separators=(',', ':'))}" + # ) + # data_out = data + # assert ( + # router_json_cmp( + # r1, + # "show mgmt get-data / only-config exact", + # data_out, + # exact=True, + # ) + # == None + # ) + + # check "merge" of the whole config + data = { + "frr-interface:lib": { + "interface": [{"name": "eth2", "description": "eth2-desc"}] + }, + "frr-vrf:lib": {"vrf": [{"name": "vrf4"}]}, + } + r1.vtysh_cmd( + f"conf\nmgmt edit merge / lock commit {json.dumps(data, separators=(',', ':'))}" + ) + data_out = data + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-interface:lib only-config exact", + { + "frr-interface:lib": { + "interface": [{"name": "eth2", "description": "eth2-desc"}] + } + }, + ) + == None + ) + assert ( + router_json_cmp( + r1, + "show mgmt get-data /frr-vrf:lib only-config exact", + {"frr-vrf:lib": {"vrf": [{"name": "vrf4"}]}}, + ) + == None + ) + + def test_mgmt_chaos_stop_start_frr(request): """ Kill mgmtd - verify that watch frr restarts. diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf index 5bb268ebeff3..3c116a003bea 100644 --- a/tests/topotests/msdp_topo1/r1/pimd.conf +++ b/tests/topotests/msdp_topo1/r1/pimd.conf @@ -20,3 +20,7 @@ ip msdp peer 192.168.0.2 source 192.168.0.1 ip msdp peer 192.168.1.2 source 192.168.1.1 ip pim rp 10.254.254.1 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.2 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf index 733bd6f2f1a1..4ea2c8231438 100644 --- a/tests/topotests/msdp_topo1/r2/pimd.conf +++ b/tests/topotests/msdp_topo1/r2/pimd.conf @@ -16,3 +16,7 @@ ip msdp peer 192.168.0.1 source 192.168.0.2 ip msdp peer 192.168.2.2 source 192.168.2.1 ip pim rp 10.254.254.2 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.1 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf index 28085913fb9c..46de4fbe384a 100644 --- a/tests/topotests/msdp_topo1/r4/pimd.conf +++ b/tests/topotests/msdp_topo1/r4/pimd.conf @@ -20,3 +20,16 @@ ip msdp peer 192.168.2.1 source 192.168.2.2 ip msdp peer 192.168.3.1 source 192.168.3.2 ip pim rp 10.254.254.4 ip pim join-prune-interval 5 +! +access-list forbidden-multicast seq 5 deny 229.2.1.0 0.0.0.255 +access-list forbidden-multicast seq 1000 permit any +access-list local-only-multicast seq 5 deny 229.3.1.0 0.0.0.255 +access-list local-only-multicast seq 6 deny ip 192.168.4.100 0.0.0.0 229.10.1.0 0.0.0.255 +access-list local-only-multicast seq 1000 permit any +! +router pim + msdp peer 192.168.2.1 sa-filter forbidden-multicast in + msdp peer 192.168.2.1 sa-filter local-only-multicast out + msdp peer 192.168.3.1 sa-filter forbidden-multicast in + msdp peer 192.168.3.1 sa-filter local-only-multicast out +! diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 1af58b0a010f..ff80052d2665 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -66,7 +66,9 @@ def build_topo(tgen): # Create a host connected and direct at r4: tgen.add_host("h1", "192.168.4.100/24", "via 192.168.4.1") + tgen.add_host("h3", "192.168.4.120/24", "via 192.168.4.1") switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["h3"]) # Create a host connected and direct at r1: switch = tgen.add_switch("s6") @@ -82,7 +84,6 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): - daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) @@ -101,7 +102,7 @@ def setup_module(mod): app_helper.init(tgen) -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() app_helper.cleanup() @@ -359,7 +360,7 @@ def test_msdp(): "192.168.10.100": { "source": "192.168.10.100", "group": "229.1.2.3", - "rp": "192.168.1.1", + "rp": "10.254.254.1", "local": "no", "sptSetup": "no", } @@ -394,7 +395,7 @@ def test_msdp(): "192.168.10.100": { "source": "192.168.10.100", "group": "229.1.2.3", - "rp": "192.168.1.1", + "rp": "10.254.254.1", "local": "no", "sptSetup": "yes", } @@ -428,6 +429,87 @@ def test_msdp(): assert val is None, "multicast route convergence failure" +def test_msdp_sa_filter(): + "Start a number of multicast streams and check if filtering works" + + tgen = get_topogen() + + # Flow from r1 -> r4 + for multicast_address in ["229.2.1.1", "229.2.1.2", "229.2.2.1"]: + app_helper.run("h1", [multicast_address, "h1-eth0"]) + app_helper.run("h2", ["--send=0.7", multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 + for multicast_address in ["229.3.1.1", "229.3.1.2", "229.3.2.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 but with more sources + for multicast_address in ["229.10.1.1", "229.11.1.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + app_helper.run("h3", ["--send=0.7", multicast_address, "h3-eth0"]) + + # Test that we don't learn any filtered multicast streams. + r4_sa_expected = { + "229.2.1.1": None, + "229.2.1.2": None, + "229.2.2.1": { + "192.168.10.100": { + "local": "no", + "sptSetup": "yes", + } + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r4"], + "show ip msdp sa json", + r4_sa_expected, + ) + logger.info("Waiting for r4 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + # Test that we don't send any filtered multicast streams. + r1_sa_expected = { + "229.3.1.1": None, + "229.3.1.2": None, + "229.3.2.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + } + }, + "229.10.1.1": { + "192.168.4.100": None, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + "229.11.1.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + }, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + "show ip msdp sa json", + r1_sa_expected, + ) + logger.info("Waiting for r1 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/msdp_topo2/r1/bgpd.conf b/tests/topotests/msdp_topo2/r1/bgpd.conf new file mode 100644 index 000000000000..67f04d8eabf9 --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as 65002 + neighbor 192.168.3.3 remote-as 65003 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r1/pimd.conf b/tests/topotests/msdp_topo2/r1/pimd.conf new file mode 100644 index 000000000000..58a4c21e4030 --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.1 +! +interface r1-eth0 + ip pim +! +interface r1-eth1 + ip pim +! +interface r1-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.1.2 source 192.168.1.1 +ip msdp peer 192.168.3.3 source 192.168.3.1 +ip pim rp 10.254.254.1 diff --git a/tests/topotests/msdp_topo2/r1/zebra.conf b/tests/topotests/msdp_topo2/r1/zebra.conf new file mode 100644 index 000000000000..3219fad36da1 --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +interface r1-eth1 + ip address 192.168.3.1/24 +! +interface r1-eth2 + ip address 192.168.6.1/24 +! +interface lo + ip address 10.254.254.1/32 +! diff --git a/tests/topotests/msdp_topo2/r2/bgpd.conf b/tests/topotests/msdp_topo2/r2/bgpd.conf new file mode 100644 index 000000000000..b9f316898c7e --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as 65001 + neighbor 192.168.2.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r2/pimd.conf b/tests/topotests/msdp_topo2/r2/pimd.conf new file mode 100644 index 000000000000..66e630264c1b --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.2 +! +interface r2-eth0 + ip pim +! +interface r2-eth1 + ip pim +! +ip msdp peer 192.168.1.1 source 192.168.1.2 +ip msdp peer 192.168.2.5 source 192.168.2.2 +ip pim rp 10.254.254.2 diff --git a/tests/topotests/msdp_topo2/r2/zebra.conf b/tests/topotests/msdp_topo2/r2/zebra.conf new file mode 100644 index 000000000000..740b51a4f074 --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.2/24 +! +interface lo + ip address 10.254.254.2/32 +! diff --git a/tests/topotests/msdp_topo2/r3/bgpd.conf b/tests/topotests/msdp_topo2/r3/bgpd.conf new file mode 100644 index 000000000000..ecd25b050e19 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.3.1 remote-as 65001 + neighbor 192.168.4.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r3/pimd.conf b/tests/topotests/msdp_topo2/r3/pimd.conf new file mode 100644 index 000000000000..e8e53268e381 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.3 +! +interface r3-eth0 + ip pim +! +interface r3-eth1 + ip pim +! +ip msdp peer 192.168.3.1 source 192.168.3.3 +ip msdp peer 192.168.4.4 source 192.168.4.3 +ip pim rp 10.254.254.3 diff --git a/tests/topotests/msdp_topo2/r3/zebra.conf b/tests/topotests/msdp_topo2/r3/zebra.conf new file mode 100644 index 000000000000..d1be65f636a9 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r3-eth0 + ip address 192.168.3.3/24 +! +interface r3-eth1 + ip address 192.168.4.3/24 +! +interface lo + ip address 10.254.254.3/32 +! diff --git a/tests/topotests/msdp_topo2/r4/bgpd.conf b/tests/topotests/msdp_topo2/r4/bgpd.conf new file mode 100644 index 000000000000..430517bc2b07 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65004 + no bgp ebgp-requires-policy + neighbor 192.168.4.3 remote-as 65003 + neighbor 192.168.5.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r4/pimd.conf b/tests/topotests/msdp_topo2/r4/pimd.conf new file mode 100644 index 000000000000..32e3c613fa04 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.4 +! +interface r4-eth0 + ip pim +! +interface r4-eth1 + ip pim +! +ip msdp peer 192.168.4.3 source 192.168.4.4 +ip msdp peer 192.168.5.5 source 192.168.5.4 +ip pim rp 10.254.254.4 diff --git a/tests/topotests/msdp_topo2/r4/zebra.conf b/tests/topotests/msdp_topo2/r4/zebra.conf new file mode 100644 index 000000000000..045d2e8070a3 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r4-eth0 + ip address 192.168.4.4/24 +! +interface r4-eth1 + ip address 192.168.5.4/24 +! +interface lo + ip address 10.254.254.4/32 +! diff --git a/tests/topotests/msdp_topo2/r5/bgpd.conf b/tests/topotests/msdp_topo2/r5/bgpd.conf new file mode 100644 index 000000000000..053dd3d3efc1 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65005 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as 65002 + neighbor 192.168.5.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r5/pimd.conf b/tests/topotests/msdp_topo2/r5/pimd.conf new file mode 100644 index 000000000000..e6cdd14c8212 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.5 +! +interface r5-eth0 + ip pim +! +interface r5-eth1 + ip pim +! +interface r5-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.2.2 source 192.168.2.5 +ip msdp peer 192.168.5.4 source 192.168.5.5 +ip pim rp 10.254.254.5 diff --git a/tests/topotests/msdp_topo2/r5/zebra.conf b/tests/topotests/msdp_topo2/r5/zebra.conf new file mode 100644 index 000000000000..195e0035100a --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r5-eth0 + ip address 192.168.2.5/24 +! +interface r5-eth1 + ip address 192.168.5.5/24 +! +interface r5-eth2 + ip address 192.168.7.5/24 +! +interface lo + ip address 10.254.254.5/32 +! diff --git a/tests/topotests/msdp_topo2/test_msdp_topo2.py b/tests/topotests/msdp_topo2/test_msdp_topo2.py new file mode 100755 index 000000000000..def5368f4172 --- /dev/null +++ b/tests/topotests/msdp_topo2/test_msdp_topo2.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_msdp_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2024 by +# Adriano Marto Reis +# + +""" +test_msdp_topo2.py: Test the FRR PIM MSDP peer. + + ────────────────────► + shortest path + ┌──┐ + ┌───────┤r2├───────┐ +sender │ s1 └──┘ s2 │ receiver + ┌──┐ ┌─┴┐ ┌─┴┐ ┌──┐ + │h1├────┤r1│ │r5├────┤h2│ + └──┘ s6 └─┬┘ └─┬┘ s7 └──┘ + │ ┌──┐ ┌──┐ │ + └───┤r3├────┤r4├───┘ + s3 └──┘ s4 └──┘ s5 +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from lib.pim import McastTesterHelper + +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] + +app_helper = McastTesterHelper() + +MCAST_ADDR = "229.1.2.3" + +def build_topo(tgen): + "Build function" + + for routern in range(1, 6): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s6") + tgen.add_host("h1", "192.168.6.100/24", "via 192.168.6.1") + switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s7") + tgen.add_host("h2", "192.168.7.100/24", "via 192.168.7.5") + switch.add_link(tgen.gears["h2"]) + switch.add_link(tgen.gears["r5"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + daemon_file = "{}/{}/bgpd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BGP, daemon_file) + + daemon_file = "{}/{}/pimd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_PIM, daemon_file) + + tgen.start_router() + + app_helper.init(tgen) + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + app_helper.cleanup() + tgen.stop_topology() + + +def test_bgp_convergence(): + """ + Wait for BGP protocol convergence + All the loopback addresses (10.254.254.x) must be reachable from all + routers. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + routes = { + "r1": "10.254.254.1/32", + "r2": "10.254.254.2/32", + "r3": "10.254.254.3/32", + "r4": "10.254.254.4/32", + "r5": "10.254.254.5/32", + } + + for router1 in routes.keys(): + for router2, route in routes.items(): + if router1 != router2: + logger.info("waiting route {} in {}".format(route, router1)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router1], + "show ip route json", + {route: [{"protocol": "bgp"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router1) + assert result is None, assertmsg + + +def test_msdp_peers(): + """ + Waits for the MSPD peer connections to be established. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + expected_msdp_peers = { + "r1": { + "192.168.1.2": { + "peer": "192.168.1.2", + "local": "192.168.1.1", + "state": "established", + }, + "192.168.3.3": { + "peer": "192.168.3.3", + "local": "192.168.3.1", + "state": "established", + }, + }, + "r2": { + "192.168.1.1": { + "peer": "192.168.1.1", + "local": "192.168.1.2", + "state": "established", + }, + "192.168.2.5": { + "peer": "192.168.2.5", + "local": "192.168.2.2", + "state": "established", + }, + }, + "r3": { + "192.168.3.1": { + "peer": "192.168.3.1", + "local": "192.168.3.3", + "state": "established", + }, + "192.168.4.4": { + "peer": "192.168.4.4", + "local": "192.168.4.3", + "state": "established", + }, + }, + "r4": { + "192.168.4.3": { + "peer": "192.168.4.3", + "local": "192.168.4.4", + "state": "established", + }, + "192.168.5.5": { + "peer": "192.168.5.5", + "local": "192.168.5.4", + "state": "established", + }, + }, + "r5": { + "192.168.2.2": { + "peer": "192.168.2.2", + "local": "192.168.2.5", + "state": "established", + }, + "192.168.5.4": { + "peer": "192.168.5.4", + "local": "192.168.5.5", + "state": "established", + }, + }, + } + + for router, peers in expected_msdp_peers.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp peer json", + peers, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_msdp_sa(): + """ + Waits for the MSDP SA to be propagated. + The MSDP SA must be present on all routers. The MSDP SA must indicate + the original RP. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_sa_r1 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "-", + "local": "yes", + } + } + } + + expected_sa_r2_r3_r4_r5 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "10.254.254.1", + "local": "no", + } + } + } + + expected_sa = { + "r1": expected_sa_r1, + "r2": expected_sa_r2_r3_r4_r5, + "r3": expected_sa_r2_r3_r4_r5, + "r4": expected_sa_r2_r3_r4_r5, + "r5": expected_sa_r2_r3_r4_r5, + } + + for router, sa in expected_sa.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp sa json", + sa, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_mroute(): + """ + Wait for the multicast routes. + The multicast routes must connect the shortest path between h1 and h2: + h1 ─► r1 ─► r2 ─► r5 ─► h2 + + The routers r3 and r4 must have no multicast routes, as they are not + included in the shortest path between h1 and h2. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_mroutes = { + "r1": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r1-eth2", + "oil": { + "r1-eth0": {"source": "192.168.6.100", "group": MCAST_ADDR}, + "r1-eth1": None, + }, + }, + }, + }, + "r2": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r2-eth0", + "oil": { + "r2-eth1": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + "r3": { + }, + "r4": { + }, + "r5": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r5-eth0", + "oil": { + "r5-eth1": None, + "r5-eth2": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + } + + for router, mroute in expected_mroutes.items(): + logger.info("Waiting for {} mroute data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip mroute json", + mroute, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "mroute convergence failure" + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py index 7eb583803715..b8eb67a32eca 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py @@ -221,7 +221,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py index 8b174bf9b833..bab7fddf9e73 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py @@ -175,7 +175,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py index 9ee411206d07..1775c9baeda5 100644 --- a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py @@ -202,7 +202,6 @@ def teardown_module(): def clear_bsrp_data(tgen, topo): - """ clear bsm databas after test" Parameters @@ -218,7 +217,6 @@ def clear_bsrp_data(tgen, topo): """ for dut in tgen.routers(): - rnode = tgen.routers()[dut] logger.info("[DUT: %s]: clear_bsrp_data") diff --git a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py index 302a77858504..e4df5089099f 100644 --- a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py +++ b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py @@ -182,7 +182,6 @@ def teardown_module(): def clear_bsrp_data(tgen, topo): - """ clear bsm databas after test" Parameters @@ -198,7 +197,6 @@ def clear_bsrp_data(tgen, topo): """ for dut in tgen.routers(): - rnode = tgen.routers()[dut] logger.info("[DUT: %s]: clear_bsrp_data") diff --git a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py index 00d38fe647dc..5aa2ea65f7b5 100755 --- a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py +++ b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py @@ -20,10 +20,7 @@ import os import sys -import json import time -import datetime -from time import sleep import pytest # Save the Current Working Directory to find configuration files. @@ -43,14 +40,9 @@ write_test_footer, step, reset_config_on_routers, - shutdown_bringup_interface, apply_raw_config, add_interfaces_to_vlan, - kill_router_daemons, - start_router_daemons, - create_static_routes, check_router_status, - topo_daemons, required_linux_kernel_version, ) from lib.pim import ( @@ -59,9 +51,6 @@ verify_mroutes, clear_mroute, clear_pim_interface_traffic, - verify_pim_config, - verify_upstream_iif, - verify_multicast_traffic, verify_multicast_flag_state, verify_igmp_groups, McastTesterHelper, diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py index 1de6eac8975d..eefa96a38962 100755 --- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py @@ -42,7 +42,7 @@ from time import sleep import pytest -pytestmark = pytest.mark.pimd +pytestmark = [pytest.mark.pimd] # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -64,7 +64,6 @@ reset_config_on_routers, shutdown_bringup_interface, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -83,8 +82,6 @@ from lib.topojson import build_config_from_json -pytestmark = [pytest.mark.pimd] - TOPOLOGY = """ @@ -216,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py index 17f52cb86050..0af2efcc7e36 100755 --- a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py +++ b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py @@ -37,7 +37,7 @@ import time import pytest -pytestmark = pytest.mark.pimd +pytestmark = [pytest.mark.pimd] # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -62,7 +62,6 @@ start_router_daemons, stop_router, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -81,8 +80,6 @@ from lib.topojson import build_config_from_json -pytestmark = [pytest.mark.pimd] - TOPOLOGY = """ @@ -213,7 +210,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py index 2c1241c0ccc9..9488ae02bf27 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -45,7 +45,7 @@ import json import functools -pytestmark = pytest.mark.pimd +pytestmark = [pytest.mark.pimd] # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -57,7 +57,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( start_topology, write_test_header, @@ -68,7 +68,6 @@ apply_raw_config, check_router_status, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -91,7 +90,6 @@ from lib.topojson import build_config_from_json CWD = os.path.dirname(os.path.realpath(__file__)) -pytestmark = pytest.mark.pimd TOPOLOGY = """ @@ -265,11 +263,14 @@ def verify_state_incremented(state_before, state_after): for intf, v2 in v1.items(): for state, value in v2.items(): if value >= state_after[ttype][intf][state]: - errormsg = "[DUT: %s]: state %s value has not incremented, Initial value: %s, Current value: %s [FAILED!!]" % ( - intf, - state, - value, - state_after[ttype][intf][state], + errormsg = ( + "[DUT: %s]: state %s value has not incremented, Initial value: %s, Current value: %s [FAILED!!]" + % ( + intf, + state, + value, + state_after[ttype][intf][state], + ) ) return errormsg @@ -328,7 +329,6 @@ def find_tos_in_tcpdump(tgen, router, message, cap_file): filepath = os.path.join(tgen.logdir, router, cap_file) with open(filepath) as f: - if len(re.findall(message, f.read())) < 1: errormsg = "[DUT: %s]: Verify Message: %s in tcpdump" " [FAILED!!]" % ( router, @@ -353,7 +353,7 @@ def verify_pim_stats_increament(stats_before, stats_after): """ for router, stats_data in stats_before.items(): - for stats, value in stats_data.items(): + for stats, _ in stats_data.items(): if stats_before[router][stats] >= stats_after[router][stats]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py index 825281afbb01..11f3cc4254aa 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py @@ -55,7 +55,6 @@ apply_raw_config, create_static_routes, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -191,7 +190,7 @@ def reset_stats(stats): """ for router, state_data in stats.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): stats[router][state] = 0 logger.info( "[DUT: %s]: stats %s value has reset" " reset, Current value: %s", @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py index c492d95d40af..38b9b2ecb13a 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py @@ -87,7 +87,6 @@ import os import sys import time -from time import sleep import datetime import pytest @@ -112,10 +111,7 @@ reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, create_static_routes, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -128,10 +124,7 @@ verify_pim_rp_info, verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py index 690c92f58087..6f078a68d8d2 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py @@ -112,9 +112,6 @@ reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, - create_static_routes, ) from lib.pim import ( create_pim_config, @@ -123,9 +120,7 @@ verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, clear_igmp_interfaces, clear_pim_interfaces, diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py index 8aa2e4efa1eb..48c0a78f9805 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py @@ -123,14 +123,9 @@ verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py index 5728a4d08eee..bbd5501dbb64 100644 --- a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py +++ b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py @@ -25,7 +25,6 @@ import os import sys -import json import time import pytest @@ -356,7 +355,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" @@ -1682,7 +1681,7 @@ def test_mroutes_updated_correctly_after_source_interface_shut_noshut_p1(request step("Shut and No shut source interface multiple time") - for i in range(0, 2): + for _ in range(0, 2): step("Shut and no shut the source interface from DUT") intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_i2, False) diff --git a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py index 1fb81c0d7091..893b80083ea7 100644 --- a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py +++ b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py @@ -213,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json b/tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json new file mode 100644 index 000000000000..dc9e1ac49b57 --- /dev/null +++ b/tests/topotests/multicast_pim_uplink_topo4/multicast_pim_uplink_topo4.json @@ -0,0 +1,295 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24, "link_local": "disable"}, + "lo_prefix": {"ipv4": "1.0.", "v4mask": 32}, + "routers": { + "r1": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "r2-link1": {"ipv4": "auto", "pim": "enable"}, + "r2-link2": {"ipv4": "auto", "pim": "enable"}, + "r2-link3": {"ipv4": "auto", "pim": "enable"}, + "r2-link4": {"ipv4": "auto", "pim": "enable"}, + "r3-link1": {"ipv4": "auto", "pim": "enable"}, + "r3-link2": {"ipv4": "auto", "pim": "enable"}, + "r3-link3": {"ipv4": "auto", "pim": "enable"}, + "r3-link4": {"ipv4": "auto", "pim": "enable"}, + "r4": {"ipv4": "auto", "pim": "enable"}, + "r5": {"ipv4": "auto", "pim": "enable"}, + "i1": {"ipv4": "auto", "pim": "enable"}, + "i2": {"ipv4": "auto", "pim": "enable"}, + "i9": {"ipv4": "auto", "pim": "enable"} + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {}, + "r1-link2": {}, + "r1-link3": {}, + "r1-link4": {} + } + }, + "r3": { + "dest_link": { + "r1-link1": {}, + "r1-link2": {}, + "r1-link3": {}, + "r1-link4": {} + } + }, + "r4": { + "dest_link": { + "r1": {} + } + }, + "r5": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "r1-link1": {"ipv4": "auto", "pim": "enable"}, + "r1-link2": {"ipv4": "auto", "pim": "enable"}, + "r1-link3": {"ipv4": "auto", "pim": "enable"}, + "r1-link4": {"ipv4": "auto", "pim": "enable"}, + "r4-link1": {"ipv4": "auto", "pim": "enable"}, + "r4-link2": {"ipv4": "auto", "pim": "enable"}, + "r4-link3": {"ipv4": "auto", "pim": "enable"}, + "r4-link4": {"ipv4": "auto", "pim": "enable"}, + "i3": {"ipv4": "auto", "pim": "enable"}, + "i4": {"ipv4": "auto", "pim": "enable"} + }, + "bgp": { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {}, + "r2-link2": {}, + "r2-link3": {}, + "r2-link4": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {}, + "r2-link2": {}, + "r2-link3": {}, + "r2-link4": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "r1-link1": {"ipv4": "auto", "pim": "enable"}, + "r1-link2": {"ipv4": "auto", "pim": "enable"}, + "r1-link3": {"ipv4": "auto", "pim": "enable"}, + "r1-link4": {"ipv4": "auto", "pim": "enable"}, + "r4-link1": {"ipv4": "auto", "pim": "enable"}, + "r4-link2": {"ipv4": "auto", "pim": "enable"}, + "r4-link3": {"ipv4": "auto", "pim": "enable"}, + "r4-link4": {"ipv4": "auto", "pim": "enable"}, + "i5": {"ipv4": "auto", "pim": "enable"} + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {} + } + }, + "r4": { + "dest_link": { + "r3-link1": {}, + "r3-link2": {}, + "r3-link3": {}, + "r3-link4": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "r2-link1": {"ipv4": "auto", "pim": "enable"}, + "r2-link2": {"ipv4": "auto", "pim": "enable"}, + "r2-link3": {"ipv4": "auto", "pim": "enable"}, + "r2-link4": {"ipv4": "auto", "pim": "enable"}, + "r3-link1": {"ipv4": "auto", "pim": "enable"}, + "r3-link2": {"ipv4": "auto", "pim": "enable"}, + "r3-link3": {"ipv4": "auto", "pim": "enable"}, + "r3-link4": {"ipv4": "auto", "pim": "enable"}, + "r1": {"ipv4": "auto", "pim": "enable"}, + "r5": {"ipv4": "auto", "pim": "enable"}, + "i6": {"ipv4": "auto", "pim": "enable"}, + "i7": {"ipv4": "auto", "pim": "enable"} + }, + "bgp": { + "local_as": "400", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {}, + "r4-link2": {}, + "r4-link3": {}, + "r4-link4": {} + } + }, + "r3": { + "dest_link": { + "r4-link1": {}, + "r4-link2": {}, + "r4-link3": {}, + "r4-link4": {} + } + }, + "r1": { + "dest_link": { + "r4": {} + } + }, + "r5": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": {"ipv4": "auto", "type": "loopback", "pim": "enable"}, + "r1": {"ipv4": "auto", "pim": "enable"}, + "r4": {"ipv4": "auto", "pim": "enable"}, + "i8": {"ipv4": "auto", "pim": "enable"} + }, + "bgp": { + "local_as": "500", + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ], + "neighbor": { + "r1": { + "dest_link": { + "r5": {} + } + }, + "r4": { + "dest_link": { + "r5": {} + } + } + } + } + } + } + } + }, + "i1": { + "links": { + "r1": {"ipv4": "auto"} + } + }, + "i2": { + "links": { + "r1": {"ipv4": "auto"} + } + }, + "i3": { + "links": { + "r2": {"ipv4": "auto"} + } + }, + "i4": { + "links": { + "r2": {"ipv4": "auto"} + } + }, + "i5": { + "links": { + "r3": {"ipv4": "auto"} + } + }, + "i6": { + "links": { + "r4": {"ipv4": "auto"} + } + }, + "i7": { + "links": { + "r4": {"ipv4": "auto"} + } + }, + "i8": { + "links": { + "r5": {"ipv4": "auto"} + } + }, + "i9": { + "links": { + "r1": {"ipv4": "auto"} + } + } + + } +} diff --git a/tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py b/tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py new file mode 100644 index 000000000000..d384baa45254 --- /dev/null +++ b/tests/topotests/multicast_pim_uplink_topo4/test_multicast_pim_uplink_topo4.py @@ -0,0 +1,893 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2024 by Architecture Technology Corp. (ATCorp) +# + +""" +Following tests are covered to test multicast pim sm: + +1. TC:1 Verify static group populated when static "ip igmp static-group " in configured +2. TC:2 Verify mroute and upstream populated with correct OIL/IIF with static group +3. TC:3 Verify static group not allowed for "224.0.0.0/24" and non multicast group +4. TC:4 Verify static group removed from DUT while removing "ip igmp static-group" CLI +5. TC:5 Verify static groups after removing and adding static-group config +""" + +import os +import sys +import time +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + step, + addKernelRoute, + reset_config_on_routers, + shutdown_bringup_interface, + required_linux_kernel_version, +) +from lib.pim import ( + create_pim_config, + create_igmp_config, + verify_mroutes, + clear_pim_interface_traffic, + verify_upstream_iif, + clear_mroute, + verify_pim_rp_info, + verify_static_groups, + McastTesterHelper, +) +from lib.bgp import ( + verify_bgp_convergence, +) +from lib.topolog import logger +from lib.topojson import build_config_from_json + +# Global variables +TOPOLOGY = """ + + i9 i3-+-i4 i6-+-i7 + | | | + i1--- R1-------R2----------R4------R5---i8 + | | | + i2 R3-------------------+ + + + | + i5 + + Description: + i1, i2, i3. i4, i5, i6, i7, i8 - FRR running iperf to send IGMP + join and traffic + R1 - DUT (LHR/FHR) + R2 - RP + R3 - Transit + R4 - (LHR/FHR) + R5 - Transit +""" +# Global variables +RP_RANGE1 = "226.0.0.1/32" +RP_RANGE2 = "226.0.0.2/32" +RP_RANGE3 = "226.0.0.3/32" +RP_RANGE4 = "226.0.0.4/32" +RP_RANGE5 = "226.0.0.5/32" +RP_RANGE6 = "232.0.0.1/32" +RP_RANGE7 = "232.0.0.2/32" +RP_RANGE8 = "232.0.0.3/32" +RP_RANGE9 = "232.0.0.4/32" +RP_RANGE10 = "232.0.0.5/32" + +GROUP_RANGE = "224.0.0.0/4" +IGMP_GROUP = "225.1.1.1/32" +IGMP_JOIN = "225.1.1.1" +GROUP_RANGE_1 = [ + "225.1.1.1/32", + "225.1.1.2/32", + "225.1.1.3/32", + "225.1.1.4/32", + "225.1.1.5/32", +] +IGMP_JOIN_RANGE_1 = ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"] +IGMP_JOIN_RANGE_2 = ["224.0.0.1", "224.0.0.2", "224.0.0.3", "192.0.0.4", "192.0.0.5"] +IGMP_JOIN_RANGE_3 = [ + "226.0.0.1", + "226.0.0.2", + "226.0.0.3", + "226.0.0.4", + "226.0.0.5", + "232.0.0.1", + "232.0.0.2", + "232.0.0.3", + "232.0.0.4", + "232.0.0.5", +] +GROUP_RANGE_3 = [ + "226.0.0.1/32", + "226.0.0.2/32", + "226.0.0.3/32", + "226.0.0.4/32", + "226.0.0.5/32", + "232.0.0.1/32", + "232.0.0.2/32", + "232.0.0.3/32", + "232.0.0.4/32", + "232.0.0.5/32", +] + +r1_r2_links = [] +r1_r3_links = [] +r2_r1_links = [] +r2_r4_links = [] +r3_r1_links = [] +r3_r4_links = [] +r4_r2_links = [] +r4_r3_links = [] + +pytestmark = [pytest.mark.pimd] + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.19") + if result is not True: + pytest.skip("Kernel requirements are not met") + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + testdir = os.path.dirname(os.path.realpath(__file__)) + json_file = "{}/multicast_pim_uplink_topo4.json".format(testdir) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + build_config_from_json(tgen, tgen.json_topo) + + # Pre-requisite data + get_interfaces_names(topo) + + # XXX Replace this using "with McastTesterHelper()... " in each test if possible. + global app_helper + app_helper = McastTesterHelper(tgen) + + # Verify BGP convergence + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + app_helper.cleanup() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Local APIs +# +##################################################### + + +def get_interfaces_names(topo): + """ + API to fetch interfaces names and create list, which further would be used + for verification + + Parameters + ---------- + * `topo` : inout JSON data + """ + + for link in range(1, 5): + intf = topo["routers"]["r1"]["links"]["r2-link{}".format(link)]["interface"] + r1_r2_links.append(intf) + + intf = topo["routers"]["r1"]["links"]["r3-link{}".format(link)]["interface"] + r1_r3_links.append(intf) + + intf = topo["routers"]["r2"]["links"]["r1-link{}".format(link)]["interface"] + r2_r1_links.append(intf) + + intf = topo["routers"]["r3"]["links"]["r1-link{}".format(link)]["interface"] + r3_r1_links.append(intf) + + intf = topo["routers"]["r2"]["links"]["r4-link{}".format(link)]["interface"] + r2_r4_links.append(intf) + + intf = topo["routers"]["r4"]["links"]["r2-link{}".format(link)]["interface"] + r4_r2_links.append(intf) + + intf = topo["routers"]["r4"]["links"]["r3-link{}".format(link)]["interface"] + r4_r3_links.append(intf) + + +def shutdown_interfaces(tgen): + """ + API to Shut down interfaces which is not + used in all the testcases as part of this TDS + + Parameters + ---------- + * `tgen`: topogen object + + """ + logger.info("shutting down extra interfaces") + intf_r1_r4 = topo["routers"]["r1"]["links"]["r4"]["interface"] + intf_r1_r5 = topo["routers"]["r1"]["links"]["r5"]["interface"] + intf_r4_r1 = topo["routers"]["r4"]["links"]["r1"]["interface"] + intf_r5_r1 = topo["routers"]["r5"]["links"]["r1"]["interface"] + intf_r4_r5 = topo["routers"]["r4"]["links"]["r5"]["interface"] + intf_r5_r4 = topo["routers"]["r5"]["links"]["r4"]["interface"] + shutdown_bringup_interface(tgen, "r1", intf_r1_r4, False) + shutdown_bringup_interface(tgen, "r1", intf_r1_r5, False) + shutdown_bringup_interface(tgen, "r4", intf_r4_r1, False) + shutdown_bringup_interface(tgen, "r5", intf_r5_r1, False) + shutdown_bringup_interface(tgen, "r4", intf_r4_r5, False) + shutdown_bringup_interface(tgen, "r5", intf_r5_r4, False) + + +def config_to_send_igmp_join_and_traffic( + tgen, topo, tc_name, iperf, iperf_intf, GROUP_RANGE, join=False, traffic=False +): + """ + API to do pre-configuration to send IGMP join and multicast + traffic + + parameters: + ----------- + * `tgen`: topogen object + * `topo`: input json data + * `tc_name`: caller test case name + * `iperf`: router running iperf + * `iperf_intf`: interface name router running iperf + * `GROUP_RANGE`: group range + * `join`: IGMP join, default False + * `traffic`: multicast traffic, default False + """ + + if join: + # Add route to kernal + result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + if traffic: + # Add route to kernal + result = addKernelRoute(tgen, iperf, iperf_intf, GROUP_RANGE) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + router_list = tgen.routers() + for router in router_list.keys(): + if router == iperf: + continue + + rnode = router_list[router] + rnode.run("echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter") + + return True + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_ip_igmp_static_groups_p0(request): + """ + TC_1 Verify static group populated when static + "ip igmp static-group " in configured + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("shut down not required interfaces") + shutdown_interfaces(tgen) + + step("Enable the PIM on all the interfaces of R1, R2, R3, R4") + step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected") + step("Enable the IGMP on R11 interfac of R1 and configure static groups") + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict = { + "r1": { + "igmp": { + "interfaces": { + intf_r1_i1: {"igmp": {"static-group": IGMP_JOIN_RANGE_1}}, + intf_r1_i2: {"igmp": {"static-group": IGMP_JOIN_RANGE_1}}, + } + } + } + } + + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure static RP for (225.1.1.1-5) as R2") + + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE, + } + ] + } + } + } + result = create_pim_config(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify static group using show ip igmp static-group") + dut = "r1" + interfaces = [intf_r1_i1, intf_r1_i2] + for interface in interfaces: + result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_mroute_with_igmp_static_groups_p0(request): + """ + TC_2 Verify mroute and upstream populated with correct OIL/IIF with + static groups + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("shut down not required interfaces") + shutdown_interfaces(tgen) + + step("Enable the PIM on all the interfaces of R1, R2, R3, R4") + step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected") + step("Enable the IGMP on R11 interfac of R1 and configure static groups") + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict = { + "r1": { + "igmp": { + "interfaces": { + intf_r1_i1: {"igmp": {"version": "2", "static-group": IGMP_JOIN_RANGE_1}}, + intf_r1_i2: {"igmp": {"version": "2", "static-group": IGMP_JOIN_RANGE_1}}, + } + } + } + } + + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure static RP for (225.1.1.1-5) as R2") + + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE, + } + ] + } + } + } + result = create_pim_config(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify static group using show ip igmp static-group") + dut = "r1" + interfaces = [intf_r1_i1, intf_r1_i2] + for interface in interfaces: + result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + step("verify RP-info populated in DUT") + dut = "r1" + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + SOURCE = "Static" + oif = r1_r2_links + result = verify_pim_rp_info(tgen, topo, dut, GROUP_RANGE_1, oif, rp_address, SOURCE) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Send traffic from R4 to all the groups ( 225.1.1.1 to 225.1.1.5)") + + result = app_helper.run_traffic("i6", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + source_i6 = topo["routers"]["i6"]["links"]["r4"]["ipv4"].split("/")[0] + + r1_r2_r3 = r1_r2_links + r1_r3_links + input_dict_starg = [ + { + "dut": "r1", + "src_address": "*", + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r1", + "src_address": "*", + "iif": r1_r2_links, + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + ] + + input_dict_sg = [ + { + "dut": "r1", + "src_address": source_i6, + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r1", + "src_address": source_i6, + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + ] + + step("Verify mroutes and iff upstream for static groups") + for input_dict in [input_dict_starg, input_dict_sg]: + for data in input_dict: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("Verify mroutes not created with local interface ip ") + + input_dict_local_sg = [ + { + "dut": "r1", + "src_address": intf_r1_i1, + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + }, + { + "dut": "r1", + "src_address": intf_r1_i2, + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i2"]["interface"], + }, + ] + + for data in input_dict_local_sg: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed Error: {}" + "sg created with local interface ip".format(tc_name, result) + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert result is not True, ( + "Testcase {} : Failed Error: {}" + "upstream created with local interface ip".format(tc_name, result) + ) + + write_test_footer(tc_name) + + +def test_igmp_static_group_with_reserved_address_p0(request): + """ + TC_3 Verify static group not allowed for "224.0.0.0/24" + and non multicast group + """ + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("shut down not required interfaces") + shutdown_interfaces(tgen) + + step("Enable the PIM on all the interfaces of R1, R2, R3, R4") + step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected") + step("Enable the IGMP on R11 interface of R1 and configure static groups") + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + input_dict = { + "r1": { + "igmp": { + "interfaces": { + intf_r1_i1: {"igmp": {"version": "2", "statig-group": IGMP_JOIN_RANGE_2}} + } + } + } + } + + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("verify static group using show ip igmp static-group") + dut = "r1" + interface = intf_r1_i1 + result = verify_static_groups( + tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False + ) + assert ( + result is not True + ), "Testcase {} :Failed \n Error: {}" "static group still present".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_remove_add_igmp_static_groups_p1(request): + """ + TC_4 Verify static group removed from DUT while + removing "ip igmp static-group" CLI + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Creating configuration from JSON + app_helper.stop_all_hosts() + clear_mroute(tgen) + reset_config_on_routers(tgen) + clear_pim_interface_traffic(tgen, topo) + + # Verify BGP convergence + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("shut down not required interfaces") + shutdown_interfaces(tgen) + + step("Enable the PIM on all the interfaces of R1, R2, R3, R4") + step("configure BGP on R1, R2, R3, R4 and enable redistribute static/connected") + step("Enable the IGMP on R11 interfac of R1 and configure static groups") + + intf_r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"] + intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] + input_dict = { + "r1": { + "igmp": { + "interfaces": { + intf_r1_i1: {"igmp": {"version": "2", "static-group": IGMP_JOIN_RANGE_1}} + } + } + } + } + + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("Configure static RP for (225.1.1.1-5) as R2") + + input_dict = { + "r2": { + "pim": { + "rp": [ + { + "rp_addr": topo["routers"]["r2"]["links"]["lo"]["ipv4"].split( + "/" + )[0], + "group_addr_range": GROUP_RANGE, + } + ] + } + } + } + result = create_pim_config(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("verify static group using show ip igmp static-group") + dut = "r1" + interface = intf_r1_i1 + result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("verify RP-info populated in DUT") + dut = "r1" + rp_address = topo["routers"]["r2"]["links"]["lo"]["ipv4"].split("/")[0] + SOURCE = "Static" + oif = r1_r2_links + result = verify_pim_rp_info(tgen, topo, dut, GROUP_RANGE_1, oif, rp_address, SOURCE) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Send traffic from R4 to all the groups ( 225.1.1.1 to 225.1.1.5)") + + result = app_helper.run_traffic("i6", IGMP_JOIN_RANGE_1, "r4") + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + source_i6 = topo["routers"]["i6"]["links"]["r4"]["ipv4"].split("/")[0] + + logger.info("waiting 30 sec for SPT switchover") + + r1_r2_r3 = r1_r2_links + r1_r3_links + input_dict_starg = [ + { + "dut": "r1", + "src_address": "*", + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + } + ] + + input_dict_sg = [ + { + "dut": "r1", + "src_address": source_i6, + "iif": r1_r2_r3, + "oil": topo["routers"]["r1"]["links"]["i1"]["interface"], + } + ] + + step("Verify mroutes and iff upstream for static groups") + for input_dict in [input_dict_starg, input_dict_sg]: + for data in input_dict: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + step("Remove static group from DUT") + input_dict = { + "r1": { + "igmp": { + "interfaces": { + intf_r1_i1: { + "igmp": { + "static-group": IGMP_JOIN_RANGE_1, + "delete_attr": True, + } + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("verify static group removed using show ip igmp static-group") + dut = "r1" + interface = intf_r1_i1 + result = verify_static_groups( + tgen, dut, interface, IGMP_JOIN_RANGE_1, expected=False + ) + assert ( + result is not True + ), "Testcase {} :Failed \n Error: {}" "static group still present".format( + tc_name, result + ) + + step("Verify mroutes and iff upstream for static groups") + for input_dict in [input_dict_starg, input_dict_sg]: + for data in input_dict: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed Error: {}" "mroutes still present".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, + data["dut"], + data["iif"], + data["src_address"], + IGMP_JOIN_RANGE_1, + expected=False, + ) + assert ( + result is not True + ), "Testcase {} : Failed Error: {}" "mroutes still present".format( + tc_name, result + ) + + step("Add static group on DUT again") + input_dict = { + "r1": { + "igmp": { + "interfaces": { + intf_r1_i1: { + "igmp": { + "static-group": IGMP_JOIN_RANGE_1, + } + } + } + } + } + } + result = create_igmp_config(tgen, topo, input_dict) + assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result) + + step("verify static group using show ip igmp static-group") + dut = "r1" + interface = intf_r1_i1 + result = verify_static_groups(tgen, dut, interface, IGMP_JOIN_RANGE_1) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify mroutes and iff upstream for static groups") + for input_dict in [input_dict_starg, input_dict_sg]: + for data in input_dict: + result = verify_mroutes( + tgen, + data["dut"], + data["src_address"], + IGMP_JOIN_RANGE_1, + data["iif"], + data["oil"], + ) + assert result is True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + result = verify_upstream_iif( + tgen, data["dut"], data["iif"], data["src_address"], IGMP_JOIN_RANGE_1 + ) + assert result is True, "Testcase {} : Failed Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/munet/__main__.py b/tests/topotests/munet/__main__.py index 4419ab94a284..145eb265ab77 100644 --- a/tests/topotests/munet/__main__.py +++ b/tests/topotests/munet/__main__.py @@ -16,8 +16,10 @@ from . import cli from . import parser +from .args import add_launch_args from .base import get_event_loop from .cleanup import cleanup_previous +from .cleanup import is_running_in_rundir from .compat import PytestConfig @@ -106,66 +108,43 @@ def main(*args): cap.add_argument( "--project-root", help="directory to stop searching for kinds config at" ) + rap = ap.add_argument_group(title="Runtime", description="runtime related options") + add_launch_args(rap.add_argument) + + # Move to munet.args? rap.add_argument( "-C", "--cleanup", action="store_true", help="Remove the entire rundir (not just node subdirs) prior to running.", ) - rap.add_argument( - "--gdb", metavar="NODE-LIST", help="comma-sep list of hosts to run gdb on" - ) - rap.add_argument( - "--gdb-breakpoints", - metavar="BREAKPOINT-LIST", - help="comma-sep list of breakpoints to set", - ) - rap.add_argument( - "--host", - action="store_true", - help="no isolation for top namespace, bridges exposed to default namespace", - ) - rap.add_argument( - "--pcap", - metavar="TARGET-LIST", - help="comma-sep list of capture targets (NETWORK or NODE:IFNAME)", - ) - rap.add_argument( - "--shell", metavar="NODE-LIST", help="comma-sep list of nodes to open shells on" - ) - rap.add_argument( - "--stderr", - metavar="NODE-LIST", - help="comma-sep list of nodes to open windows viewing stderr", - ) - rap.add_argument( - "--stdout", - metavar="NODE-LIST", - help="comma-sep list of nodes to open windows viewing stdout", - ) + # Move to munet.args? rap.add_argument( "--topology-only", action="store_true", help="Do not run any node commands", ) - rap.add_argument("--unshare-inline", action="store_true", help=argparse.SUPPRESS) rap.add_argument( "--validate-only", action="store_true", help="Validate the config against the schema definition", ) + rap.add_argument("--unshare-inline", action="store_true", help=argparse.SUPPRESS) + rap.add_argument("-v", "--verbose", action="store_true", help="be verbose") rap.add_argument( "-V", "--version", action="store_true", help="print the verison number and exit" ) + eap = ap.add_argument_group(title="Uncommon", description="uncommonly used options") eap.add_argument("--log-config", help="logging config file (yaml, toml, json, ...)") eap.add_argument( - "--no-kill", + "--kill", action="store_true", - help="Do not kill previous running processes", + help="Kill previous running processes using same rundir and exit", ) + eap.add_argument("--no-kill", action="store_true", help=argparse.SUPPRESS) eap.add_argument( "--no-cli", action="store_true", help="Do not run the interactive CLI" ) @@ -180,8 +159,18 @@ def main(*args): sys.exit(0) rundir = args.rundir if args.rundir else "/tmp/munet" + rundir = os.path.abspath(rundir) args.rundir = rundir + if args.kill: + logging.info("Killing any previous run using rundir: {rundir}") + cleanup_previous(args.rundir) + elif is_running_in_rundir(args.rundir): + logging.fatal( + "Munet processes using rundir: %s, use `--kill` to cleanup first", rundir + ) + return 1 + if args.cleanup: if os.path.exists(rundir): if not os.path.exists(f"{rundir}/config.json"): @@ -194,6 +183,9 @@ def main(*args): else: subprocess.run(["/usr/bin/rm", "-rf", rundir], check=True) + if args.kill: + return 0 + subprocess.run(f"mkdir -p {rundir} && chmod 755 {rundir}", check=True, shell=True) os.environ["MUNET_RUNDIR"] = rundir @@ -208,9 +200,6 @@ def main(*args): logger.critical("No nodes defined in config file") return 1 - if not args.no_kill: - cleanup_previous() - loop = None status = 4 try: diff --git a/tests/topotests/munet/args.py b/tests/topotests/munet/args.py new file mode 100644 index 000000000000..49ad891cefc6 --- /dev/null +++ b/tests/topotests/munet/args.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# +# April 14 2024, Christian Hopps +# +# Copyright (c) 2024, LabN Consulting, L.L.C. +# +"""Common CLI execute argument.""" + + +def add_launch_args(add_func): + + add_func("--gdb", metavar="NODE-LIST", help="comma-sep list of hosts to run gdb on") + add_func( + "--gdb-breakpoints", + metavar="BREAKPOINT-LIST", + help="comma-sep list of breakpoints to set", + ) + add_func( + "--gdb-use-emacs", + action="store_true", + help="Use emacsclient to run gdb instead of a shell", + ) + + add_func( + "--host", + action="store_true", + help="no isolation for top namespace, bridges exposed to default namespace", + ) + add_func( + "--pcap", + metavar="TARGET-LIST", + help="comma-sep list of capture targets (NETWORK or NODE:IFNAME) or 'all'", + ) + add_func( + "--shell", metavar="NODE-LIST", help="comma-sep list of nodes to open shells on" + ) + add_func( + "--stderr", + metavar="NODE-LIST", + help="comma-sep list of nodes to open windows viewing stderr", + ) + add_func( + "--stdout", + metavar="NODE-LIST", + help="comma-sep list of nodes to open windows viewing stdout", + ) + + +def add_testing_args(add_func): + add_func( + "--cli-on-error", + action="store_true", + help="CLI on test failure", + ) + + add_func( + "--coverage", + action="store_true", + help="Enable coverage gathering if supported", + ) + + add_func( + "--cov-build-dir", + help="Specify the build dir for locating coverage data files", + ) + + add_launch_args(add_func) + + add_func( + "--pause", + action="store_true", + help="Pause after each test", + ) + add_func( + "--pause-at-end", + action="store_true", + help="Pause before taking munet down", + ) + add_func( + "--pause-on-error", + action="store_true", + help="Pause after (disables default when --shell or -vtysh given)", + ) + add_func( + "--no-pause-on-error", + dest="pause_on_error", + action="store_false", + help="Do not pause after (disables default when --shell or -vtysh given)", + ) diff --git a/tests/topotests/munet/base.py b/tests/topotests/munet/base.py index 06ca4deae2ad..e77eb15dc844 100644 --- a/tests/topotests/munet/base.py +++ b/tests/topotests/munet/base.py @@ -276,6 +276,9 @@ def get_event_loop(): """ policy = asyncio.get_event_loop_policy() loop = policy.get_event_loop() + if not hasattr(os, "pidfd_open"): + return loop + owatcher = policy.get_child_watcher() logging.debug( "event_loop_fixture: global policy %s, current loop %s, current watcher %s", @@ -466,6 +469,8 @@ def _get_sub_args(self, cmd_list, defaults, use_pty=False, ns_only=False, **kwar env = {**(kwargs["env"] if "env" in kwargs else os.environ)} if "MUNET_NODENAME" not in env: env["MUNET_NODENAME"] = self.name + if "MUNET_PID" not in env and "MUNET_PID" in os.environ: + env["MUNET_PID"] = os.environ["MUNET_PID"] kwargs["env"] = env defaults.update(kwargs) @@ -513,9 +518,8 @@ def _common_prologue(self, async_exec, method, cmd, skip_pre_cmd=False, **kwargs self.logger.debug('%s("%s") [no precmd]', method, shlex.join(cmd_list)) else: self.logger.debug( - '%s: %s %s("%s", pre_cmd: "%s" use_pty: %s kwargs: %.120s)', + '%s: %s("%s", pre_cmd: "%s" use_pty: %s kwargs: %.120s)', self, - "XXX" if method == "_spawn" else "", method, cmd_list, pre_cmd_list if not skip_pre_cmd else "", @@ -566,7 +570,7 @@ def _fdspawn(self, fo, **kwargs): def _spawn(self, cmd, skip_pre_cmd=False, use_pty=False, echo=False, **kwargs): logging.debug( - '%s: XXX _spawn: cmd "%s" skip_pre_cmd %s use_pty %s echo %s kwargs %s', + '%s: _spawn: cmd "%s" skip_pre_cmd %s use_pty %s echo %s kwargs %s', self, cmd, skip_pre_cmd, @@ -579,7 +583,7 @@ def _spawn(self, cmd, skip_pre_cmd=False, use_pty=False, echo=False, **kwargs): ) self.logger.debug( - '%s: XXX %s("%s", use_pty %s echo %s defaults: %s)', + '%s: %s("%s", use_pty %s echo %s defaults: %s)', self, "PopenSpawn" if not use_pty else "pexpect.spawn", actual_cmd, @@ -778,8 +782,14 @@ async def shell_spawn( ps1 = re.escape(ps1) ps2 = re.escape(ps2) - - extra = "PAGER=cat; export PAGER; TERM=dumb; unset HISTFILE; set +o emacs +o vi" + extra = [ + "TERM=dumb", + "set +o emacs", + "set +o vi", + "unset HISTFILE", + "PAGER=cat", + "export PAGER", + ] pchg = "PS1='{0}' PS2='{1}' PROMPT_COMMAND=''\n".format(ps1p, ps2p) p.send(pchg) return ShellWrapper(p, ps1, ps2, extra_init_cmd=extra, will_echo=will_echo) @@ -865,14 +875,18 @@ async def async_cleanup_proc(self, p, pid=None): else: o, e = await p.communicate() self.logger.debug( - "%s: cmd_p already exited status: %s", self, proc_error(p, o, e) + "%s: [cleanup_proc] proc already exited status: %s", + self, + proc_error(p, o, e), ) return None if pid is None: pid = p.pid - self.logger.debug("%s: terminate process: %s (pid %s)", self, proc_str(p), pid) + self.logger.debug( + "%s: [cleanup_proc] terminate process: %s (pid %s)", self, proc_str(p), pid + ) try: # This will SIGHUP and wait a while then SIGKILL and return immediately await self.cleanup_pid(p.pid, pid) @@ -885,14 +899,19 @@ async def async_cleanup_proc(self, p, pid=None): else: o, e = await asyncio.wait_for(p.communicate(), timeout=wait_secs) self.logger.debug( - "%s: cmd_p exited after kill, status: %s", self, proc_error(p, o, e) + "%s: [cleanup_proc] exited after kill, status: %s", + self, + proc_error(p, o, e), ) except (asyncio.TimeoutError, subprocess.TimeoutExpired): - self.logger.warning("%s: SIGKILL timeout", self) + self.logger.warning("%s: [cleanup_proc] SIGKILL timeout", self) return p except Exception as error: self.logger.warning( - "%s: kill unexpected exception: %s", self, error, exc_info=True + "%s: [cleanup_proc] kill unexpected exception: %s", + self, + error, + exc_info=True, ) return p return None @@ -923,15 +942,25 @@ def _cmd_status_finish(self, p, c, ac, o, e, raises, warn): def _cmd_status(self, cmds, raises=False, warn=True, stdin=None, **kwargs): """Execute a command.""" + timeout = None + if "timeout" in kwargs: + timeout = kwargs["timeout"] + del kwargs["timeout"] + pinput, stdin = Commander._cmd_status_input(stdin) p, actual_cmd = self._popen("cmd_status", cmds, stdin=stdin, **kwargs) - o, e = p.communicate(pinput) + o, e = p.communicate(pinput, timeout=timeout) return self._cmd_status_finish(p, cmds, actual_cmd, o, e, raises, warn) async def _async_cmd_status( self, cmds, raises=False, warn=True, stdin=None, text=None, **kwargs ): """Execute a command.""" + timeout = None + if "timeout" in kwargs: + timeout = kwargs["timeout"] + del kwargs["timeout"] + pinput, stdin = Commander._cmd_status_input(stdin) p, actual_cmd = await self._async_popen( "async_cmd_status", cmds, stdin=stdin, **kwargs @@ -944,7 +973,12 @@ async def _async_cmd_status( if encoding is not None and isinstance(pinput, str): pinput = pinput.encode(encoding) - o, e = await p.communicate(pinput) + try: + o, e = await asyncio.wait_for(p.communicate(), timeout=timeout) + except (TimeoutError, asyncio.TimeoutError) as error: + raise subprocess.TimeoutExpired( + cmd=actual_cmd, timeout=timeout, output=None, stderr=None + ) from error if encoding is not None: o = o.decode(encoding) if o is not None else o e = e.decode(encoding) if e is not None else e @@ -1206,10 +1240,16 @@ def run_in_window( # XXX need to test ssh in Xterm sudo_path = get_exec_path_host(["sudo"]) # This first test case seems same as last but using list instead of string? - if self.is_vm and self.use_ssh: # pylint: disable=E1101 + if self.is_vm and self.use_ssh and not ns_only: # pylint: disable=E1101 if isinstance(cmd, str): cmd = shlex.split(cmd) - cmd = ["/usr/bin/env", f"MUNET_NODENAME={self.name}"] + cmd + cmd = [ + "/usr/bin/env", + f"MUNET_NODENAME={self.name}", + ] + if "MUNET_PID" in os.environ: + cmd.append(f"MUNET_PID={os.environ.get('MUNET_PID')}") + cmd += cmd # get the ssh cmd cmd = self._get_pre_cmd(False, True, ns_only=ns_only) + [shlex.join(cmd)] @@ -1226,8 +1266,16 @@ def run_in_window( else: # This is the command to execute to be inside the namespace. # We are getting into trouble with quoting. - # Why aren't we passing in MUNET_RUNDIR? - cmd = f"/usr/bin/env MUNET_NODENAME={self.name} {cmd}" + envvars = f"MUNET_NODENAME={self.name} NODENAME={self.name}" + if hasattr(self, "rundir"): + envvars += f" RUNDIR={self.rundir}" + if "MUNET_PID" in os.environ: + envvars += f" MUNET_PID={os.environ.get('MUNET_PID')}" + if hasattr(self.unet, "config_dirname") and self.unet.config_dirname: + envvars += f" CONFIGDIR={self.unet.config_dirname}" + elif "CONFIGDIR" in os.environ: + envvars += f" CONFIGDIR={os.environ['CONFIGDIR']}" + cmd = f"/usr/bin/env {envvars} {cmd}" # We need sudo b/c we are executing as the user inside the window system. sudo_path = get_exec_path_host(["sudo"]) nscmd = ( @@ -1332,6 +1380,14 @@ def run_in_window( # Re-adjust the layout if "TMUX" in os.environ: + cmd = [ + get_exec_path_host("tmux"), + "select-layout", + "-t", + pane_info if not tmux_target else tmux_target, + "even-horizontal", + ] + commander.cmd_status(cmd) cmd = [ get_exec_path_host("tmux"), "select-layout", @@ -1915,18 +1971,19 @@ def __init__( assert unet is None self.uflags = uflags # - # Open file descriptors for current namespaces for later resotration. + # Open file descriptors for current namespaces for later restoration. # try: + # pidfd_open is actually present in 5.4, is this 5.8 check for another + # aspect of what the pidfd_open code is relying on, something in the + # namespace code? If not we can simply check for os.pidfd_open() being + # present as our compat module linux.py runtime patches it in if + # supported by the kernel. kversion = [int(x) for x in platform.release().split("-")[0].split(".")] kvok = kversion[0] > 5 or (kversion[0] == 5 and kversion[1] >= 8) except ValueError: kvok = False - if ( - not kvok - or sys.version_info[0] < 3 - or (sys.version_info[0] == 3 and sys.version_info[1] < 9) - ): + if not kvok: # get list of namespace file descriptors before we unshare self.p_ns_fds = [] self.p_ns_fnames = [] @@ -2005,8 +2062,10 @@ def __init__( stdout=stdout, stderr=stderr, text=True, - start_new_session=not unet, shell=False, + # start_new_session=not unet + # preexec_fn=os.setsid if not unet else None, + preexec_fn=os.setsid, ) # The pid number returned is in the global pid namespace. For unshare_inline @@ -2345,14 +2404,14 @@ async def _async_delete(self): and self.pid != our_pid ): self.logger.debug( - "cleanup pid on separate pid %s from proc pid %s", + "cleanup separate pid %s from namespace proc pid %s", self.pid, self.p.pid if self.p else None, ) await self.cleanup_pid(self.pid) if self.p is not None: - self.logger.debug("cleanup proc pid %s", self.p.pid) + self.logger.debug("cleanup namespace proc pid %s", self.p.pid) await self.async_cleanup_proc(self.p) # return to the previous namespace, need to do this in case anothe munet @@ -2492,7 +2551,7 @@ def __init__(self, name=None, mtu=None, unet=None, **kwargs): self.logger.debug("Bridge: Creating") - assert len(self.name) <= 16 # Make sure fits in IFNAMSIZE + # assert len(self.name) <= 16 # Make sure fits in IFNAMSIZE self.cmd_raises(f"ip link delete {name} || true") self.cmd_raises(f"ip link add {name} type bridge") if self.mtu: @@ -2616,10 +2675,6 @@ def __init__( self.cfgopt = munet_config.ConfigOptionsProxy(pytestconfig) - super().__init__( - name, mount=True, net=isolated, uts=isolated, pid=pid, unet=None, **kwargs - ) - # This allows us to cleanup any leftover running munet's if "MUNET_PID" in os.environ: if os.environ["MUNET_PID"] != str(our_pid): @@ -2630,6 +2685,10 @@ def __init__( ) os.environ["MUNET_PID"] = str(our_pid) + super().__init__( + name, mount=True, net=isolated, uts=isolated, pid=pid, unet=None, **kwargs + ) + # this is for testing purposes do not use if not BaseMunet.g_unet: BaseMunet.g_unet = self @@ -2737,7 +2796,7 @@ def add_link(self, node1, node2, if1, if2, mtu=None, **intf_constraints): self.logger.error('"%s" len %s > 16', nsif1, len(nsif1)) elif len(nsif2) > 16: self.logger.error('"%s" len %s > 16', nsif2, len(nsif2)) - assert len(nsif1) <= 16 and len(nsif2) <= 16 # Make sure fits in IFNAMSIZE + assert len(nsif1) < 16 and len(nsif2) < 16 # Make sure fits in IFNAMSIZE self.logger.debug("%s: Creating veth pair for link %s", self, lname) @@ -2937,7 +2996,7 @@ def __init__( ) logging.debug( - 'ShellWraper: XXX prompt "%s" will_echo %s child.echo %s', + 'ShellWraper: prompt "%s" will_echo %s child.echo %s', prompt, will_echo, spawn.echo, @@ -2965,8 +3024,11 @@ def __init__( self._expectf = self.child.expect if extra_init_cmd: - self.expect_prompt() - self.child.sendline(extra_init_cmd) + if isinstance(extra_init_cmd, str): + extra_init_cmd = [extra_init_cmd] + for ecmd in extra_init_cmd: + self.expect_prompt() + self.child.sendline(ecmd) self.expect_prompt() def expect_prompt(self, timeout=-1): diff --git a/tests/topotests/munet/cleanup.py b/tests/topotests/munet/cleanup.py index c641cda68596..12ea6e2840e6 100644 --- a/tests/topotests/munet/cleanup.py +++ b/tests/topotests/munet/cleanup.py @@ -59,25 +59,33 @@ def _get_our_pids(): return {} -def _get_other_pids(): - piddict = get_pids_with_env("MUNET_PID") - unet_pids = {d["MUNET_PID"] for d in piddict.values()} +def _get_other_pids(rundir): + if rundir: + # get only munet pids using the given rundir + piddict = get_pids_with_env("MUNET_RUNDIR", str(rundir)) + else: + # Get all munet pids + piddict = get_pids_with_env("MUNET_PID") + unet_pids = {d["MUNET_PID"] for d in piddict.values() if "MUNET_PID" in d} pids_by_upid = {p: set() for p in unet_pids} for pid, envdict in piddict.items(): + if "MUNET_PID" not in envdict: + continue unet_pid = envdict["MUNET_PID"] pids_by_upid[unet_pid].add(pid) # Filter out any child pid sets whos munet pid is still running return {x: y for x, y in pids_by_upid.items() if x not in y} -def _get_pids_by_upid(ours): +def _get_pids_by_upid(ours, rundir): if ours: + assert rundir is None return _get_our_pids() - return _get_other_pids() + return _get_other_pids(rundir) -def _cleanup_pids(ours): - pids_by_upid = _get_pids_by_upid(ours).items() +def _cleanup_pids(ours, rundir): + pids_by_upid = _get_pids_by_upid(ours, rundir).items() if not pids_by_upid: return @@ -94,7 +102,7 @@ def _cleanup_pids(ours): # return # time.sleep(1) - pids_by_upid = _get_pids_by_upid(ours).items() + pids_by_upid = _get_pids_by_upid(ours, rundir).items() _kill_piddict(pids_by_upid, signal.SIGKILL) @@ -103,12 +111,16 @@ def cleanup_current(): Currently this only scans for old processes. """ - _cleanup_pids(True) + _cleanup_pids(True, None) -def cleanup_previous(): +def cleanup_previous(rundir=None): """Attempt to cleanup preview runs. Currently this only scans for old processes. """ - _cleanup_pids(False) + _cleanup_pids(False, rundir) + + +def is_running_in_rundir(rundir): + return bool(get_pids_with_env("MUNET_RUNDIR", str(rundir))) diff --git a/tests/topotests/munet/cli.py b/tests/topotests/munet/cli.py index f631073bb18a..01a7091512c7 100644 --- a/tests/topotests/munet/cli.py +++ b/tests/topotests/munet/cli.py @@ -106,9 +106,13 @@ def is_host_regex(restr): def get_host_regex(restr): - if len(restr) < 3 or restr[0] != "/" or restr[-1] != "/": + try: + if len(restr) < 3 or restr[0] != "/" or restr[-1] != "/": + return None + return re.compile(restr[1:-1]) + except re.error: + logging.error("Invalid regex") return None - return re.compile(restr[1:-1]) def host_in(restr, names): @@ -126,8 +130,8 @@ def expand_host(restr, names): hosts = [] regexp = get_host_regex(restr) if not regexp: - assert restr in names - hosts.append(restr) + if restr in names: + hosts.append(restr) else: for name in names: if regexp.fullmatch(name): @@ -325,13 +329,14 @@ def get_shcmd(unet, host, kinds, execfmt, ucmd): if not execfmt: return "" - # Do substitutions for {} in string + # Do substitutions for {} and {N} in string numfmt = len(re.findall(r"{\d*}", execfmt)) if numfmt > 1: ucmd = execfmt.format(*shlex.split(ucmd)) elif numfmt: ucmd = execfmt.format(ucmd) - elif len(re.findall(r"{[a-zA-Z_][0-9a-zA-Z_\.]*}", execfmt)): + # look for any pair of {}s but do not count escaped {{ or }} + elif len(re.findall(r"{[^}]+}", execfmt.replace("{{", "").replace("}}", ""))): if execfmt.endswith('"'): fstring = "f'''" + execfmt + "'''" else: diff --git a/tests/topotests/munet/linux.py b/tests/topotests/munet/linux.py index 417f74566acd..519c55f84d82 100644 --- a/tests/topotests/munet/linux.py +++ b/tests/topotests/munet/linux.py @@ -132,8 +132,17 @@ def pidfd_open(pid, flags=0): return fd +# Runtime patch if kernel supports the call. if not hasattr(os, "pidfd_open"): - os.pidfd_open = pidfd_open + try: + import platform + + kversion = [int(x) for x in platform.release().split("-")[0].split(".")] + kvok = kversion[0] > 5 or (kversion[0] == 5 and kversion[1] >= 4) + except ValueError: + kvok = False + if kvok: + os.pidfd_open = pidfd_open def setns(fd, nstype): # noqa: D402 diff --git a/tests/topotests/munet/logconf-mutest.yaml b/tests/topotests/munet/logconf-mutest.yaml index b450fb938227..c0b636cd6176 100644 --- a/tests/topotests/munet/logconf-mutest.yaml +++ b/tests/topotests/munet/logconf-mutest.yaml @@ -1,5 +1,8 @@ version: 1 formatters: + result_color: + class: munet.mulog.ResultColorFormatter + format: '%(levelname)5s: %(message)s' brief: format: '%(levelname)5s: %(message)s' operfmt: @@ -22,7 +25,7 @@ handlers: info_console: level: INFO class: logging.StreamHandler - formatter: brief + formatter: result_color stream: ext://sys.stderr oper_console: level: DEBUG diff --git a/tests/topotests/munet/mucmd.py b/tests/topotests/munet/mucmd.py index 5518c6dcfee9..cd356f38ad20 100644 --- a/tests/topotests/munet/mucmd.py +++ b/tests/topotests/munet/mucmd.py @@ -9,7 +9,6 @@ import argparse import json import os -import subprocess import sys from pathlib import Path @@ -90,19 +89,14 @@ def main(*args): ecmd = "/usr/bin/nsenter" eargs = [ecmd] - output = subprocess.check_output(["/usr/bin/nsenter", "--help"], encoding="utf-8") - if " -a," in output: - eargs.append("-a") - else: - # -U doesn't work - for flag in ["-u", "-i", "-m", "-n", "-C", "-T"]: - if f" {flag}," in output: - eargs.append(flag) + #start mucmd same way base process is started + eargs.append(f"--mount=/proc/{pid}/ns/mnt") + eargs.append(f"--net=/proc/{pid}/ns/net") eargs.append(f"--pid=/proc/{pid}/ns/pid_for_children") + eargs.append(f"--uts=/proc/{pid}/ns/uts") eargs.append(f"--wd={rundir}") - eargs.extend(["-t", pid]) eargs += args.shellcmd - # print("Using ", eargs) + #print("Using ", eargs) return os.execvpe(ecmd, eargs, {**env, **envcfg}) diff --git a/tests/topotests/munet/mulog.py b/tests/topotests/munet/mulog.py index f840eae2d800..968acd9d19e6 100644 --- a/tests/topotests/munet/mulog.py +++ b/tests/topotests/munet/mulog.py @@ -12,6 +12,9 @@ from pathlib import Path +do_color = True + + class MultiFileHandler(logging.FileHandler): """A logging handler that logs to new files based on the logger name. @@ -118,5 +121,28 @@ def __init__(self, fmt=None, datefmt=None, style="%", **kwargs): super().__init__(fmt, datefmt, style, **kwargs) def format(self, record): + if not do_color: + return super().format(record) formatter = self.formatters.get(record.levelno) return formatter.format(record) + + +class ResultColorFormatter(logging.Formatter): + """A formatter that colorizes PASS/FAIL strings based on level.""" + + green = "\x1b[32m" + red = "\x1b[31m" + reset = "\x1b[0m" + + def format(self, record): + s = super().format(record) + if not do_color: + return s + idx = s.find("FAIL") + if idx >= 0 and record.levelno > logging.INFO: + s = s[:idx] + self.red + "FAIL" + self.reset + s[idx + 4 :] + elif record.levelno == logging.INFO: + idx = s.find("PASS") + if idx >= 0: + s = s[:idx] + self.green + "PASS" + self.reset + s[idx + 4 :] + return s diff --git a/tests/topotests/munet/munet-schema.json b/tests/topotests/munet/munet-schema.json index a1dcd878dd56..6ebc368dcb21 100644 --- a/tests/topotests/munet/munet-schema.json +++ b/tests/topotests/munet/munet-schema.json @@ -93,12 +93,24 @@ "image": { "type": "string" }, + "hostnet": { + "type": "boolean" + }, "server": { "type": "string" }, "server-port": { "type": "number" }, + "ssh-identity-file": { + "type": "string" + }, + "ssh-user": { + "type": "string" + }, + "ssh-password": { + "type": "string" + }, "qemu": { "type": "object", "properties": { @@ -108,6 +120,15 @@ "disk": { "type": "string" }, + "disk-driver": { + "type": "string" + }, + "disk-template": { + "type": "string" + }, + "initial-cmd": { + "type": "string" + }, "kerenel": { "type": "string" }, @@ -141,6 +162,9 @@ "password": { "type": "string" }, + "initial-password": { + "type": "string" + }, "expects": { "type": "array", "items": { @@ -362,6 +386,9 @@ }, "ipv6": { "type": "string" + }, + "external": { + "type": "boolean" } } } @@ -401,12 +428,24 @@ "image": { "type": "string" }, + "hostnet": { + "type": "boolean" + }, "server": { "type": "string" }, "server-port": { "type": "number" }, + "ssh-identity-file": { + "type": "string" + }, + "ssh-user": { + "type": "string" + }, + "ssh-password": { + "type": "string" + }, "qemu": { "type": "object", "properties": { @@ -416,6 +455,15 @@ "disk": { "type": "string" }, + "disk-driver": { + "type": "string" + }, + "disk-template": { + "type": "string" + }, + "initial-cmd": { + "type": "string" + }, "kerenel": { "type": "string" }, @@ -449,6 +497,9 @@ "password": { "type": "string" }, + "initial-password": { + "type": "string" + }, "expects": { "type": "array", "items": { diff --git a/tests/topotests/munet/mutest/__main__.py b/tests/topotests/munet/mutest/__main__.py index c87031112d61..a78c69e26efd 100644 --- a/tests/topotests/munet/mutest/__main__.py +++ b/tests/topotests/munet/mutest/__main__.py @@ -20,9 +20,13 @@ from pathlib import Path from typing import Union +from munet import mulog from munet import parser +from munet.args import add_testing_args from munet.base import Bridge from munet.base import get_event_loop +from munet.cli import async_cli +from munet.compat import PytestConfig from munet.mutest import userapi as uapi from munet.native import L3NodeMixin from munet.native import Munet @@ -36,7 +40,9 @@ exec_formatter = logging.Formatter("%(asctime)s %(levelname)5s: %(name)s: %(message)s") -async def get_unet(config: dict, croot: Path, rundir: Path, unshare: bool = False): +async def get_unet( + config: dict, croot: Path, rundir: Path, args: Namespace, unshare: bool = False +): """Create and run a new Munet topology. The topology is built from the given ``config`` to run inside the path indicated @@ -48,6 +54,7 @@ async def get_unet(config: dict, croot: Path, rundir: Path, unshare: bool = Fals value will be modified and stored in the built ``Munet`` object. croot: common root of all tests, used to search for ``kinds.yaml`` files. rundir: the path to the run directory for this topology. + args: argparse args unshare: True to unshare the process into it's own private namespace. Yields: @@ -58,7 +65,11 @@ async def get_unet(config: dict, croot: Path, rundir: Path, unshare: bool = Fals try: try: unet = await async_build_topology( - config, rundir=str(rundir), unshare_inline=unshare + config, + rundir=str(rundir), + args=args, + pytestconfig=PytestConfig(args), + unshare_inline=unshare, ) except Exception as error: logging.debug("unet build failed: %s", error, exc_info=True) @@ -221,9 +232,13 @@ async def execute_test( targets["."] = unet tc = uapi.TestCase( - str(test_num), test_name, test, targets, logger, reslog, args.full_summary + str(test_num), test_name, test, targets, args, logger, reslog, args.full_summary ) - passed, failed, e = tc.execute() + try: + passed, failed, e = tc.execute() + except uapi.CLIOnErrorError as error: + await async_cli(unet) + passed, failed, e = 0, 0, error run_time = time.time() - tc.info.start_time @@ -278,6 +293,10 @@ async def run_tests(args): start_time = time.time() try: for dirpath in tests: + if args.validate_only: + parser.validate_config(configs[dirpath], reslog, args) + continue + test_files = tests[dirpath] for test in test_files: tnum += 1 @@ -294,10 +313,12 @@ async def run_tests(args): root_logger.addHandler(exec_handler) try: - async for unet in get_unet(config, common, rundir): + async for unet in get_unet(config, common, rundir, args): + if not printed_header: print_header(reslog, unet) printed_header = True + passed, failed, e = await execute_test( unet, test, args, tnum, exec_handler ) @@ -321,6 +342,9 @@ async def run_tests(args): except KeyboardInterrupt: pass + if args.validate_only: + return False + run_time = time.time() - start_time tnum = 0 tpassed = 0 @@ -357,8 +381,10 @@ async def run_tests(args): for result in results: test_name, passed, failed, e = result tnum += 1 - s = "FAIL" if failed or e else "PASS" - reslog.info(" %s %s:%s", s, tnum, test_name) + if failed or e: + reslog.warning(" FAIL %s:%s", tnum, test_name) + else: + reslog.info(" PASS %s:%s", tnum, test_name) reslog.info("-" * 70) reslog.info( @@ -386,35 +412,47 @@ async def async_main(args): def main(): ap = ArgumentParser() ap.add_argument( - "--dist", - type=int, - nargs="?", - const=-1, - default=0, - action="store", - metavar="NUM-THREADS", - help="Run in parallel, value is num. of threads or no value for auto", + "-v", dest="verbose", action="count", default=0, help="More -v's, more verbose" ) - ap.add_argument("-d", "--rundir", help="runtime directory for tempfiles, logs, etc") ap.add_argument( + "-V", "--version", action="store_true", help="print the verison number and exit" + ) + ap.add_argument("paths", nargs="*", help="Paths to collect tests from") + + rap = ap.add_argument_group(title="Runtime", description="runtime related options") + rap.add_argument( + "-d", "--rundir", help="runtime directory for tempfiles, logs, etc" + ) + add_testing_args(rap.add_argument) + + eap = ap.add_argument_group(title="Uncommon", description="uncommonly used options") + eap.add_argument( "--file-select", default="mutest_*.py", help="shell glob for finding tests" ) - ap.add_argument("--log-config", help="logging config file (yaml, toml, json, ...)") - ap.add_argument( - "-V", + eap.add_argument( "--full-summary", action="store_true", help="print full summary headers from docstrings", ) - ap.add_argument( - "-v", dest="verbose", action="count", default=0, help="More -v's, more verbose" + eap.add_argument("--log-config", help="logging config file (yaml, toml, json, ...)") + eap.add_argument( + "--validate-only", + action="store_true", + help="Validate the munet configs against the schema definition", ) - ap.add_argument("paths", nargs="*", help="Paths to collect tests from") + args = ap.parse_args() + if args.version: + from importlib import metadata # pylint: disable=C0415 + + print(metadata.version("munet")) + sys.exit(0) + rundir = args.rundir if args.rundir else "/tmp/mutest" - args.rundir = Path(rundir) - os.environ["MUNET_RUNDIR"] = rundir + rundir = Path(rundir).absolute() + args.rundir = rundir + os.environ["MUNET_RUNDIR"] = str(rundir) subprocess.run(f"mkdir -p {rundir} && chmod 755 {rundir}", check=True, shell=True) config = parser.setup_logging(args, config_base="logconf-mutest") @@ -425,6 +463,9 @@ def main(): fconfig.get("format"), fconfig.get("datefmt") ) + if not hasattr(sys.stderr, "isatty") or not sys.stderr.isatty(): + mulog.do_color = False + loop = None status = 4 try: diff --git a/tests/topotests/munet/mutest/userapi.py b/tests/topotests/munet/mutest/userapi.py index 1df8c0d012b6..abc63af36588 100644 --- a/tests/topotests/munet/mutest/userapi.py +++ b/tests/topotests/munet/mutest/userapi.py @@ -65,8 +65,11 @@ import logging import pprint import re +import subprocess +import sys import time +from argparse import Namespace from pathlib import Path from typing import Any from typing import Union @@ -76,6 +79,51 @@ from munet.base import Commander +class ScriptError(Exception): + """An unrecoverable script failure.""" + + +class CLIOnErrorError(Exception): + """Enter CLI after error.""" + + +def pause_test(desc=""): + isatty = sys.stdout.isatty() + if not isatty: + desc = f" for {desc}" if desc else "" + logging.info("NO PAUSE on non-tty terminal%s", desc) + return + + while True: + if desc: + print(f"\n== PAUSING: {desc} ==") + try: + user = input('PAUSED, "cli" for CLI, "pdb" to debug, "Enter" to continue: ') + except EOFError: + print("^D...continuing") + break + user = user.strip() + if user == "cli": + raise CLIOnErrorError() + if user == "pdb": + breakpoint() # pylint: disable=W1515 + elif user: + print(f'Unrecognized input: "{user}"') + else: + break + + +def act_on_result(success, args, desc=""): + if args.pause: + pause_test(desc) + elif success: + return + if args.cli_on_error: + raise CLIOnErrorError() + if args.pause_on_error: + pause_test(desc) + + class TestCaseInfo: """Object to hold nestable TestCase Results.""" @@ -140,11 +188,11 @@ def __init__( name: str, path: Path, targets: dict, + args: Namespace, output_logger: logging.Logger = None, result_logger: logging.Logger = None, full_summary: bool = False, ): - self.info = TestCaseInfo(tag, name, path) self.__saved_info = [] self.__short_doc_header = not full_summary @@ -158,6 +206,7 @@ def __init__( self.__in_section = False self.targets = targets + self.args = args self.last = "" self.last_m = None @@ -248,7 +297,6 @@ def __print_header(self, tag, header, add_newline=False): self.rlog.info("%s. %s", tag, header) def __exec_script(self, path, print_header, add_newline): - # Below was the original method to avoid the global TestCase # variable; however, we need global functions so we can import them # into test scripts. Without imports pylint will complain about undefined @@ -287,7 +335,10 @@ def __exec_script(self, path, print_header, add_newline): # Extract any docstring as a title. if print_header: - title = locals()[f"_{name}"].__doc__.lstrip() + title = locals()[f"_{name}"].__doc__ + if title is None: + title = "" + title = title.lstrip() if self.__short_doc_header and (title := title.lstrip()): if (idx := title.find("\n")) != -1: title = title[:idx].strip() @@ -301,6 +352,10 @@ def __exec_script(self, path, print_header, add_newline): # Here's where we can do async in the future if we want. # result = await locals()[f"_{name}"](_ok_result) + except ScriptError as error: + return error + except CLIOnErrorError: + raise except Exception as error: logging.error( "Unexpected exception executing %s: %s", name, error, exc_info=True @@ -383,7 +438,9 @@ def _command( target: the target to execute the command on. cmd: string to execut on the target. """ - out = self.targets[target].cmd_nostatus(cmd, warn=False) + out = self.targets[target].cmd_nostatus( + cmd, stdin=subprocess.DEVNULL, warn=False + ) self.last = out = out.rstrip() report = out if out else "" self.logf("COMMAND OUTPUT:\n%s", report) @@ -393,19 +450,21 @@ def _command_json( self, target: str, cmd: str, - ) -> dict: + ) -> Union[list, dict]: """Execute a json ``cmd`` and return json result. Args: target: the target to execute the command on. - cmd: string to execut on the target. + cmd: string to execute on the target. """ - out = self.targets[target].cmd_nostatus(cmd, warn=False) + out = self.targets[target].cmd_nostatus( + cmd, stdin=subprocess.DEVNULL, warn=False + ) self.last = out = out.rstrip() try: js = json.loads(out) except Exception as error: - js = {} + js = None self.olog.warning( "JSON load failed. Check command output is in JSON format: %s", error, @@ -420,6 +479,7 @@ def _match_command( match: str, expect_fail: bool, flags: int, + exact_match: bool, ) -> (bool, Union[str, list]): """Execute a ``cmd`` and check result. @@ -429,6 +489,8 @@ def _match_command( match: regex to ``re.search()`` for in output. expect_fail: if True then succeed when the regexp doesn't match. flags: python regex flags to modify matching behavior + exact_match: if True then ``match`` must be exactly matched somewhere + in the output of ``cmd`` using ``str.find()``. Returns: (success, matches): if the match fails then "matches" will be None, @@ -436,6 +498,17 @@ def _match_command( ``matches`` otherwise group(0) (i.e., the matching text). """ out = self._command(target, cmd) + if exact_match: + if match not in out: + success = expect_fail + ret = None + else: + success = not expect_fail + ret = match + level = logging.DEBUG if success else logging.WARNING + self.olog.log(level, "exactly matched:%s:", ret) + return success, ret + search = re.search(match, out, flags) self.last_m = search if search is None: @@ -455,28 +528,63 @@ def _match_command_json( self, target: str, cmd: str, - match: Union[str, dict], + match: Union[str, list, dict], expect_fail: bool, - ) -> Union[str, dict]: + exact_match: bool, + ) -> (bool, Union[list, dict]): """Execute a json ``cmd`` and check result. Args: target: the target to execute the command on. cmd: string to execut on the target. - match: A json ``str`` or object (``dict``) to compare against the json - output from ``cmd``. + match: A json ``str``, object (``dict``), or array (``list``) to + compare against the json output from ``cmd``. expect_fail: if True then succeed when the json doesn't match. + exact_match: if True then the json must exactly match. """ js = self._command_json(target, cmd) + if js is None: + # Always fail on bad json, even if user expected failure + # return expect_fail, {} + return False, {} + try: + # Convert to string to validate the input is valid JSON + if not isinstance(match, str): + match = json.dumps(match) expect = json.loads(match) except Exception as error: expect = {} self.olog.warning( "JSON load failed. Check match value is in JSON format: %s", error ) - - if json_diff := json_cmp(expect, js): + # Always fail on bad json, even if user expected failure + # return expect_fail, {} + return False, {} + + if exact_match: + deep_diff = json_cmp(expect, js) + # Convert DeepDiff completely into dicts or lists at all levels + json_diff = json.loads(deep_diff.to_json()) + else: + deep_diff = json_cmp( + expect, js, ignore_order=True, cutoff_intersection_for_pairs=1 + ) + # Convert DeepDiff completely into dicts or lists at all levels + json_diff = json.loads(deep_diff.to_json()) + # Remove new fields in json object from diff + if json_diff.get("dictionary_item_added") is not None: + del json_diff["dictionary_item_added"] + # Remove new json objects in json array from diff + if (new_items := json_diff.get("iterable_item_added")) is not None: + new_item_paths = list(new_items.keys()) + for path in new_item_paths: + if type(new_items[path]) is dict: + del new_items[path] + if len(new_items) == 0: + del json_diff["iterable_item_added"] + + if json_diff: success = expect_fail if not success: self.logf("JSON DIFF:%s:" % json_diff) @@ -489,14 +597,24 @@ def _wait( self, target: str, cmd: str, - match: Union[str, dict], + match: Union[str, list, dict], is_json: bool, timeout: float, interval: float, expect_fail: bool, flags: int, - ) -> Union[str, dict]: - """Execute a command repeatedly waiting for result until timeout.""" + exact_match: bool, + ) -> Union[str, list, dict]: + """Execute a command repeatedly waiting for result until timeout. + + ``match`` is a regular expression to search for in the output of ``cmd`` + when ``is_json`` is False. + + When ``is_json`` is True ``match`` must be a json object, a json array, + or a ``str`` which parses into a json object. Likewise, the ``cmd`` output + is parsed into a json object or array and then a comparison is done between + the two json objects or arrays. + """ startt = time.time() endt = startt + timeout @@ -504,10 +622,12 @@ def _wait( ret = None while not success and time.time() < endt: if is_json: - success, ret = self._match_command_json(target, cmd, match, expect_fail) + success, ret = self._match_command_json( + target, cmd, match, expect_fail, exact_match + ) else: success, ret = self._match_command( - target, cmd, match, expect_fail, flags + target, cmd, match, expect_fail, flags, exact_match ) if not success: time.sleep(interval) @@ -524,6 +644,7 @@ def include(self, pathname: str, new_section: bool = False): """ path = Path(pathname) path = self.info.path.parent.joinpath(path) + do_cli = False self.oplogf( "include: new path: %s create section: %s currently __in_section: %s", @@ -543,7 +664,12 @@ def include(self, pathname: str, new_section: bool = False): self.info.path = path self.oplogf("include: swapped info path: new %s old %s", path, old_path) - self.__exec_script(path, print_header=new_section, add_newline=new_section) + try: + e = self.__exec_script( + path, print_header=new_section, add_newline=new_section + ) + except CLIOnErrorError: + do_cli = True if new_section: # Something within the section creating include has also created a section @@ -570,6 +696,11 @@ def include(self, pathname: str, new_section: bool = False): self.info.path = old_path self.oplogf("include: restored info path: %s", old_path) + if do_cli: + raise CLIOnErrorError() + if e: + raise ScriptError(e) + def __end_section(self): self.oplogf("__end_section: __in_section: %s", self.__in_section) info = self.__pop_execinfo() @@ -626,7 +757,7 @@ def step(self, target: str, cmd: str) -> str: ) return self._command(target, cmd) - def step_json(self, target: str, cmd: str) -> dict: + def step_json(self, target: str, cmd: str) -> Union[list, dict]: """See :py:func:`~munet.mutest.userapi.step_json`. :meta private: @@ -649,13 +780,14 @@ def match_step( desc: str = "", expect_fail: bool = False, flags: int = re.DOTALL, + exact_match: bool = False, ) -> (bool, Union[str, list]): """See :py:func:`~munet.mutest.userapi.match_step`. :meta private: """ self.logf( - "#%s.%s:%s:MATCH_STEP:%s:%s:%s:%s:%s:%s", + "#%s.%s:%s:MATCH_STEP:%s:%s:%s:%s:%s:%s:%s", self.tag, self.steps + 1, self.info.path, @@ -665,10 +797,14 @@ def match_step( desc, expect_fail, flags, + exact_match, + ) + success, ret = self._match_command( + target, cmd, match, expect_fail, flags, exact_match ) - success, ret = self._match_command(target, cmd, match, expect_fail, flags) if desc: self.__post_result(target, success, desc) + act_on_result(success, self.args, desc) return success, ret def test_step(self, expr_or_value: Any, desc: str, target: str = "") -> bool: @@ -678,22 +814,24 @@ def test_step(self, expr_or_value: Any, desc: str, target: str = "") -> bool: """ success = bool(expr_or_value) self.__post_result(target, success, desc) + act_on_result(success, self.args, desc) return success def match_step_json( self, target: str, cmd: str, - match: Union[str, dict], + match: Union[str, list, dict], desc: str = "", expect_fail: bool = False, - ) -> (bool, Union[str, dict]): + exact_match: bool = False, + ) -> (bool, Union[list, dict]): """See :py:func:`~munet.mutest.userapi.match_step_json`. :meta private: """ self.logf( - "#%s.%s:%s:MATCH_STEP_JSON:%s:%s:%s:%s:%s", + "#%s.%s:%s:MATCH_STEP_JSON:%s:%s:%s:%s:%s:%s", self.tag, self.steps + 1, self.info.path, @@ -702,10 +840,14 @@ def match_step_json( match, desc, expect_fail, + exact_match, + ) + success, ret = self._match_command_json( + target, cmd, match, expect_fail, exact_match ) - success, ret = self._match_command_json(target, cmd, match, expect_fail) if desc: self.__post_result(target, success, desc) + act_on_result(success, self.args, desc) return success, ret def wait_step( @@ -718,6 +860,7 @@ def wait_step( interval=0.5, expect_fail: bool = False, flags: int = re.DOTALL, + exact_match: bool = False, ) -> (bool, Union[str, list]): """See :py:func:`~munet.mutest.userapi.wait_step`. @@ -726,7 +869,7 @@ def wait_step( if interval is None: interval = min(timeout / 20, 0.25) self.logf( - "#%s.%s:%s:WAIT_STEP:%s:%s:%s:%s:%s:%s:%s:%s", + "#%s.%s:%s:WAIT_STEP:%s:%s:%s:%s:%s:%s:%s:%s:%s", self.tag, self.steps + 1, self.info.path, @@ -738,24 +881,35 @@ def wait_step( desc, expect_fail, flags, + exact_match, ) success, ret = self._wait( - target, cmd, match, False, timeout, interval, expect_fail, flags + target, + cmd, + match, + False, + timeout, + interval, + expect_fail, + flags, + exact_match, ) if desc: self.__post_result(target, success, desc) + act_on_result(success, self.args, desc) return success, ret def wait_step_json( self, target: str, cmd: str, - match: Union[str, dict], + match: Union[str, list, dict], desc: str = "", timeout=10, interval=None, expect_fail: bool = False, - ) -> (bool, Union[str, dict]): + exact_match: bool = False, + ) -> (bool, Union[list, dict]): """See :py:func:`~munet.mutest.userapi.wait_step_json`. :meta private: @@ -763,7 +917,7 @@ def wait_step_json( if interval is None: interval = min(timeout / 20, 0.25) self.logf( - "#%s.%s:%s:WAIT_STEP:%s:%s:%s:%s:%s:%s:%s", + "#%s.%s:%s:WAIT_STEP:%s:%s:%s:%s:%s:%s:%s:%s", self.tag, self.steps + 1, self.info.path, @@ -774,12 +928,14 @@ def wait_step_json( interval, desc, expect_fail, + exact_match, ) success, ret = self._wait( - target, cmd, match, True, timeout, interval, expect_fail, 0 + target, cmd, match, True, timeout, interval, expect_fail, 0, exact_match ) if desc: self.__post_result(target, success, desc) + act_on_result(success, self.args, desc) return success, ret @@ -864,15 +1020,15 @@ def step(target: str, cmd: str) -> str: return TestCase.g_tc.step(target, cmd) -def step_json(target: str, cmd: str) -> dict: - """Execute a json ``cmd`` on a ``target`` and return the json object. +def step_json(target: str, cmd: str) -> Union[list, dict]: + """Execute a json ``cmd`` on a ``target`` and return the json object or array. Args: target: the target to execute the ``cmd`` on. cmd: string to execute on the target. Returns: - Returns the json object after parsing the ``cmd`` output. + Returns the json object or array after parsing the ``cmd`` output. If json parse fails, a warning is logged and an empty ``dict`` is used. """ @@ -904,6 +1060,7 @@ def match_step( desc: str = "", expect_fail: bool = False, flags: int = re.DOTALL, + exact_match: bool = False, ) -> (bool, Union[str, list]): """Execute a ``cmd`` on a ``target`` check result. @@ -922,44 +1079,53 @@ def match_step( desc: description of test, if no description then no result is logged. expect_fail: if True then succeed when the regexp doesn't match. flags: python regex flags to modify matching behavior + exact_match: if True then ``match`` must be exactly matched somewhere + in the output of ``cmd`` using ``str.find()``. Returns: Returns a 2-tuple. The first value is a bool indicating ``success``. The second value will be a list from ``re.Match.groups()`` if non-empty, otherwise ``re.Match.group(0)`` if there was a match otherwise None. """ - return TestCase.g_tc.match_step(target, cmd, match, desc, expect_fail, flags) + return TestCase.g_tc.match_step( + target, cmd, match, desc, expect_fail, flags, exact_match + ) def match_step_json( target: str, cmd: str, - match: Union[str, dict], + match: Union[str, list, dict], desc: str = "", expect_fail: bool = False, -) -> (bool, Union[str, dict]): + exact_match: bool = False, +) -> (bool, Union[list, dict]): """Execute a ``cmd`` on a ``target`` check result. - Execute ``cmd`` on ``target`` and check if the json object in ``match`` + Execute ``cmd`` on ``target`` and check if the json object or array in ``match`` matches or doesn't match (according to the ``expect_fail`` value) the json output from ``cmd``. Args: target: the target to execute the ``cmd`` on. cmd: string to execut on the ``target``. - match: A json ``str`` or object (``dict``) to compare against the json - output from ``cmd``. + match: A json ``str``, object (``dict``), or array (``list``) to compare + against the json output from ``cmd``. desc: description of test, if no description then no result is logged. expect_fail: if True then succeed if the a json doesn't match. + exact_match: if True then the json must exactly match. Returns: Returns a 2-tuple. The first value is a bool indicating ``success``. The - second value is a ``str`` diff if there is a difference found in the json - compare, otherwise the value is the json object (``dict``) from the ``cmd``. + second value is a ``dict`` of the diff if there is a difference found in + the json compare, otherwise the value is the json object (``dict``) or + array (``list``) from the ``cmd``. If json parse fails, a warning is logged and an empty ``dict`` is used. """ - return TestCase.g_tc.match_step_json(target, cmd, match, desc, expect_fail) + return TestCase.g_tc.match_step_json( + target, cmd, match, desc, expect_fail, exact_match + ) def wait_step( @@ -971,6 +1137,7 @@ def wait_step( interval: float = 0.5, expect_fail: bool = False, flags: int = re.DOTALL, + exact_match: bool = False, ) -> (bool, Union[str, list]): """Execute a ``cmd`` on a ``target`` repeatedly, looking for a result. @@ -991,6 +1158,8 @@ def wait_step( desc: description of test, if no description then no result is logged. expect_fail: if True then succeed when the regexp *doesn't* match. flags: python regex flags to modify matching behavior + exact_match: if True then ``match`` must be exactly matched somewhere + in the output of ``cmd`` using ``str.find()``. Returns: Returns a 2-tuple. The first value is a bool indicating ``success``. @@ -998,37 +1167,31 @@ def wait_step( otherwise ``re.Match.group(0)`` if there was a match otherwise None. """ return TestCase.g_tc.wait_step( - target, cmd, match, desc, timeout, interval, expect_fail, flags + target, cmd, match, desc, timeout, interval, expect_fail, flags, exact_match ) def wait_step_json( target: str, cmd: str, - match: Union[str, dict], + match: Union[str, list, dict], desc: str = "", timeout=10, interval=None, expect_fail: bool = False, -) -> (bool, Union[str, dict]): + exact_match: bool = False, +) -> (bool, Union[list, dict]): """Execute a cmd repeatedly and wait for matching result. Execute ``cmd`` on ``target``, every ``interval`` seconds until the output of ``cmd`` matches or doesn't match (according to the ``expect_fail`` value) ``match``, for up to ``timeout`` seconds. - ``match`` is a regular expression to search for in the output of ``cmd`` when - ``is_json`` is False. - - When ``is_json`` is True ``match`` must be a json object or a ``str`` which - parses into a json object. Likewise, the ``cmd`` output is parsed into a json - object and then a comparison is done between the two json objects. - Args: target: the target to execute the ``cmd`` on. cmd: string to execut on the ``target``. - match: A json object or str representation of one to compare against json - output from ``cmd``. + match: A json object, json array, or str representation of json to compare + against json output from ``cmd``. desc: description of test, if no description then no result is logged. timeout: The number of seconds to repeat the ``cmd`` looking for a match (or non-match if ``expect_fail`` is True). @@ -1037,17 +1200,18 @@ def wait_step_json( average the cmd will execute 10 times. The minimum calculated interval is .25s, shorter values can be passed explicitly. expect_fail: if True then succeed if the a json doesn't match. + exact_match: if True then the json must exactly match. Returns: Returns a 2-tuple. The first value is a bool indicating ``success``. - The second value is a ``str`` diff if there is a difference found in the - json compare, otherwise the value is a json object (dict) from the ``cmd`` - output. + The second value is a ``dict`` of the diff if there is a difference + found in the json compare, otherwise the value is a json object (``dict``) + or array (``list``) from the ``cmd`` output. If json parse fails, a warning is logged and an empty ``dict`` is used. """ return TestCase.g_tc.wait_step_json( - target, cmd, match, desc, timeout, interval, expect_fail + target, cmd, match, desc, timeout, interval, expect_fail, exact_match ) diff --git a/tests/topotests/munet/mutini.py b/tests/topotests/munet/mutini.py index e5f993171400..3ce372cf602e 100755 --- a/tests/topotests/munet/mutini.py +++ b/tests/topotests/munet/mutini.py @@ -15,6 +15,7 @@ import logging import os import re +import select import shlex import signal import subprocess @@ -119,9 +120,15 @@ def exit_with_status(status): sys.exit(ec) -def waitpid(tag): - logging.debug("%s: waitid for exiting process", tag) - idobj = os.waitid(os.P_ALL, 0, os.WEXITED) +def __waitpid(tag, nohang=False): # pylint: disable=inconsistent-return-statements + if nohang: + idobj = os.waitid(os.P_ALL, 0, os.WEXITED | os.WNOHANG) + if idobj is None: + return True + else: + idobj = os.waitid(os.P_ALL, 0, os.WEXITED) + assert idobj is not None + pid = idobj.si_pid status = idobj.si_status @@ -130,13 +137,23 @@ def waitpid(tag): logging.debug( "%s: reaped zombie %s (%s) w/ status %s", tag, pid, pidname, status ) - return + return False logging.debug("reaped child with status %s", status) exit_with_status(status) # NOTREACHED +def waitpid(tag): + logging.debug("%s: waitid for exiting process", tag) + __waitpid(tag, False) + + while True: + logging.debug("%s: checking for another exiting process", tag) + if __waitpid(tag, True): + return + + def sig_trasmit(signum, _): signame = signal.Signals(signum).name if g.child_pid == -1: @@ -158,10 +175,6 @@ def sig_trasmit(signum, _): def sig_sigchld(signum, _): assert signum == S.SIGCHLD - try: - waitpid("SIGCHLD") - except ChildProcessError as error: - logging.warning("got SIGCHLD but no pid to wait on: %s", error) def setup_init_signals(): @@ -250,6 +263,19 @@ def is_creating_pid_namespace(): return p1name != p2name +def poll_for_pids(msg, tag): + poller = select.poll() + while True: + logging.info("%s", msg) + events = poller.poll(1000) + logging.info("init: poll: checking for zombies and child exit: %s", events) + try: + waitpid(tag) + except ChildProcessError as error: + logging.warning("init: got SIGCHLD but no pid to wait on: %s", error) + # NOTREACHED + + def be_init(new_pg, exec_args): # # Arrange for us to be killed when our parent dies, this will subsequently also kill @@ -299,10 +325,7 @@ def be_init(new_pg, exec_args): # Reap children as init process vdebug("installing local handler for SIGCHLD") signal.signal(signal.SIGCHLD, sig_sigchld) - - while True: - logging.info("init: waiting to reap zombies") - linux.pause() + poll_for_pids("init: waiting to reap zombies", "PAUSE-EXIT") # NOTREACHED # Set (parent) signal handlers before any fork to avoid race @@ -321,9 +344,8 @@ def be_init(new_pg, exec_args): os.execvp(exec_args[0], exec_args) # NOTREACHED - while True: - logging.info("parent: waiting for child pid %s to exit", g.child_pid) - waitpid("parent") + poll_for_pids(f"parent: waiting for child pid {g.child_pid} to exit", "PARENT") + # NOTREACHED def unshare(flags): @@ -411,9 +433,7 @@ def main(): if g.orig_pid != 1 and not new_pid: # Simply hold the namespaces - while True: - logging.info("holding namespace waiting to be signaled to exit") - linux.pause() + poll_for_pids("holding namespace waiting to be signaled to exit", "PARENT") # NOTREACHED be_init(not args.no_proc_group, args.rest) diff --git a/tests/topotests/munet/native.py b/tests/topotests/munet/native.py index fecf709d1aaa..b7c6e4a63eaf 100644 --- a/tests/topotests/munet/native.py +++ b/tests/topotests/munet/native.py @@ -8,8 +8,10 @@ # pylint: disable=protected-access """A module that defines objects for standalone use.""" import asyncio +import base64 import errno import getpass +import glob import ipaddress import logging import os @@ -20,12 +22,16 @@ import subprocess import time +from pathlib import Path + from . import cli from .base import BaseMunet from .base import Bridge from .base import Commander +from .base import InterfaceMixin from .base import LinuxNamespace from .base import MunetError +from .base import SharedNamespace from .base import Timeout from .base import _async_get_exec_path from .base import _get_exec_path @@ -38,6 +44,7 @@ from .config import find_matching_net_config from .config import find_with_kv from .config import merge_kind_config +from .watchlog import WatchLog class L3ContainerNotRunningError(MunetError): @@ -127,6 +134,22 @@ def convert_ranges_to_bitmask(ranges): return bitmask +class ExternalNetwork(SharedNamespace, InterfaceMixin): + """A network external to munet.""" + + def __init__(self, name=None, unet=None, logger=None, mtu=None, config=None): + """Create an external network.""" + del logger # avoid linter + del mtu # avoid linter + # Do we want to use os.getpid() rather than unet.pid? + super().__init__(name, pid=unet.pid, nsflags=unet.nsflags, unet=unet) + self.config = config if config else {} + + async def _async_delete(self): + self.logger.debug("%s: deleting", self) + await super()._async_delete() + + class L2Bridge(Bridge): """A linux bridge with no IP network address.""" @@ -391,6 +414,10 @@ def has_cleanup_cmd(self) -> bool: async def async_cleanup_cmd(self): """Run the configured cleanup commands for this node.""" + if self.cleanup_called: + return + self.cleanup_called = True + return await self._async_cleanup_cmd() def has_ready_cmd(self) -> bool: @@ -430,14 +457,14 @@ def pytest_hook_run_cmd(self, stdout, stderr): outopt = outopt if outopt is not None else "" if outopt == "all" or self.name in outopt.split(","): outname = stdout.name if hasattr(stdout, "name") else stdout - self.run_in_window(f"tail -F {outname}", title=f"O:{self.name}") + self.run_in_window(f"tail -n+1 -F {outname}", title=f"O:{self.name}") if stderr: erropt = self.unet.cfgopt.getoption("--stderr") erropt = erropt if erropt is not None else "" if erropt == "all" or self.name in erropt.split(","): errname = stderr.name if hasattr(stderr, "name") else stderr - self.run_in_window(f"tail -F {errname}", title=f"E:{self.name}") + self.run_in_window(f"tail -n+1 -F {errname}", title=f"E:{self.name}") def pytest_hook_open_shell(self): if not self.unet: @@ -455,13 +482,18 @@ def pytest_hook_open_shell(self): bps = self.unet.cfgopt.getoption("--gdb-breakpoints", "").split(",") for bp in bps: - gdbcmd += f" '-ex=b {bp}'" + if bp: + gdbcmd += f" '-ex=b {bp}'" - cmds = self.config.get("gdb-run-cmd", []) + cmds = self.config.get("gdb-run-cmds", []) for cmd in cmds: gdbcmd += f" '-ex={cmd}'" - self.run_in_window(gdbcmd) + self.run_in_window(gdbcmd, ns_only=True) + + # We need somehow signal from the launched gdb that it has continued + # this is non-trivial so for now just wait a while. :/ + time.sleep(5) elif should_gdb and use_emacs: gdbcmd = gdbcmd.replace("gdb ", "gdb -i=mi ") ecbin = self.get_exec_path("emacsclient") @@ -545,17 +577,38 @@ async def _async_delete(self): await super()._async_delete() +class HostnetNode(NodeMixin, LinuxNamespace): + """A node for running commands in the host network namespace.""" + + def __init__(self, name, pid=True, **kwargs): + if "net" in kwargs: + del kwargs["net"] + super().__init__(name, pid=pid, net=False, **kwargs) + + self.logger.debug("%s: creating", self) + + self.mgmt_ip = None + self.mgmt_ip6 = None + self.set_ns_cwd(self.rundir) + + super().pytest_hook_open_shell() + self.logger.info("%s: created", self) + + def get_ifname(self, netname): # pylint: disable=useless-return + del netname + return None + + async def _async_delete(self): + self.logger.debug("%s: deleting", self) + await super()._async_delete() + + class SSHRemote(NodeMixin, Commander): """SSHRemote a node representing an ssh connection to something.""" def __init__( self, name, - server, - port=22, - user=None, - password=None, - idfile=None, **kwargs, ): super().__init__(name, **kwargs) @@ -570,32 +623,33 @@ def __init__( self.mgmt_ip = None self.mgmt_ip6 = None - self.port = port - - if user: - self.user = user - elif "SUDO_USER" in os.environ: - self.user = os.environ["SUDO_USER"] - else: + self.server = self.config["server"] + self.port = int(self.config.get("server-port", 22)) + self.sudo_user = os.environ.get("SUDO_USER") + self.user = self.config.get("ssh-user") + if not self.user: + self.user = self.sudo_user + if not self.user: self.user = getpass.getuser() - self.password = password - self.idfile = idfile - - self.server = f"{self.user}@{server}" + self.password = self.config.get("ssh-password") + self.idfile = self.config.get("ssh-identity-file") + self.use_host_network = None # Setup our base `pre-cmd` values # # We maybe should add environment variable transfer here in particular # MUNET_NODENAME. The problem is the user has to explicitly approve # of SendEnv variables. - self.__base_cmd = [ - get_exec_path_host("sudo"), - "-E", - f"-u{self.user}", - get_exec_path_host("ssh"), - ] - if port != 22: - self.__base_cmd.append(f"-p{port}") + self.__base_cmd = [] + if self.idfile and self.sudo_user: + self.__base_cmd += [ + get_exec_path_host("sudo"), + "-E", + f"-u{self.sudo_user}", + ] + self.__base_cmd.append(get_exec_path_host("ssh")) + if self.port != 22: + self.__base_cmd.append(f"-p{self.port}") self.__base_cmd.append("-q") self.__base_cmd.append("-oStrictHostKeyChecking=no") self.__base_cmd.append("-oUserKnownHostsFile=/dev/null") @@ -605,18 +659,34 @@ def __init__( # self.__base_cmd.append("-oSendVar='TEST'") self.__base_cmd_pty = list(self.__base_cmd) self.__base_cmd_pty.append("-t") - self.__base_cmd.append(self.server) - self.__base_cmd_pty.append(self.server) + server_str = f"{self.user}@{self.server}" + self.__base_cmd.append(server_str) + self.__base_cmd_pty.append(server_str) # self.set_pre_cmd(pre_cmd, pre_cmd_tty) self.logger.info("%s: created", self) - def has_ready_cmd(self) -> bool: - return bool(self.config.get("ready-cmd", "").strip()) - def _get_pre_cmd(self, use_str, use_pty, ns_only=False, **kwargs): - pre_cmd = [] - if self.unet: + # None on first use, set after + if self.use_host_network is None: + # We have networks now so try and ping the server in the namespace + if not self.unet: + self.use_host_network = True + else: + rc, _, _ = self.unet.cmd_status(f"ping -w1 -c1 {self.server}") + if rc: + self.use_host_network = True + else: + self.use_host_network = False + + if self.use_host_network: + self.logger.debug("Using host namespace for ssh connection") + else: + self.logger.debug("Using munet namespace for ssh connection") + + if self.use_host_network: + pre_cmd = [] + else: pre_cmd = self.unet._get_pre_cmd(False, use_pty, ns_only=False, **kwargs) if ns_only: return pre_cmd @@ -664,6 +734,7 @@ def __init__(self, *args, unet=None, **kwargs): self.phycount = 0 self.phy_odrivers = {} self.tapmacs = {} + self.watched_logs = {} self.intf_tc_count = 0 @@ -723,6 +794,26 @@ def __init__(self, *args, unet=None, **kwargs): if hasattr(self, "bind_mount"): self.bind_mount(hosts_file, "/etc/hosts") + def add_watch_log(self, path, watchfor_re=None): + """Add a WatchLog to this nodes watched logs. + + Args: + path: If relative is relative to the nodes ``rundir`` + watchfor_re: Regular expression to watch the log for and raise an exception + if found. + + Return: + The watching task if request or None otherwise. + """ + path = Path(path) + if not path.is_absolute(): + path = self.rundir.joinpath(path) + + wl = WatchLog(path) + self.watched_logs[wl.path] = wl + task = wl.raise_if_match_task(watchfor_re) if watchfor_re else None + return task + async def console( self, concmd, @@ -938,8 +1029,31 @@ async def add_host_intf(self, hname, lname, mtu=None): if hname in self.host_intfs: return self.host_intfs[hname] = lname + + # See if this interace is missing and needs to be fixed + rc, o, _ = self.unet.rootcmd.cmd_status("ip -o link show") + m = re.search(rf"\d+:\s+(\S+):.*altname {re.escape(hname)}\W", o) + if m: + # need to rename + dname = m.group(1) + self.logger.info("Fixing misnamed %s to %s", dname, hname) + self.unet.rootcmd.cmd_status( + f"ip link property del dev {dname} altname {hname}" + ) + self.unet.rootcmd.cmd_status(f"ip link set {dname} name {hname}") + + # Make sure the interface is there. + self.unet.rootcmd.cmd_raises(f"ip -o link show {hname}") self.unet.rootcmd.cmd_nostatus(f"ip link set {hname} down ") self.unet.rootcmd.cmd_raises(f"ip link set {hname} netns {self.pid}") + + # Wait for interface to show up in namespace + for retry in range(0, 10): + rc, o, _ = self.cmd_status(f"ip -o link show {hname}") + if not rc: + break + if retry > 0: + await asyncio.sleep(1) self.cmd_raises(f"ip link set {hname} name {lname}") if mtu: self.cmd_raises(f"ip link set {lname} mtu {mtu}") @@ -949,7 +1063,11 @@ async def rem_host_intf(self, hname): lname = self.host_intfs[hname] self.cmd_raises(f"ip link set {lname} down") self.cmd_raises(f"ip link set {lname} name {hname}") - self.cmd_raises(f"ip link set {hname} netns 1") + # We need to NOT run this command in the new pid namespace so that pid 1 is the + # root init process and so the interface gets returned to the root namespace + self.unet.rootcmd.cmd_raises( + f"nsenter -t {self.pid} -n ip link set netns 1 dev {hname}" + ) del self.host_intfs[hname] async def add_phy_intf(self, devaddr, lname): @@ -1019,12 +1137,13 @@ async def add_phy_intf(self, devaddr, lname): "Physical PCI device %s already bound to vfio-pci", devaddr ) return + self.logger.info( "Unbinding physical PCI device %s from driver %s", devaddr, driver ) self.phy_odrivers[devaddr] = driver self.unet.rootcmd.cmd_raises( - f"echo {devaddr} > /sys/bus/pci/drivers/{driver}/unbind" + f"echo {devaddr} | timeout 10 tee /sys/bus/pci/drivers/{driver}/unbind" ) # Add the device vendor and device id to vfio-pci in case it's the first time @@ -1035,7 +1154,14 @@ async def add_phy_intf(self, devaddr, lname): f"echo {vendor} {devid} > /sys/bus/pci/drivers/vfio-pci/new_id", warn=False ) - if not self.unet.rootcmd.path_exists(f"/sys/bus/pci/driver/vfio-pci/{devaddr}"): + for retry in range(0, 10): + if self.unet.rootcmd.path_exists( + f"/sys/bus/pci/drivers/vfio-pci/{devaddr}" + ): + break + if retry > 0: + await asyncio.sleep(1) + # Bind to vfio-pci if wasn't added with new_id self.logger.info("Binding physical PCI device %s to vfio-pci", devaddr) ec, _, _ = self.unet.rootcmd.cmd_status( @@ -1066,7 +1192,7 @@ async def rem_phy_intf(self, devaddr): "Unbinding physical PCI device %s from driver vfio-pci", devaddr ) self.unet.rootcmd.cmd_status( - f"echo {devaddr} > /sys/bus/pci/drivers/vfio-pci/unbind" + f"echo {devaddr} | timeout 10 tee /sys/bus/pci/drivers/vfio-pci/unbind" ) self.logger.info("Binding physical PCI device %s to driver %s", devaddr, driver) @@ -1085,13 +1211,13 @@ async def _async_delete(self): for hname in list(self.host_intfs): await self.rem_host_intf(hname) - # remove any hostintf interfaces - for devaddr in list(self.phy_intfs): - await self.rem_phy_intf(devaddr) - # delete the LinuxNamespace/InterfaceMixin await super()._async_delete() + # remove any hostintf interfaces, needs to come after normal exits + for devaddr in list(self.phy_intfs): + await self.rem_phy_intf(devaddr) + class L3NamespaceNode(L3NodeMixin, LinuxNamespace): """A namespace L3 node.""" @@ -1123,6 +1249,7 @@ def __init__(self, name, config, **kwargs): assert self.container_image self.cmd_p = None + self.cmd_pid = None self.__base_cmd = [] self.__base_cmd_pty = [] @@ -1393,7 +1520,13 @@ async def run_cmd(self): start_new_session=True, # keeps main tty signals away from podman ) - self.logger.debug("%s: async_popen => %s", self, self.cmd_p.pid) + # If our process is actually the child of an nsenter fetch its pid. + if self.nsenter_fork: + self.cmd_pid = await self.get_proc_child_pid(self.cmd_p) + + self.logger.debug( + "%s: async_popen => %s (%s)", self, self.cmd_p.pid, self.cmd_pid + ) self.pytest_hook_run_cmd(stdout, stderr) @@ -1453,11 +1586,14 @@ async def run_cmd(self): async def async_cleanup_cmd(self): """Run the configured cleanup commands for this node.""" + if self.cleanup_called: + return self.cleanup_called = True if "cleanup-cmd" not in self.config: return + # The opposite of other types, the container needs cmd_p running if not self.cmd_p: self.logger.warning("async_cleanup_cmd: container no longer running") return @@ -1542,6 +1678,7 @@ def __init__(self, name, config, **kwargs): """Create a Container Node.""" self.cont_exec_paths = {} self.launch_p = None + self.launch_pid = None self.qemu_config = config["qemu"] self.extra_mounts = [] assert self.qemu_config @@ -1569,7 +1706,15 @@ def __init__(self, name, config, **kwargs): rundir=os.path.join(self.rundir, self.name), configdir=self.unet.config_dirname, ) - self.ssh_keyfile = self.qemu_config.get("sshkey") + self.ssh_keyfile = self.config.get("ssh-identity-file") + if not self.ssh_keyfile: + self.ssh_keyfile = self.qemu_config.get("sshkey") + + self.ssh_user = self.config.get("ssh-user") + if not self.ssh_user: + self.ssh_user = self.qemu_config.get("sshuser", "root") + + self.disk_created = False @property def is_vm(self): @@ -1610,10 +1755,9 @@ def __setup_ssh(self): self.__base_cmd_pty = list(self.__base_cmd) self.__base_cmd_pty.append("-t") - user = self.qemu_config.get("sshuser", "root") - self.__base_cmd.append(f"{user}@{mgmt_ip}") + self.__base_cmd.append(f"{self.ssh_user}@{mgmt_ip}") self.__base_cmd.append("--") - self.__base_cmd_pty.append(f"{user}@{mgmt_ip}") + self.__base_cmd_pty.append(f"{self.ssh_user}@{mgmt_ip}") # self.__base_cmd_pty.append("--") return True @@ -1740,15 +1884,15 @@ def mount_volumes(self): if args: self.extra_mounts += args - async def run_cmd(self): + async def _run_cmd(self, cmd_node): """Run the configured commands for this node inside VM.""" self.logger.debug( "[rundir %s exists %s]", self.rundir, os.path.exists(self.rundir) ) - cmd = self.config.get("cmd", "").strip() + cmd = self.config.get(cmd_node, "").strip() if not cmd: - self.logger.debug("%s: no `cmd` to run", self) + self.logger.debug("%s: no `%s` to run", self, cmd_node) return None shell_cmd = self.config.get("shell", "/bin/bash") @@ -1767,15 +1911,17 @@ async def run_cmd(self): cmd += "\n" # Write a copy to the rundir - cmdpath = os.path.join(self.rundir, "cmd.shebang") + cmdpath = os.path.join(self.rundir, f"{cmd_node}.shebang") with open(cmdpath, mode="w+", encoding="utf-8") as cmdfile: cmdfile.write(cmd) commander.cmd_raises(f"chmod 755 {cmdpath}") # Now write a copy inside the VM - self.conrepl.cmd_status("cat > /tmp/cmd.shebang << EOF\n" + cmd + "\nEOF") - self.conrepl.cmd_status("chmod 755 /tmp/cmd.shebang") - cmds = "/tmp/cmd.shebang" + self.conrepl.cmd_status( + f"cat > /tmp/{cmd_node}.shebang << EOF\n" + cmd + "\nEOF" + ) + self.conrepl.cmd_status(f"chmod 755 /tmp/{cmd_node}.shebang") + cmds = f"/tmp/{cmd_node}.shebang" else: cmd = cmd.replace("%CONFIGDIR%", str(self.unet.config_dirname)) cmd = cmd.replace("%RUNDIR%", str(self.rundir)) @@ -1813,20 +1959,30 @@ async def wait(self): # When run_command supports async_ arg we can use the above... self.cmd_p = now_proc(self.cmdrepl.run_command(cmds, timeout=120)) - - # stdout and err both combined into logfile from the spawned repl - stdout = os.path.join(self.rundir, "_cmdcon-log.txt") - self.pytest_hook_run_cmd(stdout, None) else: # If we only have a console we can't run in parallel, so run to completion self.cmd_p = now_proc(self.conrepl.run_command(cmds, timeout=120)) return self.cmd_p + async def run_cmd(self): + if self.disk_created: + await self._run_cmd("initial-cmd") + await self._run_cmd("cmd") + + # stdout and err both combined into logfile from the spawned repl + if self.cmdrepl: + stdout = os.path.join(self.rundir, "_cmdcon-log.txt") + self.pytest_hook_run_cmd(stdout, None) + # InterfaceMixin override # We need a name unique in the shared namespace. def get_ns_ifname(self, ifname): - return self.name + ifname + ifname = self.name + ifname + ifname = re.sub("gigabitethernet", "GE", ifname, flags=re.I) + if len(ifname) >= 16: + ifname = ifname[0:7] + ifname[-8:] + return ifname async def add_host_intf(self, hname, lname, mtu=None): # L3QemuVM needs it's own add_host_intf for macvtap, We need to create the tap @@ -1968,29 +2124,56 @@ async def renumber_interfaces(self): con.cmd_raises(f"ip -6 route add default via {switch.ip6_address}") con.cmd_raises("ip link set lo up") - if self.unet.cfgopt.getoption("--coverage"): - con.cmd_raises("mount -t debugfs none /sys/kernel/debug") + # This is already mounted now + # if self.unet.cfgopt.getoption("--coverage"): + # con.cmd_raises("mount -t debugfs none /sys/kernel/debug") async def gather_coverage_data(self): con = self.conrepl + gcda_root = "/sys/kernel/debug/gcov" + dest = "/tmp/gcov-data.tgz" - gcda = "/sys/kernel/debug/gcov" - tmpdir = con.cmd_raises("mktemp -d").strip() - dest = "/gcov-data.tgz" - con.cmd_raises(rf"find {gcda} -type d -exec mkdir -p {tmpdir}/{{}} \;") - con.cmd_raises( - rf"find {gcda} -name '*.gcda' -exec sh -c 'cat < $0 > {tmpdir}/$0' {{}} \;" - ) - con.cmd_raises( - rf"find {gcda} -name '*.gcno' -exec sh -c 'cp -d $0 {tmpdir}/$0' {{}} \;" - ) - con.cmd_raises(rf"tar cf - -C {tmpdir} sys | gzip -c > {dest}") - con.cmd_raises(rf"rm -rf {tmpdir}") - self.logger.info("Saved coverage data in VM at %s", dest) + if gcda_root != "/sys/kernel/debug/gcov": + con.cmd_raises( + rf"cd {gcda_root} && find * -name '*.gc??' " + "| tar -cf - -T - | gzip -c > {dest}" + ) + else: + # Some tars dont try and read 0 length files so we need to copy them. + tmpdir = con.cmd_raises("mktemp -d").strip() + con.cmd_raises( + rf"cd {gcda_root} && find -type d -exec mkdir -p {tmpdir}/{{}} \;" + ) + con.cmd_raises( + rf"cd {gcda_root} && " + rf"find -name '*.gcda' -exec sh -c 'cat < $0 > {tmpdir}/$0' {{}} \;" + ) + con.cmd_raises( + rf"cd {gcda_root} && " + rf"find -name '*.gcno' -exec sh -c 'cp -d $0 {tmpdir}/$0' {{}} \;" + ) + con.cmd_raises( + rf"cd {tmpdir} && " + rf"find * -name '*.gc??' | tar -cf - -T - | gzip -c > {dest}" + ) + con.cmd_raises(rf"rm -rf {tmpdir}") + + self.logger.debug("Saved coverage data in VM at %s", dest) + ldest = os.path.join(self.rundir, "gcov-data.tgz") if self.use_ssh: - ldest = os.path.join(self.rundir, "gcov-data.tgz") self.cmd_raises(["/bin/cat", dest], stdout=open(ldest, "wb")) - self.logger.info("Saved coverage data on host at %s", ldest) + self.logger.debug("Saved coverage data on host at %s", ldest) + else: + output = con.cmd_raises(rf"base64 {dest}") + with open(ldest, "wb") as f: + f.write(base64.b64decode(output)) + self.logger.debug("Saved coverage data on host at %s", ldest) + self.logger.info("Extracting coverage for %s into %s", self.name, ldest) + + # We need to place the gcda files where munet expects to find them + gcdadir = Path(os.environ["GCOV_PREFIX"]) / self.name + self.unet.cmd_raises_nsonly(f"mkdir -p {gcdadir}") + self.unet.cmd_raises_nsonly(f"tar -C {gcdadir} -xzf {ldest}") async def _opencons( self, @@ -2048,6 +2231,7 @@ async def _opencons( expects=expects, sends=sends, timeout=timeout, + init_newline=True, trace=True, ) ) @@ -2176,30 +2360,45 @@ async def launch(self): if not nnics: args += ["-nic", "none"] - dtpl = qc.get("disk-template") + dtplpath = dtpl = qc.get("disk-template") diskpath = disk = qc.get("disk") - if dtpl and not disk: - disk = qc["disk"] = f"{self.name}-{os.path.basename(dtpl)}" - diskpath = os.path.join(self.rundir, disk) + if diskpath: + if diskpath[0] != "/": + diskpath = os.path.join(self.unet.config_dirname, diskpath) + + if dtpl and (not disk or not os.path.exists(diskpath)): + if not disk: + disk = qc["disk"] = f"{self.name}-{os.path.basename(dtpl)}" + diskpath = os.path.join(self.rundir, disk) if self.path_exists(diskpath): logging.debug("Disk '%s' file exists, using.", diskpath) else: - dtplpath = os.path.abspath( - os.path.join( - os.path.dirname(self.unet.config["config_pathname"]), dtpl - ) - ) + if dtplpath[0] != "/": + dtplpath = os.path.join(self.unet.config_dirname, dtpl) logging.info("Create disk '%s' from template '%s'", diskpath, dtplpath) self.cmd_raises( f"qemu-img create -f qcow2 -F qcow2 -b {dtplpath} {diskpath}" ) + self.disk_created = True + disk_driver = qc.get("disk-driver", "virtio") if diskpath: - args.extend( - ["-drive", f"file={diskpath},if=none,id=sata-disk0,format=qcow2"] - ) - args.extend(["-device", "ahci,id=ahci"]) - args.extend(["-device", "ide-hd,bus=ahci.0,drive=sata-disk0"]) + if disk_driver == "virtio": + args.extend(["-drive", f"file={diskpath},if=virtio,format=qcow2"]) + else: + args.extend( + ["-drive", f"file={diskpath},if=none,id=sata-disk0,format=qcow2"] + ) + args.extend(["-device", "ahci,id=ahci"]) + args.extend(["-device", "ide-hd,bus=ahci.0,drive=sata-disk0"]) + + cidiskpath = qc.get("cloud-init-disk") + if cidiskpath: + if cidiskpath[0] != "/": + cidiskpath = os.path.join(self.unet.config_dirname, cidiskpath) + args.extend(["-drive", f"file={cidiskpath},if=virtio,format=qcow2"]) + + # args.extend(["-display", "vnc=0.0.0.0:40"]) use_stdio = cc.get("stdio", True) has_cmd = self.config.get("cmd") @@ -2261,30 +2460,38 @@ async def launch(self): stdout = open(os.path.join(self.rundir, "qemu.out"), "wb") stderr = open(os.path.join(self.rundir, "qemu.err"), "wb") - self.launch_p = await self.async_popen( + self.launch_p = await self.async_popen_nsonly( args, stdin=subprocess.DEVNULL, stdout=stdout, stderr=stderr, pass_fds=pass_fds, - # We don't need this here b/c we are only ever running qemu and that's all - # we need to kill for cleanup - # XXX reconcile this - start_new_session=True, # allows us to signal all children to exit + # Don't want Keybaord interrupt etc to pass to child. + # start_new_session=True, + preexec_fn=os.setsid, ) + if self.nsenter_fork: + self.launch_pid = await self.get_proc_child_pid(self.launch_p) + self.pytest_hook_run_cmd(stdout, stderr) # We've passed these on, so don't need these open here anymore. for fd in pass_fds: os.close(fd) - self.logger.debug("%s: async_popen => %s", self, self.launch_p.pid) + self.logger.debug( + "%s: popen => %s (%s)", self, self.launch_p.pid, self.launch_pid + ) confiles = ["_console"] if use_cmdcon: confiles.append("_cmdcon") + password = cc.get("password", "") + if self.disk_created: + password = cc.get("initial-password", password) + # # Connect to the console socket, retrying # @@ -2294,7 +2501,7 @@ async def launch(self): prompt=prompt, is_bourne=not bool(prompt), user=cc.get("user", "root"), - password=cc.get("password", ""), + password=password, expects=cc.get("expects"), sends=cc.get("sends"), timeout=int(cc.get("timeout", 60)), @@ -2307,10 +2514,10 @@ async def launch(self): # the monitor output has super annoying ANSI escapes in it output = self.monrepl.cmd_nostatus("info status") - self.logger.info("VM status: %s", output) + self.logger.debug("VM status: %s", output) output = self.monrepl.cmd_nostatus("info kvm") - self.logger.info("KVM status: %s", output) + self.logger.debug("KVM status: %s", output) # # Set thread affinity @@ -2348,13 +2555,10 @@ def launch_completed(self, future): "%s: node launch (qemu) cmd wait() canceled: %s", future, error ) - async def cleanup_qemu(self): - """Launch qemu.""" - if self.launch_p: - await self.async_cleanup_proc(self.launch_p) - async def async_cleanup_cmd(self): """Run the configured cleanup commands for this node.""" + if self.cleanup_called: + return self.cleanup_called = True if "cleanup-cmd" not in self.config: @@ -2372,7 +2576,7 @@ async def _async_delete(self): # Need to cleanup early b/c it is running on the VM if self.cmd_p: - await self.async_cleanup_proc(self.cmd_p) + await self.async_cleanup_proc(self.cmd_p, self.cmd_pid) self.cmd_p = None try: @@ -2388,9 +2592,9 @@ async def _async_delete(self): if not self.launch_p: self.logger.warning("async_delete: qemu is not running") else: - await self.cleanup_qemu() + await self.async_cleanup_proc(self.launch_p, self.launch_pid) except Exception as error: - self.logger.warning("%s: failued to cleanup qemu process: %s", self, error) + self.logger.warning("%s: failed to cleanup qemu process: %s", self, error) await super()._async_delete() @@ -2745,7 +2949,9 @@ async def add_native_link(self, node1, node2, c1=None, c2=None): else: node2.set_lan_addr(node1, c2) - if "physical" not in c1 and not node1.is_vm: + if isinstance(node1, ExternalNetwork): + pass + elif "physical" not in c1 and not node1.is_vm: node1.set_intf_constraints(if1, **c1) if "physical" not in c2 and not node2.is_vm: node2.set_intf_constraints(if2, **c2) @@ -2758,14 +2964,8 @@ def add_l3_node(self, name, config=None, **kwargs): cls = L3QemuVM elif config and config.get("server"): cls = SSHRemote - kwargs["server"] = config["server"] - kwargs["port"] = int(config.get("server-port", 22)) - if "ssh-identity-file" in config: - kwargs["idfile"] = config.get("ssh-identity-file") - if "ssh-user" in config: - kwargs["user"] = config.get("ssh-user") - if "ssh-password" in config: - kwargs["password"] = config.get("ssh-password") + elif config and config.get("hostnet"): + cls = HostnetNode else: cls = L3NamespaceNode return super().add_host(name, cls=cls, config=config, **kwargs) @@ -2775,20 +2975,113 @@ def add_network(self, name, config=None, **kwargs): if config is None: config = {} - cls = L3Bridge if config.get("ip") else L2Bridge + if config.get("external"): + cls = ExternalNetwork + elif config.get("ip"): + cls = L3Bridge + else: + cls = L2Bridge mtu = kwargs.get("mtu", config.get("mtu")) return super().add_switch(name, cls=cls, config=config, mtu=mtu, **kwargs) - async def run(self): + def coverage_setup(self): + bdir = self.cfgopt.getoption("--cov-build-dir") + if not bdir: + # Try and find the build dir using common prefix of gcno files + common = None + cwd = os.getcwd() + for f in glob.iglob(rf"{cwd}/**/*.gcno", recursive=True): + if not common: + common = os.path.dirname(f) + else: + common = os.path.commonprefix([common, f]) + if not common: + break + assert ( + bdir + ), "Can't locate build directory for coverage data, use --cov-build-dir" + + bdir = Path(bdir).resolve() + rundir = Path(self.rundir).resolve() + gcdadir = rundir / "gcda" + os.environ["GCOV_BUILD_DIR"] = str(bdir) + os.environ["GCOV_PREFIX_STRIP"] = str(len(bdir.parts) - 1) + os.environ["GCOV_PREFIX"] = str(gcdadir) + + # commander.cmd_raises(f"find {bdir} -name '*.gc??' -exec chmod o+rw {{}} +") + group_id = bdir.stat().st_gid + commander.cmd_raises(f"mkdir -p {gcdadir}") + commander.cmd_raises(f"chown -R root:{group_id} {gcdadir}") + commander.cmd_raises(f"chmod 2775 {gcdadir}") + + async def coverage_finish(self): + rundir = Path(self.rundir).resolve() + bdir = Path(os.environ["GCOV_BUILD_DIR"]) + gcdadir = Path(os.environ["GCOV_PREFIX"]) + + # Create .gcno symlinks if they don't already exist, for kernel they will + self.logger.info("Creating .gcno symlinks from '%s' to '%s'", gcdadir, bdir) + commander.cmd_raises( + f'cd "{gcdadir}"; bdir="{bdir}"' + + """ +for f in $(find . -name '*.gcda'); do + f=${f#./}; + f=${f%.gcda}.gcno; + if [ ! -h "$f" ]; then + ln -fs $bdir/$f $f; + touch -h -r $bdir/$f $f; + echo $f; + fi; +done""" + ) + + # Get the results into a summary file + data_file = rundir / "coverage.info" + self.logger.info("Gathering coverage data into: %s", data_file) + commander.cmd_raises( + f"lcov --directory {gcdadir} --capture --output-file {data_file}" + ) + + # Get coverage info filtered to a specific set of files + report_file = rundir / "coverage.info" + self.logger.debug("Generating coverage summary: %s", report_file) + output = commander.cmd_raises(f"lcov --summary {data_file}") + self.logger.info("\nCOVERAGE-SUMMARY-START\n%s\nCOVERAGE-SUMMARY-END", output) + # terminalreporter.write( + # f"\nCOVERAGE-SUMMARY-START\n{output}\nCOVERAGE-SUMMARY-END\n" + # ) + + async def load_images(self, images): tasks = [] + for image in images: + logging.debug("Checking for image %s", image) + rc, _, _ = self.rootcmd.cmd_status( + f"podman image inspect {image}", warn=False + ) + if not rc: + continue + logging.info("Pulling missing image %s", image) + aw = self.rootcmd.async_cmd_raises(f"podman pull {image}") + tasks.append(asyncio.create_task(aw)) + if not tasks: + return + _, pending = await asyncio.wait(tasks, timeout=600) + assert not pending, "Failed to pull container images" + async def run(self): + tasks = [] hosts = self.hosts.values() + + images = {x.container_image for x in hosts if hasattr(x, "container_image")} + await self.load_images(images) + launch_nodes = [x for x in hosts if hasattr(x, "launch")] launch_nodes = [x for x in launch_nodes if x.config.get("qemu")] - run_nodes = [x for x in hosts if hasattr(x, "has_run_cmd") and x.has_run_cmd()] - ready_nodes = [ - x for x in hosts if hasattr(x, "has_ready_cmd") and x.has_ready_cmd() - ] + run_nodes = [x for x in hosts if x.has_run_cmd()] + ready_nodes = [x for x in hosts if x.has_ready_cmd()] + + if self.cfgopt.getoption("--coverage"): + self.coverage_setup() pcapopt = self.cfgopt.getoption("--pcap") pcapopt = pcapopt if pcapopt else "" @@ -2814,6 +3107,8 @@ async def run(self): logging.debug("Launching nodes") await asyncio.gather(*[x.launch() for x in launch_nodes]) + logging.debug("Launched nodes -- Queueing Waits") + # Watch for launched processes to exit for node in launch_nodes: task = asyncio.create_task( @@ -2822,17 +3117,23 @@ async def run(self): task.add_done_callback(node.launch_completed) tasks.append(task) + logging.debug("Wait complete queued, running cmd") + if run_nodes: # would like a info when verbose here. logging.debug("Running `cmd` on nodes") await asyncio.gather(*[x.run_cmd() for x in run_nodes]) + logging.debug("Ran cmds -- Queueing Waits") + # Watch for run_cmd processes to exit for node in run_nodes: task = asyncio.create_task(node.cmd_p.wait(), name=f"Node-{node.name}-cmd") task.add_done_callback(node.cmd_completed) tasks.append(task) + logging.debug("Wait complete queued, waiting for ready") + # Wait for nodes to be ready if ready_nodes: @@ -2842,10 +3143,10 @@ async def wait_until_ready(x): await asyncio.sleep(0.25) logging.debug("%s is ready!", x) + tasks = [asyncio.create_task(wait_until_ready(x)) for x in ready_nodes] + logging.debug("Waiting for ready on nodes: %s", ready_nodes) - _, pending = await asyncio.wait( - [wait_until_ready(x) for x in ready_nodes], timeout=30 - ) + _, pending = await asyncio.wait(tasks, timeout=30) if pending: logging.warning("Timeout waiting for ready: %s", pending) for nr in pending: @@ -2853,6 +3154,8 @@ async def wait_until_ready(x): raise asyncio.TimeoutError() logging.debug("All nodes ready") + logging.debug("All done returning tasks: %s", tasks) + return tasks async def _async_delete(self): @@ -2860,15 +3163,6 @@ async def _async_delete(self): self.logger.debug("%s: deleting.", self) - if self.cfgopt.getoption("--coverage"): - nodes = ( - x for x in self.hosts.values() if hasattr(x, "gather_coverage_data") - ) - try: - await asyncio.gather(*(x.gather_coverage_data() for x in nodes)) - except Exception as error: - logging.warning("Error gathering coverage data: %s", error) - pause = bool(self.cfgopt.getoption("--pause-at-end")) pause = pause or bool(self.cfgopt.getoption("--pause")) if pause: @@ -2879,6 +3173,25 @@ async def _async_delete(self): except Exception as error: self.logger.error("\n...continuing after error: %s", error) + # Run cleanup-cmd's. + nodes = (x for x in self.hosts.values() if x.has_cleanup_cmd()) + try: + await asyncio.gather(*(x.async_cleanup_cmd() for x in nodes)) + except Exception as error: + logging.warning("Error running cleanup cmds: %s", error) + + # Gather any coverage data + if self.cfgopt.getoption("--coverage"): + nodes = ( + x for x in self.hosts.values() if hasattr(x, "gather_coverage_data") + ) + try: + await asyncio.gather(*(x.gather_coverage_data() for x in nodes)) + except Exception as error: + logging.warning("Error gathering coverage data: %s", error) + + await self.coverage_finish() + # XXX should we cancel launch and run tasks? try: diff --git a/tests/topotests/munet/parser.py b/tests/topotests/munet/parser.py index 4fc0c75a60ed..a8b73a25e7eb 100644 --- a/tests/topotests/munet/parser.py +++ b/tests/topotests/munet/parser.py @@ -230,7 +230,7 @@ def load_kinds(args, search=None): if args: os.chdir(args.rundir) - args_config = args.kinds_config if args else None + args_config = args.kinds_config if args and hasattr(args, "kinds_config") else None try: if search is None: search = [cwd] @@ -305,7 +305,7 @@ async def async_build_topology( # create search directories from common root if given cpath = Path(config["config_pathname"]).absolute() - project_root = args.project_root if args else None + project_root = args.project_root if args and hasattr(args, "project_root") else None if not search_root: search_root = find_project_root(cpath, project_root) if not search_root: @@ -341,7 +341,11 @@ async def async_build_topology( pytestconfig=pytestconfig, isolated=isolated, pid=top_level_pidns, - unshare_inline=args.unshare_inline if args else unshare_inline, + unshare_inline=( + args.unshare_inline + if args and hasattr(args, "unshare_inline") + else unshare_inline + ), logger=logger, ) diff --git a/tests/topotests/munet/testing/fixtures.py b/tests/topotests/munet/testing/fixtures.py index 25039df5418a..3c6ddf9aedef 100644 --- a/tests/topotests/munet/testing/fixtures.py +++ b/tests/topotests/munet/testing/fixtures.py @@ -25,7 +25,6 @@ from ..base import Bridge from ..base import get_event_loop from ..cleanup import cleanup_current -from ..cleanup import cleanup_previous from ..native import L3NodeMixin from ..parser import async_build_topology from ..parser import get_config @@ -95,7 +94,7 @@ def _push_log_handler(desc, logpath): logging.debug("conftest: adding %s logging at %s", desc, logpath) root_logger = logging.getLogger() handler = logging.FileHandler(logpath, mode="w") - fmt = logging.Formatter("%(asctime)s %(levelname)5s: %(message)s") + fmt = logging.Formatter("%(asctime)s %(levelname)5s: %(name)s: %(message)s") handler.setFormatter(fmt) root_logger.addHandler(handler) return handler @@ -130,9 +129,12 @@ def session_autouse(): else: is_worker = True - if not is_worker: - # This is unfriendly to multi-instance - cleanup_previous() + # We dont want to kill all munet and we don't have the rundir here yet + # This was more useful back when we used to leave processes around a lot + # more. + # if not is_worker: + # # This is unfriendly to multi-instance + # cleanup_previous() # We never pop as we want to keep logging _push_log_handler("session", "/tmp/unet-test/pytest-session.log") @@ -150,8 +152,9 @@ def session_autouse(): @pytest.fixture(autouse=True, scope="module") def module_autouse(request): - logpath = get_test_logdir(request.node.name, True) - logpath = os.path.join("/tmp/unet-test", logpath, "pytest-exec.log") + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + logpath = get_test_logdir(request.node.nodeid, True) + logpath = os.path.join(root_path, logpath, "pytest-exec.log") with log_handler("module", logpath): sdir = os.path.dirname(os.path.realpath(request.fspath)) with chdir(sdir, "module autouse fixture"): @@ -161,7 +164,7 @@ def module_autouse(request): raise Exception("Base Munet was not cleaned up/deleted") -@pytest.fixture(scope="module") +@pytest.fixture(scope="session") def event_loop(): """Create an instance of the default event loop for the session.""" loop = get_event_loop() @@ -174,7 +177,8 @@ def event_loop(): @pytest.fixture(scope="module") def rundir_module(): - d = os.path.join("/tmp/unet-test", get_test_logdir(module=True)) + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + d = os.path.join(root_path, get_test_logdir(module=True)) logging.debug("conftest: test module rundir %s", d) return d @@ -213,18 +217,14 @@ async def _unet_impl( param, exc_info=True, ) - pytest.skip( - f"unet fixture: unet build failed: {error}", allow_module_level=True - ) - raise + pytest.fail(f"unet fixture: unet build failed: {error}") try: tasks = await _unet.run() except Exception as error: logging.debug("unet fixture: unet run failed: %s", error, exc_info=True) await _unet.async_delete() - pytest.skip(f"unet fixture: unet run failed: {error}", allow_module_level=True) - raise + pytest.fail(f"unet fixture: unet run failed: {error}") logging.debug("unet fixture: containers running") @@ -379,7 +379,8 @@ async def stepfunction(desc=""): @pytest.fixture(scope="function") def rundir(): - d = os.path.join("/tmp/unet-test", get_test_logdir(module=False)) + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + d = os.path.join(root_path, get_test_logdir(module=False)) logging.debug("conftest: test function rundir %s", d) return d @@ -387,9 +388,8 @@ def rundir(): # Configure logging @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_setup(item): - d = os.path.join( - "/tmp/unet-test", get_test_logdir(nodeid=item.nodeid, module=False) - ) + root_path = os.environ.get("MUNET_RUNDIR", "/tmp/unet-test") + d = os.path.join(root_path, get_test_logdir(nodeid=item.nodeid, module=False)) config = item.config logging_plugin = config.pluginmanager.get_plugin("logging-plugin") filename = Path(d, "pytest-exec.log") diff --git a/tests/topotests/munet/testing/hooks.py b/tests/topotests/munet/testing/hooks.py index 9b6a49a18ce0..f6f211536734 100644 --- a/tests/topotests/munet/testing/hooks.py +++ b/tests/topotests/munet/testing/hooks.py @@ -18,6 +18,7 @@ import pytest +from ..args import add_testing_args from ..base import BaseMunet # pylint: disable=import-error from ..cli import cli # pylint: disable=import-error from .util import pause_test @@ -29,85 +30,7 @@ def pytest_addoption(parser): - parser.addoption( - "--cli-on-error", - action="store_true", - help="CLI on test failure", - ) - - parser.addoption( - "--coverage", - action="store_true", - help="Enable coverage gathering if supported", - ) - - parser.addoption( - "--gdb", - default="", - metavar="HOST[,HOST...]", - help="Comma-separated list of nodes to launch gdb on, or 'all'", - ) - parser.addoption( - "--gdb-breakpoints", - default="", - metavar="BREAKPOINT[,BREAKPOINT...]", - help="Comma-separated list of breakpoints", - ) - parser.addoption( - "--gdb-use-emacs", - action="store_true", - help="Use emacsclient to run gdb instead of a shell", - ) - - parser.addoption( - "--pcap", - default="", - metavar="NET[,NET...]", - help="Comma-separated list of networks to capture packets on, or 'all'", - ) - - parser.addoption( - "--pause", - action="store_true", - help="Pause after each test", - ) - parser.addoption( - "--pause-at-end", - action="store_true", - help="Pause before taking munet down", - ) - parser.addoption( - "--pause-on-error", - action="store_true", - help="Pause after (disables default when --shell or -vtysh given)", - ) - parser.addoption( - "--no-pause-on-error", - dest="pause_on_error", - action="store_false", - help="Do not pause after (disables default when --shell or -vtysh given)", - ) - - parser.addoption( - "--shell", - default="", - metavar="NODE[,NODE...]", - help="Comma-separated list of nodes to spawn shell on, or 'all'", - ) - - parser.addoption( - "--stdout", - default="", - metavar="NODE[,NODE...]", - help="Comma-separated list of nodes to open tail-f stdout window on, or 'all'", - ) - - parser.addoption( - "--stderr", - default="", - metavar="NODE[,NODE...]", - help="Comma-separated list of nodes to open tail-f stderr window on, or 'all'", - ) + add_testing_args(parser.addoption) def pytest_configure(config): @@ -146,6 +69,18 @@ def pytest_configure(config): elif b and not is_xdist and not have_windows: pytest.exit(f"{winopt} use requires byobu/TMUX/SCREEN/XTerm") + cli_pause = ( + config.getoption("--cli-on-error") + or config.getoption("--pause") + or config.getoption("--pause-at-end") + or config.getoption("--pause-on-error") + ) + if config.getoption("--capture") == "fd" and cli_pause: + pytest.exit( + "CLI is not compatible with `--capture=fd`, " + "please run again with `-s` or other `--capture` value" + ) + def pytest_runtest_makereport(item, call): """Pause or invoke CLI as directed by config.""" @@ -196,10 +131,10 @@ def pytest_runtest_makereport(item, call): if error: item.skip_more_pause = True - # we can't asyncio.run() (which pause does) if we are unhsare_inline + # we can't asyncio.run() (which pause does) if we are not unhsare_inline # at this point, count on an autouse fixture to pause instead in this # case - if not BaseMunet.g_unet or not BaseMunet.g_unet.unshare_inline: + if BaseMunet.g_unet and BaseMunet.g_unet.unshare_inline: pause_test(f"before test '{item.nodeid}'") # check for a result to try and catch setup (or module setup) failure diff --git a/tests/topotests/munet/watchlog.py b/tests/topotests/munet/watchlog.py new file mode 100644 index 000000000000..27bc3251a679 --- /dev/null +++ b/tests/topotests/munet/watchlog.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: GPL-2.0-or-later +# +# August 21 2023, Christian Hopps +# +# Copyright (c) 2023, LabN Consulting, L.L.C. +# +"""A module supporting an object for watching a logfile.""" +import asyncio +import logging +import re + +from pathlib import Path + + +class MatchFoundError(Exception): + """An error raised when a match is not found.""" + def __init__(self, watchlog, match): + self.watchlog = watchlog + self.match = match + super().__init__(watchlog, match) + + +class WatchLog: + """An object for watching a logfile.""" + + def __init__(self, path, encoding="utf-8"): + """Watch a logfile. + + Args: + path: that path of the logfile to watch + encoding: the encoding of the logfile + """ + # Immutable + self.path = Path(path) + self.encoding = encoding + + # Mutable + self.content = "" + self.last_snap_mark = 0 + self.last_user_mark = 0 + self.stat = None + + if self.path.exists(): + self.snapshot() + + def _stat_snapshot(self): + ostat = self.stat + + if not self.path.exists(): + self.stat = None + return ostat is not None + + stat = self.path.stat() + self.stat = stat + + if ostat is None: + return True + + return ( + stat.st_mtime_ns != ostat.st_mtime_ns + or stat.st_ctime_ns != ostat.st_ctime_ns + or stat.st_ino != ostat.st_ino + or stat.st_size != ostat.st_size + ) + + def reset(self): + self.content = "" + self.last_user_mark = 0 + self.last_snap_mark = 0 + + def update_content(self): + ostat = self.stat + osize = ostat.st_size if ostat else 0 + oino = ostat.st_ino if ostat else -1 + if not self._stat_snapshot(): + logging.debug("XXX logfile %s no stat change", self.path) + return "" + + nino = self.stat.st_ino + # If the inode changed and we had content previously warn + if oino != -1 and oino != nino and self.content: + logging.warning( + "logfile %s replaced (new inode) resetting content", self.path + ) + self.reset() + osize = 0 + + nsize = self.stat.st_size + if osize > nsize: + logging.warning("logfile %s shrunk resetting content", self.path) + self.reset() + osize = 0 + + if osize == nsize: + logging.debug( + "XXX watchlog: %s no update, osize == nsize == %s", self.path, osize + ) + return "" + + # Read non-blocking + with open(self.path, "r", encoding=self.encoding) as f: + if osize: + f.seek(osize) + logging.debug( + "XXX watchlog: %s reading new content from %s to %s", + self.path, + osize, + nsize, + ) + newcontent = f.read(nsize - osize) + + self.content += newcontent + return newcontent + + def raise_if_match_task(self, match): + """Start an async task that searches for a match. + + This doesn't work well with pytest as the task must be awaited for the exception + to propagate. + """ + + async def scan_for_match(wl, regex): + while True: + logging.debug("watchlog: %s scan for updating content", wl.path) + wl.update_content() + if m := regex.search(wl.content): + logging.error( + "XXX watchlog: %s regexp FOUND raising exception!", wl.path + ) + raise MatchFoundError(wl, m) + await asyncio.sleep(2) + + aw = scan_for_match(self, re.compile(match)) + return asyncio.create_task(aw) + + def from_mark(self, mark=None): + """Return the file content starting from ``mark``. + + If ``mark`` is None then return content since last ``set_mark`` was called. + + Args: + mark: the mark in the content to return file content from. + + Return: + returns the content between ``mark`` and the end of content. + """ + return self.content[mark:] + + def set_mark(self): + """Set a mark for later use.""" + last_mark = self.last_user_mark + self.last_user_mark = len(self.content) + return last_mark + + def snapshot(self): + """Update the file content and return new text. + + Returns any new text added since the last snapshot, + also updates the snapshot mark. + + Return: + Newly added text. + """ + # Update the content which may reset marks + self.update_content() + + last_mark = self.last_snap_mark + self.last_snap_mark = len(self.content) + return self.content[last_mark:] diff --git a/tests/topotests/nb_config/r1/frr.conf b/tests/topotests/nb_config/r1/frr.conf new file mode 100644 index 000000000000..677ec0b86d55 --- /dev/null +++ b/tests/topotests/nb_config/r1/frr.conf @@ -0,0 +1,6 @@ +log timestamp precision 6 +log file frr.log + +interface r1-eth0 + ip address 1.1.1.1/24 +exit diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py new file mode 100644 index 000000000000..09d6407d5b07 --- /dev/null +++ b/tests/topotests/nb_config/test_nb_config.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# February 24 2024, Christian Hopps +# +# Copyright (c) 2024, LabN Consulting, L.L.C. +# +""" +Test Northbound Config Operations +""" +import json +import os + +import pytest +from lib.topogen import Topogen +from lib.topotest import json_cmp + +pytestmark = [pytest.mark.mgmtd] + +CWD = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for _, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_access_list_config_ordering(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + output = r1.vtysh_multicmd( + ["conf t", "access-list test seq 1 permit host 10.0.0.1"] + ) + output = r1.vtysh_cmd("show ip access-list test json") + got = json.loads(output) + expected = json.loads( + '{"zebra":{"test":{"type":"Standard", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "address":"10.0.0.1", "mask":"0.0.0.0"}]}}}' + ) + result = json_cmp(got, expected) + assert result is None + + # + # If the northbound mis-orders the create/delete then this test fails. + # https://github.com/FRRouting/frr/pull/15423/commits/38b85e0c2bc555b8827dbd2cb6515b6febf548b4 + # + output = r1.vtysh_multicmd(["conf t", "access-list test seq 1 permit 10.0.0.0/8"]) + output = r1.vtysh_cmd("show ip access-list test json") + got = json.loads(output) + expected = json.loads( + '{"zebra":{"test":{"type":"Zebra", "addressFamily":"IPv4", "rules":[{"sequenceNumber":1, "filterType":"permit", "prefix":"10.0.0.0/8", "exact-match":false}]}}}' + ) + result = json_cmp(got, expected) + assert result is None diff --git a/tests/topotests/nhrp_redundancy/r1/nhrp_cache.json b/tests/topotests/nhrp_redundancy/r1/nhrp_cache.json new file mode 100644 index 000000000000..a94dd9fecfb1 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r1/nhrp_cache.json @@ -0,0 +1,40 @@ +{ + "attr": { + "entriesCount": 3 + }, + "table": [ + { + "interface": "r1-gre0", + "type": "dynamic", + "protocol": "176.16.1.4", + "nbma": "192.168.2.4", + "claimed_nbma": "192.168.2.4", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r1-gre0", + "type": "local", + "protocol": "176.16.1.1", + "nbma": "192.168.1.1", + "claimed_nbma": "192.168.1.1", + "used": false, + "timeout": false, + "auth": false, + "identity": "-" + }, + { + "interface": "r1-gre0", + "type": "dynamic", + "protocol": "176.16.1.5", + "nbma": "192.168.2.5", + "claimed_nbma": "192.168.2.5", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r1/nhrp_route.json b/tests/topotests/nhrp_redundancy/r1/nhrp_route.json new file mode 100644 index 000000000000..b5f3e29e7418 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r1/nhrp_route.json @@ -0,0 +1,48 @@ +{ + "176.16.1.4\/32": [ + { + "prefix": "176.16.1.4\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r1-gre0", + "active": true + } + ] + } + ], + "176.16.1.5\/32": [ + { + "prefix": "176.16.1.5\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r1-gre0", + "active": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r1/nhrpd.conf b/tests/topotests/nhrp_redundancy/r1/nhrpd.conf new file mode 100644 index 000000000000..ad48ce3769a7 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r1/nhrpd.conf @@ -0,0 +1,9 @@ +!debug nhrp all +nhrp nflog-group 1 +interface r1-gre0 + ip nhrp holdtime 10 + ip nhrp network-id 42 + ip nhrp registration no-unique + ip nhrp redirect + tunnel source r1-eth0 +exit diff --git a/tests/topotests/nhrp_redundancy/r1/zebra.conf b/tests/topotests/nhrp_redundancy/r1/zebra.conf new file mode 100644 index 000000000000..0f11563f575d --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r1/zebra.conf @@ -0,0 +1,12 @@ +ip forwarding +interface r1-eth0 + ip address 192.168.1.1/24 +! +ip route 192.168.2.0/24 192.168.1.6 +interface r1-gre0 + ip address 176.16.1.1/32 + no link-detect + ipv6 nd suppress-ra +! +ip route 4.4.4.0/24 176.16.1.4 +ip route 5.5.5.0/24 176.16.1.5 diff --git a/tests/topotests/nhrp_redundancy/r2/nhrp_cache.json b/tests/topotests/nhrp_redundancy/r2/nhrp_cache.json new file mode 100644 index 000000000000..91557a191826 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r2/nhrp_cache.json @@ -0,0 +1,40 @@ +{ + "attr": { + "entriesCount": 3 + }, + "table": [ + { + "interface": "r2-gre0", + "type": "local", + "protocol": "176.16.1.2", + "nbma": "192.168.1.2", + "claimed_nbma": "192.168.1.2", + "used": false, + "timeout": false, + "auth": false, + "identity": "-" + }, + { + "interface": "r2-gre0", + "type": "dynamic", + "protocol": "176.16.1.4", + "nbma": "192.168.2.4", + "claimed_nbma": "192.168.2.4", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r2-gre0", + "type": "dynamic", + "protocol": "176.16.1.5", + "nbma": "192.168.2.5", + "claimed_nbma": "192.168.2.5", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r2/nhrp_route.json b/tests/topotests/nhrp_redundancy/r2/nhrp_route.json new file mode 100644 index 000000000000..f1fa6e54c1bc --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r2/nhrp_route.json @@ -0,0 +1,48 @@ +{ + "176.16.1.4\/32": [ + { + "prefix": "176.16.1.4\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r2-gre0", + "active": true + } + ] + } + ], + "176.16.1.5\/32": [ + { + "prefix": "176.16.1.5\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r2-gre0", + "active": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r2/nhrpd.conf b/tests/topotests/nhrp_redundancy/r2/nhrpd.conf new file mode 100644 index 000000000000..4d63f07d1f71 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r2/nhrpd.conf @@ -0,0 +1,9 @@ +!debug nhrp all +nhrp nflog-group 1 +interface r2-gre0 + ip nhrp holdtime 10 + ip nhrp network-id 42 + ip nhrp registration no-unique + ip nhrp redirect + tunnel source r2-eth0 +exit diff --git a/tests/topotests/nhrp_redundancy/r2/zebra.conf b/tests/topotests/nhrp_redundancy/r2/zebra.conf new file mode 100644 index 000000000000..1a9c4ff91544 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r2/zebra.conf @@ -0,0 +1,12 @@ +ip forwarding +interface r2-eth0 + ip address 192.168.1.2/24 +! +ip route 192.168.2.0/24 192.168.1.6 +interface r2-gre0 + ip address 176.16.1.2/32 + no link-detect + ipv6 nd suppress-ra +! +ip route 4.4.4.0/24 176.16.1.4 +ip route 5.5.5.0/24 176.16.1.5 diff --git a/tests/topotests/nhrp_redundancy/r3/nhrp_cache.json b/tests/topotests/nhrp_redundancy/r3/nhrp_cache.json new file mode 100644 index 000000000000..ef3ab690bc5b --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r3/nhrp_cache.json @@ -0,0 +1,40 @@ +{ + "attr": { + "entriesCount": 3 + }, + "table": [ + { + "interface": "r3-gre0", + "type": "dynamic", + "protocol": "176.16.1.4", + "nbma": "192.168.2.4", + "claimed_nbma": "192.168.2.4", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r3-gre0", + "type": "local", + "protocol": "176.16.1.3", + "nbma": "192.168.1.3", + "claimed_nbma": "192.168.1.3", + "used": false, + "timeout": false, + "auth": false, + "identity": "-" + }, + { + "interface": "r3-gre0", + "type": "dynamic", + "protocol": "176.16.1.5", + "nbma": "192.168.2.5", + "claimed_nbma": "192.168.2.5", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r3/nhrp_route.json b/tests/topotests/nhrp_redundancy/r3/nhrp_route.json new file mode 100644 index 000000000000..3d548c08fdce --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r3/nhrp_route.json @@ -0,0 +1,48 @@ +{ + "176.16.1.4\/32": [ + { + "prefix": "176.16.1.4\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r3-gre0", + "active": true + } + ] + } + ], + "176.16.1.5\/32": [ + { + "prefix": "176.16.1.5\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r3-gre0", + "active": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r3/nhrpd.conf b/tests/topotests/nhrp_redundancy/r3/nhrpd.conf new file mode 100644 index 000000000000..87cc2161f8bf --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r3/nhrpd.conf @@ -0,0 +1,9 @@ +!debug nhrp all +nhrp nflog-group 1 +interface r3-gre0 + ip nhrp holdtime 10 + ip nhrp network-id 42 + ip nhrp registration no-unique + ip nhrp redirect + tunnel source r3-eth0 +exit diff --git a/tests/topotests/nhrp_redundancy/r3/zebra.conf b/tests/topotests/nhrp_redundancy/r3/zebra.conf new file mode 100644 index 000000000000..980cfbcaab7d --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r3/zebra.conf @@ -0,0 +1,12 @@ +ip forwarding +interface r3-eth0 + ip address 192.168.1.3/24 +! +ip route 192.168.2.0/24 192.168.1.6 +interface r3-gre0 + ip address 176.16.1.3/32 + no link-detect + ipv6 nd suppress-ra +! +ip route 4.4.4.0/24 176.16.1.4 +ip route 5.5.5.0/24 176.16.1.5 \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r4/nhrp_cache.json b/tests/topotests/nhrp_redundancy/r4/nhrp_cache.json new file mode 100644 index 000000000000..f87ebcf5fc7e --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r4/nhrp_cache.json @@ -0,0 +1,51 @@ +{ + "attr": { + "entriesCount": 4 + }, + "table": [ + { + "interface": "r4-gre0", + "type": "nhs", + "protocol": "176.16.1.2", + "nbma": "192.168.1.2", + "claimed_nbma": "192.168.1.2", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r4-gre0", + "type": "local", + "protocol": "176.16.1.4", + "nbma": "192.168.2.4", + "claimed_nbma": "192.168.2.4", + "used": false, + "timeout": false, + "auth": false, + "identity": "-" + }, + { + "interface": "r4-gre0", + "type": "nhs", + "protocol": "176.16.1.3", + "nbma": "192.168.1.3", + "claimed_nbma": "192.168.1.3", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r4-gre0", + "type": "nhs", + "protocol": "176.16.1.1", + "nbma": "192.168.1.1", + "claimed_nbma": "192.168.1.1", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r4/nhrp_route.json b/tests/topotests/nhrp_redundancy/r4/nhrp_route.json new file mode 100644 index 000000000000..4f1faee7a744 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r4/nhrp_route.json @@ -0,0 +1,71 @@ +{ + "176.16.1.1\/32": [ + { + "prefix": "176.16.1.1\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ], + "176.16.1.2\/32": [ + { + "prefix": "176.16.1.2\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ], + "176.16.1.3\/32": [ + { + "prefix": "176.16.1.3\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r4/nhrp_route_shortcut.json b/tests/topotests/nhrp_redundancy/r4/nhrp_route_shortcut.json new file mode 100644 index 000000000000..f8efff2059e4 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r4/nhrp_route_shortcut.json @@ -0,0 +1,118 @@ +{ + "5.5.5.5\/32": [ + { + "prefix": "5.5.5.5\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "ip": "176.16.1.5", + "afi": "ipv4", + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ], + "176.16.1.1\/32": [ + { + "prefix": "176.16.1.1\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ], + "176.16.1.2\/32": [ + { + "prefix": "176.16.1.2\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ], + "176.16.1.3\/32": [ + { + "prefix": "176.16.1.3\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ], + "176.16.1.5\/32": [ + { + "prefix": "176.16.1.5\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r4-gre0", + "active": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r4/nhrpd.conf b/tests/topotests/nhrp_redundancy/r4/nhrpd.conf new file mode 100644 index 000000000000..8a52f3386e89 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r4/nhrpd.conf @@ -0,0 +1,11 @@ +!debug nhrp all +interface r4-gre0 + ip nhrp holdtime 10 + ip nhrp network-id 42 + ip nhrp registration no-unique + ip nhrp nhs dynamic nbma 192.168.1.1 + ip nhrp nhs dynamic nbma 192.168.1.2 + ip nhrp nhs dynamic nbma 192.168.1.3 + ip nhrp shortcut + tunnel source r4-eth0 +exit diff --git a/tests/topotests/nhrp_redundancy/r4/zebra.conf b/tests/topotests/nhrp_redundancy/r4/zebra.conf new file mode 100644 index 000000000000..e4a9a6f80f74 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r4/zebra.conf @@ -0,0 +1,16 @@ +ip forwarding +interface r4-eth0 + ip address 192.168.2.4/24 +! +ip route 192.168.1.0/24 192.168.2.6 +interface r4-gre0 + ip address 176.16.1.4/32 + no link-detect + ipv6 nd suppress-ra +! +interface r4-eth1 + ip address 4.4.4.4/24 +! +ip route 0.0.0.0/0 176.16.1.1 50 +ip route 0.0.0.0/0 176.16.1.2 60 +ip route 0.0.0.0/0 176.16.1.3 70 \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r5/nhrp_cache.json b/tests/topotests/nhrp_redundancy/r5/nhrp_cache.json new file mode 100644 index 000000000000..bc041c601475 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r5/nhrp_cache.json @@ -0,0 +1,51 @@ +{ + "attr": { + "entriesCount": 4 + }, + "table": [ + { + "interface": "r5-gre0", + "type": "nhs", + "protocol": "176.16.1.2", + "nbma": "192.168.1.2", + "claimed_nbma": "192.168.1.2", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r5-gre0", + "type": "nhs", + "protocol": "176.16.1.3", + "nbma": "192.168.1.3", + "claimed_nbma": "192.168.1.3", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r5-gre0", + "type": "nhs", + "protocol": "176.16.1.1", + "nbma": "192.168.1.1", + "claimed_nbma": "192.168.1.1", + "used": false, + "timeout": true, + "auth": false, + "identity": "" + }, + { + "interface": "r5-gre0", + "type": "local", + "protocol": "176.16.1.5", + "nbma": "192.168.2.5", + "claimed_nbma": "192.168.2.5", + "used": false, + "timeout": false, + "auth": false, + "identity": "-" + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r5/nhrp_route.json b/tests/topotests/nhrp_redundancy/r5/nhrp_route.json new file mode 100644 index 000000000000..1d1c16ffb86b --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r5/nhrp_route.json @@ -0,0 +1,71 @@ +{ + "176.16.1.1\/32": [ + { + "prefix": "176.16.1.1\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r5-gre0", + "active": true + } + ] + } + ], + "176.16.1.2\/32": [ + { + "prefix": "176.16.1.2\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r5-gre0", + "active": true + } + ] + } + ], + "176.16.1.3\/32": [ + { + "prefix": "176.16.1.3\/32", + "protocol": "nhrp", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 10, + "metric": 0, + "installed": true, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1, + "nexthops": [ + { + "fib": true, + "directlyConnected": true, + "interfaceName": "r5-gre0", + "active": true + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/topotests/nhrp_redundancy/r5/nhrpd.conf b/tests/topotests/nhrp_redundancy/r5/nhrpd.conf new file mode 100644 index 000000000000..7241ed592da8 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r5/nhrpd.conf @@ -0,0 +1,11 @@ +!debug nhrp all +interface r5-gre0 + ip nhrp holdtime 10 + ip nhrp network-id 42 + ip nhrp nhs dynamic nbma 192.168.1.1 + ip nhrp nhs dynamic nbma 192.168.1.2 + ip nhrp nhs dynamic nbma 192.168.1.3 + ip nhrp registration no-unique + ip nhrp shortcut + tunnel source r5-eth0 +exit diff --git a/tests/topotests/nhrp_redundancy/r5/zebra.conf b/tests/topotests/nhrp_redundancy/r5/zebra.conf new file mode 100644 index 000000000000..9b1e1c0646e3 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r5/zebra.conf @@ -0,0 +1,16 @@ +ip forwarding +interface r5-eth0 + ip address 192.168.2.5/24 +! +ip route 192.168.1.0/24 192.168.2.6 +interface r5-gre0 + ip address 176.16.1.5/32 + no link-detect + ipv6 nd suppress-ra +! +interface r5-eth1 + ip address 5.5.5.5/24 +! +ip route 0.0.0.0/0 176.16.1.1 50 +ip route 0.0.0.0/0 176.16.1.2 60 +ip route 0.0.0.0/0 176.16.1.3 70 diff --git a/tests/topotests/nhrp_redundancy/r6/zebra.conf b/tests/topotests/nhrp_redundancy/r6/zebra.conf new file mode 100644 index 000000000000..63a37cd5bf38 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r6/zebra.conf @@ -0,0 +1,7 @@ +ip forwarding +interface r6-eth0 + ip address 192.168.1.6/24 +! +interface r6-eth1 + ip address 192.168.2.6/24 +exit diff --git a/tests/topotests/nhrp_redundancy/r7/zebra.conf b/tests/topotests/nhrp_redundancy/r7/zebra.conf new file mode 100644 index 000000000000..5747b409561e --- /dev/null +++ b/tests/topotests/nhrp_redundancy/r7/zebra.conf @@ -0,0 +1,4 @@ +interface r7-eth0 + ip address 4.4.4.7/24 +! +ip route 0.0.0.0/0 4.4.4.4 diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot new file mode 100644 index 000000000000..c169436db04f --- /dev/null +++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.dot @@ -0,0 +1,103 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="nhrp-topo-redundant-nhs"; + + # Routers + r1 [ + shape=doubleoctagon, + label="NHS 1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="NHS 2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="NHS 3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon + label="NHC 1", + fillcolor="#f08080", + style=filled, + ]; + r5 [ + shape=doubleoctagon + label="NHC 2", + fillcolor="#f08080", + style=filled, + ]; + r6 [ + shape=doubleoctagon + label="router", + fillcolor="#f08080", + style=filled, + ]; + r7 [ + shape=doubleoctagon + label="host", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n192.168.1.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n192.168.2.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n4.4.4.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + sw4 [ + shape=oval, + label="sw4\n5.5.5.0/24", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + r1 -- sw1 [label="eth0"]; + r2 -- sw1 [label="eth0"]; + r3 -- sw1 [label="eth0"]; + r6 -- sw1 [label="eth0"]; + + r4 -- sw2 [label="eth0"]; + r5 -- sw2 [label="eth0"]; + r6 -- sw2 [label="eth1"]; + + r4 -- sw3 [label="eth1"]; + r7 -- sw3 [label="eth0"]; + + r5 -- sw4 [label="eth1"]; + +} diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py new file mode 100644 index 000000000000..ffd9abc9d471 --- /dev/null +++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py @@ -0,0 +1,422 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0-or-later +# +# test_nhrp_redundancy.py +# +# Copyright 2024, LabN Consulting, L.L.C. +# Dave LeRoy +# + +import os +import sys +import json +from functools import partial +import pytest + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from lib.common_config import ( + required_linux_kernel_version, + shutdown_bringup_interface, + retry, +) + +""" +test_nhrp_redundancy.py: Test NHS redundancy for NHRP +""" + +TOPOLOGY = """ ++------------+ +------------+ +------------+ +| | | | | | +| | | | | | +| NHS 1 | | NHS 2 | | NHS 3 | +| | | | | | ++-----+------+ +-----+------+ +-----+------+ + |.1 |.2 |.3 + | | | + | | 192.168.1.0/24 | +------+-------------------------------+------------------+-------------+------ + | + |.6 + GRE P2MP between all NHS and NHC +-----+------+ + 172.16.1.x/32 | | + | | + | Router | + | | + +-----+------+ + | + | + ---------+----------------+-------------+------ + | 192.168.2.0/24 | + | | + | |.4 |.5 ++------------+ | +-------+----+ +------+-----+ | +| | | | | | | | +| | +--------+ | | | | +| Host |.7 | | NHC 1 | | NHC 2 +-----+5.5.5.0/24 +| +---------+ | | | | | ++------------+ | +------------+ +------------+ | + | | + 4.4.4.0/24 +""" + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.nhrpd] + + +def build_topo(tgen): + "Build function" + + # Create 7 routers + for routern in range(1, 8): + tgen.add_router("r{}".format(routern)) + + # Interconnect routers 1, 2, 3, 6 + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r6"]) + + # Interconnect routers 4, 5, 6 + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + switch.add_link(tgen.gears["r6"]) + + # Connect router 4, 7 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r7"]) + + # Connect router 5 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r5"]) + + +def _populate_iface(): + tgen = get_topogen() + cmds_tot_hub = [ + "ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 192.168.1.{1} remote 0.0.0.0", + "ip link set dev {0}-gre0 up", + "echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu", + "echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6", + "echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6", + "iptables -A FORWARD -i {0}-gre0 -o {0}-gre0 -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 --hashlimit-mode srcip,dstip --hashlimit-srcmask 24 --hashlimit-dstmask 24 --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128", + ] + + cmds_tot = [ + "ip tunnel add {0}-gre0 mode gre ttl 64 key 42 dev {0}-eth0 local 192.168.2.{1} remote 0.0.0.0", + "ip link set dev {0}-gre0 up", + "echo 0 > /proc/sys/net/ipv4/ip_forward_use_pmtu", + "echo 1 > /proc/sys/net/ipv6/conf/{0}-eth0/disable_ipv6", + "echo 1 > /proc/sys/net/ipv6/conf/{0}-gre0/disable_ipv6", + ] + + for cmd in cmds_tot_hub: + # Router 1 + input = cmd.format("r1", "1") + logger.info("input: " + input) + output = tgen.net["r1"].cmd(input) + logger.info("output: " + output) + + # Router 2 + input = cmd.format("r2", "2") + logger.info("input: " + input) + output = tgen.net["r2"].cmd(input) + logger.info("output: " + output) + + # Router 3 + input = cmd.format("r3", "3") + logger.info("input: " + input) + output = tgen.net["r3"].cmd(input) + logger.info("output: " + output) + + for cmd in cmds_tot: + input = cmd.format("r4", "4") + logger.info("input: " + input) + output = tgen.net["r4"].cmd(input) + logger.info("output: " + output) + + input = cmd.format("r5", "5") + logger.info("input: " + input) + output = tgen.net["r5"].cmd(input) + logger.info("output: " + output) + + +def _verify_iptables(): + tgen = get_topogen() + # Verify iptables is installed. Required for shortcuts + rc, _, _ = tgen.net["r1"].cmd_status("iptables") + return False if rc == 127 else True + + +def setup_module(mod): + logger.info("NHRP Redundant NHS:\n {}".format(TOPOLOGY)) + + result = required_linux_kernel_version("5.0") + if result is not True: + pytest.skip("Kernel requirements are not met") + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # Starting Routers + router_list = tgen.routers() + _populate_iface() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, "{}/zebra.conf".format(rname)), + ) + if rname in ("r1", "r2", "r3", "r4", "r5"): + router.load_config( + TopoRouter.RD_NHRP, os.path.join(CWD, "{}/nhrpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_protocols_convergence(): + """ + Assert that all protocols have converged before checking for the NHRP + statuses as they depend on it. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Checking NHRP cache and IPv4 routes for convergence") + router_list = tgen.routers() + + # Check NHRP cache on servers and clients + for _, router in router_list.items(): + + json_file = "{}/{}/nhrp_cache.json".format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info("skipping file {}".format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip nhrp cache json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + + output = router.vtysh_cmd("show ip nhrp cache") + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + # Check NHRP IPV4 routes on servers and clients + for rname, router in router_list.items(): + + json_file = "{}/{}/nhrp_route.json".format(CWD, router.name) + if not os.path.isfile(json_file): + logger.info("skipping file {}".format(json_file)) + continue + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip route nhrp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + + output = router.vtysh_cmd("show ip route nhrp") + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + # Test connectivity from 1 NHRP server to all clients + pingrouter = tgen.gears["r1"] + logger.info("Check Ping IPv4 from R1 to R4 = 176.16.1.4)") + output = pingrouter.run("ping 176.16.1.4 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R4 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R4 OK") + + logger.info("Check Ping IPv4 from R1 to R5 = 176.16.1.5)") + output = pingrouter.run("ping 176.16.1.5 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R5 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R5 OK") + + # Test connectivity from 1 NHRP client to all servers + pingrouter = tgen.gears["r4"] + logger.info("Check Ping IPv4 from R4 to R1 = 176.16.1.1)") + output = pingrouter.run("ping 176.16.1.1 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R4 to R1 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R4 to R1 OK") + + logger.info("Check Ping IPv4 from R4 to R2 = 176.16.1.2)") + output = pingrouter.run("ping 176.16.1.2 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R4 to R2 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R4 to R2 OK") + + logger.info("Check Ping IPv4 from R4 to R3 = 176.16.1.3)") + output = pingrouter.run("ping 176.16.1.3 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R4 to R3 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R4 to R3 OK") + + +@retry(retry_timeout=30, initial_wait=5) +def verify_shortcut_path(): + """ + Verifying that traffic flows through shortcut path + """ + tgen = get_topogen() + pingrouter = tgen.gears["r7"] + logger.info("Check Ping IPv4 from R7 to R5 = 5.5.5.5") + + output = pingrouter.run("ping 5.5.5.5 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R7 to R5 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R7 to R5 OK") + + +def test_redundancy_shortcut(): + """ + Assert that if shortcut created and then NHS goes down, there is no traffic disruption + Stop traffic and verify next time traffic started, shortcut is initiated by backup NHS + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + if not _verify_iptables(): + pytest.skip("iptables not installed") + + logger.info("Testing NHRP shortcuts with redundant servers") + + # Verify R4 nhrp routes before shortcut creation + router = tgen.gears["r4"] + json_file = "{}/{}/nhrp_route.json".format(CWD, router.name) + assertmsg = "No nhrp_route file found" + assert os.path.isfile(json_file), assertmsg + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip route nhrp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + + output = router.vtysh_cmd("show ip route nhrp") + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + # Initiate shortcut by pinging between clients + pingrouter = tgen.gears["r7"] + logger.info("Check Ping IPv4 from R7 to R5 via shortcut = 5.5.5.5") + + output = pingrouter.run("ping 5.5.5.5 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R7 to R5 via shortcut should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R7 to R5 via shortcut OK") + + # Now check that NHRP shortcut route installed + json_file = "{}/{}/nhrp_route_shortcut.json".format(CWD, router.name) + assertmsg = "No nhrp_route file found" + assert os.path.isfile(json_file), assertmsg + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip route nhrp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + + output = router.vtysh_cmd("show ip route nhrp") + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + # Bring down primary GRE interface and verify shortcut is not disturbed + logger.info("Bringing down R1, primary NHRP server.") + shutdown_bringup_interface(tgen, "r1", "r1-gre0", False) + + # Verify shortcut is still active + pingrouter = tgen.gears["r7"] + logger.info("Check Ping IPv4 from R7 to R5 via shortcut = 5.5.5.5") + + output = pingrouter.run("ping 5.5.5.5 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = "expected ping IPv4 from R7 to R5 via shortcut should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R7 to R5 via shortcut OK") + + # Now verify shortcut is purged with lack of traffic + json_file = "{}/{}/nhrp_route.json".format(CWD, router.name) + assertmsg = "No nhrp_route file found" + assert os.path.isfile(json_file), assertmsg + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, router, "show ip route nhrp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + + output = router.vtysh_cmd("show ip route nhrp") + logger.info(output) + + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/nhrp_topo/r1/nhrpd.conf b/tests/topotests/nhrp_topo/r1/nhrpd.conf index e5224e4aabe9..8ade77d07de2 100644 --- a/tests/topotests/nhrp_topo/r1/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r1/nhrpd.conf @@ -1,7 +1,8 @@ log stdout debugging ! debug nhrp all interface r1-gre0 - ip nhrp holdtime 500 + ip nhrp authentication secret + ip nhrp holdtime 10 ip nhrp shortcut ip nhrp network-id 42 ip nhrp nhs dynamic nbma 10.2.1.2 diff --git a/tests/topotests/nhrp_topo/r2/nhrpd.conf b/tests/topotests/nhrp_topo/r2/nhrpd.conf index f9185f9a6398..d8e59936c865 100644 --- a/tests/topotests/nhrp_topo/r2/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r2/nhrpd.conf @@ -2,7 +2,8 @@ log stdout debugging nhrp nflog-group 1 interface r2-gre0 - ip nhrp holdtime 500 + ip nhrp authentication secret + ip nhrp holdtime 10 ip nhrp redirect ip nhrp network-id 42 ip nhrp registration no-unique diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index 78b82eda79b2..883300310773 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -28,7 +28,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version +from lib.common_config import required_linux_kernel_version, retry # Required to instantiate the topology builder class. @@ -182,6 +182,27 @@ def test_protocols_convergence(): assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg + # check that the NOARP flag is removed from rX-gre0 interfaces + for rname, router in router_list.items(): + if rname == "r3": + continue + + expected = { + "{}-gre0".format(rname): { + "flags": "", + } + } + test_func = partial( + topotest.router_json_cmp, + router, + "show interface {}-gre0 json".format(rname), + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + + assertmsg = '"{}-gre0 interface flags incorrect'.format(router.name) + assert result is None, assertmsg + for rname, router in router_list.items(): if rname == "r3": continue @@ -193,19 +214,64 @@ def test_protocols_convergence(): def test_nhrp_connection(): "Assert that the NHRP peers can find themselves." tgen = get_topogen() + pingrouter = tgen.gears["r1"] + hubrouter = tgen.gears["r2"] if tgen.routers_have_failure(): pytest.skip(tgen.errors) - pingrouter = tgen.gears["r1"] - logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2)") - output = pingrouter.run("ping 10.255.255.2 -f -c 1000") - logger.info(output) - if "1000 packets transmitted, 1000 received" not in output: - assertmsg = "expected ping IPv4 from R1 to R2 should be ok" - assert 0, assertmsg - else: - logger.info("Check Ping IPv4 from R1 to R2 OK") - + def ping_helper(): + output = pingrouter.run("ping 10.255.255.2 -f -c 100") + logger.info(output) + return output + + # force session to reinitialize + def relink_session(): + for r in ["r1", "r2"]: + tgen.gears[r].vtysh_cmd("clear ip nhrp cache") + tgen.net[r].cmd("ip l del {}-gre0".format(r)); + _populate_iface(); + + @retry(retry_timeout=40, initial_wait=5) + def verify_same_password(): + output = ping_helper() + if "100 packets transmitted, 100 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 OK") + + @retry(retry_timeout=40, initial_wait=5) + def verify_mismatched_password(): + output = ping_helper() + if "Network is unreachable" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 - should be down" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 missing - OK") + + ### Passwords are the same + logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2") + verify_same_password() + + ### Passwords are different + logger.info("Modify password and send ping again, should drop") + hubrouter.vtysh_cmd(""" + configure + interface r2-gre0 + ip nhrp authentication secret12 + """) + relink_session() + verify_mismatched_password() + + ### Passwords are the same - again + logger.info("Recover password and verify conectivity is back") + hubrouter.vtysh_cmd(""" + configure + interface r2-gre0 + ip nhrp authentication secret + """) + relink_session() + verify_same_password() def test_route_install(): "Test use of NHRP routes by other protocols (sharpd here)." diff --git a/tests/topotests/ospf6_ecmp_inter_area/r5/ospf6d.conf b/tests/topotests/ospf6_ecmp_inter_area/r5/ospf6d.conf index 2a6c9abd2e11..24cd3541184c 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/r5/ospf6d.conf +++ b/tests/topotests/ospf6_ecmp_inter_area/r5/ospf6d.conf @@ -4,31 +4,11 @@ interface r5-eth0 ipv6 ospf6 dead-interval 10 ! interface r5-eth1 - ipv6 ospf6 area 0 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 10 -! -interface r5-eth2 - ipv6 ospf6 area 0 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 10 -! -interface r5-eth3 ipv6 ospf6 area 1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! -interface r5-eth4 - ipv6 ospf6 area 1 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 10 -! -interface r5-eth5 - ipv6 ospf6 area 0 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 10 -! -interface r5-eth6 +interface r5-eth2 ipv6 ospf6 area 0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 diff --git a/tests/topotests/ospf6_ecmp_inter_area/r6/ospf6d.conf b/tests/topotests/ospf6_ecmp_inter_area/r6/ospf6d.conf index a1f48b51a5d9..4efaa318a914 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/r6/ospf6d.conf +++ b/tests/topotests/ospf6_ecmp_inter_area/r6/ospf6d.conf @@ -1,8 +1,23 @@ interface r6-eth0 + ipv6 ospf6 area 0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r6-eth1 + ipv6 ospf6 area 0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r6-eth2 ipv6 ospf6 area 1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! +interface r6-eth3 + ipv6 ospf6 area 0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! router ospf6 ospf6 router-id 10.254.254.6 redistribute connected diff --git a/tests/topotests/ospf6_ecmp_inter_area/r7/ospf6d.conf b/tests/topotests/ospf6_ecmp_inter_area/r7/ospf6d.conf index 0e49b0df6c72..9b7756e838c1 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/r7/ospf6d.conf +++ b/tests/topotests/ospf6_ecmp_inter_area/r7/ospf6d.conf @@ -1,11 +1,22 @@ -interface lo +interface r7-eth0 ipv6 ospf6 area 1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 ! -interface r7-eth0 +interface r7-eth1 ipv6 ospf6 area 1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! +interface r7-eth2 + ipv6 ospf6 area 1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r7-eth3 + shutdown +! router ospf6 ospf6 router-id 10.254.254.7 + redistribute connected ! diff --git a/tests/topotests/ospf6_ecmp_inter_area/r7/zebra.conf b/tests/topotests/ospf6_ecmp_inter_area/r7/zebra.conf index a410be8f7330..1608cad0b074 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/r7/zebra.conf +++ b/tests/topotests/ospf6_ecmp_inter_area/r7/zebra.conf @@ -3,3 +3,6 @@ ipv6 forwarding interface lo ipv6 address 2001:db8:7::1/64 ! +interface r7-eth2 + ipv6 address 2001:db8:8007::1/64 +! diff --git a/tests/topotests/ospf6_ecmp_inter_area/r8/ospf6d.conf b/tests/topotests/ospf6_ecmp_inter_area/r8/ospf6d.conf index fb5483ce9968..33c64979ca6f 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/r8/ospf6d.conf +++ b/tests/topotests/ospf6_ecmp_inter_area/r8/ospf6d.conf @@ -3,6 +3,19 @@ interface r8-eth0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! +interface r8-eth1 + ipv6 ospf6 area 0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r8-eth2 + ipv6 ospf6 area 0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r8-eth3 + shutdown +! router ospf6 ospf6 router-id 10.254.254.8 redistribute connected diff --git a/tests/topotests/ospf6_ecmp_inter_area/r8/zebra.conf b/tests/topotests/ospf6_ecmp_inter_area/r8/zebra.conf index 8e343d8f452f..e756cd4b9545 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/r8/zebra.conf +++ b/tests/topotests/ospf6_ecmp_inter_area/r8/zebra.conf @@ -3,3 +3,6 @@ ipv6 forwarding interface lo ipv6 address 2001:db8:8::1/64 ! +interface r8-eth2 + ipv6 address 2001:db8:8008::1/64 +! diff --git a/tests/topotests/ospf6_ecmp_inter_area/r9/ospf6d.conf b/tests/topotests/ospf6_ecmp_inter_area/r9/ospf6d.conf deleted file mode 100644 index 57fa8e32ee9f..000000000000 --- a/tests/topotests/ospf6_ecmp_inter_area/r9/ospf6d.conf +++ /dev/null @@ -1,11 +0,0 @@ -interface lo - ipv6 ospf6 area 0 -! -interface r9-eth0 - ipv6 ospf6 area 0 - ipv6 ospf6 hello-interval 2 - ipv6 ospf6 dead-interval 10 -! -router ospf6 - ospf6 router-id 10.254.254.9 -! diff --git a/tests/topotests/ospf6_ecmp_inter_area/r9/zebra.conf b/tests/topotests/ospf6_ecmp_inter_area/r9/zebra.conf deleted file mode 100644 index e267496a9854..000000000000 --- a/tests/topotests/ospf6_ecmp_inter_area/r9/zebra.conf +++ /dev/null @@ -1,5 +0,0 @@ -ipv6 forwarding -! -interface lo - ipv6 address 2001:db8:9::1/64 -! diff --git a/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py b/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py index ec15ff9b1a37..adf289e2de20 100644 --- a/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py +++ b/tests/topotests/ospf6_ecmp_inter_area/test_ospf6_ecmp_inter_area.py @@ -3,7 +3,7 @@ # test_ospf6_ecmp_inter_area.py # -# Copyright (c) 2021, 2022 by Martin Buck +# Copyright (c) 2021, 2022, 2024 by Martin Buck # Copyright (c) 2016 by # Network Device Education Foundation, Inc. ("NetDEF") # @@ -11,35 +11,42 @@ r""" test_ospf6_ecmp_inter_area.py: Test OSPFv3 ECMP inter-area nexthop update -Check proper removal of ECMP nexthops after a path used by one nexthop -disappears. We remove a path by bringing down a link required by that -path which is not adjacent to the router being checked. This is important -because when bringing down adjacent links, the kernel might remove the -nexthops itself without ospf6d having to do anything. +Check proper addition and removal of ECMP nexthops in 2 cases: Parallel +paths to one ABR and parallel ABRs. We test nexthop removal triggered by +path removal by bringing down a link required by that path which is not +adjacent to the router being checked. This is important because when +bringing down adjacent links, the kernel might remove the nexthops itself +without ospf6d having to do anything. -Useful as a regression test for #9720. +Useful as a regression test for #9720 and #15777. Topology: - . - Area 0 . Area 1 - . - -- R2 -- . ---- R6 - / \ ./ -R1 -- R3 -- R5 ---- R7 Area 1 - \ / \\ .............. - -- R4 -- \--- R8 Area 0 - \ - -- R9 - -We check routes on R1, primarily those towards R6/7/8/9. Those to R6/7 are -inter-area routes with R5 being ABR, those to R8/9 are intra-area routes -and are used for reference. R6/R8 announce external routes, R7/R9 announce -internal routes. + . + Area 0 . Area 1 + . + -- R2 ------ R5 ----- + / .\ \ + / . | \ +R1 --- R3 ------ R6 ------ R7 + \ / |. | + \ / |. | + -- R4 ---- |. | + / ./ + R8 -- + . + +We check routes on R1, primarily those towards R7/8. Those to R7 are +inter-area routes with R5/6 being ABRs, those to R8 are intra-area routes +and are used for reference. R7/R8 announce one internal and one external +route each. With all links up, we expect 3 ECMP paths and 3 nexthops on R1 towards each -of R6/7/8/9. Then we bring down the R2-R5 link, causing only 2 remaining -paths and 2 nexthops on R1. The test is successful if the number of nexthops -for the routes on R1 is as expected. +of R7/8. Then we bring down the R3-R6 link, causing only 2 remaining +paths and 2 nexthops on R1. Then we bring down the R2-R5 link, causing only +1 remaining path and 1 nexthop on R1. + +The test is successful if the number of nexthops for the routes on R1 is as +expected. """ import os @@ -65,20 +72,24 @@ def build_topo(tgen): "Build function" - # Create 9 routers - for routern in range(1, 10): + # Create 8 routers + for routern in range(1, 9): tgen.add_router("r{}".format(routern)) - tgen.gears["r1"].add_link(tgen.gears["r2"]) tgen.gears["r1"].add_link(tgen.gears["r3"]) tgen.gears["r1"].add_link(tgen.gears["r4"]) tgen.gears["r2"].add_link(tgen.gears["r5"]) - tgen.gears["r3"].add_link(tgen.gears["r5"]) - tgen.gears["r4"].add_link(tgen.gears["r5"]) - tgen.gears["r5"].add_link(tgen.gears["r6"]) + tgen.gears["r3"].add_link(tgen.gears["r6"]) + tgen.gears["r4"].add_link(tgen.gears["r6"]) tgen.gears["r5"].add_link(tgen.gears["r7"]) tgen.gears["r5"].add_link(tgen.gears["r8"]) - tgen.gears["r5"].add_link(tgen.gears["r9"]) + tgen.gears["r6"].add_link(tgen.gears["r7"]) + tgen.gears["r6"].add_link(tgen.gears["r8"]) + # Additional "loopback" interfaces. Not used for communication, just to + # hold an address we use to inject intra-/inter-area routes (the one on + # the real "lo" loopback is used for external routes). + tgen.gears["r7"].add_link(tgen.gears["r7"]) + tgen.gears["r8"].add_link(tgen.gears["r8"]) def setup_module(mod): @@ -110,15 +121,18 @@ def test_wait_protocol_convergence(): def expect_neighbor_full(router, neighbor): "Wait until OSPFv3 neighborship is full" - logger.info("waiting for OSPFv3 router '{}' neighborship with '{}'".format(router, neighbor)) + logger.info( + "waiting for OSPFv3 router '{}' neighborship with '{}'".format( + router, neighbor + ) + ) test_func = partial( topotest.router_json_cmp, tgen.gears[router], "show ipv6 ospf6 neighbor json", {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, ) - _, result = topotest.run_and_expect(test_func, None, - count=130, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg @@ -128,20 +142,20 @@ def expect_neighbor_full(router, neighbor): expect_neighbor_full("r2", "10.254.254.1") expect_neighbor_full("r2", "10.254.254.5") expect_neighbor_full("r3", "10.254.254.1") - expect_neighbor_full("r3", "10.254.254.5") + expect_neighbor_full("r3", "10.254.254.6") expect_neighbor_full("r4", "10.254.254.1") - expect_neighbor_full("r4", "10.254.254.5") + expect_neighbor_full("r4", "10.254.254.6") expect_neighbor_full("r5", "10.254.254.2") - expect_neighbor_full("r5", "10.254.254.3") - expect_neighbor_full("r5", "10.254.254.4") - expect_neighbor_full("r5", "10.254.254.6") expect_neighbor_full("r5", "10.254.254.7") expect_neighbor_full("r5", "10.254.254.8") - expect_neighbor_full("r5", "10.254.254.9") - expect_neighbor_full("r6", "10.254.254.5") + expect_neighbor_full("r6", "10.254.254.3") + expect_neighbor_full("r6", "10.254.254.7") + expect_neighbor_full("r6", "10.254.254.8") expect_neighbor_full("r7", "10.254.254.5") + expect_neighbor_full("r7", "10.254.254.6") expect_neighbor_full("r8", "10.254.254.5") - expect_neighbor_full("r9", "10.254.254.5") + expect_neighbor_full("r8", "10.254.254.6") + def test_ecmp_inter_area(): "Test whether OSPFv3 ECMP nexthops are properly updated for inter-area routes after link down" @@ -150,28 +164,49 @@ def test_ecmp_inter_area(): pytest.skip(tgen.errors) def num_nexthops(router): - routes = tgen.gears[router].vtysh_cmd("show ipv6 ospf6 route json", isjson=True) - route_prefixes_infos = sorted(routes.get("routes", {}).items()) - return [len(ri.get("nextHops", [])) for rp, ri in route_prefixes_infos] + # Careful: "show ipv6 ospf6 route json" doesn't work here. It will + # only list one route type per prefix and that might not necessarily + # be the best/selected route. "show ipv6 route ospf6 json" only + # lists selected routes, so that's more useful in this case. + routes = tgen.gears[router].vtysh_cmd("show ipv6 route ospf6 json", isjson=True) + route_prefixes_infos = sorted(routes.items()) + # Note: ri may contain one entry per routing protocol, but since + # we've explicitly requested only ospf6 above, we can count on ri[0] + # being the entry we're looking for. + return [ri[0]["internalNextHopActiveNum"] for rp, ri in route_prefixes_infos] def expect_num_nexthops(router, expected_num_nexthops, count): "Wait until number of nexthops for routes matches expectation" - logger.info("waiting for OSPFv3 router '{}' nexthops {}".format(router, expected_num_nexthops)) + logger.info( + "waiting for OSPFv3 router '{}' nexthops {}".format( + router, expected_num_nexthops + ) + ) test_func = partial(num_nexthops, router) - _, result = topotest.run_and_expect(test_func, expected_num_nexthops, - count=count, wait=3) - assert result == expected_num_nexthops, \ - "'{}' wrong number of route nexthops".format(router) + _, result = topotest.run_and_expect( + test_func, expected_num_nexthops, count=count, wait=3 + ) + assert ( + result == expected_num_nexthops + ), "'{}' wrong number of route nexthops".format(router) # Check nexthops pre link-down - expect_num_nexthops("r1", [1, 1, 1, 3, 3, 3, 3, 3], 4) + # tgen.mininet_cli() + expect_num_nexthops("r1", [1, 1, 1, 1, 2, 3, 3, 3, 3], 4) + + logger.info("triggering R3-R6 link down") + tgen.gears["r3"].run("ip link set r3-eth1 down") + + # tgen.mininet_cli() + # Check nexthops post link-down + expect_num_nexthops("r1", [1, 1, 1, 1, 1, 2, 2, 2, 2], 8) - logger.info("triggering R2-R4 link down") + logger.info("triggering R2-R5 link down") tgen.gears["r2"].run("ip link set r2-eth1 down") - #tgen.mininet_cli() + # tgen.mininet_cli() # Check nexthops post link-down - expect_num_nexthops("r1", [1, 1, 1, 2, 2, 2, 2, 2], 8) + expect_num_nexthops("r1", [1, 1, 1, 1, 1, 1, 1, 1, 1], 8) def teardown_module(_mod): diff --git a/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json index 66ee57ce8419..181d3767744f 100644 --- a/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json @@ -6,7 +6,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, @@ -25,7 +25,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -45,7 +45,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -65,7 +65,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -85,7 +85,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":50, + "metric":40, "installed":true, "nexthops":[ { @@ -105,7 +105,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -125,7 +125,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":50, + "metric":40, "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json index 624ff709e37d..13b5cd4468cf 100644 --- a/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json @@ -8,7 +8,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -26,7 +26,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, @@ -45,7 +45,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -65,7 +65,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -85,7 +85,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -105,7 +105,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -125,7 +125,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json index f9b43dcdb90e..db6ec3e3a82a 100644 --- a/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json @@ -8,7 +8,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -28,7 +28,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -46,7 +46,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, @@ -65,7 +65,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -85,7 +85,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -105,7 +105,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -125,7 +125,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json index f5212da4f683..08ccff2fc591 100644 --- a/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json @@ -8,7 +8,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -28,7 +28,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -48,7 +48,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -66,7 +66,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, @@ -85,7 +85,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -105,7 +105,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -125,7 +125,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json index 5ea4f699fe06..8ddd55b13219 100644 --- a/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json @@ -8,7 +8,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":50, + "metric":40, "installed":true, "nexthops":[ { @@ -28,7 +28,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -48,7 +48,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -68,7 +68,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -86,7 +86,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, @@ -105,7 +105,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -125,7 +125,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":50, + "metric":40, "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json index 862f1baffb21..9d45b09be89b 100644 --- a/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json @@ -8,7 +8,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -28,7 +28,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -48,7 +48,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -68,7 +68,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -88,7 +88,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -106,7 +106,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, @@ -125,7 +125,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { diff --git a/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json index f5f8f710e5b7..c4f841468de5 100644 --- a/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json +++ b/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json @@ -8,7 +8,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":50, + "metric":40, "installed":true, "nexthops":[ { @@ -28,7 +28,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -48,7 +48,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":30, + "metric":20, "installed":true, "nexthops":[ { @@ -68,7 +68,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":40, + "metric":30, "installed":true, "nexthops":[ { @@ -88,7 +88,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":50, + "metric":40, "installed":true, "nexthops":[ { @@ -108,7 +108,7 @@ "selected":true, "destSelected":true, "distance":110, - "metric":20, + "metric":10, "installed":true, "nexthops":[ { @@ -126,7 +126,7 @@ "vrfId":0, "vrfName":"default", "distance":110, - "metric":10, + "metric":0, "nexthops":[ { "directlyConnected":true, diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index 45e1bc8db387..ba705e3dfc79 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -135,7 +135,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ip_route.ref.diff b/tests/topotests/ospf6_loopback_cost/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step6/show_ip_route.ref.diff rename to tests/topotests/ospf6_loopback_cost/__init__.py diff --git a/tests/topotests/ospf6_loopback_cost/r1/frr.conf b/tests/topotests/ospf6_loopback_cost/r1/frr.conf new file mode 100644 index 000000000000..d85166bc6ca4 --- /dev/null +++ b/tests/topotests/ospf6_loopback_cost/r1/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ipv6 address 2001:db8::1/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 passive +! +int r1-eth0 + ipv6 address 2001:db8:1::1/64 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 dead-interval 4 +! +router ospf6 + ospf6 router-id 0.0.0.1 +exit +! diff --git a/tests/topotests/ospf6_loopback_cost/r2/frr.conf b/tests/topotests/ospf6_loopback_cost/r2/frr.conf new file mode 100644 index 000000000000..8f3e2caab653 --- /dev/null +++ b/tests/topotests/ospf6_loopback_cost/r2/frr.conf @@ -0,0 +1,16 @@ +! +int lo + ipv6 address 2001:db8::2/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 passive +! +int r2-eth0 + ipv6 address 2001:db8:1::2/64 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 dead-interval 4 +! +router ospf6 + ospf6 router-id 0.0.0.2 +exit +! diff --git a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py new file mode 100644 index 000000000000..077a9e4205e1 --- /dev/null +++ b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis +# + +""" +Test if OSPFv3 loopback interfaces get a cost of 0. + +https://www.rfc-editor.org/rfc/rfc5340.html#page-37: + +If the interface type is point-to-multipoint or the interface is +in the state Loopback, the global scope IPv6 addresses associated +with the interface (if any) are copied into the intra-area-prefix-LSA +with the PrefixOptions LA-bit set, the PrefixLength set to 128, and +the metric set to 0. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.ospf6d + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(): + tgen = get_topogen() + tgen.stop_topology() + + +def test_ospf6_loopback_cost(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _show_ipv6_route(): + output = json.loads(r1.vtysh_cmd("show ipv6 route json")) + expected = { + "2001:db8::1/128": [ + { + "metric": 0, + "distance": 110, + } + ], + "2001:db8::2/128": [ + { + "metric": 10, + "distance": 110, + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _show_ipv6_route, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "Loopback cost isn't 0" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf6_point_to_multipoint/README.md b/tests/topotests/ospf6_point_to_multipoint/README.md new file mode 100644 index 000000000000..59c9837aea97 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/README.md @@ -0,0 +1,137 @@ +# OSPFv3 (IPv6) Topology Test (point-to-multipoint) + +## Topology + -----\ + SW1 - Stub Net 1 SW2 - Stub Net 2 \ + fc00:1:1:1::/64 fc00:2:2:2::/64 \ + \___________________/ \___________________/ | + | | | + | | | + | ::1 | ::2 | + +---------+---------+ +---------+---------+ | + | R1 | | R2 | | + | FRRouting | | FRRouting | | + | Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | + +---------+---------+ +---------+---------+ | + | ::1 | ::2 \ + \______ ___________/ OSPFv3 + \ / Area 0.0.0.0 + \ / / + ~~~~~~~~~~~~~~~~~~ | + ~~ SW5 ~~ | + ~~ Switch ~~ | + ~~ fc00:A:A:A::/64 ~~ | + ~~~~~~~~~~~~~~~~~~ | + | /---- | + | ::3 | SW3 - Stub Net 3 | + +---------+---------+ /-+ fc00:3:3:3::/64 | + | R3 | / | / + | FRRouting +--/ \---- / + | Rtr-ID: 10.0.0.3 | ::3 ___________/ + +---------+---------+ \ + | ::3 \ + | \ + ~~~~~~~~~~~~~~~~~~ | + ~~ SW6 ~~ | + ~~ Switch ~~ | + ~~ fc00:B:B:B::/64 ~~ \ + ~~~~~~~~~~~~~~~~~~ OSPFv3 + | Area 0.0.0.1 + | ::4 / + +---------+---------+ /---- | + | R4 | | SW4 - Stub Net 4 | + | FRRouting +------+ fc00:4:4:4::/64 | + | Rtr-ID: 10.0.0.4 | ::4 | / + +-------------------+ \---- / + -----/ + +## FRR Configuration + +Full config as used is in r1 / r2 / r3 / r4 / r5 subdirectories + +Simplified `R1` config (R1 is similar) + + hostname r1 + ! + interface r1-stubnet + ipv6 address fc00:1:1:1::1/64 + ipv6 ospf6 passive + ipv6 ospf6 area 0.0.0.0 + ! + interface r1-sw5 + ipv6 address fc00:a:a:a::1/64 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.0 + ! + router ospf6 + router-id 10.0.0.1 + log-adjacency-changes detail + redistribute static + ! + ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 + +Simplified `R3` config + + hostname r3 + ! + interface r3-stubnet + ipv6 address fc00:3:3:3::3/64 + ipv6 ospf6 passive + ipv6 ospf6 area 0.0.0.0 + ! + interface r3-sw5 + ipv6 address fc00:a:a:a::3/64 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 p2p-p2mp connected-prefixes include + ! + interface r3-sw6 + ipv6 address fc00:b:b:b::3/64 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.1 + ipv6 ospf6 p2p-p2mp connected-prefixes include + ! + router ospf6 + router-id 10.0.0.3 + log-adjacency-changes detail + redistribute static + ! + ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 + +## Tests executed + +### Check if FRR is running + +Test is executed by running + + vtysh -c "show logging" | grep "Logging configuration for" + +on each FRR router. This should return the logging information for all daemons registered +to Zebra and the list of running daemons is compared to the daemons started for this test (`zebra` and `ospf6d`) + +### Check if OSPFv3 to converge + +OSPFv3 is expected to converge on each view within 60s total time. Convergence is verified by executing (on each node) + + vtysh -c "show ipv6 ospf neigh" + +and checking for "Full" neighbor status in the output. An additional 15 seconds after the full converge is waited for +routes to populate before the following routing table checks are executed + +### Check OSPFv3 Routing Tables + +Routing table is verified by running + + vtysh -c "show ipv6 route" + +on each node and comparing the result to the stored example config (see `show_ipv6_route.ref` in r1 / r2 / r3 / r4 directories). +Link-Local addresses are masked out before the compare. + +### Check Linux Kernel Routing Table + +Linux Kernel IPv6 Routing table is verified on each FRR node with + + ip -6 route + +Tables are compared with reference routing table (see `ip_6_address.ref` in r1 / r2 / r3 / r4 directories). +Link-Local addresses are translated after getting collected on each node with interface name to make them consistent diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref new file mode 100644 index 000000000000..203f2def5e9e --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.nhg.ref @@ -0,0 +1,14 @@ +fc00:1111:1111:1111::/64 nhid XXXX via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium +fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium +fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium +fc00:a:a:a::2 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::3 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::3 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::4 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref new file mode 100644 index 000000000000..b77c99674000 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r1/ip_6_address.ref @@ -0,0 +1,14 @@ +fc00:1111:1111:1111::/64 via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium +fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium +fc00:a:a:a::2 via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::3 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::3 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::4 via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf new file mode 100644 index 000000000000..79a9dcae116b --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r1/ospf6d.conf @@ -0,0 +1,30 @@ +hostname r1 +log file ospf6d.log +! +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding +! +interface r1-sw5 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 + ipv6 ospf6 p2p-p2mp connected-prefixes include +! +interface r1-stubnet + ipv6 ospf6 passive + ipv6 ospf6 area 0.0.0.0 +! +router ospf6 + ospf6 router-id 10.0.0.1 + log-adjacency-changes detail + redistribute static +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref new file mode 100644 index 000000000000..911b3e40d68c --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r1/show_ipv6_route.ref @@ -0,0 +1,13 @@ +O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet, weight 1, XX:XX:XX +O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX +O>* fc00:a:a:a::2/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:a:a:a::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:b:b:b::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:b:b:b::4/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX +O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf new file mode 100644 index 000000000000..3a7db9f25e36 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r1/zebra.conf @@ -0,0 +1,20 @@ +! +hostname r1 +log file zebra.log +! +! debug zebra events +! debug zebra rib +! +interface r1-stubnet + ipv6 address fc00:1:1:1::1/64 +! +interface r1-sw5 + ipv6 address fc00:a:a:a::1/64 +! +interface lo +! +ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref new file mode 100644 index 000000000000..d4534b10bb6d --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.nhg.ref @@ -0,0 +1,14 @@ +fc00:1111:1111:1111::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:1:1:1::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 nhid XXXX via fc00:2:2:2::1234 dev r2-stubnet proto XXXX metric 20 pref medium +fc00:2:2:2::/64 dev r2-stubnet proto XXXX metric 256 pref medium +fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r2-sw5 proto XXXX metric 256 pref medium +fc00:a:a:a::1 nhid XXXX via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::3 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::3 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::4 nhid XXXX via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref new file mode 100644 index 000000000000..330b696c3a18 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r2/ip_6_address.ref @@ -0,0 +1,14 @@ +fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fc00:2:2:2::1234 dev r2-stubnet proto XXXX metric 20 pref medium +fc00:2:2:2::/64 dev r2-stubnet proto XXXX metric 256 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r2-sw5 proto XXXX metric 256 pref medium +fc00:a:a:a::1 via fe80::__(r1-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::3 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::3 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::4 via fe80::__(r3-sw5)__ dev r2-sw5 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf new file mode 100644 index 000000000000..751d8d84e7db --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r2/ospf6d.conf @@ -0,0 +1,30 @@ +hostname r2 +log file ospf6d.log +! +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding +! +interface r2-sw5 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 + ipv6 ospf6 p2p-p2mp connected-prefixes include +! +interface r2-stubnet + ipv6 ospf6 passive + ipv6 ospf6 area 0.0.0.0 +! +router ospf6 + ospf6 router-id 10.0.0.2 + log-adjacency-changes detail + redistribute static +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref new file mode 100644 index 000000000000..2eff0291ad97 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r2/show_ipv6_route.ref @@ -0,0 +1,13 @@ +O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet, weight 1, XX:XX:XX +O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX +O>* fc00:a:a:a::1/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:a:a:a::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:b:b:b::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:b:b:b::4/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX +O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf new file mode 100644 index 000000000000..5571dc979c70 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r2/zebra.conf @@ -0,0 +1,20 @@ +! +hostname r2 +log file zebra.log +! +! debug zebra events +! debug zebra rib +! +interface r2-stubnet + ipv6 address fc00:2:2:2::2/64 +! +interface r2-sw5 + ipv6 address fc00:a:a:a::2/64 +! +interface lo +! +ipv6 route fc00:2222:2222:2222::/64 fc00:2:2:2::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref new file mode 100644 index 000000000000..903c1d962fb8 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.nhg.ref @@ -0,0 +1,13 @@ +fc00:1111:1111:1111::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:1:1:1::/64 nhid XXXX via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 nhid XXXX via fc00:3:3:3::1234 dev r3-stubnet proto XXXX metric 20 pref medium +fc00:3:3:3::/64 dev r3-stubnet proto XXXX metric 256 pref medium +fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 nhid XXXX via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r3-sw5 proto XXXX metric 256 pref medium +fc00:a:a:a::1 nhid XXXX via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::2 nhid XXXX via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 dev r3-sw6 proto XXXX metric 256 pref medium +fc00:b:b:b::4 nhid XXXX via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref new file mode 100644 index 000000000000..3dbcf36b4806 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r3/ip_6_address.ref @@ -0,0 +1,13 @@ +fc00:1111:1111:1111::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:1:1:1::/64 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fc00:3:3:3::1234 dev r3-stubnet proto XXXX metric 20 pref medium +fc00:3:3:3::/64 dev r3-stubnet proto XXXX metric 256 pref medium +fc00:4444:4444:4444::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium +fc00:4:4:4::/64 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::/64 dev r3-sw5 proto XXXX metric 256 pref medium +fc00:a:a:a::1 via fe80::__(r1-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:a:a:a::2 via fe80::__(r2-sw5)__ dev r3-sw5 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 dev r3-sw6 proto XXXX metric 256 pref medium +fc00:b:b:b::4 via fe80::__(r4-sw6)__ dev r3-sw6 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf new file mode 100644 index 000000000000..74e8ddf00f7c --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r3/ospf6d.conf @@ -0,0 +1,37 @@ +hostname r3 +log file ospf6d.log +! +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding +! +interface r3-sw5 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 + ipv6 ospf6 p2p-p2mp connected-prefixes include +! +interface r3-sw6 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 + ipv6 ospf6 p2p-p2mp connected-prefixes include +! +interface r3-stubnet + ipv6 ospf6 passive + ipv6 ospf6 area 0.0.0.0 +! +router ospf6 + ospf6 router-id 10.0.0.3 + log-adjacency-changes detail + redistribute static +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref new file mode 100644 index 000000000000..df949e64ea11 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r3/show_ipv6_route.ref @@ -0,0 +1,12 @@ +O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX +O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX +O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:XX +O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX +O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX +O>* fc00:a:a:a::1/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX +O>* fc00:a:a:a::2/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX +O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX +O>* fc00:b:b:b::4/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX +O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX +O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX +O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf new file mode 100644 index 000000000000..3cc5626bd7e5 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r3/zebra.conf @@ -0,0 +1,23 @@ +! +hostname r3 +log file zebra.log +! +! debug zebra events +! debug zebra rib +! +interface r3-stubnet + ipv6 address fc00:3:3:3::3/64 +! +interface r3-sw5 + ipv6 address fc00:a:a:a::3/64 +! +interface r3-sw6 + ipv6 address fc00:b:b:b::3/64 +! +interface lo +! +ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref new file mode 100644 index 000000000000..ca1e2f0d7866 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.nhg.ref @@ -0,0 +1,14 @@ +fc00:1111:1111:1111::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:1:1:1::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 nhid XXXX via fc00:4:4:4::1234 dev r4-stubnet proto XXXX metric 20 pref medium +fc00:4:4:4::/64 dev r4-stubnet proto XXXX metric 256 pref medium +fc00:a:a:a::/64 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::1 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::2 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::3 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 dev r4-sw6 proto XXXX metric 256 pref medium +fc00:b:b:b::3 nhid XXXX via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref new file mode 100644 index 000000000000..4f4e72fc27be --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r4/ip_6_address.ref @@ -0,0 +1,14 @@ +fc00:1111:1111:1111::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:1:1:1::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:2222:2222:2222::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:2:2:2::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:3333:3333:3333::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:3:3:3::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:4444:4444:4444::/64 via fc00:4:4:4::1234 dev r4-stubnet proto XXXX metric 20 pref medium +fc00:4:4:4::/64 dev r4-stubnet proto XXXX metric 256 pref medium +fc00:a:a:a::/64 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::1 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::2 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:a:a:a::3 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium +fc00:b:b:b::/64 dev r4-sw6 proto XXXX metric 256 pref medium +fc00:b:b:b::3 via fe80::__(r3-sw6)__ dev r4-sw6 proto XXXX metric 20 pref medium diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf b/tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf new file mode 100644 index 000000000000..25b8551dd792 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r4/ospf6d.conf @@ -0,0 +1,30 @@ +hostname r4 +log file ospf6d.log +! +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding +! +interface r4-sw6 + ipv6 ospf6 network point-to-multipoint + ipv6 ospf6 area 0.0.0.1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 + ipv6 ospf6 p2p-p2mp connected-prefixes include +! +interface r4-stubnet + ipv6 ospf6 passive + ipv6 ospf6 area 0.0.0.1 +! +router ospf6 + ospf6 router-id 10.0.0.4 + log-adjacency-changes detail + redistribute static +! +line vty + exec-timeout 0 0 +! diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref b/tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref new file mode 100644 index 000000000000..f377ca3a8882 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r4/show_ipv6_route.ref @@ -0,0 +1,13 @@ +O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet, weight 1, XX:XX:XX +O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:a:a:a::1/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:a:a:a::2/128 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:a:a:a::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX +O>* fc00:b:b:b::3/128 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX +O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf b/tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf new file mode 100644 index 000000000000..20e27cea46ae --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/r4/zebra.conf @@ -0,0 +1,20 @@ +! +hostname r4 +log file zebra.log +! +! debug zebra events +! debug zebra rib +! +interface r4-stubnet + ipv6 address fc00:4:4:4::4/64 +! +interface r4-sw6 + ipv6 address fc00:b:b:b::4/64 +! +interface lo +! +ipv6 route fc00:4444:4444:4444::/64 fc00:4:4:4::1234 +! +! +line vty +! diff --git a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py new file mode 100644 index 000000000000..73a902244251 --- /dev/null +++ b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py @@ -0,0 +1,392 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_ospf6_point_to_multipoint.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2023 by +# Network Device Education Foundation, Inc. ("NetDEF") +# + +r""" +test_ospf6_point_to_multipoint.py: + + -----\ + SW1 - Stub Net 1 SW2 - Stub Net 2 \ + fc00:1:1:1::/64 fc00:2:2:2::/64 \ +\___________________/ \___________________/ | + | | | + | | | + | ::1 | ::2 | ++---------+---------+ +---------+---------+ | +| R1 | | R2 | | +| FRRouting | | FRRouting | | +| Rtr-ID: 10.0.0.1 | | Rtr-ID: 10.0.0.2 | | ++---------+---------+ +---------+---------+ | + | ::1 | ::2 \ + \______ ___________/ OSPFv3 + \ / Area 0.0.0.0 + \ / / + ~~~~~~~~~~~~~~~~~~ | + ~~ SW5 ~~ | + ~~ Switch ~~ | + ~~ fc00:A:A:A::/64 ~~ | + ~~~~~~~~~~~~~~~~~~ | + | /---- | + | ::3 | SW3 - Stub Net 3 | + +---------+---------+ /-+ fc00:3:3:3::/64 | + | R3 | / | / + | FRRouting +--/ \---- / + | Rtr-ID: 10.0.0.3 | ::3 ___________/ + +---------+---------+ \ + | ::3 \ + | \ + ~~~~~~~~~~~~~~~~~~ | + ~~ SW6 ~~ | + ~~ Switch ~~ | + ~~ fc00:B:B:B::/64 ~~ \ + ~~~~~~~~~~~~~~~~~~ OSPFv3 + | Area 0.0.0.1 + | ::4 / + +---------+---------+ /---- | + | R4 | | SW4 - Stub Net 4 | + | FRRouting +------+ fc00:4:4:4::/64 | + | Rtr-ID: 10.0.0.4 | ::4 | / + +-------------------+ \---- / + -----/ +""" + +import os +import re +import sys +import pytest + +from functools import partial + + +# Save the Current Working Directory to find configuration files later. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + + +pytestmark = [pytest.mark.ospfd] + + +def build_topo(tgen): + # Create 4 routers + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + # + # Wire up the switches and routers + # Note that we specify the link names so we match the config files + # + + # Create a empty network for router 1 + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"], nodeif="r1-stubnet") + + # Create a empty network for router 2 + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"], nodeif="r2-stubnet") + + # Create a empty network for router 3 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"], nodeif="r3-stubnet") + + # Create a empty network for router 4 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r4"], nodeif="r4-stubnet") + + # Interconnect routers 1, 2, and 3 + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r1"], nodeif="r1-sw5") + switch.add_link(tgen.gears["r2"], nodeif="r2-sw5") + switch.add_link(tgen.gears["r3"], nodeif="r3-sw5") + + # Interconnect routers 3 and 4 + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r3"], nodeif="r3-sw6") + switch.add_link(tgen.gears["r4"], nodeif="r4-sw6") + + +##################################################### +## +## Tests starting +## +##################################################### + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + logger.info("** %s: Setup Topology" % mod.__name__) + logger.info("******************************************") + + # For debugging after starting net, but before starting FRR, + # uncomment the next line + # tgen.mininet_cli() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + # For debugging after starting FRR daemons, uncomment the next line + # tgen.mininet_cli() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_wait_protocol_convergence(): + "Wait for OSPFv3 to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_neighbor_full(router, neighbor): + "Wait until OSPFv3 convergence." + logger.info("waiting OSPFv3 router '{}'".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 neighbor json", + {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + expect_neighbor_full("r1", "10.0.0.2") + expect_neighbor_full("r1", "10.0.0.3") + + expect_neighbor_full("r2", "10.0.0.1") + expect_neighbor_full("r2", "10.0.0.3") + + expect_neighbor_full("r3", "10.0.0.1") + expect_neighbor_full("r3", "10.0.0.2") + expect_neighbor_full("r3", "10.0.0.4") + + expect_neighbor_full("r4", "10.0.0.3") + + +def compare_show_ipv6(rname, expected): + """ + Calls 'show ipv6 route' for router `rname` and compare the obtained + result with the expected output. + """ + tgen = get_topogen() + + # Use the vtysh output, with some masking to make comparison easy + current = topotest.ip6_route_zebra(tgen.gears[rname]) + + # Use just the 'O'spf lines of the output + linearr = [] + for line in current.splitlines(): + if re.match("^O", line): + linearr.append(line) + + current = "\n".join(linearr) + + return topotest.difflines( + topotest.normalize_text(current), + topotest.normalize_text(expected), + title1="Current output", + title2="Expected output", + ) + + +def test_ospfv3_routingTable(): + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + # For debugging, uncomment the next line + # tgen.mininet_cli() + + # Verify OSPFv3 Routing Table + for router, _ in tgen.routers().items(): + logger.info('Waiting for router "%s" convergence', router) + + # Load expected results from the command + reffile = os.path.join(CWD, "{}/show_ipv6_route.ref".format(router)) + expected = open(reffile).read() + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(compare_show_ipv6, router, expected) + result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5) + assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff) + + +def test_linux_ipv6_kernel_routingTable(): + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + # Verify Linux Kernel Routing Table + logger.info("Verifying Linux IPv6 Kernel Routing Table") + + failures = 0 + + # Get a list of all current link-local addresses first as they change for + # each run and we need to translate them + linklocals = [] + for i in range(1, 5): + linklocals += tgen.net["r{}".format(i)].get_ipv6_linklocal() + + # Now compare the routing tables (after substituting link-local addresses) + + for i in range(1, 5): + # Actual output from router + actual = tgen.gears["r{}".format(i)].run("ip -6 route").rstrip() + if "nhid" in actual: + refTableFile = os.path.join(CWD, "r{}/ip_6_address.nhg.ref".format(i)) + else: + refTableFile = os.path.join(CWD, "r{}/ip_6_address.ref".format(i)) + + if os.path.isfile(refTableFile): + expected = open(refTableFile).read().rstrip() + # Fix newlines (make them all the same) + expected = ("\n".join(expected.splitlines())).splitlines(1) + + # Mask out Link-Local mac addresses + for ll in linklocals: + actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0]) + # Mask out protocol name or number + actual = re.sub(r"[ ]+proto [0-9a-z]+ +", " proto XXXX ", actual) + actual = re.sub(r"[ ]+nhid [0-9]+ +", " nhid XXXX ", actual) + # Remove ff00::/8 routes (seen on some kernels - not from FRR) + actual = re.sub(r"ff00::/8.*", "", actual) + + # Strip empty lines + actual = actual.lstrip() + actual = actual.rstrip() + actual = re.sub(r" +", " ", actual) + + filtered_lines = [] + for line in sorted(actual.splitlines()): + if line.startswith("fe80::/64 ") or line.startswith( + "unreachable fe80::/64 " + ): + continue + filtered_lines.append(line) + actual = "\n".join(filtered_lines).splitlines(1) + + # Print Actual table + # logger.info("Router r%s table" % i) + # for line in actual: + # logger.info(line.rstrip()) + + # Generate Diff + diff = topotest.get_textdiff( + actual, + expected, + title1="actual OSPFv3 IPv6 routing table", + title2="expected OSPFv3 IPv6 routing table", + ) + + # Empty string if it matches, otherwise diff contains unified diff + if diff: + sys.stderr.write( + "r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n" + % (i, diff) + ) + failures += 1 + else: + logger.info("r%s ok" % i) + + assert failures == 0, ( + "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" + % (i, diff) + ) + else: + logger.error("r{} failed - no nhid ref file: {}".format(i, refTableFile)) + + assert False, ( + "Linux Kernel IPv6 Routing Table verification failed for router r%s\n" + % (i) + ) + + +def test_shutdown_check_stderr(): + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + if os.environ.get("TOPOTESTS_CHECK_STDERR") is None: + logger.info( + "SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n" + ) + pytest.skip("Skipping test for Stderr output") + + net = tgen.net + + logger.info("\n\n** Verifying unexpected STDERR output from daemons") + logger.info("******************************************") + + for i in range(1, 5): + net["r%s" % i].stopRouter() + log = net["r%s" % i].getStdErr("ospf6d") + if log: + logger.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log)) + log = net["r%s" % i].getStdErr("zebra") + if log: + logger.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log)) + + +def test_shutdown_check_memleak(): + "Run the memory leak test and report results." + + if os.environ.get("TOPOTESTS_CHECK_MEMLEAK") is None: + logger.info( + "SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)" + ) + pytest.skip("Skipping test for memory leaks") + + tgen = get_topogen() + + net = tgen.net + + for i in range(1, 5): + net["r%s" % i].stopRouter() + net["r%s" % i].report_memory_leaks( + os.environ.get("TOPOTESTS_CHECK_MEMLEAK"), os.path.basename(__file__) + ) + + +if __name__ == "__main__": + + # To suppress tracebacks, either use the following pytest call or + # add "--tb=no" to cli + # retval = pytest.main(["-s", "--tb=no"]) + + retval = pytest.main(["-s"]) + sys.exit(retval) diff --git a/tests/topotests/ospf6_topo1/r1/ospf6d.conf b/tests/topotests/ospf6_topo1/r1/ospf6d.conf index 5f1ceee964bc..d2693ec07d1c 100644 --- a/tests/topotests/ospf6_topo1/r1/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r1/ospf6d.conf @@ -10,11 +10,13 @@ log file ospf6d.log ! debug ospf6 flooding ! interface r1-stubnet + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r1-sw5 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 @@ -23,8 +25,6 @@ router ospf6 ospf6 router-id 10.0.0.1 log-adjacency-changes detail redistribute static - interface r1-stubnet area 0.0.0.0 - interface r1-sw5 area 0.0.0.0 ! line vty exec-timeout 0 0 diff --git a/tests/topotests/ospf6_topo1/r2/ospf6d.conf b/tests/topotests/ospf6_topo1/r2/ospf6d.conf index d51b41e1e583..c9e88f1545ea 100644 --- a/tests/topotests/ospf6_topo1/r2/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r2/ospf6d.conf @@ -10,11 +10,13 @@ log file ospf6d.log ! debug ospf6 flooding ! interface r2-stubnet + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r2-sw5 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 @@ -23,8 +25,6 @@ router ospf6 ospf6 router-id 10.0.0.2 log-adjacency-changes detail redistribute static - interface r2-stubnet area 0.0.0.0 - interface r2-sw5 area 0.0.0.0 ! line vty exec-timeout 0 0 diff --git a/tests/topotests/ospf6_topo1/r3/ospf6d.conf b/tests/topotests/ospf6_topo1/r3/ospf6d.conf index cad71ac067b3..e1c3e44d0e20 100644 --- a/tests/topotests/ospf6_topo1/r3/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r3/ospf6d.conf @@ -10,16 +10,19 @@ log file ospf6d.log ! debug ospf6 flooding ! interface r3-stubnet + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r3-sw5 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r3-sw6 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 @@ -28,9 +31,6 @@ router ospf6 ospf6 router-id 10.0.0.3 log-adjacency-changes detail redistribute static - interface r3-stubnet area 0.0.0.0 - interface r3-sw5 area 0.0.0.0 - interface r3-sw6 area 0.0.0.1 ! line vty exec-timeout 0 0 diff --git a/tests/topotests/ospf6_topo1/r4/ospf6d.conf b/tests/topotests/ospf6_topo1/r4/ospf6d.conf index f0b166bc4bce..230ec7aad457 100644 --- a/tests/topotests/ospf6_topo1/r4/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r4/ospf6d.conf @@ -10,11 +10,13 @@ log file ospf6d.log ! debug ospf6 flooding ! interface r4-stubnet + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r4-sw6 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 network broadcast ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 @@ -23,8 +25,6 @@ router ospf6 ospf6 router-id 10.0.0.4 log-adjacency-changes detail redistribute static - interface r4-stubnet area 0.0.0.1 - interface r4-sw6 area 0.0.0.1 ! line vty exec-timeout 0 0 diff --git a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py index 5649757010c3..85075a79aaf8 100644 --- a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -351,7 +351,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py index f982990987b5..ccf25a0fc84b 100755 --- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py +++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py @@ -186,7 +186,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -260,7 +260,7 @@ def test_ospfv3_routingTable(): # For debugging, uncomment the next line # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -391,7 +391,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py index 0531e81d4431..18b72772fe49 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py @@ -147,7 +147,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2893,7 +2893,7 @@ def test_ospf_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf": { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py index 603aeadb855b..cdc5d126b47f 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py @@ -139,7 +139,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py index 8dd103013b4e..922c5a0e0b3c 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py @@ -109,7 +109,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index e58f081f9636..dc237e9512cd 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -118,7 +118,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index aba313db9f73..21e767522adb 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -121,7 +121,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -193,7 +193,7 @@ def test_ospf_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]) nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py index bd7db644d14a..7c37af02ace8 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py @@ -51,7 +51,6 @@ create_static_routes, step, topo_daemons, - shutdown_bringup_interface, check_router_status, start_topology, write_test_header, @@ -65,8 +64,6 @@ write_test_header, write_test_footer, reset_config_on_routers, - stop_router, - start_router, step, create_static_routes, kill_router_daemons, @@ -163,7 +160,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -183,7 +180,6 @@ def teardown_module(mod): logger.info("=" * 40) - def red_static(dut, config=True): """Local def for Redstribute static routes inside ospf.""" global topo @@ -367,7 +363,13 @@ def test_ospf_flood_red_tc1_p0(request): }, } result = verify_ospf_database( - tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0", expected=False + tgen, + topo, + dut, + input_dict_db, + lsatype="router", + rid="100.1.1.0", + expected=False, ) assert result is not True, ( "Testcase {} : Failed \n " @@ -573,7 +575,9 @@ def test_ospf_flood_red_tc2_p0(request): result = verify_ospf_database( tgen, topo, dut, input_dict_db, lsatype="router", rid=lsid ) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) step("Wait for 120 secs and verify that LSA's are not refreshed. ") # get LSA age @@ -636,7 +640,13 @@ def test_ospf_flood_red_tc2_p0(request): }, } result = verify_ospf_database( - tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0", expected=False + tgen, + topo, + dut, + input_dict_db, + lsatype="router", + rid="100.1.1.0", + expected=False, ) assert result is not True, ( "Testcase {} : Failed \n " @@ -815,7 +825,9 @@ def test_ospf_flood_red_tc3_p0(request): result = verify_ospf_database( tgen, topo, dut, input_dict_db, lsatype="router", rid=lsid ) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) step("Wait for 120 secs and verify that LSA's are not refreshed. ") # get LSA age @@ -1022,7 +1034,13 @@ def test_ospf_flood_red_tc3_p0(request): }, } result = verify_ospf_database( - tgen, topo, dut, input_dict_db, lsatype="router", rid="100.1.1.0", expected=False + tgen, + topo, + dut, + input_dict_db, + lsatype="router", + rid="100.1.1.0", + expected=False, ) assert result is not True, ( diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py index d669e21d4d2e..9c531c03abae 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py @@ -119,7 +119,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -165,7 +165,7 @@ def test_ospf_learning_tc15_p0(request): step("Verify that Type 3 summary LSA is originated for the same Area 0") ip = topo["routers"]["r1"]["links"]["r3-link0"]["ipv4"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) dut = "r0" input_dict = { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py index a90d7dbdc05f..6aec98c71bb2 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py @@ -105,7 +105,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index c9f43cdfe497..eee51796c929 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index f0950a2db33e..193f5c8c5f08 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -49,7 +49,7 @@ verify_ospf_interface, ) -pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] +pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.staticd] # Global variables @@ -130,7 +130,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -177,7 +177,7 @@ def test_ospf_redistribution_tc5_p0(request): step("verify intra area route is calculated for r0-r3 interface ip in R1") ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] input_dict = { "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]} @@ -208,7 +208,7 @@ def test_ospf_redistribution_tc5_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break @@ -301,7 +301,7 @@ def test_ospf_redistribution_tc6_p0(request): step("verify intra area route is calculated for r0-r3 interface ip in R1") ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] input_dict = { "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]} @@ -332,7 +332,7 @@ def test_ospf_redistribution_tc6_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index 757d6fb1d581..33841b9ab20a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -115,7 +115,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -607,7 +607,7 @@ def test_ospf_show_p1(request): "r0": { "ospf": { "ifUp": True, - "ifFlags": "", + "ifFlags": "", "ospfEnabled": True, "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", @@ -634,7 +634,7 @@ def test_ospf_show_p1(request): # show ip ospf route ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] input_dict = { "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]} diff --git a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py index ade55321f9b6..2d1637995269 100644 --- a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py +++ b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py @@ -72,7 +72,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py index 79374281cb7a..3bed390b1882 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py @@ -29,7 +29,6 @@ write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py index 46c0da309f7b..3468a6511be7 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py @@ -190,8 +190,10 @@ def test_ospf_gr_helper_tc3_p1(request): ospf_covergence is True ), "OSPF is not after reset config \n Error: {}".format(ospf_covergence) - step("Configure DR priority 100 on R0 and clear ospf neighbors " - "on all the routers.") + step( + "Configure DR priority 100 on R0 and clear ospf neighbors " + "on all the routers." + ) input_dict = { "r0": { diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py index 3be28196d884..a9028673d205 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py @@ -29,7 +29,6 @@ write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index 73185d501def..73b660e59031 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -144,7 +144,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json b/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json index c0a1f6ac00f3..ebb38482486a 100644 --- a/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json +++ b/tests/topotests/ospf_instance_redistribute/r1/sharp_installed.json @@ -8,6 +8,6 @@ "type":"sharp" } ], - "routesTotal":4, - "routesTotalFib":4 + "routesTotal":5, + "routesTotalFib":5 } diff --git a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py index 9dfe5e1b7683..ea4507736e74 100644 --- a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py +++ b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -64,16 +63,9 @@ def setup_module(module): # This is a sample of configuration loading. r1 = tgen.gears["r1"] - r1.load_config( - TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf") - ) - r1.load_config( - TopoRouter.RD_OSPF, os.path.join(CWD, "r1/ospfd-3.conf"), - "-n 3" - ) - r1.load_config( - TopoRouter.RD_SHARP, os.path.join(CWD, "r1/sharpd.conf") - ) + r1.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf")) + r1.load_config(TopoRouter.RD_OSPF, os.path.join(CWD, "r1/ospfd-3.conf"), "-n 3") + r1.load_config(TopoRouter.RD_SHARP, os.path.join(CWD, "r1/sharpd.conf")) tgen.start_router() @@ -103,13 +95,15 @@ def test_install_sharp_instance_routes(): expected = json.loads(open(json_file).read()) test_func = partial( - topotest.router_json_cmp, r1, "show ip route summ json", expected) + topotest.router_json_cmp, r1, "show ip route summ json", expected + ) logger.info("Ensuring that they exist in the rib/fib") _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) assertmsg = '"r1" sharp routes are not installed' assert result is None, assertmsg + def test_ospf_instance_redistribute(): tgen = get_topogen() @@ -124,7 +118,8 @@ def test_ospf_instance_redistribute(): expected = json.loads(open(json_file).read()) test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected) + topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected + ) _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) assertmsg = '"r1" ospf instance 3 does not have the proper redistributed routes' @@ -139,7 +134,8 @@ def test_ospf_instance_redistribute(): expected = json.loads(open(json_file).read()) test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected) + topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected + ) _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) assertmsg = '"r1" ospf instance 3 does not have the proper redistributed routes' @@ -161,15 +157,14 @@ def test_ospf_instance_default_information(): expected = json.loads(open(json_file).read()) test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected) + topotest.router_json_cmp, r1, "show ip ospf 3 data json", expected + ) _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) assertmsg = '"r1" ospf instance 3 does not properly redistribute the default route' assert result is None, assertmsg - if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) - diff --git a/tests/topotests/ospf_metric_propagation/r1/frr.conf b/tests/topotests/ospf_metric_propagation/r1/frr.conf index 85230494dd15..4966e6a9da1b 100644 --- a/tests/topotests/ospf_metric_propagation/r1/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r1/frr.conf @@ -8,18 +8,18 @@ interface r1-eth0 ip address 10.0.1.1/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r1-eth1 vrf blue ip address 10.0.10.1/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! ! interface r1-eth2 vrf green ip address 10.0.91.1/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! ! router ospf diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json index 4f1ced81fb7b..2392b40fa985 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-1.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":34, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.10.5", - "afi":"ipv4", "interfaceName":"r1-eth1", - "vrf":"blue", - "active":true, - "weight":1 + "vrf":"blue" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json index 882d3ca4f09b..9a3d3d87b75f 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-2.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":136, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json index cd528459ab23..5f0331f3cd5b 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-3.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":1138, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json index 133f37549e16..f312291e8627 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-4.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":1218, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json index 5d8050902144..e88c0371743c 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-5.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":238, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.1.2", - "afi":"ipv4", "interfaceName":"r1-eth0", - "vrf":"default", - "active":true, - "weight":1 + "vrf":"default" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json index 1b59707b98f2..f1fec860a9d3 100644 --- a/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json +++ b/tests/topotests/ospf_metric_propagation/r1/show_ip_route-6.json @@ -2,32 +2,15 @@ "10.0.94.0/24":[ { "prefix":"10.0.94.0/24", - "prefixLen":24, "protocol":"bgp", "vrfName":"green", - "selected":true, - "destSelected":true, - "distance":20, "metric":136, "installed":true, - "table":12, - "internalStatus":16, - "internalFlags":8, - "internalNextHopNum":1, - "internalNextHopActiveNum":1, - "nexthopGroupId":"*", - "installedNexthopGroupId":"*", - "uptime":"*", "nexthops":[ { - "flags":3, - "fib":true, "ip":"10.0.10.5", - "afi":"ipv4", "interfaceName":"r1-eth1", - "vrf":"blue", - "active":true, - "weight":1 + "vrf":"blue" } ] } diff --git a/tests/topotests/ospf_metric_propagation/r2/frr.conf b/tests/topotests/ospf_metric_propagation/r2/frr.conf index e67a374ff552..0ac5001b1b99 100644 --- a/tests/topotests/ospf_metric_propagation/r2/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r2/frr.conf @@ -8,18 +8,18 @@ interface r2-eth0 ip address 10.0.1.2/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r2-eth1 vrf blue ip address 10.0.20.2/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r2-eth2 vrf green ip address 10.0.70.2/24 ip ospf cost 1000 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.2 diff --git a/tests/topotests/ospf_metric_propagation/r3/frr.conf b/tests/topotests/ospf_metric_propagation/r3/frr.conf index 175851d42763..0859173f7971 100644 --- a/tests/topotests/ospf_metric_propagation/r3/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r3/frr.conf @@ -8,18 +8,18 @@ interface r3-eth0 ip address 10.0.3.3/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r3-eth1 vrf blue ip address 10.0.30.3/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r3-eth2 vrf green ip address 10.0.80.3/24 ip ospf cost 1000 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.3 diff --git a/tests/topotests/ospf_metric_propagation/r4/frr.conf b/tests/topotests/ospf_metric_propagation/r4/frr.conf index 70a47e34fa67..743da272727f 100644 --- a/tests/topotests/ospf_metric_propagation/r4/frr.conf +++ b/tests/topotests/ospf_metric_propagation/r4/frr.conf @@ -8,17 +8,17 @@ interface r4-eth0 ip address 10.0.3.4/24 ip ospf cost 100 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r4-eth1 vrf blue ip address 10.0.40.4/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface r4-eth2 vrf green ip address 10.0.94.4/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.4 diff --git a/tests/topotests/ospf_metric_propagation/ra/frr.conf b/tests/topotests/ospf_metric_propagation/ra/frr.conf index 7be9e5c33e90..2434faeabc97 100644 --- a/tests/topotests/ospf_metric_propagation/ra/frr.conf +++ b/tests/topotests/ospf_metric_propagation/ra/frr.conf @@ -7,17 +7,17 @@ ip forwarding interface ra-eth0 ip address 10.0.50.5/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface ra-eth1 ip address 10.0.10.5/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface ra-eth2 ip address 10.0.20.5/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.5 diff --git a/tests/topotests/ospf_metric_propagation/rb/frr.conf b/tests/topotests/ospf_metric_propagation/rb/frr.conf index a7dbf82278ce..b83532a8405a 100644 --- a/tests/topotests/ospf_metric_propagation/rb/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rb/frr.conf @@ -7,17 +7,17 @@ ip forwarding interface rb-eth0 ip address 10.0.50.6/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface rb-eth1 ip address 10.0.30.6/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface rb-eth2 ip address 10.0.40.6/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.6 diff --git a/tests/topotests/ospf_metric_propagation/rc/frr.conf b/tests/topotests/ospf_metric_propagation/rc/frr.conf index f5a2ed7c4f17..dd8077c3949f 100644 --- a/tests/topotests/ospf_metric_propagation/rc/frr.conf +++ b/tests/topotests/ospf_metric_propagation/rc/frr.conf @@ -7,12 +7,12 @@ ip forwarding interface rc-eth0 ip address 10.0.70.7/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! interface rc-eth1 ip address 10.0.80.7/24 ip ospf hello-interval 1 - ip ospf dead-interval 30 + ip ospf dead-interval 40 ! router ospf ospf router-id 10.0.255.7 diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py index 085eb1f9c123..b97b86bff9a3 100644 --- a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py +++ b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py @@ -11,14 +11,13 @@ import os import sys import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -166,7 +165,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -283,7 +282,7 @@ def test_link_1_2_3_4_down(): assert result is None, assertmsg -def test_link_1_2_4_down(): +def test_link_1_2_4_down_3_up(): "Test path R1 -> R2 -> Rc -> R3 -> R4" tgen = get_topogen() @@ -305,7 +304,7 @@ def test_link_1_2_4_down(): assert result is None, assertmsg -def test_link_1_4_down(): +def test_link_1_4_down_2_up(): "Test path R1 -> R2 -> Ra -> Rb -> R3 -> R4" tgen = get_topogen() @@ -321,13 +320,13 @@ def test_link_1_4_down(): test_func = partial( topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=2) assertmsg = "r1 JSON output mismatches" assert result is None, assertmsg -def test_link_4_down(): +def test_link_4_down_1_up(): "Test path R1 -> Ra -> Rb -> R3 -> R4" tgen = get_topogen() @@ -343,7 +342,7 @@ def test_link_4_down(): test_func = partial( topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=2) assertmsg = "r1 JSON output mismatches" assert result is None, assertmsg @@ -365,7 +364,7 @@ def test_link_1_2_3_4_up(): test_func = partial( topotest.router_json_cmp, r1, "show ip route vrf green 10.0.94.2 json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=2) assertmsg = "r1 JSON output mismatches" assert result is None, assertmsg diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf index e365e25772c3..995958132c93 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf @@ -5,12 +5,18 @@ log file /tmp/r1-frr.log ! interface r1-eth0 ip address 10.0.1.1/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! interface r1-eth1 ip address 10.0.20.1/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! interface r1-eth2 vrf neno ip address 10.0.30.1/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! ip forwarding ! diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt index 86c089ab3b57..797bced7b8be 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt @@ -1,9 +1,11 @@ O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX -C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX +C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX +L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX B>* 10.0.3.0/24 [20/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX -C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX -B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), weight 1, XX:XX:XX +C>* 10.0.20.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX +L>* 10.0.20.1/32 is directly connected, r1-eth1, weight 1, XX:XX:XX +B>* 10.0.30.0/24 [20/0] is directly connected, neno (vrf neno), weight 1, XX:XX:XX O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt index 4e818eb6f132..1dc574f36085 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt @@ -2,5 +2,6 @@ VRF neno: O>* 10.0.3.0/24 [110/20] via 10.0.30.3, r1-eth2, weight 1, XX:XX:XX B>* 10.0.4.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX O 10.0.30.0/24 [110/10] is directly connected, r1-eth2, weight 1, XX:XX:XX -C>* 10.0.30.0/24 is directly connected, r1-eth2, XX:XX:XX +C>* 10.0.30.0/24 is directly connected, r1-eth2, weight 1, XX:XX:XX +L>* 10.0.30.1/32 is directly connected, r1-eth2, weight 1, XX:XX:XX B>* 10.0.40.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf index e87899ca77e1..29909de6461d 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf @@ -5,14 +5,20 @@ log file /tmp/r2-frr.log ! interface r2-eth0 ip address 10.0.2.2/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! interface r2-eth1 ip address 10.0.20.2/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! ip route 0.0.0.0/0 10.0.20.1 ! interface r2-eth2 vrf ray ip address 10.0.40.2/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! ip forwarding ! diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt index 9681d8a04ec9..b5e81bc0e9a8 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt @@ -1,10 +1,12 @@ S>* 0.0.0.0/0 [1/0] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX O>* 10.0.1.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX -C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX +C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX +L>* 10.0.2.2/32 is directly connected, r2-eth0, weight 1, XX:XX:XX O>* 10.0.3.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX B>* 10.0.4.0/24 [20/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX -C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX +C>* 10.0.20.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX +L>* 10.0.20.2/32 is directly connected, r2-eth1, weight 1, XX:XX:XX O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX -B>* 10.0.40.0/24 [20/0] is directly connected, r2-eth2 (vrf ray), weight 1, XX:XX:XX +B>* 10.0.40.0/24 [20/0] is directly connected, ray (vrf ray), weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt index ce9903ae718f..c403496ff66e 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt @@ -6,4 +6,5 @@ O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX -C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX +C>* 10.0.40.0/24 is directly connected, r2-eth2, weight 1, XX:XX:XX +L>* 10.0.40.2/32 is directly connected, r2-eth2, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf index 2657f589d87a..35fe22e9f9bc 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf @@ -5,9 +5,13 @@ log file /tmp/r3-frr.log ! interface r3-eth0 ip address 10.0.3.3/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! interface r3-eth1 ip address 10.0.30.3/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! ip forwarding ! diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt index f6f861b73b0c..db4e268cb018 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt @@ -1,8 +1,10 @@ O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r3-eth0, weight 1, XX:XX:XX +L>* 10.0.3.3/32 is directly connected, r3-eth0, weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.30.1, r3-eth1, weight 1, XX:XX:XX O 10.0.30.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX -C>* 10.0.30.0/24 is directly connected, r3-eth1, XX:XX:XX +C>* 10.0.30.0/24 is directly connected, r3-eth1, weight 1, XX:XX:XX +L>* 10.0.30.3/32 is directly connected, r3-eth1, weight 1, XX:XX:XX O>* 10.0.40.0/24 [110/20] via 10.0.30.1, r3-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf index 79d80770622a..721c3d91c388 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf @@ -5,9 +5,13 @@ log file /tmp/r4-frr.log ! interface r4-eth0 ip address 10.0.4.4/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! interface r4-eth1 ip address 10.0.40.4/24 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! ip forwarding ! diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt index b6be5e7fdbe0..4865708578e2 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt @@ -1,7 +1,9 @@ O>* 10.0.3.0/24 [110/20] via 10.0.40.2, r4-eth1, weight 1, XX:XX:XX O 10.0.4.0/24 [110/10] is directly connected, r4-eth0, weight 1, XX:XX:XX -C>* 10.0.4.0/24 is directly connected, r4-eth0, XX:XX:XX +C>* 10.0.4.0/24 is directly connected, r4-eth0, weight 1, XX:XX:XX +L>* 10.0.4.4/32 is directly connected, r4-eth0, weight 1, XX:XX:XX O>* 10.0.30.0/24 [110/20] via 10.0.40.2, r4-eth1, weight 1, XX:XX:XX O 10.0.40.0/24 [110/10] is directly connected, r4-eth1, weight 1, XX:XX:XX -C>* 10.0.40.0/24 is directly connected, r4-eth1, XX:XX:XX +C>* 10.0.40.0/24 is directly connected, r4-eth1, weight 1, XX:XX:XX +L>* 10.0.40.4/32 is directly connected, r4-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py index 792304e19d38..10a0051a472b 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py @@ -16,7 +16,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -139,7 +139,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -182,9 +182,7 @@ def test_ospf_convergence(): "show ip ospf vrf {} route".format(vrf), expected, ) - result, diff = topotest.run_and_expect( - test_func, "", count=80, wait=1 - ) + result, diff = topotest.run_and_expect(test_func, "", count=80, wait=1) assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff) assert result, assertmsg @@ -207,9 +205,7 @@ def test_ospf_kernel_route(): test_func = partial( compare_show_ip_route_vrf, router.name, expected, vrf ) - result, diff = topotest.run_and_expect( - test_func, "", count=80, wait=1 - ) + result, diff = topotest.run_and_expect(test_func, "", count=80, wait=1) assertmsg = 'OSPF IPv4 route mismatch in router "{}": {}'.format( router.name, diff ) diff --git a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf index e1e2bfb99a77..ba131465612b 100644 --- a/tests/topotests/ospf_netns_vrf/r1/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r1/ospfd.conf @@ -3,6 +3,14 @@ hostname r1 password zebra log file /tmp/r1-ospfd.log ! +interface r1-eth0 vrf r1-ospf-cust1 + ip ospf hello-interval 1 + ip ospf dead-interval 4 +! +interface r1-eth1 vrf r1-ospf-cust1 + ip ospf hello-interval 1 + ip ospf dead-interval 4 +! router ospf vrf r1-ospf-cust1 ospf router-id 10.0.255.1 redistribute kernel diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt index 979af20c59e2..68fd30d4ccba 100644 --- a/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt +++ b/tests/topotests/ospf_netns_vrf/r1/zebraroute.txt @@ -1,8 +1,10 @@ VRF r1-ospf-cust1: O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX -C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX +C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX +L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX +L>* 10.0.3.2/32 is directly connected, r1-eth1, weight 1, XX:XX:XX O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt index ec99fad762de..f0bce905b132 100644 --- a/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt +++ b/tests/topotests/ospf_netns_vrf/r1/zebraroutedown.txt @@ -1,7 +1,9 @@ VRF r1-ospf-cust1: O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX -C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX +C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX +L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r1-eth1, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r1-eth1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX +L>* 10.0.3.2/32 is directly connected, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf index c1984276f407..01b6b1526b1c 100644 --- a/tests/topotests/ospf_netns_vrf/r2/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r2/ospfd.conf @@ -3,6 +3,13 @@ hostname r2 password zebra log file /tmp/r2-ospfd.log ! +interface r2-eth0 vrf r2-ospf-cust1 + ip ospf hello-interval 1 + ip ospf dead-interval 4 +! +interface r2-eth1 vrf r2-ospf-cust1 + ip ospf hello-interval 1 + ip ospf dead-interval 4 ! router ospf vrf r2-ospf-cust1 ospf router-id 10.0.255.2 diff --git a/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt index df66e92abc88..098eceb28bed 100644 --- a/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt +++ b/tests/topotests/ospf_netns_vrf/r2/zebraroute.txt @@ -1,8 +1,10 @@ VRF r2-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX -C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX +C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX +L>* 10.0.2.1/32 is directly connected, r2-eth0, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX +L>* 10.0.3.3/32 is directly connected, r2-eth1, weight 1, XX:XX:XX O>* 10.0.10.0/24 [110/20] via 10.0.3.1, r2-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt index 4afc354ca7ec..a9300f8dfafb 100644 --- a/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt +++ b/tests/topotests/ospf_netns_vrf/r2/zebraroutedown.txt @@ -1,7 +1,9 @@ VRF r2-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r2-eth1, weight 1, XX:XX:XX O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX -C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX +C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX +L>* 10.0.2.1/32 is directly connected, r2-eth0, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r2-eth1, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX +L>* 10.0.3.3/32 is directly connected, r2-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf index b73d547e3e13..abfaa5b9eff1 100644 --- a/tests/topotests/ospf_netns_vrf/r3/ospfd.conf +++ b/tests/topotests/ospf_netns_vrf/r3/ospfd.conf @@ -4,6 +4,14 @@ password zebra log file /tmp/r3-ospfd.log ! ! +interface r3-eth0 vrf r3-ospf-cust1 + ip ospf hello-interval 1 + ip ospf dead-interval 4 +! +interface r3-eth1 vrf r3-ospf-cust1 + ip ospf hello-interval 1 + ip ospf dead-interval 4 +! router ospf vrf r3-ospf-cust1 ospf router-id 10.0.255.3 redistribute kernel diff --git a/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt b/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt index b435c2ebe544..f58beb81a729 100644 --- a/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt +++ b/tests/topotests/ospf_netns_vrf/r3/zebraroute.txt @@ -2,7 +2,9 @@ VRF r3-ospf-cust1: O>* 10.0.1.0/24 [110/20] via 10.0.3.2, r3-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.3.3, r3-eth0, weight 1, XX:XX:XX O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX -C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX +C>* 10.0.3.0/24 is directly connected, r3-eth0, weight 1, XX:XX:XX +L>* 10.0.3.1/32 is directly connected, r3-eth0, weight 1, XX:XX:XX O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX -C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX +C>* 10.0.10.0/24 is directly connected, r3-eth1, weight 1, XX:XX:XX +L>* 10.0.10.1/32 is directly connected, r3-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt b/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt index f30a4be6c684..cfedf8fcb472 100644 --- a/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt +++ b/tests/topotests/ospf_netns_vrf/r3/zebraroutedown.txt @@ -1,4 +1,5 @@ VRF r3-ospf-cust1: O 10.0.10.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX -C>* 10.0.10.0/24 is directly connected, r3-eth1, XX:XX:XX +C>* 10.0.10.0/24 is directly connected, r3-eth1, weight 1, XX:XX:XX +L>* 10.0.10.1/32 is directly connected, r3-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py index 2716f63348c8..eae8806a5943 100644 --- a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py +++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py @@ -87,6 +87,7 @@ def setup_module(mod): router.net.set_intf_netns(rname + "-eth0", ns, up=True) router.net.set_intf_netns(rname + "-eth1", ns, up=True) + router.load_config(TopoRouter.RD_MGMTD, None, "--vrfwnetns") router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)), @@ -103,13 +104,13 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # Move interfaces out of vrf namespace and delete the namespace router_list = tgen.routers() - for rname, router in router_list.items(): + for rname, _ in router_list.items(): tgen.net[rname].reset_intf_netns(rname + "-eth0") tgen.net[rname].reset_intf_netns(rname + "-eth1") tgen.net[rname].delete_netns(rname + "-ospf-cust1") diff --git a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py index 432ddf098623..4a67fa33a6fe 100644 --- a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py +++ b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py @@ -106,7 +106,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -199,9 +199,7 @@ def test_rib_step3(): pytest.skip(tgen.errors) logger.info("Removing NSSA default on rt4") - tgen.net["rt3"].cmd( - 'vtysh -c "conf t" -c "router ospf" -c "area 1 nssa"' - ) + tgen.net["rt3"].cmd('vtysh -c "conf t" -c "router ospf" -c "area 1 nssa"') for rname in ["rt1", "rt2", "rt3", "rt4"]: router_compare_json_output( diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf new file mode 100644 index 000000000000..ca84349cdcf2 --- /dev/null +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp-non-broadcast.conf @@ -0,0 +1,26 @@ +! +hostname r1 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r1-eth0 + ip address 10.1.0.1/24 + ip ospf network point-to-multipoint non-broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +interface r1-eth1 + ip address 10.1.1.1/24 + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +router ospf + ospf router-id 1.1.1.1 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.1.0/24 area 0 + neighbor 10.1.0.2 poll-interval 5 + neighbor 10.1.0.3 poll-interval 5 + neighbor 10.1.0.4 poll-interval 5 +! diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf new file mode 100644 index 000000000000..89f255bb44ea --- /dev/null +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -0,0 +1,29 @@ +! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all + +hostname r1 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r1-eth0 + ip address 10.1.0.1/24 + ip ospf network point-to-multipoint + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +interface r1-eth1 + ip address 10.1.1.1/24 + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +router ospf + ospf router-id 1.1.1.1 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.1.0/24 area 0 +! diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf new file mode 100644 index 000000000000..6e26897c494b --- /dev/null +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp-non-broadcast.conf @@ -0,0 +1,29 @@ +! +hostname r2 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r2-eth0 + ip address 10.1.0.2/24 + ip ospf network point-to-multipoint non-broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +interface r2-eth1 + ip address 10.1.2.2/24 + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +! +! +router ospf + ospf router-id 2.2.2.2 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.2.0/24 area 0 + neighbor 10.1.0.1 poll-interval 5 + neighbor 10.1.0.3 poll-interval 5 + neighbor 10.1.0.4 poll-interval 5 +! diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf new file mode 100644 index 000000000000..429330987e06 --- /dev/null +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -0,0 +1,32 @@ +! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! +hostname r2 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r2-eth0 + ip address 10.1.0.2/24 + ip ospf network point-to-multipoint + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +interface r2-eth1 + ip address 10.1.2.2/24 + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +! +! +router ospf + ospf router-id 2.2.2.2 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.2.0/24 area 0 +! diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf new file mode 100644 index 000000000000..a69e0557bee7 --- /dev/null +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp-non-broadcast.conf @@ -0,0 +1,28 @@ +! +hostname r3 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r3-eth0 + ip address 10.1.0.3/24 + ip ospf network point-to-multipoint non-broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +interface r3-eth1 + ip address 10.1.3.3/24 + ip ospf network broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +router ospf + ospf router-id 3.3.3.3 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.3.0/24 area 0 + neighbor 10.1.0.1 poll-interval 5 + neighbor 10.1.0.2 poll-interval 5 + neighbor 10.1.0.4 poll-interval 5 diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf new file mode 100644 index 000000000000..eada78450e81 --- /dev/null +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -0,0 +1,31 @@ +! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! +hostname r3 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r3-eth0 + ip address 10.1.0.3/24 + ip ospf network point-to-multipoint + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +interface r3-eth1 + ip address 10.1.3.3/24 + ip ospf network broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +router ospf + ospf router-id 3.3.3.3 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.3.0/24 area 0 diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf new file mode 100644 index 000000000000..1b8388584b82 --- /dev/null +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp-non-broadcast.conf @@ -0,0 +1,28 @@ +! +hostname r4 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r4-eth0 + ip address 10.1.0.4/24 + ip ospf network point-to-multipoint non-broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +interface r4-eth1 + ip address 10.1.4.4/24 + ip ospf network broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +router ospf + ospf router-id 4.4.4.4 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.4.0/24 area 0 + neighbor 10.1.0.1 poll-interval 5 + neighbor 10.1.0.2 poll-interval 5 + neighbor 10.1.0.3 poll-interval 5 diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf new file mode 100644 index 000000000000..3146ea095762 --- /dev/null +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -0,0 +1,31 @@ +! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! +hostname r4 +password zebra +log file /tmp/r1-frr.log +ip forwarding +! +interface r4-eth0 + ip address 10.1.0.4/24 + ip ospf network point-to-multipoint + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +interface r4-eth1 + ip address 10.1.4.4/24 + ip ospf network broadcast + ip ospf hello-interval 1 + ip ospf dead-interval 30 +! +! +router ospf + ospf router-id 4.4.4.4 + distance 20 + network 10.1.0.0/24 area 0 + network 10.1.4.0/24 area 0 diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py new file mode 100644 index 000000000000..455c737f0d71 --- /dev/null +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -0,0 +1,524 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# test_ospf_prefix_p2mp_broadcast.py +# +# Copyright (c) 2024 LabN Consulting +# Acee Lindem +# + +import os +import sys +from time import sleep +from functools import partial +import pytest + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +from lib.common_config import ( + step, +) + + +""" +test_ospf_p2mp_broadcast.py: Test OSPF Point-to-multipoint +""" + +TOPOLOGY = """ + +-----+ +-----+ +10.1.1.0/24 | r1 | | r2 | 10.1.2.0/24 + -----------+ | | +---------- + +--+--+ +--+--+ + | 10.1.0.0/24 | + | +-------+ | + +---- | |-----+ + | P2MP | + +---- | |-----+ + | +-------+ | + | | + | | + +--+--+ +-+---+ +10.1.3.0/24 | r3 | | r4 | 10.1.4.0/24 + -----------+ | | +---------- + +-----+ +-----+ + + +""" + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.ospfd, pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 4 routers + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("r3") + tgen.add_router("r4") + + # Interconect them all to the P2MP network + switch = tgen.add_switch("s0-p2mp") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + # Add standalone network to router 1 + switch = tgen.add_switch("s-r1-1") + switch.add_link(tgen.gears["r1"]) + + # Add standalone network to router 2 + switch = tgen.add_switch("s-r2-1") + switch.add_link(tgen.gears["r2"]) + + # Add standalone network to router 3 + switch = tgen.add_switch("s-r3-1") + switch.add_link(tgen.gears["r3"]) + + # Add standalone network to router 4 + switch = tgen.add_switch("s-r4-1") + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + logger.info("OSPF Point-to-MultiPoint:\n {}".format(TOPOLOGY)) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # Starting Routers + router_list = tgen.routers() + + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_frr_config(os.path.join(CWD, "{}/frr-p2mp.conf".format(rname))) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def verify_p2mp_interface( + tgen, router, nbr_cnt, nbr_adj_cnt, delay_reflood, nbr_filter +): + "Verify the P2MP Configuration and interface settings" + + topo_router = tgen.gears[router] + + step("Test running configuration for P2MP configuration") + rc = 0 + rc, _, _ = tgen.net[router].cmd_status( + "show running ospfd | grep 'ip ospf network point-to-multipoint'", warn=False + ) + assertmsg = ( + "'ip ospf network point-to-multipoint' applied, but not present in " + + router + + "configuration" + ) + assert rc, assertmsg + + step("Test OSPF interface for P2MP settings") + input_dict = { + "interfaces": { + "r1-eth0": { + "ospfEnabled": True, + "ipAddress": "10.1.0.1", + "ipAddressPrefixlen": 24, + "ospfIfType": "Broadcast", + "area": "0.0.0.0", + "routerId": "1.1.1.1", + "networkType": "POINTOMULTIPOINT", + "cost": 10, + "state": "Point-To-Point", + "opaqueCapable": True, + "nbrCount": nbr_cnt, + "nbrAdjacentCount": nbr_adj_cnt, + "prefixSuppression": False, + "p2mpDelayReflood": delay_reflood, + "nbrFilterPrefixList": nbr_filter, + } + } + } + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip ospf interface r1-eth0 json", + input_dict, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Interface Mismatch on router r1" + assert result is None, assertmsg + + +def verify_non_p2mp_interface(tgen): + "Verify the removal of P2MP Configuration and interface settings" + r1 = tgen.gears["r1"] + + step("Test running configuration for removal of P2MP configuration") + rc = 0 + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep -q 'ip ospf network point-to-multipoint'", warn=False + ) + assertmsg = "'ip ospf network point-to-multipoint' not applied, but present in r1 configuration" + assert rc, assertmsg + + step("Test OSPF interface for default settings") + input_dict = { + "interfaces": { + "r1-eth0": { + "ospfEnabled": True, + "ipAddress": "10.1.0.1", + "ipAddressPrefixlen": 24, + "ospfIfType": "Broadcast", + "area": "0.0.0.0", + "routerId": "1.1.1.1", + "networkType": "BROADCAST", + "cost": 10, + "opaqueCapable": True, + "prefixSuppression": False, + } + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf interface r1-eth0 json", input_dict + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Interface Mismatch on router r1" + assert result is None, assertmsg + + +def verify_p2mp_neighbor(tgen, router, neighbor, state, intf_addr, interface): + topo_router = tgen.gears[router] + + step("Verify neighbor " + neighbor + " in " + state + " state") + input_dict = { + "default": { + neighbor: [ + { + "nbrState": state, + "ifaceAddress": intf_addr, + "ifaceName": interface, + } + ], + } + } + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip ospf neighbor " + neighbor + " json", + input_dict, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Neighbor " + neighbor + " not in " + state + assert result is None, assertmsg + + +def verify_p2mp_neighbor_missing(tgen, router, neighbor): + topo_router = tgen.gears[router] + + step("Verify neighbor " + neighbor + " missing") + input_dict = {"default": {}} + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip ospf neighbor " + neighbor + " json", + input_dict, + True, # Require exact match for missing neighbor + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Neighbor " + neighbor + " not missing" + assert result is None, assertmsg + + +def verify_p2mp_route(tgen, router, prefix, prefix_len, nexthop, interface): + topo_router = tgen.gears[router] + + step("Verify router " + router + " p2mp route " + prefix + " installed") + input_dict = { + prefix: [ + { + "prefix": prefix, + "prefixLen": prefix_len, + "protocol": "ospf", + "nexthops": [ + { + "ip": nexthop, + "interfaceName": interface, + } + ], + } + ] + } + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip route " + prefix + " json", + input_dict, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = prefix + " not installed on router " + router + assert result is None, assertmsg + + +def test_p2mp_broadcast_interface(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Verify router r1 interface r1-eth0 p2mp configuration") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") + + step("Verify router r1 p2mp interface r1-eth0 neighbors") + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1" + ) + + step("Verify router r1 p2mp routes installed") + verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.2", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.3.0/24", 24, "10.1.0.3", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") + + step("Verify router r1 interface r1-eth0 p2mp configuration removal") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf t\ninterface r1-eth0\nno ip ospf network point-to-multipoint") + verify_non_p2mp_interface(tgen) + + step("Verify router r1 interface r1-eth0 p2mp configuration application") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") + + step("Verify restablishment of r1-eth0 p2mp neighbors") + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1" + ) + + step("Verify router r1 p2mp routes reinstalled") + verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.2", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.3.0/24", 24, "10.1.0.3", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") + + +def p2mp_broadcast_neighbor_filter_common(delay_reflood): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Verify router r1 interface r1-eth0 p2mp configuration") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + step("Verify router r1 p2mp interface r1-eth0 neighbors") + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1" + ) + + step("Add OSPF interface neighbor-filter to r1") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + + step("Verify the R1 configuration of 'ip ospf neighbor-filter nbr-filter'") + neighbor_filter_cfg = ( + tgen.net["r1"] + .cmd( + 'vtysh -c "show running ospfd" | grep "^ ip ospf neighbor-filter nbr-filter"' + ) + .rstrip() + ) + assertmsg = ( + "'ip ospf neighbor-filter nbr-filter' applied, but not present in configuration" + ) + assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg + + step("Verify non-existent neighbor-filter is not applied to r1 interfaces") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + step("Add nbr-filter prefix-list configuration to r1") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any") + + step( + "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent" + ) + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "nbr-filter") + + step("Add nbr-filter prefix-list configuration to block r4") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") + + step( + "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent" + ) + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") + verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") + + step("Verify route to r4 subnet is now through r2") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.2", "r1-eth0") + + step("Add nbr-filter prefix-list configuration to block r2") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32") + + step( + "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent" + ) + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") + verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") + + step("Verify route to r4 and r2 subnet are now through r3") + verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.3", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.3", "r1-eth0") + + step("Remove neighbor filter configuration and verify") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nno ip ospf neighbor-filter") + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep -q 'ip ospf neighbor-filter'", warn=False + ) + assertmsg = "'ip ospf neighbor' not applied, but present in R1 configuration" + assert rc, assertmsg + + step("Verify interface neighbor-filter is removed and neighbors present") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + step("Add neighbor filter configuration and verify neighbors are filtered") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") + verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") + verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") + + step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor") + r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + + step("Delete nbr-filter prefix-list and verify neighbors are present") + r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + +def test_p2mp_broadcast_neighbor_filter(): + p2mp_broadcast_neighbor_filter_common(False) + + +def test_p2mp_broadcast_neighbor_filter_delay_reflood(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Modify router r1 interface r1-eth0 p2mp delay-reflood configuration") + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + verify_p2mp_interface(tgen, "r1", 3, 3, True, "N/A") + + step("Modify router r2 interface r2-eth0 p2mp delay-reflood configuration") + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + "conf t\ninterface r2-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r3 interface r3-eth0 p2mp delay-reflood configuration") + r3 = tgen.gears["r3"] + r3.vtysh_cmd( + "conf t\ninterface r3-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r4 interface r4-eth0 p2mp delay-reflood configuration") + r4 = tgen.gears["r4"] + r4.vtysh_cmd( + "conf t\ninterface r4-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + p2mp_broadcast_neighbor_filter_common(True) + + step("Recreate a partial P2MP mesh with neighbor filters") + step("Add nbr-filter prefix-list configuration to block r4") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.3/32") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.4/32") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf neighbor-filter nbr-filter") + + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nip ospf neighbor-filter nbr-filter") + + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nip ospf neighbor-filter nbr-filter") + + step( + "Add redistribution and spaced static routes to r1 to test delay flood retransmission" + ) + r1.vtysh_cmd("conf t\nrouter ospf\nredistribute static") + r1.vtysh_cmd("conf t\nip route 20.1.1.1/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.2/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.3/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.4/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.5/32 null0") + sleep(1) + + step( + "Verify the routes are installed on r1 with delay-reflood in P2MP partial mesh" + ) + verify_p2mp_route(tgen, "r4", "20.1.1.1/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.2/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.3/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.4/32", 32, "10.1.0.3", "r4-eth0") + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py new file mode 100644 index 000000000000..83137a8992b9 --- /dev/null +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py @@ -0,0 +1,447 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_ospf_prefix_p2mp_non_broadcast.py +# +# Copyright (c) 2024 LabN Consulting +# Acee Lindem +# + +import os +import sys +from time import sleep +from functools import partial +import pytest + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +from lib.common_config import ( + step, +) + + +""" +test_ospf_p2mp_non_broadcast.py: Test OSPF Point-to-multipoint Non-Broadcast + Full Mesh +""" + +TOPOLOGY = """ + +-----+ +-----+ +10.1.1.0/24 | r1 | | r2 | 10.1.2.0/24 + -----------+ | | +---------- + +--+--+ +--+--+ + | 10.1.0.0/24 | + | +-------+ | + +---- | |-----+ + | P2MP | + +---- | |-----+ + | +-------+ | + | | + | | + +--+--+ +-+---+ +10.1.3.0/24 | r3 | | r4 | 10.1.4.0/24 + -----------+ | | +---------- + +-----+ +-----+ + + +""" + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.ospfd, pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 4 routers + tgen.add_router("r1") + tgen.add_router("r2") + tgen.add_router("r3") + tgen.add_router("r4") + + # Interconect them all to the P2MP network + switch = tgen.add_switch("s0-p2mp") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + # Add standalone network to router 1 + switch = tgen.add_switch("s-r1-1") + switch.add_link(tgen.gears["r1"]) + + # Add standalone network to router 2 + switch = tgen.add_switch("s-r2-1") + switch.add_link(tgen.gears["r2"]) + + # Add standalone network to router 3 + switch = tgen.add_switch("s-r3-1") + switch.add_link(tgen.gears["r3"]) + + # Add standalone network to router 4 + switch = tgen.add_switch("s-r4-1") + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + logger.info("OSPF Point-to-MultiPoint Non-Broadcast:\n {}".format(TOPOLOGY)) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # Starting Routers + router_list = tgen.routers() + + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_frr_config( + os.path.join(CWD, "{}/frr-p2mp-non-broadcast.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, non_broadcast): + "Verify the P2MP Configuration and interface settings" + + topo_router = tgen.gears[router] + + step("Test running configuration for P2MP configuration") + rc = 0 + rc, _, _ = tgen.net[router].cmd_status( + "show running ospfd | grep 'ip ospf network point-to-multipoint'", warn=False + ) + assertmsg = ( + "'ip ospf network point-to-multipoint' applied, but not present in " + + router + + "configuration" + ) + assert rc, assertmsg + + step("Test OSPF interface for P2MP settings") + input_dict = { + "interfaces": { + "r1-eth0": { + "ospfEnabled": True, + "ipAddress": "10.1.0.1", + "ipAddressPrefixlen": 24, + "ospfIfType": "Broadcast", + "area": "0.0.0.0", + "routerId": "1.1.1.1", + "networkType": "POINTOMULTIPOINT", + "cost": 10, + "state": "Point-To-Point", + "opaqueCapable": True, + "nbrCount": nbr_cnt, + "nbrAdjacentCount": nbr_adj_cnt, + "prefixSuppression": False, + "p2mpDelayReflood": False, + "p2mpNonBroadcast": non_broadcast, + } + } + } + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip ospf interface r1-eth0 json", + input_dict, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Interface Mismatch on router r1" + assert result is None, assertmsg + + +def verify_p2mp_neighbor(tgen, router, neighbor, state, intf_addr, interface): + topo_router = tgen.gears[router] + + step("Verify neighbor " + neighbor + " in " + state + " state") + input_dict = { + "default": { + neighbor: [ + { + "nbrState": state, + "ifaceAddress": intf_addr, + "ifaceName": interface, + } + ], + } + } + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip ospf neighbor " + neighbor + " json", + input_dict, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Neighbor " + neighbor + " not in " + state + assert result is None, assertmsg + + +def verify_p2mp_route(tgen, router, prefix, prefix_len, nexthop, interface): + topo_router = tgen.gears[router] + + step("Verify router " + router + " p2mp route " + prefix + " installed") + input_dict = { + prefix: [ + { + "prefix": prefix, + "prefixLen": prefix_len, + "protocol": "ospf", + "nexthops": [ + { + "ip": nexthop, + "interfaceName": interface, + } + ], + } + ] + } + test_func = partial( + topotest.router_json_cmp, + topo_router, + "show ip route " + prefix + " json", + input_dict, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = prefix + " not installed on router " + router + assert result is None, assertmsg + + +def test_p2mp_non_broadcast_connectivity(): + tgen = get_topogen() + r1 = tgen.gears["r1"] + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Verify router r1 interface OSPF point-to-multipoint non-broadcast interface") + verify_p2mp_interface(tgen, "r1", 3, 3, True) + + step("Verify router r1 interface r1-eth0 p2mp non-broadcast configuration") + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep -q 'ip ospf network point-to-multipoint non-broadcast'", + warn=False, + ) + assertmsg = "'ip ospf network point-to-multipoint non-broadcast' applied, but not present in R1 configuration" + assert rc, assertmsg + + step("Verify router r1 OSPF point-to-multipoint neighbors") + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1" + ) + + step("Verify router r1 OSPF point-to-multipoint routes are installed") + verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.2", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.3.0/24", 24, "10.1.0.3", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") + + step("Remove r1 interface r1-eth0 p2mp non-broadcast configuration") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint") + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep -q 'ip ospf network point-to-multipoint non-broadcast'", + warn=False, + ) + assertmsg = "'ip ospf network point-to-multipoint non-broadcast' not applied, but present in r1 configuration" + assert rc, assertmsg + + step("Verify router r1 interface OSPF point-to-multipoint broadcast interface") + verify_p2mp_interface(tgen, "r1", 3, 3, False) + + step("Add r1 interface r1-eth0 p2mp non-broadcast configuration back") + r1.vtysh_cmd( + "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint non-broadcast" + ) + rc, _, _ = tgen.net["r1"].cmd_status( + "show running ospfd | grep 'ip ospf network point-to-multipoint non-broadcast'", + warn=False, + ) + assertmsg = "'ip ospf netrwork point-to-multipoint non-broadcast' applied, but not present in R1 configuration" + assert rc, assertmsg + + step("Verify router r1 interface OSPF point-to-multipoint non-broadcast interface") + verify_p2mp_interface(tgen, "r1", 3, 3, True) + + step( + "Verify router r1 OSPF point-to-multipoint neighbors adjacencies restablished." + ) + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1" + ) + verify_p2mp_neighbor( + tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1" + ) + + +def test_p2mp_non_broadcast_partial_mesh_connectivity(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + """ + test_ospf_p2mp_non_broadcast.py: Test OSPF Point-to-multipoint Non-Broadcast + Partial Mesh + """ + + TOPOLOGY = """ + +-----+ +------+ + 10.1.1.0/24 | r1 | | r4 | 10.1.4.0/24 + -----------+ | | +---------- + +-+---+ +--+-+-+ + | P2MP | + | Non-Broadcast | + | 10.1.0.0/24 | + +-+---+ +-+---+ + 10.1.2.0/24 | r2 | | r3 | 10.1.3.0/24 + -----------+ +--------------+ +---------- + +-----+ +-----+ + + + """ + logger.info("OSPF Point-to-MultiPoint Non-Broadcast:\n {}".format(TOPOLOGY)) + + step("Change configuration to a partial mesh") + step("Delete neighbors in full mesh") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.3") + r1.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.4") + r2 = tgen.gears["r2"] + r2.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.4") + r3 = tgen.gears["r3"] + r3.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.1") + r4 = tgen.gears["r4"] + r4.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.1") + r4.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.2") + + step("Flap interfaces on P2MP network to avoid transients") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nshut") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nshut") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nshut") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nshut") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nno shut") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nno shut") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nno shut") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nno shut") + + step("Verify router r1 interface OSPF point-to-multipoint non-broadcast interface") + verify_p2mp_interface(tgen, "r1", 1, 1, True) + + step("Verify router r1 interface r1-eth0 p2mp neighbor") + verify_p2mp_neighbor( + tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" + ) + + step("Verify router r1 p2mp routes are installed") + verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.2", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.3.0/24", 24, "10.1.0.2", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.2", "r1-eth0") + + """ + test_ospf_p2mp_non_broadcast.py: Test OSPF Point-to-multipoint Non-Broadcast + Modified Partial Mesh + """ + + TOPOLOGY = """ + +-----+ +------+ + 10.1.1.0/24 | r1 | | r4 | 10.1.4.0/24 + -----------+ +-------------+ +---------- + +-----+ +--+-+-+ + P2MP | + Non-Broadcast | + 10.1.0.0/24 | + +-+---+ +-+---+ + 10.1.2.0/24 | r2 | | r3 | 10.1.3.0/24 + -----------+ +--------------+ +---------- + +-----+ +-----+ + + + """ + logger.info("OSPF Point-to-MultiPoint Non-Broadcast:\n {}".format(TOPOLOGY)) + + step("Change configuration to a partial mesh") + step("Modify neighbors in partial mesh") + r1 = tgen.gears["r1"] + r1.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.2") + r1.vtysh_cmd("conf t\nrouter ospf\nneighbor 10.1.0.4 poll-interval 5") + r2 = tgen.gears["r2"] + r2.vtysh_cmd("conf t\nrouter ospf\nno neighbor 10.1.0.1") + r4 = tgen.gears["r4"] + r4.vtysh_cmd("conf t\nrouter ospf\nneighbor 10.1.0.1") + + step("Flap interfaces on P2MP network to avoid transients") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nshut") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nshut") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nshut") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nshut") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nno shut") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nno shut") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nno shut") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nno shut") + + step("Verify router r1 interface r1-eth0") + step("Verify router r1 interface OSPF point-to-multipoint non-broadcast interface") + verify_p2mp_interface(tgen, "r1", 1, 1, True) + + step("Verify router r1 interface r1-eth0 p2mp neighbor") + input_dict = { + "neighbors": { + "4.4.4.4": [ + { + "nbrState": "Full/DROther", + "ifaceAddress": "10.1.0.4", + "ifaceName": "r1-eth0:10.1.0.1", + } + ], + } + } + test_func = partial( + topotest.router_json_cmp, r1, "show ip ospf neighbor json", input_dict + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = "P2MP Non-Broadcast Neighbors not adjacent on router r1" + assert result is None, assertmsg + + step("Verify router r1 interface r1-eth0 p2mp routes are installed") + verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.4", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.3.0/24", 24, "10.1.0.4", "r1-eth0") + verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py index d5ea7ebc4048..f91cba8d3c57 100644 --- a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py +++ b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py @@ -10,21 +10,16 @@ import os import sys -import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -125,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_single_switch/r1_frr.conf b/tests/topotests/ospf_single_switch/r1_frr.conf new file mode 100644 index 000000000000..8fbb24133d89 --- /dev/null +++ b/tests/topotests/ospf_single_switch/r1_frr.conf @@ -0,0 +1,18 @@ +! +hostname r1 +ip forwarding +! +interface r1-eth0 + ip address 203.0.113.1/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r1-eth1 + ip address 10.0.1.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.1 +! diff --git a/tests/topotests/ospf_single_switch/r2_frr.conf b/tests/topotests/ospf_single_switch/r2_frr.conf new file mode 100644 index 000000000000..ea75ad6f0deb --- /dev/null +++ b/tests/topotests/ospf_single_switch/r2_frr.conf @@ -0,0 +1,18 @@ +! +hostname r2 +ip forwarding +! +interface r2-eth0 + ip address 203.0.113.2/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r2-eth1 + ip address 10.0.2.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.2 +! diff --git a/tests/topotests/ospf_single_switch/r3_frr.conf b/tests/topotests/ospf_single_switch/r3_frr.conf new file mode 100644 index 000000000000..e04e76edbb89 --- /dev/null +++ b/tests/topotests/ospf_single_switch/r3_frr.conf @@ -0,0 +1,18 @@ +! +hostname r3 +ip forwarding +! +interface r3-eth0 + ip address 203.0.113.3/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r3-eth1 + ip address 10.0.3.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.3 +! diff --git a/tests/topotests/ospf_single_switch/r4_frr.conf b/tests/topotests/ospf_single_switch/r4_frr.conf new file mode 100644 index 000000000000..9f0115853927 --- /dev/null +++ b/tests/topotests/ospf_single_switch/r4_frr.conf @@ -0,0 +1,18 @@ +! +hostname r4 +ip forwarding +! +interface r4-eth0 + ip address 203.0.113.4/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r4-eth1 + ip address 10.0.4.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.4 +! diff --git a/tests/topotests/ospf_single_switch/r5_frr.conf b/tests/topotests/ospf_single_switch/r5_frr.conf new file mode 100644 index 000000000000..c9f34974c2c6 --- /dev/null +++ b/tests/topotests/ospf_single_switch/r5_frr.conf @@ -0,0 +1,18 @@ +! +hostname r5 +ip forwarding +! +interface r5-eth0 + ip address 203.0.113.5/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r5-eth1 + ip address 10.0.5.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.5 +! diff --git a/tests/topotests/ospf_single_switch/r6_frr.conf b/tests/topotests/ospf_single_switch/r6_frr.conf new file mode 100644 index 000000000000..ba4b0bd28631 --- /dev/null +++ b/tests/topotests/ospf_single_switch/r6_frr.conf @@ -0,0 +1,18 @@ +! +hostname r6 +ip forwarding +! +interface r6-eth0 + ip address 203.0.113.6/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r6-eth1 + ip address 10.0.6.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.6 +! diff --git a/tests/topotests/ospf_single_switch/r7_frr.conf b/tests/topotests/ospf_single_switch/r7_frr.conf new file mode 100644 index 000000000000..3b28381ee80f --- /dev/null +++ b/tests/topotests/ospf_single_switch/r7_frr.conf @@ -0,0 +1,18 @@ +! +hostname r7 +ip forwarding +! +interface r7-eth0 + ip address 203.0.113.7/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r7-eth1 + ip address 10.0.7.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.7 +! diff --git a/tests/topotests/ospf_single_switch/r8_frr.conf b/tests/topotests/ospf_single_switch/r8_frr.conf new file mode 100644 index 000000000000..3b1b0e5f6434 --- /dev/null +++ b/tests/topotests/ospf_single_switch/r8_frr.conf @@ -0,0 +1,18 @@ +! +hostname r8 +ip forwarding +! +interface r8-eth0 + ip address 203.0.113.8/24 + ip ospf network point-to-multipoint + ip ospf area 0.0.0.0 + !ip ospf prefix-suppression +! +interface r8-eth1 + ip address 10.0.8.1/24 + ip ospf passive + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.0.8 +! diff --git a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py new file mode 100644 index 000000000000..0a8d8456daab --- /dev/null +++ b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# Copyright (c) 2023 by +# Adriano Marto Reis +# + +import os +import sys +import json +import subprocess +from functools import partial +import pytest + +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +from lib.common_config import verify_rib +from lib.ospf import verify_ospf_rib + +pytestmark = pytest.mark.ospfd + +""" +A large set of routers are connected to the same switch. Each router shares a +single network. All shared networks must be reachable from all routers. +""" + +TOPOLOGY = """ + net1 net2 netN + --- --- --- + | | OSPF-passive | + | | | + +---+---+ +---+---+ +---+---+ + | | | | | | + | r1 | | r2 | (...) | rN | + | | | | | | + +---+---+ +---+---+ +---+---+ + | | OSPF-active | + | | | + +----------------+--------------------------------+ + switch + + +""" + +N_ROUTERS = 8 + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + + +def build_topo(tgen): + "Build the topology" + + # Create a single switch to connect all the routers + switch = tgen.add_switch("switch") + + # Create routers + for router_id in range(1, N_ROUTERS + 1): + router = tgen.add_router(f"r{router_id}") + switch.add_link(router) + + # The shared network needs to be connected to something + dummy = tgen.add_switch(f"s{router_id}") + dummy.add_link(router) + + +def setup_module(mod): + logger.info("OSPF single switch:\n {}".format(TOPOLOGY)) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # Starting Routers + router_list = tgen.routers() + + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_frr_config(os.path.join(CWD, "{}_frr.conf".format(rname))) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(): + "Tear-down the test environment" + tgen = get_topogen() + tgen.stop_topology() + + +def is_iproute2_json_supported(): + """ + Checks if the command 'ip -j route' is supported. + """ + try: + output = subprocess.run( + ["ip", "-j", "route", "get", "0.0.0.0"], stdout=subprocess.PIPE + ).stdout.decode() + json.loads(output) + return True + except json.decoder.JSONDecodeError: + return False + + +@pytest.mark.skipif( + not is_iproute2_json_supported(), reason="'ip -j route' not supported" +) +def test_all_routes_advertised(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + # networks advertised by each router and the expected next hops + networks = { + "r1": ("10.0.1.0/24", "203.0.113.1"), + "r2": ("10.0.2.0/24", "203.0.113.2"), + "r3": ("10.0.3.0/24", "203.0.113.3"), + "r4": ("10.0.4.0/24", "203.0.113.4"), + "r5": ("10.0.5.0/24", "203.0.113.5"), + "r6": ("10.0.6.0/24", "203.0.113.6"), + "r7": ("10.0.7.0/24", "203.0.113.7"), + "r8": ("10.0.8.0/24", "203.0.113.8"), + } + + for router_orig in tgen.routers().keys(): + for router_dest, network in networks.items(): + if router_orig != router_dest: + input_dict = { + router_orig: { + "static_routes": [ + { + "network": network[0], + } + ] + } + } + result = verify_ospf_rib( + tgen, router_orig, input_dict, next_hop=network[1] + ) + assert result is True, "Error: {}".format(result) + result = verify_rib( + tgen, "ipv4", router_orig, input_dict, next_hop=network[1] + ) + assert result is True, "Error: {}".format(result) + + check_route(router_orig, network[0], network[1]) + + +def check_route(router_name, network, expected_nexthop): + """ + Checks if the given network is present on the given router and has the + expected next hop. + """ + tgen = get_topogen() + router = tgen.gears[router_name] + + expected_response = { + network: [ + { + "prefix": network, + "protocol": "ospf", + "nexthops": [ + { + "ip": expected_nexthop, + "active": True, + }, + ], + }, + ], + } + + test_func = partial( + topotest.router_json_cmp, + router, + f"show ip route {network} json", + expected_response, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert ( + result is None + ), f"{router_name} (ospfd): no route {network} via {expected_nexthop}" + + address = network.split("/")[0] + output = router.cmd(f"ip -j route get {address}") + logger.info(output) + routes = json.loads(output) + assert ( + routes[0]["gateway"] == expected_nexthop + ), f"{router_name} (kernel): no route {address} via {expected_nexthop}" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py index 21ae14323137..ec076bb3ccfd 100755 --- a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py +++ b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py index 936b438e9d7c..bac585dd8f96 100644 --- a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_suppress_fa/r1/initial.json b/tests/topotests/ospf_suppress_fa/r1/initial.json new file mode 100644 index 000000000000..f0e61101bff5 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/initial.json @@ -0,0 +1,44 @@ +{ + "routerId":"10.0.12.1", + "asExternalLinkStates":[ + { + "options":"*|-|-|-|-|-|E|-", + "lsaFlags":6, + "lsaType":"AS-external-LSA", + "linkStateId":"3.3.1.1", + "advertisingRouter":"10.0.23.2", + "networkMask":32, + "metricType":"E2 (Larger than any link state path)", + "tos":0, + "metric":20, + "forwardAddress":"10.0.23.3", + "externalRouteTag":0 + }, + { + "options":"*|-|-|-|-|-|E|-", + "lsaFlags":6, + "lsaType":"AS-external-LSA", + "linkStateId":"3.3.2.2", + "advertisingRouter":"10.0.23.2", + "networkMask":32, + "metricType":"E2 (Larger than any link state path)", + "tos":0, + "metric":20, + "forwardAddress":"10.0.23.3", + "externalRouteTag":0 + }, + { + "options":"*|-|-|-|-|-|E|-", + "lsaFlags":6, + "lsaType":"AS-external-LSA", + "linkStateId":"3.3.3.3", + "advertisingRouter":"10.0.23.2", + "networkMask":32, + "metricType":"E2 (Larger than any link state path)", + "tos":0, + "metric":20, + "forwardAddress":"10.0.23.3", + "externalRouteTag":0 + } + ] +} diff --git a/tests/topotests/ospf_suppress_fa/r1/neighbor.json b/tests/topotests/ospf_suppress_fa/r1/neighbor.json new file mode 100644 index 000000000000..417fcbee1180 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/neighbor.json @@ -0,0 +1,13 @@ +{ + "neighbors":{ + "10.0.23.2":[ + { + "nbrPriority":1, + "converged":"Full", + "role":"DROther", + "ifaceAddress":"10.0.12.2", + "ifaceName":"r1-eth0:10.0.12.1" + } + ] + } +} diff --git a/tests/topotests/ospf_suppress_fa/r1/post.json b/tests/topotests/ospf_suppress_fa/r1/post.json new file mode 100644 index 000000000000..98cbf8f1cc84 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/post.json @@ -0,0 +1,44 @@ +{ + "routerId":"10.0.12.1", + "asExternalLinkStates":[ + { + "options":"*|-|-|-|-|-|E|-", + "lsaFlags":6, + "lsaType":"AS-external-LSA", + "linkStateId":"3.3.1.1", + "advertisingRouter":"10.0.23.2", + "networkMask":32, + "metricType":"E2 (Larger than any link state path)", + "tos":0, + "metric":20, + "forwardAddress":"0.0.0.0", + "externalRouteTag":0 + }, + { + "options":"*|-|-|-|-|-|E|-", + "lsaFlags":6, + "lsaType":"AS-external-LSA", + "linkStateId":"3.3.2.2", + "advertisingRouter":"10.0.23.2", + "networkMask":32, + "metricType":"E2 (Larger than any link state path)", + "tos":0, + "metric":20, + "forwardAddress":"0.0.0.0", + "externalRouteTag":0 + }, + { + "options":"*|-|-|-|-|-|E|-", + "lsaFlags":6, + "lsaType":"AS-external-LSA", + "linkStateId":"3.3.3.3", + "advertisingRouter":"10.0.23.2", + "networkMask":32, + "metricType":"E2 (Larger than any link state path)", + "tos":0, + "metric":20, + "forwardAddress":"0.0.0.0", + "externalRouteTag":0 + } + ] +} diff --git a/tests/topotests/ospf_suppress_fa/r2/ospfd.conf b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf index ebc7d252fdfd..ecc35f7e7831 100644 --- a/tests/topotests/ospf_suppress_fa/r2/ospfd.conf +++ b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf @@ -10,6 +10,7 @@ interface r2-eth1 ip ospf dead-interval 10 ! router ospf + ospf router-id 10.0.23.2 network 10.0.12.0/24 area 0 network 10.0.23.0/24 area 1 area 1 nssa diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py index d5583ac06abb..7f9ad27eab99 100644 --- a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -22,7 +22,8 @@ import os import sys -import re +import json +from functools import partial import pytest # Save the Current Working Directory to find configuration files. @@ -33,6 +34,7 @@ # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger # Required to instantiate the topology builder class. @@ -75,6 +77,7 @@ def setup_module(mod): TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) ) + logger.info("Module Setup") tgen.start_router() @@ -93,7 +96,17 @@ def test_converge_protocols(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - topotest.sleep(10, "Waiting for OSPF convergence") + router = tgen.gears["r1"] + json_file = "{}/r1/neighbor.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show ip ospf neighbor json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "r1 has not converged" + + logger.info("Converged Protocol") def ospf_configure_suppress_fa(router_name, area): @@ -114,58 +127,55 @@ def ospf_unconfigure_suppress_fa(router_name, area): router.vtysh_cmd("conf t\nrouter ospf\narea {} nssa\nexit\n".format(area)) -def ospf_get_lsa_type5(router_name): - "Return a dict with link state id as key and forwarding addresses as value" - - result = dict() - tgen = get_topogen() - router = tgen.gears[router_name] - cmd = "show ip ospf database external\n" - output = topotest.normalize_text(router.vtysh_cmd(cmd)) - for line in output.splitlines(): - re0 = re.match(r"\s+Link State ID: (\S+) \(External Network Number\)", line) - if re0: - lsa = re0.group(1) - re1 = re.match(r"\s+Forward Address: (\S+)", line) - if re1: - result[lsa] = re1.group(1) - return result - - -@pytest.fixture(scope="module", name="original") def test_ospf_set_suppress_fa(): "Test OSPF area [x] nssa suppress-fa" + logger.info("Testing Turning on/off suppress-fa") + tgen = get_topogen() + # Get current forwarding address for each LSA type-5 in r1 - initial = ospf_get_lsa_type5("r1") + logger.info("Get Initial State") + router = tgen.gears["r1"] + json_file = "{}/r1/initial.json".format(CWD) + expected_initial = json.loads(open(json_file).read()) + + test_func_initial = partial( + topotest.router_json_cmp, + router, + "show ip ospf data external json", + expected_initial, + ) + _, result = topotest.run_and_expect(test_func_initial, None, count=30, wait=1) + assert result is None, "Unable to get expected initial states" + logger.info("Configure suppress-fa") # Configure suppres-fa in r2 area 1 ospf_configure_suppress_fa("r2", "1") - topotest.sleep(10, "Waiting for OSPF convergence") - # Check forwarding address on r1 for all statics is 0.0.0.0 - assertmsg = "Forwarding address is not 0.0.0.0 after enabling OSPF suppress-fa" - suppress = ospf_get_lsa_type5("r1") - for prefix in suppress: - assert suppress[prefix] == "0.0.0.0", assertmsg + logger.info("Ensure that OSPF has converged on new values") + json_file = "{}/r1/post.json".format(CWD) + expected_post = json.loads(open(json_file).read()) - # Return the original forwarding addresses so we can compare them - # in the test_ospf_unset_supress_fa - return initial + test_func_post = partial( + topotest.router_json_cmp, + router, + "show ip ospf data external json", + expected_post, + ) + _, result = topotest.run_and_expect(test_func_post, None, count=30, wait=1) + assert result is None, "Unable to get expected state after turning on suppress-fa" -def test_ospf_unset_supress_fa(original): - "Test OSPF no area [x] nssa suppress-fa" + logger.info("Test OSPF no area [x] nssa suppress-fa") # Remove suppress-fa in r2 area 1 ospf_unconfigure_suppress_fa("r2", "1") - topotest.sleep(10, "Waiting for OSPF convergence") - # Check forwarding address is the original value on r1 for all statics - assertmsg = "Forwarding address is not correct after removing OSPF suppress-fa" - restore = ospf_get_lsa_type5("r1") - for prefix in restore: - assert restore[prefix] == original[prefix], assertmsg + logger.info("Has OSPF returned to original values") + _, result = topotest.run_and_expect(test_func_post, None, count=30, wait=1) + assert ( + result is None + ), "Unable to return to original state after turning off suppress-fa" if __name__ == "__main__": diff --git a/tests/topotests/ospf_te_topo1/r1/ospfd.conf b/tests/topotests/ospf_te_topo1/r1/ospfd.conf index 312dd2697e81..1541f3f2fccb 100644 --- a/tests/topotests/ospf_te_topo1/r1/ospfd.conf +++ b/tests/topotests/ospf_te_topo1/r1/ospfd.conf @@ -2,13 +2,13 @@ interface lo ip ospf area 0.0.0.0 ! -interface r1-eth0 +interface eth0 ip ospf network point-to-point ip ospf hello-interval 2 ip ospf dead-interval 10 ip ospf area 0.0.0.0 ! -interface r1-eth1 +interface eth1 ip ospf network point-to-point ip ospf hello-interval 2 ip ospf dead-interval 10 diff --git a/tests/topotests/ospf_te_topo1/r1/zebra.conf b/tests/topotests/ospf_te_topo1/r1/zebra.conf index c47789a16633..dc50e3dd6d91 100644 --- a/tests/topotests/ospf_te_topo1/r1/zebra.conf +++ b/tests/topotests/ospf_te_topo1/r1/zebra.conf @@ -2,7 +2,7 @@ interface lo ip address 10.0.255.1/32 ! -interface r1-eth0 +interface eth0 ip address 10.0.0.1/24 link-params metric 20 @@ -12,7 +12,7 @@ interface r1-eth0 enable exit-link-params ! -interface r1-eth1 +interface eth1 ip address 10.0.1.1/24 link-params enable diff --git a/tests/topotests/ospf_te_topo1/r2/ospfd.conf b/tests/topotests/ospf_te_topo1/r2/ospfd.conf index e9c3f65bc267..acc2e6b234a9 100644 --- a/tests/topotests/ospf_te_topo1/r2/ospfd.conf +++ b/tests/topotests/ospf_te_topo1/r2/ospfd.conf @@ -2,25 +2,25 @@ interface lo ip ospf area 0.0.0.0 ! -interface r2-eth0 +interface eth0 ip ospf network point-to-point ip ospf hello-interval 2 ip ospf dead-interval 10 ip ospf area 0.0.0.0 ! -interface r2-eth1 +interface eth1 ip ospf network point-to-point ip ospf hello-interval 2 ip ospf dead-interval 10 ip ospf area 0.0.0.0 ! -interface r2-eth2 +interface eth2 ip ospf network point-to-point ip ospf area 0.0.0.0 ip ospf hello-interval 2 ip ospf dead-interval 10 ! -interface r2-eth3 +interface eth3 ip ospf network point-to-point ip ospf hello-interval 2 ip ospf dead-interval 10 diff --git a/tests/topotests/ospf_te_topo1/r2/zebra.conf b/tests/topotests/ospf_te_topo1/r2/zebra.conf index a9771f70ca02..6fe4dd0a5a08 100644 --- a/tests/topotests/ospf_te_topo1/r2/zebra.conf +++ b/tests/topotests/ospf_te_topo1/r2/zebra.conf @@ -2,25 +2,25 @@ interface lo ip address 10.0.255.2/32 ! -interface r2-eth0 +interface eth0 ip address 10.0.0.2/24 link-params enable exit-link-params ! -interface r2-eth1 +interface eth1 ip address 10.0.1.2/24 link-params enable exit-link-params ! -interface r2-eth2 +interface eth2 ip address 10.0.3.2/24 link-params enable exit-link-params ! -interface r2-eth3 +interface eth3 ip address 10.0.4.2/24 link-params metric 30 diff --git a/tests/topotests/ospf_te_topo1/r3/ospfd.conf b/tests/topotests/ospf_te_topo1/r3/ospfd.conf index caa5f1e1eb21..fc94437b6491 100644 --- a/tests/topotests/ospf_te_topo1/r3/ospfd.conf +++ b/tests/topotests/ospf_te_topo1/r3/ospfd.conf @@ -2,13 +2,13 @@ interface lo ip ospf area 0.0.0.0 ! -interface r3-eth0 +interface eth0 ip ospf network point-to-point ip ospf area 0.0.0.0 ip ospf hello-interval 2 ip ospf dead-interval 10 ! -interface r3-eth1 +interface eth1 ip ospf network point-to-point ip ospf area 0.0.0.0 ip ospf hello-interval 2 diff --git a/tests/topotests/ospf_te_topo1/r3/zebra.conf b/tests/topotests/ospf_te_topo1/r3/zebra.conf index 4cf907708548..262b5adc9258 100644 --- a/tests/topotests/ospf_te_topo1/r3/zebra.conf +++ b/tests/topotests/ospf_te_topo1/r3/zebra.conf @@ -2,14 +2,14 @@ interface lo ip address 10.0.255.3/32 ! -interface r3-eth0 +interface eth0 ip address 10.0.3.1/24 link-params enable admin-grp 0x20 exit-link-params ! -interface r3-eth1 +interface eth1 ip address 10.0.5.1/24 link-params enable diff --git a/tests/topotests/ospf_te_topo1/r4/ospfd.conf b/tests/topotests/ospf_te_topo1/r4/ospfd.conf index cd508017d3b4..5ec7918aff2a 100644 --- a/tests/topotests/ospf_te_topo1/r4/ospfd.conf +++ b/tests/topotests/ospf_te_topo1/r4/ospfd.conf @@ -2,7 +2,7 @@ interface lo ip ospf area 0.0.0.0 ! -interface r4-eth0 +interface eth0 ip ospf network point-to-point ip ospf hello-interval 2 ip ospf dead-interval 10 diff --git a/tests/topotests/ospf_te_topo1/r4/zebra.conf b/tests/topotests/ospf_te_topo1/r4/zebra.conf index 18c003b230c6..c48268509442 100644 --- a/tests/topotests/ospf_te_topo1/r4/zebra.conf +++ b/tests/topotests/ospf_te_topo1/r4/zebra.conf @@ -2,7 +2,7 @@ interface lo ip address 10.0.255.4/32 ! -interface r4-eth0 +interface eth0 ip address 10.0.4.1/24 link-params enable diff --git a/tests/topotests/ospf_te_topo1/test_ospf_te_topo1.py b/tests/topotests/ospf_te_topo1/test_ospf_te_topo1.py index c8533cfbba61..11fecc32111b 100644 --- a/tests/topotests/ospf_te_topo1/test_ospf_te_topo1.py +++ b/tests/topotests/ospf_te_topo1/test_ospf_te_topo1.py @@ -18,22 +18,22 @@ | 10.0.225.1 | | | +------------+ - r1-eth0| |r1-eth1 + eth0| |eth1 | | 10.0.0.0/24| |10.0.1.0/24 | | - r2-eth0| |r2-eth1 + eth0| |eth1 +------------+ +------------+ | | | | - | R2 |r2-eth2 r3-eth0| R3 | + | R2 |eth2 eth0| R3 | | 10.0.255.2 +------------------+ 10.0.255.3 | | | 10.0.3.0/24 | | +------------+ +------+-----+ - r2-eth3| r3-eth1| + eth3| eth1| | | 10.0.4.0/24| 10.0.5.0/24| | | - r4-eth0| V + eth0| V +------------+ ASBR 10.0.255.5 | | | R4 | @@ -70,30 +70,24 @@ def build_topo(tgen): "Build function" # Create 4 routers - for routern in range(1, 5): - tgen.add_router("r{}".format(routern)) + r1 = tgen.add_router("r1") + r2 = tgen.add_router("r2") + r3 = tgen.add_router("r3") + r4 = tgen.add_router("r4") # Interconect router 1 and 2 with 2 links - switch = tgen.add_switch("s1") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) - switch = tgen.add_switch("s2") - switch.add_link(tgen.gears["r1"]) - switch.add_link(tgen.gears["r2"]) + tgen.add_link(r1, r2, ifname1="eth0", ifname2="eth0") + tgen.add_link(r1, r2, ifname1="eth1", ifname2="eth1") # Interconect router 3 and 2 - switch = tgen.add_switch("s3") - switch.add_link(tgen.gears["r3"]) - switch.add_link(tgen.gears["r2"]) + tgen.add_link(r2, r3, ifname1="eth2", ifname2="eth0") # Interconect router 4 and 2 - switch = tgen.add_switch("s4") - switch.add_link(tgen.gears["r4"]) - switch.add_link(tgen.gears["r2"]) + tgen.add_link(r2, r4, ifname1="eth3", ifname2="eth0") # Interconnect router 3 with next AS - switch = tgen.add_switch("s5") - switch.add_link(tgen.gears["r3"]) + s1 = tgen.add_switch("s1") + tgen.add_link(r3, s1, ifname1="eth1", ifname2="eth0") def setup_module(mod): @@ -174,8 +168,7 @@ def test_step2(): tgen = setup_testcase("Step2: Shutdown interface between r1 & r2") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth1" -c "shutdown"') - tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth1" -c "shutdown"') + tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface eth1" -c "shutdown"') for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step2.json") @@ -227,28 +220,27 @@ def test_step5(): tgen = setup_testcase("Step5: Re-enable interface between r1 & r2") - tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface r1-eth1" -c "no shutdown"') - tgen.net["r2"].cmd('vtysh -c "conf t" -c "interface r2-eth1" -c "no shutdown"') + tgen.net["r1"].cmd('vtysh -c "conf t" -c "interface eth1" -c "no shutdown"') for rname in ["r1", "r2", "r3", "r4"]: compare_ted_json_output(tgen, rname, "ted_step5.json") def test_step6(): - "Step6: Set delay and jitter for interface r4-eth0 on r4, remove use-bw \ - for interface r2-eth3 on r2 and verify that corresponding Edges are \ + "Step6: Set delay and jitter for interface eth0 on r4, remove use-bw \ + for interface eth3 on r2 and verify that corresponding Edges are \ updated in the TED on all routers" tgen = setup_testcase("Step6: Modify link parameters on r2 & r4") tgen.net["r2"].cmd( - 'vtysh -c "conf t" -c "interface r2-eth3" -c "link-params" -c "no use-bw"' + 'vtysh -c "conf t" -c "interface eth3" -c "link-params" -c "no use-bw"' ) tgen.net["r4"].cmd( - 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay 20000"' + 'vtysh -c "conf t" -c "interface eth0" -c "link-params" -c "delay 20000"' ) tgen.net["r4"].cmd( - 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay-variation 10000"' + 'vtysh -c "conf t" -c "interface eth0" -c "link-params" -c "delay-variation 10000"' ) for rname in ["r1", "r2", "r3", "r4"]: diff --git a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py index f939f3f578f0..246672488844 100644 --- a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py +++ b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py @@ -110,7 +110,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_topo1/r1/ospf6d.conf b/tests/topotests/ospf_topo1/r1/ospf6d.conf index ca3497b4a58d..0e6c7dadfb5e 100644 --- a/tests/topotests/ospf_topo1/r1/ospf6d.conf +++ b/tests/topotests/ospf_topo1/r1/ospf6d.conf @@ -4,10 +4,12 @@ router ospf6 redistribute kernel redistribute connected redistribute static - interface r1-eth0 area 0.0.0.0 - interface r1-eth1 area 0.0.0.0 +! +interface r1-eth0 + ipv6 ospf6 area 0.0.0.0 ! int r1-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 dead-interval 10 ipv6 ospf6 hello-interval 2 ! diff --git a/tests/topotests/ospf_topo1/r2/ospf6d.conf b/tests/topotests/ospf_topo1/r2/ospf6d.conf index 44047e1a4eeb..f6a1f505304f 100644 --- a/tests/topotests/ospf_topo1/r2/ospf6d.conf +++ b/tests/topotests/ospf_topo1/r2/ospf6d.conf @@ -4,14 +4,14 @@ router ospf6 redistribute kernel redistribute connected redistribute static - interface r2-eth0 area 0.0.0.0 - interface r2-eth1 area 0.0.0.0 ! int r2-eth0 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! int r2-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! diff --git a/tests/topotests/ospf_topo1/r3/ospf6d.conf b/tests/topotests/ospf_topo1/r3/ospf6d.conf index 13ad9a7356a7..278a01696858 100644 --- a/tests/topotests/ospf_topo1/r3/ospf6d.conf +++ b/tests/topotests/ospf_topo1/r3/ospf6d.conf @@ -4,19 +4,19 @@ router ospf6 redistribute kernel redistribute connected redistribute static - interface r3-eth0 area 0.0.0.0 - interface r3-eth1 area 0.0.0.0 - interface r3-eth2 area 0.0.0.1 ! int r3-eth0 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! int r3-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! int r3-eth2 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! diff --git a/tests/topotests/ospf_topo1/r4/ospf6d.conf b/tests/topotests/ospf_topo1/r4/ospf6d.conf index f9bde0e83c0e..777dd0b7b7f0 100644 --- a/tests/topotests/ospf_topo1/r4/ospf6d.conf +++ b/tests/topotests/ospf_topo1/r4/ospf6d.conf @@ -4,14 +4,14 @@ router ospf6 redistribute kernel redistribute connected redistribute static - interface r4-eth0 area 0.0.0.1 - interface r4-eth1 area 0.0.0.1 ! int r4-eth0 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! int r4-eth1 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! diff --git a/tests/topotests/ospf_topo1/test_ospf_topo1.py b/tests/topotests/ospf_topo1/test_ospf_topo1.py index a079f5698ff1..b9bdee3db467 100644 --- a/tests/topotests/ospf_topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf_topo1/test_ospf_topo1.py @@ -93,7 +93,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step6/show_ipv6_route.ref.diff b/tests/topotests/ospf_topo2/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step6/show_ipv6_route.ref.diff rename to tests/topotests/ospf_topo2/__init__.py diff --git a/tests/topotests/ospf_topo2/r1/frr.conf b/tests/topotests/ospf_topo2/r1/frr.conf new file mode 100644 index 000000000000..9bc336185946 --- /dev/null +++ b/tests/topotests/ospf_topo2/r1/frr.conf @@ -0,0 +1,61 @@ +frr defaults traditional +hostname r1 +log syslog informational +service integrated-vtysh-config +! +ip router-id 192.0.2.1 +! +interface eth1 + ip address 192.0.2.1/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::1/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth2 + ip address 192.0.2.1/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::1/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth3 + ip address 192.0.2.1/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::1/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface lo + ip address 192.0.2.1/32 + ip ospf area 0.0.0.0 + ip ospf passive + ipv6 address 2001:db8::1/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 passive +exit +! +router ospf + log-adjacency-changes +exit +! +router ospf6 + log-adjacency-changes +exit +! +end \ No newline at end of file diff --git a/tests/topotests/ospf_topo2/r2/frr.conf b/tests/topotests/ospf_topo2/r2/frr.conf new file mode 100644 index 000000000000..d2ffb7337791 --- /dev/null +++ b/tests/topotests/ospf_topo2/r2/frr.conf @@ -0,0 +1,61 @@ +frr defaults traditional +hostname r2 +log syslog informational +service integrated-vtysh-config +! +ip router-id 192.0.2.2 +! +interface eth1 + ip address 192.0.2.2/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::2/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth2 + ip address 192.0.2.2/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::2/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth3 + ip address 192.0.2.2/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::2/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface lo + ip address 192.0.2.2/32 + ip ospf area 0.0.0.0 + ip ospf passive + ipv6 address 2001:db8::2/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 passive +exit +! +router ospf + log-adjacency-changes +exit +! +router ospf6 + log-adjacency-changes +exit +! +end \ No newline at end of file diff --git a/tests/topotests/ospf_topo2/r3/frr.conf b/tests/topotests/ospf_topo2/r3/frr.conf new file mode 100644 index 000000000000..e87b8972f041 --- /dev/null +++ b/tests/topotests/ospf_topo2/r3/frr.conf @@ -0,0 +1,61 @@ +frr defaults traditional +hostname r3 +log syslog informational +service integrated-vtysh-config +! +ip router-id 192.0.2.3 +! +interface eth1 + ip address 192.0.2.3/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::3/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth2 + ip address 192.0.2.3/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::3/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth3 + ip address 192.0.2.3/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::3/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface lo + ip address 192.0.2.3/32 + ip ospf area 0.0.0.0 + ip ospf passive + ipv6 address 2001:db8::3/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 passive +exit +! +router ospf + log-adjacency-changes +exit +! +router ospf6 + log-adjacency-changes +exit +! +end \ No newline at end of file diff --git a/tests/topotests/ospf_topo2/r4/frr.conf b/tests/topotests/ospf_topo2/r4/frr.conf new file mode 100644 index 000000000000..4e33d75299a2 --- /dev/null +++ b/tests/topotests/ospf_topo2/r4/frr.conf @@ -0,0 +1,61 @@ +frr defaults traditional +hostname r4 +log syslog informational +service integrated-vtysh-config +! +ip router-id 192.0.2.4 +! +interface eth1 + ip address 192.0.2.4/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::4/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth2 + ip address 192.0.2.4/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::4/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface eth3 + ip address 192.0.2.4/32 + ip ospf area 0.0.0.0 + ip ospf dead-interval minimal hello-multiplier 4 + ip ospf network point-to-point + ipv6 address 2001:db8::4/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 dead-interval 4 + ipv6 ospf6 hello-interval 1 + ipv6 ospf6 network point-to-point +exit +! +interface lo + ip address 192.0.2.4/32 + ip ospf area 0.0.0.0 + ip ospf passive + ipv6 address 2001:db8::4/128 + ipv6 ospf6 area 0.0.0.0 + ipv6 ospf6 passive +exit +! +router ospf + log-adjacency-changes +exit +! +router ospf6 + log-adjacency-changes +exit +! +end \ No newline at end of file diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.dot b/tests/topotests/ospf_topo2/test_ospf_topo2.dot new file mode 100644 index 000000000000..e35afbbaad7c --- /dev/null +++ b/tests/topotests/ospf_topo2/test_ospf_topo2.dot @@ -0,0 +1,44 @@ +graph template { + label="ospf_topo2"; + splines = "line" + + # Routers + r1 [ + shape=doubleoctagon, + label="r1\n192.0.2.1\n2001:db8::1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon, + label="r2\n\192.0.2.2\n2001:db8::2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon, + label="r3\n192.0.2.3\n2001:db8::3", + fillcolor="#f08080", + style=filled, + ]; + r4 [ + shape=doubleoctagon, + label="r4\n192.0.2.4\n2001:db8::4", + fillcolor="#f08080", + style=filled, + ]; + + # Connections + r1 -- r2 [label="eth1"]; + r1 -- r2 [label="eth2"]; + + r2 -- r3 [label="eth3\neth1"]; + r1 -- r4 [label="eth3\neth1"]; + + r4 -- r3 [label="eth2"]; + r4 -- r3 [label="eth3"]; + + # Group r1 and r2 above, r3 and r4 below + { rank=min; r1; r2; } + { rank=max; r3; r4; } +} diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.png b/tests/topotests/ospf_topo2/test_ospf_topo2.png new file mode 100644 index 000000000000..7eb0a1d68499 Binary files /dev/null and b/tests/topotests/ospf_topo2/test_ospf_topo2.png differ diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.py b/tests/topotests/ospf_topo2/test_ospf_topo2.py new file mode 100644 index 000000000000..45ae338a245d --- /dev/null +++ b/tests/topotests/ospf_topo2/test_ospf_topo2.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# test_ospf_topo2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2017 by +# Network Device Education Foundation, Inc. ("NetDEF") +# + +""" +test_ospf_topo2.py: Test correct route removal. + +Proofs the following issue: +https://github.com/FRRouting/frr/issues/14488 + +""" + +import ipaddress +import json +import pytest +import sys +import time + +from lib.topogen import Topogen + + +pytestmark = [ + pytest.mark.ospf6d, + pytest.mark.ospfd, +] + + +def build_topo(tgen): + """Build the topology used by all tests below.""" + + # Create 4 routers + r1 = tgen.add_router("r1") + r2 = tgen.add_router("r2") + r3 = tgen.add_router("r3") + r4 = tgen.add_router("r4") + + # The r1/r2 and r3/r4 router pairs have two connections each + tgen.add_link(r1, r2, ifname1="eth1", ifname2="eth1") + tgen.add_link(r1, r2, ifname1="eth2", ifname2="eth2") + tgen.add_link(r3, r4, ifname1="eth2", ifname2="eth2") + tgen.add_link(r3, r4, ifname1="eth3", ifname2="eth3") + + # The r1/r4 and r2/r3 router pairs have one connection each + tgen.add_link(r1, r4, ifname1="eth3", ifname2="eth1") + tgen.add_link(r2, r3, ifname1="eth3", ifname2="eth1") + + +@pytest.fixture(scope="function") +def tgen(request): + """Setup/Teardown the environment and provide tgen argument to tests. + + Do this once per function as some of the tests will leave the router + in an unclean state. + + """ + + tgen = Topogen(build_topo, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + + yield tgen + + tgen.stop_topology() + + +def ospf_neighbors(router, ip_version): + """List the OSPF neighbors for the given router and IP version.""" + + if ip_version == 4: + cmd = "show ip ospf neighbor json" + else: + cmd = "show ipv6 ospf neighbor json" + + output = router.vtysh_cmd(cmd) + + if ip_version == 4: + return [v for n in json.loads(output)["neighbors"].values() for v in n] + else: + return json.loads(output)["neighbors"] + + +def ospf_neighbor_uptime(router, interface, ip_version): + """Uptime of the neighbor with the given interface name in seconds.""" + + for neighbor in ospf_neighbors(router, ip_version): + if ip_version == 4: + if not neighbor["ifaceName"].startswith("{}:".format(interface)): + continue + + return neighbor["upTimeInMsec"] / 1000 + else: + if neighbor["interfaceName"] != interface: + continue + + h, m, s = [int(d) for d in neighbor["duration"].split(":")] + return h * 3600 + m * 60 + s + + raise KeyError( + "No IPv{} neighbor with interface name {} on {}".format( + ip_version, interface, router.name + ) + ) + + +def ospf_routes(router, prefix): + """List the OSPF routes for the given router and prefix.""" + + if ipaddress.ip_interface(prefix).ip.version == 4: + cmd = "show ip route {} json" + else: + cmd = "show ipv6 route {} json" + + output = router.vtysh_cmd(cmd.format(prefix)) + return json.loads(output)[prefix] + + +def ospf_nexthops(router, prefix, protocol): + """List the OSPF nexthops for the given prefix.""" + + for route in ospf_routes(router, prefix): + if route["protocol"] != protocol: + continue + + for nexthop in route["nexthops"]: + yield nexthop + + +def ospf_directly_connected_interfaces(router, ip_version): + """The names of the directly connected interfaces, as discovered + through the OSPF nexthops. + + """ + + if ip_version == 4: + prefix = "192.0.2.{}/32".format(router.name.strip("r")) + else: + prefix = "fe80::/64" + + hops = ospf_nexthops(router, prefix, protocol="connected") + return sorted([n["interfaceName"] for n in hops if n["directlyConnected"]]) + + +def wait_for_ospf(router, ip_version, neighbors, timeout=60): + """Wait until the router has the given number of neighbors that are + fully converged. + + Note that this checks for the exact number of neighbors, so if one neighbor + is requested and three are converged, the wait continues. + + """ + + until = time.monotonic() + timeout + + if ip_version == 4: + filter = {"converged": "Full"} + else: + filter = {"state": "Full"} + + def is_match(neighbor): + for k, v in filter.items(): + if neighbor[k] != v: + return False + + return True + + while time.monotonic() < until: + found = sum(1 for n in ospf_neighbors(router, ip_version) if is_match(n)) + + if neighbors == found: + return + + raise TimeoutError( + "Waited over {}s for {} neighbors to reach {}".format( + timeout, neighbors, filter + ) + ) + + +@pytest.mark.parametrize("ip_version", [4, 6]) +def test_interface_up(tgen, ip_version): + """Verify the initial routing table, before any changes.""" + + # Wait for the routers to be ready + routers = {id: tgen.gears[id] for id in ("r1", "r2", "r3", "r4")} + + for router in routers.values(): + wait_for_ospf(router, ip_version=ip_version, neighbors=3) + + # Verify that the link-local routes are correct + for router in routers.values(): + connected = ospf_directly_connected_interfaces(router, ip_version) + + if ip_version == 4: + expected = ["eth1", "eth2", "eth3", "lo"] + else: + expected = ["eth1", "eth2", "eth3"] + + assert ( + connected == expected + ), "Expected all interfaces to be connected on {}".format(router.name) + + +@pytest.mark.parametrize("ip_version", [4, 6]) +def test_interface_down(tgen, ip_version): + """Verify the routing table after taking interfaces down.""" + + # Wait for the routers to be ready + routers = {id: tgen.gears[id] for id in ("r1", "r2", "r3", "r4")} + + for id, router in routers.items(): + wait_for_ospf(router, ip_version=ip_version, neighbors=3) + + # Keep track of the uptime of the eth3 neighbor + uptime = ospf_neighbor_uptime(routers["r1"], "eth3", ip_version) + before = time.monotonic() + + # Take the links between r1 and r2 down + routers["r1"].cmd_raises("ip link set down dev eth1") + routers["r1"].cmd_raises("ip link set down dev eth2") + + # Wait for OSPF to converge + wait_for_ospf(routers["r1"], ip_version=ip_version, neighbors=1) + + # The uptime of the unaffected eth3 neighbor should be monotonic + new_uptime = ospf_neighbor_uptime(routers["r1"], "eth3", ip_version) + took = round(time.monotonic() - before, 3) + + # IPv6 has a resolution of 1s, for IPv4 some slack is necesssary. + if ip_version == 4: + offset = 0.25 + else: + offset = 1 + + assert ( + new_uptime + offset >= uptime + took + ), "The eth3 neighbor uptime must not decrease" + + # We should only find eth3 once OSPF has converged + connected = ospf_directly_connected_interfaces(routers["r1"], ip_version) + + if ip_version == 4: + expected = ["eth3", "lo"] + else: + expected = ["eth3"] + + assert connected == expected, "Expected only eth1 and eth2 to be disconnected" + + +@pytest.mark.parametrize("ip_version", [4, 6]) +def test_interface_flap(tgen, ip_version): + """Verify the routing table after enabling an interface that was down.""" + + # Wait for the routers to be ready + routers = {id: tgen.gears[id] for id in ("r1", "r2", "r3", "r4")} + + for id, router in routers.items(): + wait_for_ospf(router, ip_version=ip_version, neighbors=3) + + # Keep track of the uptime of the eth3 neighbor + uptime = ospf_neighbor_uptime(routers["r1"], "eth3", ip_version) + before = time.monotonic() + + # Take the links between r1 and r2 down + routers["r1"].cmd_raises("ip link set down dev eth1") + routers["r2"].cmd_raises("ip link set down dev eth2") + + # Wait for OSPF to converge + wait_for_ospf(routers["r1"], ip_version=ip_version, neighbors=1) + + # Take the links between r1 and r2 up + routers["r1"].cmd_raises("ip link set up dev eth1") + routers["r2"].cmd_raises("ip link set up dev eth2") + + # Wait for OSPF to converge + wait_for_ospf(routers["r1"], ip_version=ip_version, neighbors=3) + + # The uptime of the unaffected eth3 neighbor should be monotonic + new_uptime = ospf_neighbor_uptime(routers["r1"], "eth3", ip_version) + took = round(time.monotonic() - before, 3) + + # IPv6 has a resolution of 1s, for IPv4 some slack is necesssary. + if ip_version == 4: + offset = 0.25 + else: + offset = 1 + + assert ( + new_uptime + offset >= uptime + took + ), "The eth3 neighbor uptime must not decrease" + + # We should find all interfaces again + connected = ospf_directly_connected_interfaces(routers["r1"], ip_version) + + if ip_version == 4: + expected = ["eth1", "eth2", "eth3", "lo"] + else: + expected = ["eth1", "eth2", "eth3"] + + assert connected == expected, "Expected all interfaces to be connected" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py index d07f5dc5c9a0..712c4e1d7c0e 100644 --- a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py +++ b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py @@ -89,7 +89,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/README.md b/tests/topotests/ospf_unnumbered_point_to_multipoint/README.md new file mode 100644 index 000000000000..d9b681752f87 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/README.md @@ -0,0 +1,41 @@ +# OSPFv2 (IPv4) Topology Test Unumbered (point-to-multipoint over Ethernet) + +## Topology + + SW1 SW2 + \___________________/ \___________________/ + | | + | | + | eth0:10.0.10.1/32 | eth0:10.0.20.1/32 + +---------+---------+ +---------+---------+ + | R1 | | R2 | + | FRRouting | | FRRouting | + | RID: 10.0.255.1 | | RID: 10.0.255.2 | + +---------+---------+ +---------+---------+ + | eth1:10.1.1.2/32 | eth1:10.1.2.2/32 + \______ ___________/ + \ / + \ / + ~~~~~~~~~~~~~~~~~~ + ~~ SW4 ~~ + ~~ Switch ~~ + ~~ ~~ + ~~~~~~~~~~~~~~~~~~ + | + | eth0:10.1.3.2/32 (unumbered) + +---------+---------+ + | R3 | + | FRRouting | + | RID: 10.0.255.3 | + +---------+---------+ + | eth0:10.0.30.1/24 + | + ~~~~~~~~~~~~~~~~~~ + ~~ SW3 ~~ + ~~ Switch ~~ + ~~ ~~ + ~~~~~~~~~~~~~~~~~~ + +## FRR Configuration + +See full config from r1 / r2 / r3 subdirectories diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/ospf-route.json b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/ospf-route.json new file mode 100644 index 000000000000..563522dd287e --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/ospf-route.json @@ -0,0 +1 @@ +{"10.0.10.1\/32":{"routeType":"N","transit":false,"cost":10,"area":"0.0.0.0"},"10.0.20.1\/32":{"routeType":"N","transit":false,"cost":20,"area":"0.0.0.0"},"10.0.30.0\/24":{"routeType":"N","transit":false,"cost":20,"area":"0.0.0.0"}} diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/ospfd.conf b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/ospfd.conf new file mode 100644 index 000000000000..c7327b630f86 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/ospfd.conf @@ -0,0 +1,11 @@ +! +interface r1-eth1 + ip ospf network point-to-multipoint + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf prefix-suppress 10.1.1.2 +! +router ospf + ospf router-id 10.0.255.1 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/v4_route.json b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/v4_route.json new file mode 100644 index 000000000000..4395b748d73d --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/v4_route.json @@ -0,0 +1,122 @@ +{ + "10.0.10.1\/32": [ + { + "prefix": "10.0.10.1\/32", + "prefixLen": 32, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "distance": 110, + "metric": 10, + "table": 254, + "internalStatus": 0, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.0.10.1\/32", + "prefixLen": 32, + "protocol": "local", + "vrfId": 0, + "vrfName": "default", + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.0.10.1\/32", + "prefixLen": 32, + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.20.1\/32": [ + { + "prefix": "10.0.20.1\/32", + "prefixLen": 32, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 110, + "metric": 20, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.30.0\/24": [ + { + "prefix": "10.0.30.0\/24", + "prefixLen": 24, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 110, + "metric": 20, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.1.1.2\/32": [ + { + "prefix": "10.1.1.2\/32", + "prefixLen": 32, + "protocol": "local", + "vrfId": 0, + "vrfName": "default", + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.1.1.2\/32", + "prefixLen": 32, + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ] +} diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/zebra.conf b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/zebra.conf new file mode 100644 index 000000000000..63c75d0315f0 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface r1-eth0 + ip address 10.0.10.1/32 +! +interface r1-eth1 + ip address 10.1.1.2/32 +! diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/ospf-route.json b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/ospf-route.json new file mode 100644 index 000000000000..8d87e33fd936 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/ospf-route.json @@ -0,0 +1 @@ +{"10.0.10.1\/32":{"routeType":"N","transit":false,"cost":20,"area":"0.0.0.0"},"10.0.20.1\/32":{"routeType":"N","transit":false,"cost":10,"area":"0.0.0.0"},"10.0.30.0\/24":{"routeType":"N","transit":false,"cost":20,"area":"0.0.0.0"}} diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/ospfd.conf b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/ospfd.conf new file mode 100644 index 000000000000..5d0439f73443 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/ospfd.conf @@ -0,0 +1,11 @@ +! +interface r2-eth1 + ip ospf network point-to-multipoint + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf prefix-suppress 10.1.2.2 +! +router ospf + ospf router-id 10.0.255.2 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/v4_route.json b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/v4_route.json new file mode 100644 index 000000000000..870b10601965 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/v4_route.json @@ -0,0 +1,122 @@ +{ + "10.0.10.1\/32": [ + { + "prefix": "10.0.10.1\/32", + "prefixLen": 32, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 110, + "metric": 20, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.20.1\/32": [ + { + "prefix": "10.0.20.1\/32", + "prefixLen": 32, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "distance": 110, + "metric": 10, + "table": 254, + "internalStatus": 0, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.0.20.1\/32", + "prefixLen": 32, + "protocol": "local", + "vrfId": 0, + "vrfName": "default", + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.0.20.1\/32", + "prefixLen": 32, + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.30.0\/24": [ + { + "prefix": "10.0.30.0\/24", + "prefixLen": 24, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 110, + "metric": 20, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.1.2.2\/32": [ + { + "prefix": "10.1.2.2\/32", + "prefixLen": 32, + "protocol": "local", + "vrfId": 0, + "vrfName": "default", + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.1.2.2\/32", + "prefixLen": 32, + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ] +} diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/zebra.conf b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/zebra.conf new file mode 100644 index 000000000000..60ff53b78c87 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r2/zebra.conf @@ -0,0 +1,7 @@ +! +interface r2-eth0 + ip address 10.0.20.1/32 +! +interface r2-eth1 + ip address 10.1.2.2/32 +! diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/ospf-route.json b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/ospf-route.json new file mode 100644 index 000000000000..44ffe640f1d7 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/ospf-route.json @@ -0,0 +1 @@ +{"10.0.10.1\/32":{"routeType":"N","transit":false,"cost":20,"area":"0.0.0.0"},"10.0.20.1\/32":{"routeType":"N","transit":false,"cost":20,"area":"0.0.0.0"},"10.0.30.0\/24":{"routeType":"N","transit":false,"cost":10,"area":"0.0.0.0"}} diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/ospfd.conf b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/ospfd.conf new file mode 100644 index 000000000000..579e273544dc --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/ospfd.conf @@ -0,0 +1,11 @@ +! +interface r3-eth1 + ip ospf network point-to-multipoint + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf prefix-suppress 10.1.3.2 +! +router ospf + ospf router-id 10.0.255.3 + network 0.0.0.0/0 area 0 +! diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/v4_route.json b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/v4_route.json new file mode 100644 index 000000000000..61d955566e21 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/v4_route.json @@ -0,0 +1,126 @@ +{ + "10.0.10.1\/32": [ + { + "prefix": "10.0.10.1\/32", + "prefixLen": 32, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 110, + "metric": 20, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.20.1\/32": [ + { + "prefix": "10.0.20.1\/32", + "prefixLen": 32, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 110, + "metric": 20, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.30.0\/24": [ + { + "prefix": "10.0.30.0\/24", + "prefixLen": 24, + "protocol": "ospf", + "vrfId": 0, + "vrfName": "default", + "distance": 110, + "metric": 10, + "table": 254, + "internalStatus": 0, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.0.30.0\/24", + "prefixLen": 24, + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.0.30.1\/32": [ + { + "prefix": "10.0.30.1\/32", + "prefixLen": 32, + "protocol": "local", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ], + "10.1.3.2\/32": [ + { + "prefix": "10.1.3.2\/32", + "prefixLen": 32, + "protocol": "local", + "vrfId": 0, + "vrfName": "default", + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 0, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + }, + { + "prefix": "10.1.3.2\/32", + "prefixLen": 32, + "protocol": "connected", + "vrfId": 0, + "vrfName": "default", + "selected": true, + "destSelected": true, + "distance": 0, + "metric": 0, + "installed": true, + "table": 254, + "internalStatus": 16, + "internalFlags": 8, + "internalNextHopNum": 1, + "internalNextHopActiveNum": 1 + } + ] +} diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/zebra.conf b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/zebra.conf new file mode 100644 index 000000000000..327bb8fbdc99 --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/r3/zebra.conf @@ -0,0 +1,7 @@ +! +interface r3-eth0 + ip address 10.0.30.1/24 +! +interface r3-eth1 + ip address 10.1.3.2/32 +! diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py new file mode 100644 index 000000000000..a97b1145476e --- /dev/null +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_ospf_unnumbered_point_to_multipoint.py +# +# Copyright (c) 2024 by +# Vincent Jardin +# + +""" +test_ospf_unnumbered_point_to_multipoint.py: Test the OSPF unnumbered for routers with point to multipoint over Ethernet +""" + +import os +import sys +from functools import partial +import pytest +import json + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.ospfd] + + +CWD = os.path.dirname(os.path.realpath(__file__)) + + +def build_topo(tgen): + "Build function" + + # Create routers + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + # Create a empty network for router 1 + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + # Create a empty network for router 2 + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + + # Create a empty network for router 3 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + + # Interconect router 1, 2 and r3 to a common switch 4 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + # The multicast packet delivery is somewhat controlled by + # the rp_filter. Setting it to '0' allows the kernel to pass + # up the mcast packet not destined for the local routers + # network. + topotest.sysctl_assure(tgen.net["r1"], "net.ipv4.conf.r1-eth1.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r1"], "net.ipv4.conf.all.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r2"], "net.ipv4.conf.r2-eth1.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r2"], "net.ipv4.conf.all.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r3"], "net.ipv4.conf.r3-eth1.rp_filter", 0) + topotest.sysctl_assure(tgen.net["r3"], "net.ipv4.conf.all.rp_filter", 0) + + # Initialize all routers. + tgen.start_router() + # tgen.mininet_cli() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_ospf_convergence(): + "Test OSPF daemon convergence and that we have received the ospf routes" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + for router, rnode in tgen.routers().items(): + logger.info('Waiting for router "%s" convergence', router) + + json_file = "{}/{}/ospf-route.json".format(CWD, router) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, rnode, "show ip ospf route json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=160, wait=0.5) + assertmsg = '"{}" JSON output mismatches'.format(router) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_ospf_kernel_route(): + "Test OSPF kernel route installation and we have the onlink success" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + rlist = tgen.routers().values() + for router in rlist: + logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name) + + json_file = "{}/{}/v4_route.json".format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show ip route json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"{}" JSON output mistmatches'.format(router) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index 7a7ea85e2fd5..89a34ff9b58d 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -16,7 +16,6 @@ import subprocess import sys import time -from datetime import datetime, timedelta from functools import partial import pytest @@ -35,8 +34,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.ospfd] @@ -277,7 +275,7 @@ def _test_add_data(tgen, apibin): "linkStateId": "230.0.0.2", "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "opaqueData": "00000202", + "opaqueValues": {"opaqueData": "00000202"}, }, ], } @@ -327,7 +325,9 @@ def _test_add_data(tgen, apibin): "linkStateId": "231.0.0.1", "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "opaqueData": "00010101", + "opaqueValues": { + "opaqueData": "00010101", + }, }, ], } @@ -376,7 +376,9 @@ def _test_add_data(tgen, apibin): "linkStateId": "232.0.0.3", "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000001", - "opaqueData": "deadbeaf01234567", + "opaqueValues": { + "opaqueData": "deadbeaf01234567", + }, }, ] } @@ -427,7 +429,9 @@ def _test_add_data(tgen, apibin): "linkStateId": "232.0.0.3", "advertisingRouter": "1.0.0.0", "lsaSeqNumber": "80000002", - "opaqueData": "ebadf00d", + "opaqueValues": { + "opaqueData": "ebadf00d", + }, }, ] } @@ -574,7 +578,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "76bf", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "230.0.0.2", @@ -583,7 +587,7 @@ def _test_opaque_add_del(tgen, apibin): "checksum": "8aa2", "length": 24, "opaqueId": 2, - "opaqueDataLength": 4, + "opaqueLength": 4, }, ] } @@ -599,7 +603,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "5bd8", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "231.0.0.2", @@ -607,7 +611,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "7690", "length": 28, - "opaqueDataLength": 8, + "opaqueLength": 8, }, ], }, @@ -621,7 +625,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "5ed5", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "232.0.0.2", @@ -629,7 +633,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "d9bd", "length": 24, - "opaqueDataLength": 4, + "opaqueLength": 4, }, ], }, @@ -734,7 +738,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "76bf", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "230.0.0.2", @@ -744,7 +748,7 @@ def _test_opaque_add_del(tgen, apibin): "checksum": "8aa2", "length": 24, "opaqueId": 2, - "opaqueDataLength": 4, + "opaqueLength": 4, }, ] } @@ -760,7 +764,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "5bd8", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "lsaAge": 3600, @@ -770,7 +774,7 @@ def _test_opaque_add_del(tgen, apibin): "checksum": "4fe2", # data removed "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, ], }, @@ -785,7 +789,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "5ed5", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "232.0.0.2", @@ -793,7 +797,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "d9bd", "length": 24, - "opaqueDataLength": 4, + "opaqueLength": 4, }, ], }, @@ -827,7 +831,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "76bf", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "230.0.0.2", @@ -837,7 +841,7 @@ def _test_opaque_add_del(tgen, apibin): "checksum": "8aa2", "length": 24, "opaqueId": 2, - "opaqueDataLength": 4, + "opaqueLength": 4, }, ] } @@ -854,7 +858,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "5bd8", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "lsaAge": 3600, @@ -864,7 +868,7 @@ def _test_opaque_add_del(tgen, apibin): "checksum": "4fe2", # data removed "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, ], }, @@ -879,7 +883,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "5ed5", "length": 20, - "opaqueDataLength": 0, + "opaqueLength": 0, }, { "linkStateId": "232.0.0.2", @@ -888,7 +892,7 @@ def _test_opaque_add_del(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "d9bd", "length": 24, - "opaqueDataLength": 4, + "opaqueLength": 4, }, ], }, @@ -1044,7 +1048,7 @@ def _test_opaque_add_restart_add(tgen, apibin): "lsaSeqNumber": "80000001", "checksum": "b07a", "length": 28, - "opaqueDataLength": 8, + "opaqueLength": 8, }, ], }, @@ -1100,7 +1104,7 @@ def _test_opaque_add_restart_add(tgen, apibin): "lsaSeqNumber": "80000003", "checksum": "cb27", "length": 28, - "opaqueDataLength": 8, + "opaqueLength": 8, }, ], }, @@ -1205,7 +1209,10 @@ def _test_opaque_interface_disable(tgen, apibin): } } test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf interface json", r1_interface_without_opaque + topotest.router_json_cmp, + r1, + "show ip ospf interface json", + r1_interface_without_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" @@ -1232,7 +1239,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 4 in test_ospf_opaque_interface_disable and STEP 59 in CI tests step("Verify that the r1 neighbor options don't include opaque") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_without_opaque + topotest.router_json_cmp, + r1, + "show ip ospf neighbor detail json", + r1_neighbor_without_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF neighbor has opaque option in optionsList" @@ -1241,7 +1251,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 5 in test_ospf_opaque_interface_disable and STEP 60 in CI tests step("Verify that the r1 neighbor options don't include opaque") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_without_opaque + topotest.router_json_cmp, + r2, + "show ip ospf neighbor detail json", + r2_neighbor_without_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF neighbor has opaque option in optionsList" @@ -1282,7 +1295,10 @@ def _test_opaque_interface_disable(tgen, apibin): } } test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_with_opaque + topotest.router_json_cmp, + r2, + "show ip ospf interface json", + r2_interface_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF interface has opaque capability disabled" @@ -1338,19 +1354,17 @@ def _test_opaque_interface_disable(tgen, apibin): "asExternalOpaqueLsaCount": 1, } opaque_area_empty_database = { - "routerId":"2.0.0.0", - "areaLocalOpaqueLsa":{ - "areas":{ - "1.2.3.4":[ - ] - } - } + "routerId": "2.0.0.0", + "areaLocalOpaqueLsa": {"areas": {"1.2.3.4": []}}, } # STEP 9 in test_ospf_opaque_interface_disable and STEP 64 in CI tests step("Check that LSAs are added on r1") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf database json", opaque_LSAs_in_database + topotest.router_json_cmp, + r1, + "show ip ospf database json", + opaque_LSAs_in_database, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF database doesn't contain opaque LSAs" @@ -1359,8 +1373,11 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 10 in test_ospf_opaque_interface_disable and STEP 65 in CI tests step("Check that LSAs are not added on r2") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf database opaque-area json", - opaque_area_empty_database, True + topotest.router_json_cmp, + r2, + "show ip ospf database opaque-area json", + opaque_area_empty_database, + True, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF area database contains opaque LSAs" @@ -1382,7 +1399,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 13 in test_ospf_opaque_interface_disable and STEP 68 in CI tests step("Verify the ospf opaque option is applied to the r1 interface") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf interface json", r1_interface_with_opaque + topotest.router_json_cmp, + r1, + "show ip ospf interface json", + r1_interface_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" @@ -1409,7 +1429,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 14 in test_ospf_opaque_interface_disable and STEP 69 in CI tests step("Verify that the r1 neighbor options include opaque") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_with_opaque + topotest.router_json_cmp, + r1, + "show ip ospf neighbor detail json", + r1_neighbor_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF neighbor doesn't have opaque option in optionsList" @@ -1418,7 +1441,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 15 in test_ospf_opaque_interface_disable and STEP 70 in CI tests step("Verify that the r2 neighbor options include opaque") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_with_opaque + topotest.router_json_cmp, + r2, + "show ip ospf neighbor detail json", + r2_neighbor_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF neighbor doesn't have opaque option in optionsList" @@ -1427,7 +1453,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 16 in test_ospf_opaque_interface_disable and STEP 71 in CI tests step("Check that LSAs are now added to r2") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf database json", opaque_LSAs_in_database + topotest.router_json_cmp, + r2, + "show ip ospf database json", + opaque_LSAs_in_database, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF database doesn't contains opaque LSAs" @@ -1463,7 +1492,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 20 in test_ospf_opaque_interface_disable and STEP 75 in CI tests step("Verify the ospf opaque option is not applied to the r2 interface") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_without_opaque + topotest.router_json_cmp, + r2, + "show ip ospf interface json", + r2_interface_without_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF interface doesn't have opaque capability disabled" @@ -1472,7 +1504,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 21 in test_ospf_opaque_interface_disable and STEP 76 in CI tests step("Verify that the r1 neighbor options don't include opaque") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_without_opaque + topotest.router_json_cmp, + r1, + "show ip ospf neighbor detail json", + r1_neighbor_without_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF neighbor has opaque option in optionsList" @@ -1481,7 +1516,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 22 in test_ospf_opaque_interface_disable and STEP 77 in CI tests step("Verify that the r2 neighbor options don't include opaque") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_without_opaque + topotest.router_json_cmp, + r2, + "show ip ospf neighbor detail json", + r2_neighbor_without_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF neighbor has opaque option in optionsList" @@ -1490,7 +1528,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 23 in test_ospf_opaque_interface_disable and STEP 78 in CI tests step("Verify that r1 still has the opaque LSAs") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf database json", opaque_LSAs_in_database + topotest.router_json_cmp, + r1, + "show ip ospf database json", + opaque_LSAs_in_database, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF database doesn't contain opaque LSAs" @@ -1499,8 +1540,11 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 24 in test_ospf_opaque_interface_disable and STEP 79 in CI tests step("Verify that r2 doesn't have the opaque LSAs") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf database opaque-area json", - opaque_area_empty_database, True + topotest.router_json_cmp, + r2, + "show ip ospf database opaque-area json", + opaque_area_empty_database, + True, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF area database contains opaque LSAs" @@ -1524,7 +1568,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 27 in test_ospf_opaque_interface_disable and STEP 82 in CI tests step("Verify the ospf opaque option is applied to the r2 interface") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf interface json", r2_interface_with_opaque + topotest.router_json_cmp, + r2, + "show ip ospf interface json", + r2_interface_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF interface doesn't have opaque capability disabled" @@ -1533,7 +1580,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 28 in test_ospf_opaque_interface_disable and STEP 83 in CI tests step("Verify that the r2 neighbor options include opaque") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf neighbor detail json", r2_neighbor_with_opaque + topotest.router_json_cmp, + r2, + "show ip ospf neighbor detail json", + r2_neighbor_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF neighbor doesn't have opaque option in optionsList" @@ -1542,7 +1592,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 29 in test_ospf_opaque_interface_disable and STEP 84 in CI tests step("Verify that the r1 neighbor options include opaque") test_func = partial( - topotest.router_json_cmp, r1, "show ip ospf neighbor detail json", r1_neighbor_with_opaque + topotest.router_json_cmp, + r1, + "show ip ospf neighbor detail json", + r1_neighbor_with_opaque, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r1 OSPF neighbor doesn't have opaque option in optionsList" @@ -1551,7 +1604,10 @@ def _test_opaque_interface_disable(tgen, apibin): # STEP 30 in test_ospf_opaque_interface_disable and STEP 85 in CLI tests step("Verify that r2 now has the opaque LSAs") test_func = partial( - topotest.router_json_cmp, r2, "show ip ospf database json", opaque_LSAs_in_database + topotest.router_json_cmp, + r2, + "show ip ospf database json", + opaque_LSAs_in_database, ) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assertmsg = "r2 OSPF database doesn't contain opaque LSAs" @@ -1581,6 +1637,93 @@ def test_ospf_opaque_interface_disable(tgen): _test_opaque_interface_disable(tgen, apibin) +def _test_opaque_link_local_lsa_crash(tgen, apibin): + "Test disabling opaque capability on an interface" + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + tc_name = "opaque_interface_disable" + + p = None + # Log to our stdin, stderr + pout = open(os.path.join(r1.net.logdir, "r1/intf-disable.log"), "a+") + try: + step("Add a link-local opaque LSA for r1-eth0") + pread = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,1,feedaceedeadbeef"]) + + input_dict = { + "linkLocalOpaqueLsa": { + "areas": { + "1.2.3.4": [ + { + "linkStateId": "230.0.0.1", + "advertisingRouter": "1.0.0.0", + "lsaSeqNumber": "80000001", + "opaqueValues": { + "opaqueData": "feedaceedeadbeef", + }, + }, + ], + } + }, + } + + # verify content + json_cmd = "show ip ospf da opaque-link json" + assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None + + step("Shut down r1-eth0 and verify there is no crash") + r1.vtysh_multicmd("conf t\ninterface r1-eth0\nshut") + time.sleep(2) + + step("Bring r1-eth0 back up and verify there is no crash") + r1.vtysh_multicmd("conf t\ninterface r1-eth0\nno shut") + + step("Add another link-local opaque LSA for r1-eth0") + pread = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,1,feedaceecafebeef"]) + + input_dict = { + "linkLocalOpaqueLsa": { + "areas": { + "1.2.3.4": [ + { + "linkStateId": "230.0.0.1", + "advertisingRouter": "1.0.0.0", + "lsaSeqNumber": "80000001", + "opaqueValues": { + "opaqueData": "feedaceecafebeef", + }, + }, + ], + } + }, + } + # verify content + json_cmd = "show ip ospf da opaque-link json" + assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None + + except Exception: + if p: + p.terminate() + if p.wait(): + comm_error(p) + p = None + raise + finally: + if p: + p.terminate() + p.wait() + p = None + + +@pytest.mark.parametrize("tgen", [2], indirect=True) +def test_ospf_opaque_link_local_lsa_crash(tgen): + apibin = os.path.join(CLIENTDIR, "ospfclient.py") + rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) + logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) + _test_opaque_link_local_lsa_crash(tgen, apibin) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py index 49c25ab8f6da..c431147e5591 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py @@ -29,7 +29,6 @@ from lib.common_config import ( start_topology, write_test_header, - kill_router_daemons, write_test_footer, reset_config_on_routers, stop_router, @@ -37,7 +36,6 @@ verify_rib, create_static_routes, step, - start_router_daemons, create_route_maps, shutdown_bringup_interface, create_prefix_lists, @@ -163,7 +161,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2456,7 +2454,7 @@ def test_ospfv3_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf6": { diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py index 58608e249b2e..5f88f6d8357c 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -14,9 +14,7 @@ import time import pytest from time import sleep -from copy import deepcopy import json -from lib.topotest import frr_unicode pytestmark = pytest.mark.ospf6d @@ -39,11 +37,8 @@ shutdown_bringup_interface, ) from lib.topolog import logger -from lib.topojson import build_topo_from_json, build_config_from_json -from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface, clear_ospf -from ipaddress import IPv4Address - -# Global variables +from lib.topojson import build_config_from_json +from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface topo = None # Reading the data from JSON File for topology creation jsonFile = "{}/ospfv3_authentication.json".format(CWD) @@ -118,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. * `mod`: module name @@ -175,7 +170,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -208,7 +203,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -266,7 +261,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -283,7 +278,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -295,7 +290,7 @@ def test_ospf6_auth_trailer_tc1_md5(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -341,7 +336,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -374,7 +369,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -432,7 +427,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -449,7 +444,7 @@ def test_ospf6_auth_trailer_tc2_sha256(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -461,7 +456,66 @@ def test_ospf6_auth_trailer_tc2_sha256(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " + "show ip ospf6 neighbor cmd." + ) + + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) + assert ospf6_covergence is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, ospf6_covergence + ) + + step("Change the key ID on R2 to not match R1") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "30", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify on R1 that R2 nbr is deleted due to key-id mismatch " + "after dead interval expiry" + ) + # wait till the dead timer expiry + sleep(6) + dut = "r2" + ospf6_covergence = verify_ospf6_neighbor( + tgen, topo, dut=dut, expected=False, retry_timeout=5 + ) + assert ospf6_covergence is not True, "Testcase {} :Failed \n Error: {}".format( + tc_name, ospf6_covergence + ) + + step("Correct the key ID on R2 so that it matches R1") + r2_ospf6_auth = { + "r2": { + "links": { + "r1": { + "ospf6": { + "hash-algo": "hmac-sha-256", + "key": "ospf6", + "key-id": "10", + } + } + } + } + } + result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -524,7 +578,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -555,7 +609,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -600,7 +654,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -617,7 +671,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -629,7 +683,7 @@ def test_ospf6_auth_trailer_tc3_keychain_md5(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -692,7 +746,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -723,7 +777,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -768,7 +822,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 using" + "Verify that the neighbor is FULL between R1 and R2 using" " show ip ospf6 neighbor cmd." ) @@ -785,7 +839,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): dut = "r2" step( - "Verify that the neighbour is not FULL between R1 and R2 using " + "Verify that the neighbor is not FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) ospf6_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut, expected=False) @@ -797,7 +851,7 @@ def test_ospf6_auth_trailer_tc4_keychain_sha256(request): shutdown_bringup_interface(tgen, dut, intf, True) step( - "Verify that the neighbour is FULL between R1 and R2 using " + "Verify that the neighbor is FULL between R1 and R2 using " "show ip ospf6 neighbor cmd." ) @@ -843,7 +897,7 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -876,11 +930,11 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is not FULL between R1 and R2 " + "Verify that the neighbor is not FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) - step("Verify that the neighbour is FULL between R1 and R2.") + step("Verify that the neighbor is FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -913,7 +967,7 @@ def test_ospf6_auth_trailer_tc5_md5_keymissmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -959,7 +1013,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -991,7 +1045,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1024,7 +1078,7 @@ def test_ospf6_auth_trailer_tc6_sha256_mismatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -1095,7 +1149,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -1125,7 +1179,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1156,7 +1210,7 @@ def test_ospf6_auth_trailer_tc7_keychain_md5_missmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -1227,7 +1281,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -1257,7 +1311,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1288,7 +1342,7 @@ def test_ospf6_auth_trailer_tc8_keychain_sha256_missmatch(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) @@ -1335,7 +1389,7 @@ def test_ospf6_auth_trailer_tc9_keychain_not_configured(request): result = config_ospf6_interface(tgen, topo, r1_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r1" @@ -1365,7 +1419,7 @@ def test_ospf6_auth_trailer_tc9_keychain_not_configured(request): result = config_ospf6_interface(tgen, topo, r2_ospf6_auth) assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - step("Verify that the neighbour is not FULL between R1 and R2.") + step("Verify that the neighbor is not FULL between R1 and R2.") # wait for dead time expiry. sleep(6) dut = "r2" @@ -1396,7 +1450,7 @@ def test_ospf6_auth_trailer_tc10_no_auth_trailer(request): router2 = tgen.gears["r2"] step( - "Verify that the neighbour is FULL between R1 and R2 " + "Verify that the neighbor is FULL between R1 and R2 " "using show ipv6 ospf6 neighbor cmd." ) diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py index 0c1e3fa43e87..45652a3ee8e6 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py @@ -122,7 +122,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -285,7 +285,7 @@ def test_ospfv3_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(llip) llip = get_llip("r0", "r1") diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py index 7c6773260edf..95f2493c2a8b 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py @@ -13,11 +13,6 @@ import sys import time import pytest -import json -from copy import deepcopy -from ipaddress import IPv4Address -from lib.topotest import frr_unicode -import ipaddress # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -37,9 +32,6 @@ verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, - create_interfaces_cfg, get_frr_ipv6_linklocal, ) from lib.topolog import logger @@ -47,16 +39,11 @@ from lib.ospf import ( verify_ospf6_neighbor, - config_ospf_interface, clear_ospf, verify_ospf6_rib, create_router_ospf, - verify_ospf6_interface, - verify_ospf6_database, - config_ospf6_interface, ) -from ipaddress import IPv6Address pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] @@ -137,7 +124,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py index dc4ce888306e..cc96cd1731b7 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py @@ -78,7 +78,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py index 90548fb5ced4..4ad725e3e69a 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py @@ -13,15 +13,10 @@ import sys import time import pytest -from copy import deepcopy import ipaddress from lib.ospf import ( verify_ospf6_neighbor, - config_ospf6_interface, - clear_ospf, verify_ospf6_rib, - verify_ospf6_interface, - verify_ospf6_database, create_router_ospf, ) @@ -29,12 +24,6 @@ # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.bgp import ( - verify_bgp_convergence, - create_router_bgp, - clear_bgp_and_verify, - verify_bgp_rib, -) from lib.topolog import logger from lib.common_config import ( start_topology, @@ -44,12 +33,9 @@ verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, create_interfaces_cfg, check_router_status, ) -from ipaddress import IPv4Address from lib.topolog import logger from lib.topojson import build_config_from_json @@ -410,7 +396,7 @@ def test_ospfv3_learning_tc15_p0(request): step("Verify that Type 3 summary LSA is originated for the same Area 0") ip = topo["routers"]["r1"]["links"]["r3-link0"]["ipv6"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) input_dict = { "r1": { diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py index 069806a3ef46..ff88badeebcc 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py @@ -136,7 +136,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py index 645dea8dec44..06989db894de 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py @@ -45,7 +45,6 @@ verify_ospf6_neighbor, clear_ospf, verify_ospf6_rib, - verify_ospf_database, create_router_ospf, config_ospf6_interface, verify_ospf6_interface, @@ -127,7 +126,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -262,7 +261,7 @@ def test_ospfv3_redistribution_tc5_p0(request): step("verify intra area route is calculated for r0-r3 interface ip in R1") ip = topo["routers"]["r0"]["links"]["r3"]["ipv6"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) llip = get_llip("r0", "r1") assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, llip) @@ -379,7 +378,7 @@ def test_ospfv3_redistribution_tc6_p0(request): step("verify intra area route is calculated for r0-r3 interface ip in R1") ip = topo["routers"]["r0"]["links"]["r3"]["ipv6"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) llip = get_llip("r0", "r1") assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, llip) nh = llip diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py index 7199f160fe5b..d981a84597b3 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py @@ -36,7 +36,6 @@ step, create_interfaces_cfg, create_debug_log_config, - apply_raw_config, ) from lib.topolog import logger from lib.topojson import build_config_from_json @@ -121,7 +120,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -389,6 +388,11 @@ def test_ospfv3_hello_tc10_p0(request): step("Bring up the base config as per the topology") reset_config_on_routers(tgen) + ospf_covergence = verify_ospf6_neighbor(tgen) + assert ( + ospf_covergence is True + ), "Testcase {} [01]: Reset Failed \n Error: {}".format(tc_name, ospf_covergence) + step("modify hello timer from default value to some other value on r1") topo1 = { @@ -403,7 +407,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [02]: Failed \n Error: {}".format( + tc_name, result + ) step( "verify that new timer value is configured and applied using " @@ -423,7 +429,9 @@ def test_ospfv3_hello_tc10_p0(request): } } result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [03]: Failed \n Error: {}".format( + tc_name, result + ) step("modify hello timer from default value to r1 hello timer on r2") @@ -439,7 +447,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [04]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -456,12 +466,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [05]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [06]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -478,7 +490,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [07]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -492,7 +506,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [08]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -509,12 +525,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [09]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [10]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -531,7 +549,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [11]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -545,7 +565,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [12]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -562,12 +584,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [13]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [14]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("configure hello timer = 1 on r1 and r2") @@ -583,7 +607,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [15]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -597,7 +623,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [16]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -614,12 +642,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [17]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [18]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step(" Configure hello timer = 65535") @@ -635,7 +665,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [19]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -649,7 +681,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [20]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -666,11 +700,13 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [21]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format( + assert ospf_covergence is True, "Testcase {} [22]: Failed \n Error: {}".format( tc_name, ospf_covergence ) step(" Try configuring timer values outside range for example 65536") @@ -688,7 +724,7 @@ def test_ospfv3_hello_tc10_p0(request): result = create_interfaces_cfg(tgen, topo1) assert ( result is not True - ), "Testcase {} : Failed \n Create interface failed. Error: {}".format( + ), "Testcase {} [23]: Failed \n Create interface failed. Error: {}".format( tc_name, result ) @@ -707,13 +743,17 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [24]: Failed \n Error: {}".format( + tc_name, result + ) step("Verify that timer value is deleted from intf & set to default value 40 sec.") input_dict = {"r1": {"links": {"r0": {"ospf6": {"timerIntervalsConfigHello": 10}}}}} dut = "r1" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [25]: Failed \n Error: {}".format( + tc_name, result + ) write_test_footer(tc_name) @@ -1124,7 +1164,7 @@ def test_ospfv3_show_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) ip = topo["routers"]["r0"]["links"]["r3"]["ipv6"] - ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network) + ip_net = str(ipaddress.ip_interface("{}".format(ip)).network) nh = topo["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0] input_dict = { "r1": { diff --git a/tests/topotests/pbr_topo1/r1/pbr-map.json b/tests/topotests/pbr_topo1/r1/pbr-map.json index bfa0ecb84905..aaf2b5e8dc99 100644 --- a/tests/topotests/pbr_topo1/r1/pbr-map.json +++ b/tests/topotests/pbr_topo1/r1/pbr-map.json @@ -18,7 +18,7 @@ { "sequenceNumber":10, "vrfUnchanged":false, - "installed":true, + "installed":false, "installedReason":"Invalid Src or Dst", "nexthopGroup":{ "name":"C", @@ -98,7 +98,7 @@ { "sequenceNumber":5, "vrfUnchanged":false, - "installed":false, + "installed":true, "installedReason":"Invalid NH-group", "nexthopGroup":{ "name":"B", @@ -111,7 +111,7 @@ { "sequenceNumber":10, "vrfUnchanged":true, - "installed":false, + "installed":true, "installedReason":"Valid", "matchSrc":"1.2.0.0\/16", "matchDst":"3.4.5.0\/24" diff --git a/tests/topotests/pim_acl/test_pim_acl.py b/tests/topotests/pim_acl/test_pim_acl.py index 6e5092dabb50..d8eececf8151 100755 --- a/tests/topotests/pim_acl/test_pim_acl.py +++ b/tests/topotests/pim_acl/test_pim_acl.py @@ -169,7 +169,7 @@ def setup_module(module): tgen.start_router() -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index 24987e516d24..ce1abe42bb09 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -18,7 +18,7 @@ import json from functools import partial -pytestmark = pytest.mark.pimd +pytestmark = [pytest.mark.pimd] CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -29,9 +29,6 @@ from lib.topolog import logger -pytestmark = [pytest.mark.pimd] - - def build_topo(tgen): "Build function" @@ -91,7 +88,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_blue_route.json b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_route.json new file mode 100644 index 000000000000..c5e89d18e87b --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_route.json @@ -0,0 +1,54 @@ +{ + "blue": { + "vrfName": "blue", + "192.168.0.1/32": { + "routeType": "N", + "transit": false, + "cost": 0, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": " ", + "directlyAttachedTo": "blue" + } + ] + }, + "192.168.0.11/32": { + "routeType": "N", + "transit": false, + "cost": 10, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": "192.168.101.11", + "via": "r1-eth1", + "advertisedRouter": "192.168.0.11" + } + ] + }, + "192.168.100.0/24": { + "routeType": "N", + "transit": false, + "cost": 10, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": " ", + "directlyAttachedTo": "r1-eth0" + } + ] + }, + "192.168.101.0/24": { + "routeType": "N", + "transit": true, + "cost": 10, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": " ", + "directlyAttachedTo": "r1-eth1" + } + ] + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_red_route.json b/tests/topotests/pim_igmp_vrf/r1/ospf_red_route.json new file mode 100644 index 000000000000..2fc340d4c899 --- /dev/null +++ b/tests/topotests/pim_igmp_vrf/r1/ospf_red_route.json @@ -0,0 +1,54 @@ +{ + "red": { + "vrfName": "red", + "192.168.0.1/32": { + "routeType": "N", + "transit": false, + "cost": 0, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": " ", + "directlyAttachedTo": "red" + } + ] + }, + "192.168.0.12/32": { + "routeType": "N", + "transit": false, + "cost": 10, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": "192.168.101.12", + "via": "r1-eth3", + "advertisedRouter": "192.168.0.12" + } + ] + }, + "192.168.100.0/24": { + "routeType": "N", + "transit": false, + "cost": 10, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": " ", + "directlyAttachedTo": "r1-eth2" + } + ] + }, + "192.168.101.0/24": { + "routeType": "N", + "transit": true, + "cost": 10, + "area": "0.0.0.0", + "nexthops": [ + { + "ip": " ", + "directlyAttachedTo": "r1-eth3" + } + ] + } + } +} diff --git a/tests/topotests/pim_igmp_vrf/r1/ospfd.conf b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf index 88eb5a8a054c..9b9a261b1d31 100644 --- a/tests/topotests/pim_igmp_vrf/r1/ospfd.conf +++ b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf @@ -1,6 +1,8 @@ hostname r1 ! ! debug ospf event +! debug ospf nsm +! debug ospf packet hello ! ! interface r1-eth1 diff --git a/tests/topotests/pim_igmp_vrf/r1/pimd.conf b/tests/topotests/pim_igmp_vrf/r1/pimd.conf index 040c3d01b1d0..c4ddced0227a 100644 --- a/tests/topotests/pim_igmp_vrf/r1/pimd.conf +++ b/tests/topotests/pim_igmp_vrf/r1/pimd.conf @@ -2,6 +2,7 @@ hostname r1 ! ! debug igmp events ! debug igmp packets +! debug mroute detail ! debug pim events ! debug pim packets ! debug pim trace diff --git a/tests/topotests/pim_igmp_vrf/r11/ospfd.conf b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf index 86fb66db6175..e52737cb1841 100644 --- a/tests/topotests/pim_igmp_vrf/r11/ospfd.conf +++ b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf @@ -1,6 +1,8 @@ hostname r11 ! ! debug ospf event +! debug ospf nsm +! debug ospf packet hello ! interface r11-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_igmp_vrf/r12/ospfd.conf b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf index f0dcabece2c3..cd944061f776 100644 --- a/tests/topotests/pim_igmp_vrf/r12/ospfd.conf +++ b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf @@ -1,6 +1,8 @@ hostname r12 ! ! debug ospf event +! debug ospf nsm +! debug ospf packet hello ! interface r12-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py index ddc430330d3d..d6d879d45fe7 100755 --- a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py +++ b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py @@ -60,7 +60,7 @@ +---------+ +------------+ | +---------+ | Host H1 | 192.168.100.0/24 | | .1 | .11 | Host H2 | | receive |------------------| VRF Blue |---------+--------| PIM RP | -|IGMP JOIN| .10 .1 | | 192.168.101.0/24 | | +|IGMP JOIN| .10 .1 | | 192.168.101.0/24 | | +---------+ | | +---------+ =| = = R1 = = |= +---------+ | | +---------+ @@ -68,7 +68,7 @@ | receive |------------------| VRF Red |---------+--------| PIM RP | |IGMP JOIN| .20 .1 | | .1 | .12 | | +---------+ +------------+ | +---------+ - .4 | + .4 | +----------+ | Host H4 | | Source | @@ -80,6 +80,7 @@ import os import sys import pytest +import logging # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -192,8 +193,19 @@ def setup_module(module): tgen.start_router() + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip( + "Installed iproute2 version does not support VRFs", allow_module_level=True + ) + + if os.getenv("MROUTE_VRF_MISSING"): + pytest.skip( + "Kernel does not support vrf mroute tables.", allow_module_level=True + ) -def teardown_module(module): + +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -202,16 +214,13 @@ def test_ospf_convergence(): "Test for OSPFv2 convergence" tgen = get_topogen() - # iproute2 needs to support VRFs for this suite to run. - if not iproute2_is_vrf_capable(): - pytest.skip("Installed iproute2 version does not support VRFs") - # Skip if previous fatal error condition is raised if tgen.routers_have_failure(): pytest.skip(tgen.errors) logger.info("Checking OSPFv2 convergence on router r1 for VRF blue") + # Check for blue neighbor router = tgen.gears["r1"] reffile = os.path.join(CWD, "r1/ospf_blue_neighbor.json") expected = json.loads(open(reffile).read()) @@ -223,7 +232,22 @@ def test_ospf_convergence(): expected, ) _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) - assertmsg = "OSPF router R1 did not converge on VRF blue" + assertmsg = "OSPF router R1 did not converge on VRF blue (nbr)" + assert res is None, assertmsg + + # Check for blue loopback route + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ospf_blue_route.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip ospf vrf blue route json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "OSPF router R1 did not converge on VRF blue (route)" assert res is None, assertmsg logger.info("Checking OSPFv2 convergence on router r1 for VRF red") @@ -236,7 +260,22 @@ def test_ospf_convergence(): topotest.router_json_cmp, router, "show ip ospf vrf red neighbor json", expected ) _, res = topotest.run_and_expect(test_func, None, count=60, wait=2) - assertmsg = "OSPF router R1 did not converge on VRF red" + assertmsg = "OSPF router R1 did not converge on VRF red (nbr)" + assert res is None, assertmsg + + # Check for red loopback route + router = tgen.gears["r1"] + reffile = os.path.join(CWD, "r1/ospf_red_route.json") + expected = json.loads(open(reffile).read()) + + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip ospf vrf red route json", + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=30, wait=2) + assertmsg = "OSPF router R1 did not converge on VRF red (route)" assert res is None, assertmsg @@ -275,10 +314,13 @@ def test_pim_convergence(): assert res is None, assertmsg -def test_vrf_pimreg_interfaces(): +def _test_vrf_pimreg_interfaces(): "Adding PIM RP in VRF information and verify pimreg interfaces" tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + r1 = tgen.gears["r1"] r1.vtysh_cmd("conf\ninterface blue\nip pim") r1.vtysh_cmd("conf\nvrf blue\nip pim rp 192.168.0.11 239.100.0.1/32\nexit-vrf") @@ -292,7 +334,7 @@ def test_vrf_pimreg_interfaces(): "show ip pim vrf blue inter pimreg11 json", expected, ) - _, res = topotest.run_and_expect(test_func, None, count=5, wait=2) + _, res = topotest.run_and_expect(test_func, None, count=15, wait=2) assertmsg = "PIM router R1, VRF blue (table 11) pimreg11 interface missing or incorrect status" assert res is None, assertmsg @@ -308,10 +350,20 @@ def test_vrf_pimreg_interfaces(): "show ip pim vrf red inter pimreg12 json", expected, ) - _, res = topotest.run_and_expect(test_func, None, count=5, wait=2) + _, res = topotest.run_and_expect(test_func, None, count=15, wait=2) assertmsg = "PIM router R1, VRF red (table 12) pimreg12 interface missing or incorrect status" assert res is None, assertmsg +def test_vrf_pimreg_interfaces(): + tgen = get_topogen() + r1 = tgen.gears["r1"] + try: + _test_vrf_pimreg_interfaces() + except Exception: + # get some debug info. + output = r1.net.cmd_nostatus("ip -o link") + logging.error("ip link info after failure: %s", output) + raise ################################## ### Test PIM / IGMP with VRF diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 6c2d42ef40ab..db806fed395f 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -1,6 +1,8 @@ # Skip pytests example directory [pytest] +# NEEDS_EXABGP_4_2_11_FRR + # asyncio_mode = auto # We always turn this on inside conftest.py, default shown @@ -41,8 +43,10 @@ markers = bfdd: Tests that run against BFDD bgpd: Tests that run against BGPD eigrpd: Tests that run against EIGRPD + fpm: Tests that run against the FPM isisd: Tests that run against ISISD ldpd: Tests that run against LDPD + mgmtd: Tests that run against MGMTD nhrpd: Tests that run against NHRPD ospf6d: Tests that run against OSPF6D ospfd: Tests that run against OSPFD diff --git a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py index 7d958fd496d6..c07b1ffc1521 100644 --- a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py +++ b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py index 71c90931fb38..26680f54600e 100644 --- a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py +++ b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py @@ -20,7 +20,6 @@ from functools import partial from lib import topotest from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger pytestmark = [ pytest.mark.bfdd, @@ -32,10 +31,7 @@ def tgen(request): "Setup/Teardown the environment and provide tgen argument to tests" - topodef = { - "s1": ("r1", "r2"), - "s2": ("r1", "r3") - } + topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r3")} tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() @@ -68,16 +64,17 @@ def show_rip_json(router): for route in routes: match = re.match( - r"(.)\((.)\)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)", route) + r"(.)\((.)\)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)", route + ) if match is None: continue route_entry = { - "code": match[1], - "subCode": match[2], - "nextHop": match[4], - "metric": int(match[5]), - "from": match[6], + "code": match[1], + "subCode": match[2], + "nextHop": match[4], + "metric": int(match[5]), + "from": match[6], } if json.get(match[3]) is None: @@ -95,12 +92,8 @@ def test_function(): "Internal test function." return topotest.json_cmp(show_rip_json(router), routes) - _, result = topotest.run_and_expect(test_function, - None, - count=time_amount, - wait=1) - assert result is None, "Unexpected routing table in {}".format( - router.name) + _, result = topotest.run_and_expect(test_function, None, count=time_amount, wait=1) + assert result is None, "Unexpected routing table in {}".format(router.name) def expect_bfd_peers(router, peers): @@ -119,91 +112,87 @@ def test_rip_convergence(tgen): "Test that RIP learns the neighbor routes." expect_routes( - tgen.gears["r1"], { - "10.254.254.2/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.0.2" - }], - "10.254.254.3/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.1.2" - }], - "10.254.254.100/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.0.2", - }, { - "code": "R", - "subCode": "n", - "from": "192.168.1.2", - }] - }, 40) - - expect_bfd_peers(tgen.gears["r1"], [{ - "peer": "192.168.0.2", - "status": "up", - "receive-interval": 1000, - "transmit-interval": 1000, - }, { - "peer": "192.168.1.2", - "status": "up", - "receive-interval": 1000, - "transmit-interval": 1000, - }]) + tgen.gears["r1"], + { + "10.254.254.2/32": [{"code": "R", "subCode": "n", "from": "192.168.0.2"}], + "10.254.254.3/32": [{"code": "R", "subCode": "n", "from": "192.168.1.2"}], + "10.254.254.100/32": [ + { + "code": "R", + "subCode": "n", + "from": "192.168.0.2", + }, + { + "code": "R", + "subCode": "n", + "from": "192.168.1.2", + }, + ], + }, + 40, + ) + + expect_bfd_peers( + tgen.gears["r1"], + [ + { + "peer": "192.168.0.2", + "status": "up", + "receive-interval": 1000, + "transmit-interval": 1000, + }, + { + "peer": "192.168.1.2", + "status": "up", + "receive-interval": 1000, + "transmit-interval": 1000, + }, + ], + ) expect_routes( - tgen.gears["r2"], { - "10.254.254.1/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.0.1" - }], - "10.254.254.3/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.0.1" - }], - "10.254.254.100/32": [{ - "code": "S", - "subCode": "r", - "from": "self" - }] - }, 40) - - expect_bfd_peers(tgen.gears["r2"], [{ - "peer": "192.168.0.1", - "status": "up", - "receive-interval": 1000, - "transmit-interval": 1000, - }]) + tgen.gears["r2"], + { + "10.254.254.1/32": [{"code": "R", "subCode": "n", "from": "192.168.0.1"}], + "10.254.254.3/32": [{"code": "R", "subCode": "n", "from": "192.168.0.1"}], + "10.254.254.100/32": [{"code": "S", "subCode": "r", "from": "self"}], + }, + 40, + ) + + expect_bfd_peers( + tgen.gears["r2"], + [ + { + "peer": "192.168.0.1", + "status": "up", + "receive-interval": 1000, + "transmit-interval": 1000, + } + ], + ) expect_routes( - tgen.gears["r3"], { - "10.254.254.1/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.1.1" - }], - "10.254.254.2/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.1.1" - }], - "10.254.254.100/32": [{ - "code": "S", - "subCode": "r", - "from": "self" - }] - }, 40) - - expect_bfd_peers(tgen.gears["r3"], [{ - "peer": "192.168.1.1", - "status": "up", - "receive-interval": 1000, - "transmit-interval": 1000, - }]) + tgen.gears["r3"], + { + "10.254.254.1/32": [{"code": "R", "subCode": "n", "from": "192.168.1.1"}], + "10.254.254.2/32": [{"code": "R", "subCode": "n", "from": "192.168.1.1"}], + "10.254.254.100/32": [{"code": "S", "subCode": "r", "from": "self"}], + }, + 40, + ) + + expect_bfd_peers( + tgen.gears["r3"], + [ + { + "peer": "192.168.1.1", + "status": "up", + "receive-interval": 1000, + "transmit-interval": 1000, + } + ], + ) def test_rip_bfd_convergence(tgen): @@ -212,30 +201,30 @@ def test_rip_bfd_convergence(tgen): tgen.gears["r3"].link_enable("r3-eth0", False) expect_routes( - tgen.gears["r1"], { - "10.254.254.2/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.0.2" - }], + tgen.gears["r1"], + { + "10.254.254.2/32": [{"code": "R", "subCode": "n", "from": "192.168.0.2"}], "10.254.254.3/32": None, - "10.254.254.100/32": [{ - "code": "R", - "subCode": "n", - "from": "192.168.0.2", - }] - }, 6) + "10.254.254.100/32": [ + { + "code": "R", + "subCode": "n", + "from": "192.168.0.2", + } + ], + }, + 6, + ) expect_routes( - tgen.gears["r3"], { + tgen.gears["r3"], + { "10.254.254.1/32": None, "10.254.254.2/32": None, - "10.254.254.100/32": [{ - "code": "S", - "subCode": "r", - "from": "self" - }] - }, 6) + "10.254.254.100/32": [{"code": "S", "subCode": "r", "from": "self"}], + }, + 6, + ) def test_memory_leak(tgen): diff --git a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py index c2b28c4a3efe..ebc36d1fdc1c 100644 --- a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py +++ b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -40,7 +40,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_topo1/r1/show_ip_rip.ref b/tests/topotests/rip_topo1/r1/show_ip_rip.ref index a0b77c886e3b..b49a042dac1f 100644 --- a/tests/topotests/rip_topo1/r1/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r1/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r2/show_ip_rip.ref b/tests/topotests/rip_topo1/r2/show_ip_rip.ref index b61fb45eac5b..d0e7e81bc528 100644 --- a/tests/topotests/rip_topo1/r2/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r2/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r3/show_ip_rip.ref b/tests/topotests/rip_topo1/r3/show_ip_rip.ref index 1df299b5e650..bb4afc76b75d 100644 --- a/tests/topotests/rip_topo1/r3/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r3/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py index 08bb9999288e..060b558f0df3 100644 --- a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py +++ b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripngd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_route_map/test_ripng_route_map.py b/tests/topotests/ripng_route_map/test_ripng_route_map.py index e1cc88e9b68d..4fadb5fbcf7f 100644 --- a/tests/topotests/ripng_route_map/test_ripng_route_map.py +++ b/tests/topotests/ripng_route_map/test_ripng_route_map.py @@ -20,8 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.ripngd] @@ -39,7 +38,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref index 30d0f31e18f6..8645979cc021 100644 --- a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref index fe5bcc8b310f..2c4db1ab5405 100644 --- a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref index 909ad663baeb..2ba0aa6d8fe5 100644 --- a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/route_scale/r1/installed.routes.json b/tests/topotests/route_scale/r1/installed.routes.json index 25d209f9eb4e..6e09f52f1c33 100644 --- a/tests/topotests/route_scale/r1/installed.routes.json +++ b/tests/topotests/route_scale/r1/installed.routes.json @@ -11,6 +11,6 @@ "type":"sharp" } ], - "routesTotal":1000032, - "routesTotalFib":1000032 + "routesTotal":1000064, + "routesTotalFib":1000064 } diff --git a/tests/topotests/route_scale/r1/no.routes.json b/tests/topotests/route_scale/r1/no.routes.json index abebd1b143e3..13dc7675a102 100644 --- a/tests/topotests/route_scale/r1/no.routes.json +++ b/tests/topotests/route_scale/r1/no.routes.json @@ -6,6 +6,6 @@ "type":"connected" } ], - "routesTotal":32, - "routesTotalFib":32 + "routesTotal":64, + "routesTotalFib":64 } diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py index 6227e81b986a..4b19bebe677d 100644 --- a/tests/topotests/route_scale/scale_test_common.py +++ b/tests/topotests/route_scale/scale_test_common.py @@ -86,6 +86,23 @@ def scale_converge_protocols(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) + logger.info("Ensuring that Connected Routes are actually installed") + r1 = tgen.gears["r1"] + expected = { + "routes": [ + {"fib": 32, "rib": 32, "type": "connected"}, + {"fib": 32, "rib": 32, "type": "local"}, + ], + "routesTotal": 64, + "routesTotalFib": 64, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip route summary json", expected + ) + success, result = topotest.run_and_expect(test_func, None, 60, 1) + assert success, "Connected routes are not properly installed:\n{}".format(result) + def run_one_setup(r1, s): "Run one ecmp config" @@ -151,7 +168,7 @@ def route_install_helper(iter): logger.info( "Limited memory available: {}, skipping x32 testcase".format(total_mem) ) - return; + return installed_file = "{}/r1/installed.routes.json".format(CWD) expected_installed = json.loads(open(installed_file).read()) @@ -165,7 +182,7 @@ def route_install_helper(iter): # Table of defaults, used for timeout values and 'expected' objects scale_defaults = dict( - zip(scale_keys, [None, None, 10, 50, expected_installed, expected_removed]) + zip(scale_keys, [None, None, 10, 60, expected_installed, expected_removed]) ) # List of params for each step in the test; note extra time given @@ -182,7 +199,6 @@ def route_install_helper(iter): # Build up a list of dicts with params for each step of the test; # use defaults where the step doesn't supply a value - scale_setups = [] s = scale_steps[iter] d = dict(zip(scale_keys, s)) diff --git a/tests/topotests/route_scale/test_route_scale1.py b/tests/topotests/route_scale/test_route_scale1.py index 0f25b28c742c..68af979c2ffd 100644 --- a/tests/topotests/route_scale/test_route_scale1.py +++ b/tests/topotests/route_scale/test_route_scale1.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,39 +23,52 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger -from scale_test_common import scale_build_common, scale_setup_module, route_install_helper, scale_test_memory_leak, scale_converge_protocols, scale_teardown_module +from scale_test_common import ( + scale_build_common, + scale_setup_module, + route_install_helper, + scale_test_memory_leak, + scale_converge_protocols, + scale_teardown_module, +) pytestmark = [pytest.mark.sharpd] + def build(tgen): scale_build_common(tgen) + def setup_module(module): scale_setup_module(module) + def teardown_module(_mod): scale_teardown_module(_mod) + def test_converge_protocols(): scale_converge_protocols() + def test_route_install_2nh(): route_install_helper(1) + def test_route_install_4nh(): route_install_helper(2) + def test_route_install_16nh(): route_install_helper(4) + def test_memory_leak(): scale_test_memory_leak() + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/route_scale/test_route_scale2.py b/tests/topotests/route_scale/test_route_scale2.py index 3b55fcd8f597..4be8554a0f2b 100644 --- a/tests/topotests/route_scale/test_route_scale2.py +++ b/tests/topotests/route_scale/test_route_scale2.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,39 +23,52 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger -from scale_test_common import scale_build_common, scale_setup_module, route_install_helper, scale_test_memory_leak, scale_converge_protocols, scale_teardown_module +from scale_test_common import ( + scale_build_common, + scale_setup_module, + route_install_helper, + scale_test_memory_leak, + scale_converge_protocols, + scale_teardown_module, +) pytestmark = [pytest.mark.sharpd] + def build(tgen): scale_build_common(tgen) + def setup_module(module): scale_setup_module(module) + def teardown_module(_mod): scale_teardown_module(_mod) + def test_converge_protocols(): scale_converge_protocols() + def test_route_install_1nh(): route_install_helper(0) + def test_route_install_8nh(): route_install_helper(3) + def test_route_install_32nh(): route_install_helper(5) + def test_memory_leak(): scale_test_memory_leak() + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/simple_snmp_test/test_simple_snmp.py b/tests/topotests/simple_snmp_test/test_simple_snmp.py index ee02c7b51993..0387e2927405 100755 --- a/tests/topotests/simple_snmp_test/test_simple_snmp.py +++ b/tests/topotests/simple_snmp_test/test_simple_snmp.py @@ -79,7 +79,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step6/show_mpls_table.ref.diff b/tests/topotests/srv6_encap_src_addr/__init__.py similarity index 100% rename from tests/topotests/isis_tilfa_topo1/rt2/step6/show_mpls_table.ref.diff rename to tests/topotests/srv6_encap_src_addr/__init__.py diff --git a/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr.json b/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr.json new file mode 100644 index 000000000000..431027f099dc --- /dev/null +++ b/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr.json @@ -0,0 +1,9 @@ +{ + "parameters": { + "encapsulation":{ + "sourceAddress": { + "configured": "fc00:0:1::1" + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr_set.json b/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr_set.json new file mode 100644 index 000000000000..431027f099dc --- /dev/null +++ b/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr_set.json @@ -0,0 +1,9 @@ +{ + "parameters": { + "encapsulation":{ + "sourceAddress": { + "configured": "fc00:0:1::1" + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr_unset.json b/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr_unset.json new file mode 100644 index 000000000000..18b317f5f31b --- /dev/null +++ b/tests/topotests/srv6_encap_src_addr/r1/expected_srv6_encap_src_addr_unset.json @@ -0,0 +1,9 @@ +{ + "parameters": { + "encapsulation":{ + "sourceAddress": { + "configured": "::" + } + } + } +} \ No newline at end of file diff --git a/tests/topotests/srv6_encap_src_addr/r1/setup.sh b/tests/topotests/srv6_encap_src_addr/r1/setup.sh new file mode 100644 index 000000000000..36ed713f2416 --- /dev/null +++ b/tests/topotests/srv6_encap_src_addr/r1/setup.sh @@ -0,0 +1,2 @@ +ip link add dummy0 type dummy +ip link set dummy0 up diff --git a/tests/topotests/srv6_encap_src_addr/r1/zebra.conf b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf new file mode 100644 index 000000000000..c570756b5243 --- /dev/null +++ b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf @@ -0,0 +1,17 @@ +hostname r1 +! +! debug zebra events +! debug zebra rib detailed +! +log stdout notifications +log monitor notifications +log commands +log file zebra.log debugging +! +segment-routing + srv6 + encapsulation + source-address fc00:0:1::1 + ! + ! +! diff --git a/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py new file mode 100755 index 000000000000..854bc1cdade9 --- /dev/null +++ b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_srv6_encap_src_addr.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2022 by +# University of Rome Tor Vergata, Carmine Scarpitta +# + +""" +test_srv6_encap_src_addr.py: +Test for SRv6 encap source address on zebra +""" + +import os +import sys +import json +import pytest + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd] + + +def open_json_file(filename): + try: + with open(filename, "r") as f: + return json.load(f) + except IOError: + assert False, "Could not read file {}".format(filename) + + +def setup_module(mod): + tgen = Topogen({None: "r1"}, mod.__name__) + tgen.start_topology() + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) + ) + tgen.start_router() + + +def teardown_module(): + tgen = get_topogen() + tgen.stop_topology() + + +def test_zebra_srv6_encap_src_addr(tgen): + "Test SRv6 encapsulation source address." + logger.info("Test SRv6 encapsulation source address.") + r1 = tgen.gears["r1"] + + # Generate expected results + json_file = "{}/r1/expected_srv6_encap_src_addr.json".format(CWD) + expected = json.loads(open(json_file).read()) + + ok = topotest.router_json_cmp_retry( + r1, "show segment-routing srv6 manager json", expected + ) + assert ok, '"r1" JSON output mismatches' + + output = r1.cmd("ip sr tunsrc show") + assert output == "tunsrc addr fc00:0:1::1\n" + + +def test_zebra_srv6_encap_src_addr_unset(tgen): + "Test SRv6 encapsulation source address unset." + logger.info("Test SRv6 encapsulation source address unset.") + r1 = tgen.gears["r1"] + + # Unset SRv6 encapsulation source address + r1.vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + encapsulation + no source-address + """ + ) + + # Generate expected results + json_file = "{}/r1/expected_srv6_encap_src_addr_unset.json".format(CWD) + expected = json.loads(open(json_file).read()) + + ok = topotest.router_json_cmp_retry( + r1, "show segment-routing srv6 manager json", expected + ) + assert ok, '"r1" JSON output mismatches' + + output = r1.cmd("ip sr tunsrc show") + assert output == "tunsrc addr ::\n" + + +def test_zebra_srv6_encap_src_addr_set(tgen): + "Test SRv6 encapsulation source address set." + logger.info("Test SRv6 encapsulation source address set.") + r1 = tgen.gears["r1"] + + # Set SRv6 encapsulation source address + r1.vtysh_cmd( + """ + configure terminal + segment-routing + srv6 + encapsulation + source-address fc00:0:1::1 + """ + ) + + # Generate expected results + json_file = "{}/r1/expected_srv6_encap_src_addr_set.json".format(CWD) + expected = json.loads(open(json_file).read()) + + ok = topotest.router_json_cmp_retry( + r1, "show segment-routing srv6 manager json", expected + ) + assert ok, '"r1" JSON output mismatches' + + output = r1.cmd("ip sr tunsrc show") + assert output == "tunsrc addr fc00:0:1::1\n" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/srv6_locator/r1/sharpd.conf b/tests/topotests/srv6_locator/r1/sharpd.conf index d46085935c80..371e6f694a2d 100644 --- a/tests/topotests/srv6_locator/r1/sharpd.conf +++ b/tests/topotests/srv6_locator/r1/sharpd.conf @@ -1,7 +1,6 @@ hostname r1 ! log stdout notifications -log monitor notifications log commands log file sharpd.log debugging ! diff --git a/tests/topotests/srv6_locator/r1/zebra.conf b/tests/topotests/srv6_locator/r1/zebra.conf index 85001d710e54..695cf0a73c2a 100644 --- a/tests/topotests/srv6_locator/r1/zebra.conf +++ b/tests/topotests/srv6_locator/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 ! debug zebra rib detailed ! log stdout notifications -log monitor notifications log commands log file zebra.log debugging ! diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py index 3a27d9c2fc5f..bab6746409ab 100755 --- a/tests/topotests/srv6_locator/test_srv6_locator.py +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -56,7 +56,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -81,12 +81,12 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf b/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf index d46085935c80..371e6f694a2d 100644 --- a/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf +++ b/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf @@ -1,7 +1,6 @@ hostname r1 ! log stdout notifications -log monitor notifications log commands log file sharpd.log debugging ! diff --git a/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf b/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf index 30a520b79815..96033b657321 100644 --- a/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf +++ b/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 ! debug zebra rib detailed ! log stdout notifications -log monitor notifications log commands log file zebra.log debugging ! diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py similarity index 95% rename from tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py rename to tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py index 92980d3b179e..d3df902aaed1 100755 --- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py +++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py @@ -52,7 +52,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -77,12 +77,12 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_usid/r1/sharpd.conf b/tests/topotests/srv6_locator_usid/r1/sharpd.conf index d46085935c80..371e6f694a2d 100644 --- a/tests/topotests/srv6_locator_usid/r1/sharpd.conf +++ b/tests/topotests/srv6_locator_usid/r1/sharpd.conf @@ -1,7 +1,6 @@ hostname r1 ! log stdout notifications -log monitor notifications log commands log file sharpd.log debugging ! diff --git a/tests/topotests/srv6_locator_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf index 190e831ac1e8..1a02e28be26f 100644 --- a/tests/topotests/srv6_locator_usid/r1/zebra.conf +++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 ! debug zebra rib detailed ! log stdout notifications -log monitor notifications log commands log file zebra.log debugging ! diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py index 54187351b2f4..e0c05c517991 100755 --- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py +++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -70,13 +70,13 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" diff --git a/tests/topotests/srv6_static_route/r1/staticd.conf b/tests/topotests/srv6_static_route/r1/staticd.conf index a75c69f26b5f..3c65a68c7bd7 100644 --- a/tests/topotests/srv6_static_route/r1/staticd.conf +++ b/tests/topotests/srv6_static_route/r1/staticd.conf @@ -1,7 +1,6 @@ hostname r1 ! log stdout notifications -log monitor notifications log commands log file staticd.log debugging ! diff --git a/tests/topotests/srv6_static_route/r1/zebra.conf b/tests/topotests/srv6_static_route/r1/zebra.conf index cc704186010c..a596eeba88e5 100644 --- a/tests/topotests/srv6_static_route/r1/zebra.conf +++ b/tests/topotests/srv6_static_route/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 ! debug zebra rib detailed ! log stdout notifications -log monitor notifications log commands log file zebra.log debugging ! diff --git a/tests/topotests/srv6_static_route/test_srv6_route.py b/tests/topotests/srv6_static_route/test_srv6_route.py index 7a4cd39f2ddd..f23e199d4a6f 100755 --- a/tests/topotests/srv6_static_route/test_srv6_route.py +++ b/tests/topotests/srv6_static_route/test_srv6_route.py @@ -55,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -74,7 +74,7 @@ def _check_srv6_static_route(router, expected_route_file): def check_srv6_static_route(router, expected_file): func = functools.partial(_check_srv6_static_route, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=15, wait=1) + _, result = topotest.run_and_expect(func, None, count=15, wait=1) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py index c1e249cc8f0f..a0f11c0126bc 100644 --- a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py +++ b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial import functools # Save the Current Working Directory to find configuration files. @@ -113,7 +110,7 @@ def _check_mpls_state(router, interface, configured=True): test_func = functools.partial( _check_mpls_state_interface, router, interface, up=configured ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) return success diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py index e01351506d9e..0d6b3e7b1d68 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -150,7 +150,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py index 9d35b7dcd3c8..ff349f279ec1 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index 2efc0fdf1b19..c74d8d70a6d1 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -65,8 +65,6 @@ NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"} NEXT_HOP_IP = {} -pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] - def setup_module(mod): """ @@ -115,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -551,7 +549,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): protocol = "bgp" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -571,7 +569,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): dut = "r2" ntwk_r2_vm6 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) ).network ) input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} @@ -914,7 +912,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): protocol = "bgp" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -931,7 +929,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): dut = "r1" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + "{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -945,7 +943,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): dut = "r2" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + "{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -959,7 +957,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ebgp(request): protocol = "bgp" ntwk_r2_vm6 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) ).network ) input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py index abae75e76e2f..926a9909e1c4 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -110,7 +110,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py index 820a736ad7c1..933e5410958b 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -152,7 +152,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py index 1ad963f314e1..9fabd9d5714b 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -133,7 +133,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 03782409593e..f1b7606e79f6 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -111,7 +111,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -547,7 +547,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): protocol = "bgp" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -567,7 +567,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): dut = "r2" ntwk_r2_vm6 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) ).network ) input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} @@ -910,7 +910,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): protocol = "bgp" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -927,7 +927,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): dut = "r1" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + "{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -941,7 +941,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): dut = "r2" ntwk_r2_vm1 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) + "{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type]) ).network ) input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}} @@ -955,7 +955,7 @@ def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request): protocol = "bgp" ntwk_r2_vm6 = str( ipaddress.ip_interface( - u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) + "{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type]) ).network ) input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}} diff --git a/tests/topotests/static_simple/r1/mgmtd.conf b/tests/topotests/static_simple/r1/mgmtd.conf index 0f9f97ca1a33..dd5761aa8452 100644 --- a/tests/topotests/static_simple/r1/mgmtd.conf +++ b/tests/topotests/static_simple/r1/mgmtd.conf @@ -1 +1,11 @@ log timestamp precision 3 + +! way too noisy +! debug northbound libyang + +debug northbound notifications +debug northbound events +debug northbound callbacks +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend diff --git a/tests/topotests/static_simple/r1/zebra.conf b/tests/topotests/static_simple/r1/zebra.conf index ec827617ab8d..e3a44362b511 100644 --- a/tests/topotests/static_simple/r1/zebra.conf +++ b/tests/topotests/static_simple/r1/zebra.conf @@ -1,5 +1,15 @@ log timestamp precision 3 +! way too noisy +! debug northbound libyang + +debug northbound notifications +debug northbound events +debug northbound callbacks +debug mgmt backend datastore frontend transaction +debug mgmt client frontend +debug mgmt client backend + interface r1-eth0 ip address 101.0.0.1/24 ipv6 address 2101::1/64 diff --git a/tests/topotests/static_simple/test_static_simple.py b/tests/topotests/static_simple/test_static_simple.py index fd87224b5743..bb3580a1d8b2 100644 --- a/tests/topotests/static_simple/test_static_simple.py +++ b/tests/topotests/static_simple/test_static_simple.py @@ -13,11 +13,10 @@ import ipaddress import math import os -import sys import re import pytest -from lib.topogen import TopoRouter, Topogen, get_topogen +from lib.topogen import TopoRouter, Topogen from lib.topolog import logger from lib.common_config import retry, step @@ -40,6 +39,8 @@ def tgen(request): router.net.add_loop("lo-red") router.net.attach_iface_to_l3vrf("lo-red", "red") router.net.attach_iface_to_l3vrf(rname + "-eth1", "red") + # + # router.load_frr_config("frr.conf") # and select daemons to run router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_MGMTD) @@ -78,7 +79,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): kernel = r1.run(f"ip -4 route show{vrfstr}") logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -114,7 +115,6 @@ def do_config( else: super_prefix = "2001::/48" if do_ipv6 else "10.0.0.0/8" - matchtype = "" matchvia = "" if via == "blackhole": pass @@ -144,7 +144,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: @@ -181,10 +181,11 @@ def guts(tgen, vrf, use_cli): r1 = tgen.routers()["r1"] - step("add via gateway", reset=True) - do_config(r1, 1, True, False, vrf=vrf, use_cli=use_cli) - step("remove via gateway") - do_config(r1, 1, False, False, vrf=vrf, use_cli=use_cli) + count = 10 + step(f"add {count} via gateway", reset=True) + do_config(r1, count, True, False, vrf=vrf, use_cli=use_cli) + step(f"remove {count} via gateway") + do_config(r1, count, False, False, vrf=vrf, use_cli=use_cli) via = f"lo-{vrf}" if vrf else "lo" step("add via loopback") diff --git a/tests/topotests/static_vrf/r1/frr.conf b/tests/topotests/static_vrf/r1/frr.conf new file mode 100644 index 000000000000..bb373b962a3b --- /dev/null +++ b/tests/topotests/static_vrf/r1/frr.conf @@ -0,0 +1,18 @@ +interface r1-eth0 vrf red + ip address 192.0.2.1/23 +exit + +interface r1-eth1 vrf blue + ip address 192.0.2.129/24 +exit + +ip route 198.51.100.1/32 192.0.2.2 nexthop-vrf red +ip route 198.51.100.1/32 192.0.2.130 nexthop-vrf blue +ip route 198.51.100.2/32 r1-eth0 nexthop-vrf red +ip route 198.51.100.2/32 r1-eth1 nexthop-vrf blue + +ip route 203.0.113.1/32 192.0.2.130 vrf red nexthop-vrf blue +ip route 203.0.113.2/32 r1-eth1 vrf red nexthop-vrf blue + +ip route 203.0.113.129/32 192.0.2.2 vrf blue nexthop-vrf red +ip route 203.0.113.130/32 r1-eth0 vrf blue nexthop-vrf red diff --git a/tests/topotests/static_vrf/test_static_vrf.py b/tests/topotests/static_vrf/test_static_vrf.py new file mode 100644 index 000000000000..97c0800133e8 --- /dev/null +++ b/tests/topotests/static_vrf/test_static_vrf.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2024 NFWare Inc. +# +# noqa: E501 +# +""" +Test static route functionality +""" + +import ipaddress + +import pytest +from lib.topogen import Topogen +from lib.common_config import retry + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",), "s2": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + # Setup VRF red + router.net.add_l3vrf("red", 10) + router.net.attach_iface_to_l3vrf(rname + "-eth0", "red") + # Setup VRF blue + router.net.add_l3vrf("blue", 20) + router.net.attach_iface_to_l3vrf(rname + "-eth1", "blue") + # Load configuration + router.load_frr_config("frr.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +@retry(retry_timeout=1, initial_wait=0.1) +def check_kernel(r1, prefix, nexthops, vrf, expected_p=True, expected_nh=True): + vrfstr = f" vrf {vrf}" if vrf else "" + + net = ipaddress.ip_network(prefix) + if net.version == 6: + kernel = r1.run(f"ip -6 route show{vrfstr} {prefix}") + else: + kernel = r1.run(f"ip -4 route show{vrfstr} {prefix}") + + if expected_p: + assert prefix in kernel, f"Failed to find \n'{prefix}'\n in \n'{kernel:.1920}'" + else: + assert ( + prefix not in kernel + ), f"Failed found \n'{prefix}'\n in \n'{kernel:.1920}'" + + if not expected_p: + return + + for nh in nexthops: + if expected_nh: + assert f"{nh}" in kernel, f"Failed to find \n'{nh}'\n in \n'{kernel:.1920}'" + else: + assert ( + f"{nh}" not in kernel + ), f"Failed found \n'{nh}'\n in \n'{kernel:.1920}'" + + +def test_static_vrf(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + # Check initial configuration + check_kernel(r1, "198.51.100.1", ["192.0.2.2", "192.0.2.130"], None) + check_kernel(r1, "198.51.100.2", ["r1-eth0", "r1-eth1"], None) + check_kernel(r1, "203.0.113.1", ["192.0.2.130"], "red") + check_kernel(r1, "203.0.113.2", ["r1-eth1"], "red") + check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue") + check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue") + + # Delete VRF red + r1.net.del_iface("red") + + # Check that "red" nexthops are removed, "blue" nexthops are still there + check_kernel(r1, "198.51.100.1", ["192.0.2.2"], None, expected_nh=False) + check_kernel(r1, "198.51.100.1", ["192.0.2.130"], None) + check_kernel(r1, "198.51.100.2", ["r1-eth0"], None, expected_nh=False) + check_kernel(r1, "198.51.100.2", ["r1-eth1"], None) + check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue", expected_p=False) + check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue", expected_p=False) + + # Delete VRF blue + r1.net.del_iface("blue") + + # Check that "blue" nexthops are removed + check_kernel(r1, "198.51.100.1", ["192.0.2.130"], None, expected_p=False) + check_kernel(r1, "198.51.100.2", ["r1-eth1"], None, expected_p=False) + + # Add VRF red back, attach "eth0" to it + r1.net.add_l3vrf("red", 10) + r1.net.attach_iface_to_l3vrf("r1-eth0", "red") + + # Check that "red" nexthops are restored + check_kernel(r1, "198.51.100.1", ["192.0.2.2"], None) + check_kernel(r1, "198.51.100.2", ["r1-eth0"], None) + + # Add VRF blue back, attach "eth1" to it + r1.net.add_l3vrf("blue", 20) + r1.net.attach_iface_to_l3vrf("r1-eth1", "blue") + + # Check that everything is restored + check_kernel(r1, "198.51.100.1", ["192.0.2.2", "192.0.2.130"], None) + check_kernel(r1, "198.51.100.2", ["r1-eth0", "r1-eth1"], None) + check_kernel(r1, "203.0.113.1", ["192.0.2.130"], "red") + check_kernel(r1, "203.0.113.2", ["r1-eth1"], "red") + check_kernel(r1, "203.0.113.129", ["192.0.2.2"], "blue") + check_kernel(r1, "203.0.113.130", ["r1-eth0"], "blue") diff --git a/tests/topotests/tc_basic/test_tc_basic.py b/tests/topotests/tc_basic/test_tc_basic.py index f64e83c3cb06..822d2016a8c8 100755 --- a/tests/topotests/tc_basic/test_tc_basic.py +++ b/tests/topotests/tc_basic/test_tc_basic.py @@ -22,9 +22,8 @@ from lib.topogen import Topogen, TopoRouter from lib.topolog import logger -pytestmark = [ - pytest.mark.sharpd -] +pytestmark = [pytest.mark.sharpd] + def build_topo(tgen): "Build function" @@ -42,6 +41,7 @@ def build_topo(tgen): switch = tgen.add_switch("s2") switch.add_link(r2) + # New form of setup/teardown using pytest fixture @pytest.fixture(scope="module") def tgen(request): @@ -79,22 +79,28 @@ def skip_on_failure(tgen): if tgen.routers_have_failure(): pytest.skip("skipped because of previous test failure") + def fetch_iproute2_tc_info(r, interface): qdisc = r.cmd("tc qdisc show dev %s" % interface) tclass = r.cmd("tc class show dev %s" % interface) tfilter = r.cmd("tc filter show dev %s" % interface) return qdisc, tclass, tfilter + # =================== # The tests functions # =================== + def test_tc_basic(tgen): "Test installing one pair of filter & class by sharpd" r1 = tgen.gears["r1"] intf = "r1-eth0" - r1.vtysh_cmd("sharp tc dev %s source 192.168.100.0/24 destination 192.168.101.0/24 ip-protocol tcp src-port 8000 dst-port 8001 rate 20mbit" % intf) + r1.vtysh_cmd( + "sharp tc dev %s source 192.168.100.0/24 destination 192.168.101.0/24 ip-protocol tcp src-port 8000 dst-port 8001 rate 20mbit" + % intf + ) time.sleep(3) @@ -115,6 +121,7 @@ def test_tc_basic(tgen): assert "dst_port 8001" in tfilter assert "src_port 8000" in tfilter + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] - sys.exit(pytest.main(args)) \ No newline at end of file + sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py index 529520cd9e81..dc47527c74c2 100644 --- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py +++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -29,7 +28,6 @@ # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger # Required to instantiate the topology builder class. @@ -144,6 +142,23 @@ def test_zebra_system_recursion(): assert result is None, "Kernel route is missing from zebra" +def test_zebra_noprefix_connected(): + "Test that a noprefixroute created does not create a connected route" + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r1"] + router.run("ip addr add 192.168.44.1/24 dev r1-eth1 noprefixroute") + expected = "% Network not in table" + test_func = partial( + topotest.router_output_cmp, router, "show ip route 192.168.44.0/24", expected + ) + result, _ = topotest.run_and_expect(test_func, "", count=20, wait=1) + assert result, "Connected Route should not have been added" + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py index 522c390c39fb..3748f9c4e3a6 100644 --- a/tests/topotests/zebra_netlink/test_zebra_netlink.py +++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py @@ -13,9 +13,7 @@ """ # pylint: disable=C0413 import ipaddress -import json import sys -from functools import partial import pytest from lib import topotest @@ -42,7 +40,7 @@ def tgen(request): # Initialize all routers. router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_SHARP) @@ -94,7 +92,7 @@ def test_zebra_netlink_batching(tgen): } match = {} - base = int(ipaddress.ip_address(u"2.1.3.7")) + base = int(ipaddress.ip_address("2.1.3.7")) for i in range(base, base + count): pfx = str(ipaddress.ip_network((i, 32))) match[pfx] = [dict(entry, prefix=pfx)] diff --git a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py index 6956ab740996..16e458062d33 100644 --- a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py +++ b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py @@ -16,7 +16,6 @@ import pytest from lib.common_config import ( - start_topology, verify_rib, verify_ip_nht, step, @@ -24,7 +23,6 @@ ) # pylint: disable=C0413 -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger @@ -33,30 +31,36 @@ pytestmark = [pytest.mark.sharpd] -#GLOBAL VARIABLES +# GLOBAL VARIABLES NH1 = "2.2.2.32" + def build_topo(tgen): tgen.add_router("r1") switch = tgen.add_switch("sw1") switch.add_link(tgen.gears["r1"]) + def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() router_list = tgen.routers() for rname, router in tgen.routers().items(): - router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) router.load_config( TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname)) ) tgen.start_router() + def teardown_module(_mod): tgen = get_topogen() tgen.stop_topology() + def test_verify_zebra_nh_resolution(request): tgen = get_topogen() tc_name = request.node.name @@ -67,31 +71,18 @@ def test_verify_zebra_nh_resolution(request): step("Configure static route") input_dict_1 = { - "r1": { - "static_routes": [ - {"network": "2.2.2.0/24", "next_hop": "r1-eth0"} - ] - } - } + "r1": {"static_routes": [{"network": "2.2.2.0/24", "next_hop": "r1-eth0"}]} + } result = create_static_routes(tgen, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result - ) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify static routes in RIB of R1") - input_dict_2 = { - "r1": { - "static_routes": [ - {"network": "2.2.2.0/24"} - ] - } - } + input_dict_2 = {"r1": {"static_routes": [{"network": "2.2.2.0/24"}]}} dut = "r1" result = verify_rib(tgen, "ipv4", dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error: {}".format( - tc_name, result) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step("Set the connected flag on the NH tracking entry") r1.vtysh_cmd("sharp watch nexthop 2.2.2.32 connected") @@ -108,8 +99,7 @@ def test_verify_zebra_nh_resolution(request): } result = verify_ip_nht(tgen, input_dict_nh) assert result is True, "Testcase {} : Failed \n" - "Error: Nexthop is missing in RIB".format( - tc_name, result) + "Error: Nexthop is missing in RIB".format(tc_name, result) step("Add a .32/32 route with the NH as itself") r1.vtysh_cmd("sharp install routes 2.2.2.32 nexthop 2.2.2.32 1") @@ -126,11 +116,12 @@ def test_verify_zebra_nh_resolution(request): } result = verify_ip_nht(tgen, input_dict_nh) assert result is True, "Testcase {} : Failed \n" - "Error: Nexthop became unresolved".format( - tc_name, result) + "Error: Nexthop became unresolved".format(tc_name, result) - step("Add a .31/32 route with the NH as 2.2.2.32" - "to verify the NH Resolution behaviour") + step( + "Add a .31/32 route with the NH as 2.2.2.32" + "to verify the NH Resolution behaviour" + ) r1.vtysh_cmd("sharp install routes 2.2.2.31 nexthop 2.2.2.32 1") step("Verify that NH 2.2.2.2/32 doesn't become unresolved") @@ -145,8 +136,8 @@ def test_verify_zebra_nh_resolution(request): } result = verify_ip_nht(tgen, input_dict_nh) assert result is True, "Testcase {} : Failed \n" - "Error: Nexthop became unresolved".format( - tc_name, result) + "Error: Nexthop became unresolved".format(tc_name, result) + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/zebra_opaque/test_zebra_opaque.py b/tests/topotests/zebra_opaque/test_zebra_opaque.py index 25fbb97806de..4f49a69bdcaf 100644 --- a/tests/topotests/zebra_opaque/test_zebra_opaque.py +++ b/tests/topotests/zebra_opaque/test_zebra_opaque.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -98,17 +98,17 @@ def _ospf6_converge(router): router = tgen.gears["r1"] test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see BGP community aliases "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv2 opaque attributes "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf6_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv3 opaque attributes "{}"'.format(router) diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 05036fa7ad47..93296cd51aa6 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -71,7 +71,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -235,7 +235,7 @@ def check_initial_routes_installed(router): return topotest.json_cmp(output, expected) test_func = partial(check_initial_routes_installed, r1) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=1) static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) expected = open(static_rmapfile).read().rstrip() diff --git a/tests/topotests/zebra_seg6_route/r1/routes_setup.json b/tests/topotests/zebra_seg6_route/r1/routes_setup.json new file mode 100644 index 000000000000..d131e4acd4cf --- /dev/null +++ b/tests/topotests/zebra_seg6_route/r1/routes_setup.json @@ -0,0 +1,28 @@ +{ + "2001::/64":[ + { + "prefix":"2001::/64", + "prefixLen":64, + "protocol":"connected", + "vrfName":"default", + "selected":true, + "destSelected":true, + "distance":0, + "metric":0, + "installed":true, + "internalStatus":16, + "internalFlags":8, + "internalNextHopNum":1, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "flags":3, + "fib":true, + "directlyConnected":true, + "interfaceName":"dum0", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/zebra_seg6_route/r1/zebra.conf b/tests/topotests/zebra_seg6_route/r1/zebra.conf index e5e360ffa53f..2d0c9e157a9e 100644 --- a/tests/topotests/zebra_seg6_route/r1/zebra.conf +++ b/tests/topotests/zebra_seg6_route/r1/zebra.conf @@ -1,7 +1,6 @@ log file zebra.log ! log stdout notifications -log monitor notifications log commands ! ! debug zebra packet diff --git a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py index 4b462a51e522..f94b7d4a9c43 100755 --- a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -59,11 +59,11 @@ def teardown_module(_mod): tgen.stop_topology() -def test_zebra_seg6local_routes(): +def test_zebra_seg6_routes(): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip(tgen.errors) - logger.info("Test for seg6local route install via ZAPI was start.") + logger.info("Test for seg6 route install via ZAPI was start.") r1 = tgen.gears["r1"] def check(router, dest, expected): @@ -73,6 +73,16 @@ def check(router, dest, expected): return False return topotest.json_cmp(output, expected) + def check_connected(router, dest, expected): + logger.info("Checking for connected") + output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) + return topotest.json_cmp(output, expected) + + expected = open_json_file(os.path.join(CWD, "{}/routes_setup.json".format("r1"))) + test_func = partial(check_connected, r1, "2001::/64", expected) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "Failed to fully setup connected routes needed" + manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) for manifest in manifests: dest = manifest["in"]["dest"] @@ -86,7 +96,7 @@ def check(router, dest, expected): ) logger.info("CHECK {} {} {}".format(dest, nh, sid)) test_func = partial(check, r1, dest, manifest["out"]) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/zebra_seg6local_route/r1/zebra.conf b/tests/topotests/zebra_seg6local_route/r1/zebra.conf index dee7a9171a83..a3b93352440c 100644 --- a/tests/topotests/zebra_seg6local_route/r1/zebra.conf +++ b/tests/topotests/zebra_seg6local_route/r1/zebra.conf @@ -1,7 +1,6 @@ log file zebra.log ! log stdout notifications -log monitor notifications log commands ! ! debug zebra packet diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py index 0dc87741aacc..a90f5c9c9818 100755 --- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -101,7 +101,7 @@ def check(router, dest, expected): dest, manifest["out"], ) - success, result = topotest.run_and_expect(test_func, None, count=25, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=25, wait=1) assert result is None, "Failed" diff --git a/tests/zebra/test_lm_plugin.c b/tests/zebra/test_lm_plugin.c index 9ad0bc4e17c7..9895c025f05f 100644 --- a/tests/zebra/test_lm_plugin.c +++ b/tests/zebra/test_lm_plugin.c @@ -48,7 +48,7 @@ static int lm_get_chunk_pi(struct label_manager_chunk **lmc, uint32_t base, vrf_id_t vrf_id) { if (base == 0) - *lmc = create_label_chunk(10, 55, 0, 1, 50, 50 + size); + *lmc = create_label_chunk(10, 55, 0, 1, 50, 50 + size, true); else *lmc = assign_label_chunk(10, 55, 0, 1, size, base); diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index d007c1d32580..2c773f7fbcb3 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -547,7 +547,7 @@ sub hash_show_words { our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; our $Iterators = qr{ - frr_each|frr_each_safe|frr_each_from| + darr_foreach_p|darr_foreach_i|frr_each|frr_each_safe|frr_each_from| frr_with_mutex|frr_with_privs| LIST_FOREACH|LIST_FOREACH_SAFE| SLIST_FOREACH|SLIST_FOREACH_SAFE|SLIST_FOREACH_PREVPTR| @@ -555,7 +555,7 @@ sub hash_show_words { TAILQ_FOREACH|TAILQ_FOREACH_SAFE|TAILQ_FOREACH_REVERSE|TAILQ_FOREACH_REVERSE_SAFE| RB_FOREACH|RB_FOREACH_SAFE|RB_FOREACH_REVERSE|RB_FOREACH_REVERSE_SAFE| SPLAY_FOREACH| - FOR_ALL_INTERFACES|FOR_ALL_INTERFACES_ADDRESSES|JSON_FOREACH| + FOR_ALL_INTERFACES|JSON_FOREACH| LY_FOR_KEYS|LY_LIST_FOR|LY_TREE_FOR|LY_TREE_DFS_BEGIN|LYD_TREE_DFS_BEGIN| RE_DEST_FOREACH_ROUTE|RE_DEST_FOREACH_ROUTE_SAFE| RNODE_FOREACH_RE|RNODE_FOREACH_RE_SAFE| @@ -563,6 +563,7 @@ sub hash_show_words { SUBGRP_FOREACH_PEER|SUBGRP_FOREACH_PEER_SAFE| SUBGRP_FOREACH_ADJ|SUBGRP_FOREACH_ADJ_SAFE| AF_FOREACH|FOREACH_AFI_SAFI|FOREACH_SAFI| + FOREACH_BE_CLIENT_BITS|FOREACH_MGMTD_BE_CLIENT_ID| LSDB_LOOP }x; @@ -4655,19 +4656,6 @@ sub process { $herecurr); } -# check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) - if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { - my $array = $1; - if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { - my $array_div = $1; - if (WARN("ARRAY_SIZE", - "Prefer ARRAY_SIZE($array)\n" . $herecurr) && - $fix) { - $fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; - } - } - } - # check for function declarations without arguments like "int foo()" if ($line =~ /(\b$Type\s*$Ident)\s*\(\s*\)/) { if (ERROR("FUNCTION_WITHOUT_ARGS", @@ -4680,6 +4668,7 @@ sub process { # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef.*\s(pim_[^\s]+|[^\s]+_pim)\s*;/ && $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && $line !~ /\b$typeTypedefs\b/ && @@ -5161,7 +5150,7 @@ sub process { # none after. May be left adjacent to another # unary operator, or a cast } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || + $opv eq '*U' || $opv eq '-U' || $opv eq '+U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { if (ERROR("SPACING", diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh index 6071f4804d9e..bf63057b0219 100755 --- a/tools/checkpatch.sh +++ b/tools/checkpatch.sh @@ -3,7 +3,8 @@ usage="./checkpatch.sh " patch=$1 tree=$2 -checkpatch="$tree/tools/checkpatch.pl --no-tree -f" +scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +checkpatch="$scriptdir/checkpatch.pl --no-tree -f" ignore="ldpd\|babeld" cwd=${PWD##*/} dirty=0 diff --git a/tools/cocci.h b/tools/cocci.h index 7d6bb4cd7f25..99076b5d3fa7 100644 --- a/tools/cocci.h +++ b/tools/cocci.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* some of this stuff doesn't seem to parse properly in coccinelle */ diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index b7a170824802..b3889e8784e1 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -34,6 +34,8 @@ show bgp nexthop show bgp vrf all summary show bgp vrf all ipv4 show bgp vrf all ipv6 +show bgp vrf all ipv4 vpn +show bgp vrf all ipv6 vpn show bgp vrf all neighbors show bgp evpn route @@ -78,9 +80,9 @@ show vrf show work-queues show debugging hashtable show running-config -show thread cpu -show thread poll -show thread timers +show event cpu +show event poll +show event timers show daemons show version CMD_LIST_END @@ -175,7 +177,7 @@ CMD_LIST_END PROC_NAME:ospf6 CMD_LIST_START show ipv6 ospf6 vrf all -show ipv6 ospf6 vrfs +show ipv6 ospf6 vrfs show ipv6 ospf6 vrf all border-routers show ipv6 ospf6 vrf all border-routers detail show ipv6 ospf6 vrf all database diff --git a/tools/etc/iproute2/rt_protos.d/frr.conf b/tools/etc/iproute2/rt_protos.d/frr.conf index bbb358fc6c5b..3e0fc2ea3790 100644 --- a/tools/etc/iproute2/rt_protos.d/frr.conf +++ b/tools/etc/iproute2/rt_protos.d/frr.conf @@ -12,3 +12,4 @@ 195 pbr 196 static 197 openfabric +198 srte diff --git a/tools/frr-llvm-cg.c b/tools/frr-llvm-cg.c index 3a7222e421fc..f366ba62f9d2 100644 --- a/tools/frr-llvm-cg.c +++ b/tools/frr-llvm-cg.c @@ -231,7 +231,7 @@ static void walk_const_fptrs(struct json_object *js_call, LLVMValueRef value, "%s: calls function pointer from unhandled const GEP\n", prefix); *hdr_written = true; - /* fallthru */ + fallthrough; default: /* to help the user / development */ if (!*hdr_written) { diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 17bf73316c6a..a88f6b616d28 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -25,6 +25,7 @@ from ipaddress import IPv6Address, ip_network from pprint import pformat + # Python 3 def iteritems(d): return iter(d.items()) @@ -93,7 +94,7 @@ def is_config_available(self): output = self("configure") - if "VTY configuration is locked by other VTY" in output: + if "configuration is locked" in output.lower(): log.error("vtysh 'configure' returned\n%s\n" % (output)) return False @@ -219,6 +220,23 @@ def get_normalized_mac_ip_line(line): return line +def get_normalized_interface_vrf(line): + """ + If 'interface vrf ' is present in file, + we need to remove the explicit "vrf " + so that the context information is created + correctly and configurations are matched appropriately. + """ + + intf_vrf = re.search(r"interface (\S+) vrf (\S+)", line) + if intf_vrf: + old_line = "vrf %s" % intf_vrf.group(2) + new_line = line.replace(old_line, "").strip() + return new_line + + return line + + # This dictionary contains a tree of all commands that we know start a # new multi-line context. All other commands are treated either as # commands inside a multi-line context or as single-line contexts. This @@ -243,6 +261,8 @@ def get_normalized_mac_ip_line(line): "router ospf6": {}, "router eigrp ": {}, "router babel": {}, + "router pim": {}, + "router pim6": {}, "mpls ldp": {"address-family ": {"interface ": {}}}, "l2vpn ": {"member pseudowire ": {}}, "key chain ": {"key ": {}}, @@ -288,12 +308,69 @@ def load_from_file(self, filename): file_output = self.vtysh.mark_file(filename) + vrf_context = None + pim_vrfs = [] + for line in file_output.split("\n"): line = line.strip() # Compress duplicate whitespaces line = " ".join(line.split()) + # Detect when we are within a vrf context for converting legacy PIM commands + if vrf_context: + re_vrf = re.match("^(exit-vrf|exit|end)$", line) + if re_vrf: + vrf_context = None + else: + re_vrf = re.match("^vrf ([a-z]+)$", line) + if re_vrf: + vrf_context = re_vrf.group(1) + + # Detect legacy pim commands that need to move under the router pim context + re_pim = re.match( + "^ip(v6)? pim ((ecmp|join|keep|mlag|packets|register|rp|send|spt|ssm).*)$", + line, + ) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line = "# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + + re_pim = re.match("^ip(v6)? ((ssmpingd|msdp).*)$", line) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line = "# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + + # Remove 'vrf ' from 'interface vrf ' + if line.startswith("interface ") and "vrf" in line: + line = get_normalized_interface_vrf(line) + if ":" in line: line = get_normalized_mac_ip_line(line) @@ -326,6 +403,9 @@ def load_from_file(self, filename): self.lines.append(line) + if len(pim_vrfs) > 0: + self.lines.append(pim_vrfs) + self.load_contexts() def load_from_show_running(self, daemon): @@ -362,7 +442,7 @@ def get_contexts(self): """ Return the parsed context as strings for display, log etc. """ - for (_, ctx) in sorted(iteritems(self.contexts)): + for _, ctx in sorted(iteritems(self.contexts)): print(str(ctx)) def save_contexts(self, key, lines): @@ -546,7 +626,6 @@ def load_contexts(self): cur_ctx_lines = [] for line in self.lines: - if not line: continue @@ -647,7 +726,7 @@ def lines_to_config(ctx_keys, line, delete): ctx_keys = [] if line: - for (i, ctx_key) in enumerate(ctx_keys): + for i, ctx_key in enumerate(ctx_keys): cmd.append(" " * i + ctx_key) line = line.lstrip() @@ -725,7 +804,7 @@ def get_normalized_ipv6_line(line): def line_exist(lines, target_ctx_keys, target_line, exact_match=True): - for (ctx_keys, line) in lines: + for ctx_keys, line in lines: if ctx_keys == target_ctx_keys: if exact_match: if line == target_line: @@ -744,7 +823,7 @@ def bgp_delete_inst_move_line(lines_to_del): bgp_defult_inst = False bgp_vrf_inst = False - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: # Find bgp default inst if ( ctx_keys[0].startswith("router bgp") @@ -757,7 +836,7 @@ def bgp_delete_inst_move_line(lines_to_del): bgp_vrf_inst = True if bgp_defult_inst and bgp_vrf_inst: - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: # move bgp default inst to end if ( ctx_keys[0].startswith("router bgp") @@ -815,13 +894,13 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): if ctx_keys[0] in pg_dict: for pg_key in pg_dict[ctx_keys[0]]: # Find 'neighbor remote-as' - pg_rmtas = "neighbor %s remote-as (\S+)" % pg_key + pg_rmtas = r"neighbor %s remote-as (\S+)" % pg_key re_pg_rmtas = re.search(pg_rmtas, line) if re_pg_rmtas: pg_dict[ctx_keys[0]][pg_key]["remoteas"] = True # Find 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -839,7 +918,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): and line and line.startswith("neighbor ") ): - nbr_rmtas = "neighbor (\S+) remote-as.*" + nbr_rmtas = r"neighbor (\S+) remote-as.*" re_nbr_rmtas = re.search(nbr_rmtas, line) if re_nbr_rmtas and ctx_keys[0] in pg_dict: for pg in pg_dict[ctx_keys[0]]: @@ -853,7 +932,6 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict): - # This method handles deletion of bgp neighbor configs, # if there is neighbor to peer-group cmd is in delete list. # As 'no neighbor .* peer-group' deletes the neighbor, @@ -861,7 +939,7 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict): # in error. lines_to_del_to_del = [] - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: if ( ctx_keys[0].startswith("router bgp") and line @@ -869,14 +947,14 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict): ): if ctx_keys[0] in del_nbr_dict: for nbr in del_nbr_dict[ctx_keys[0]]: - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) - nb_exp = "neighbor %s .*" % nbr + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) + nb_exp = r"neighbor %s .*" % nbr if not re_nbr_pg: re_nb = re.search(nb_exp, line) if re_nb: lines_to_del_to_del.append((ctx_keys, line)) - for (ctx_keys, line) in lines_to_del_to_del: + for ctx_keys, line in lines_to_del_to_del: lines_to_del.remove((ctx_keys, line)) @@ -942,7 +1020,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # "router bgp 200 no neighbor uplink1 interface remote-as internal" # "router bgp 200 no neighbor underlay peer-group" - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: if ( ctx_keys[0].startswith("router bgp") and line @@ -968,7 +1046,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # neighbor uplink1 interface remote-as internal # # 'no neighbor peer [interface] remote-as <>' - nb_remoteas = "neighbor (\S+) .*remote-as (\S+)" + nb_remoteas = r"neighbor (\S+) .*remote-as (\S+)" re_nb_remoteas = re.search(nb_remoteas, line) if re_nb_remoteas: lines_to_del_to_app.append((ctx_keys, line)) @@ -976,7 +1054,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # 'no neighbor peer [interface] peer-group <>' is in lines_to_del # copy the neighbor and look for all config removal lines associated # to neighbor and delete them from the lines_to_del - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) if re_nbr_pg: if ctx_keys[0] not in del_nbr_dict: del_nbr_dict[ctx_keys[0]] = list() @@ -993,19 +1071,20 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): del_dict[ctx_keys[0]][re_pg.group(1)] = list() found_pg_del_cmd = True + # move neighbor remote-as lines at the end + for ctx_keys, line in lines_to_del_to_app: + lines_to_del.remove((ctx_keys, line)) + lines_to_del.append((ctx_keys, line)) + if found_pg_del_cmd == False: bgp_delete_inst_move_line(lines_to_del) if del_nbr_dict: bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict) return (lines_to_add, lines_to_del) - for (ctx_keys, line) in lines_to_del_to_app: - lines_to_del.remove((ctx_keys, line)) - lines_to_del.append((ctx_keys, line)) - # {'router bgp 65001': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}, # 'router bgp 65001 vrf vrf1': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}} - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: if ( ctx_keys[0].startswith("router bgp") and line @@ -1014,7 +1093,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg_key in del_dict[ctx_keys[0]]: # 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) .*peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) .*peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -1023,7 +1102,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): del_dict[ctx_keys[0]][pg_key].append(re_nbr_pg.group(1)) lines_to_del_to_app = [] - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: if ( ctx_keys[0].startswith("router bgp") and line @@ -1032,7 +1111,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg in del_dict[ctx_keys[0]]: for nbr in del_dict[ctx_keys[0]][pg]: - nb_exp = "neighbor %s .*" % nbr + nb_exp = r"neighbor %s .*" % nbr re_nb = re.search(nb_exp, line) # add peer configs to delete list. if re_nb and line not in lines_to_del_to_del: @@ -1043,10 +1122,10 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if re_pg: lines_to_del_to_app.append((ctx_keys, line)) - for (ctx_keys, line) in lines_to_del_to_del: + for ctx_keys, line in lines_to_del_to_del: lines_to_del.remove((ctx_keys, line)) - for (ctx_keys, line) in lines_to_del_to_app: + for ctx_keys, line in lines_to_del_to_app: lines_to_del.remove((ctx_keys, line)) lines_to_del.append((ctx_keys, line)) @@ -1056,32 +1135,45 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): def pim_delete_move_lines(lines_to_add, lines_to_del): - # Under interface context, if 'no ip pim' is present # remove subsequent 'no ip pim ' options as it # they are implicitly deleted by 'no ip pim'. # Remove all such depdendent options from delete # pending list. pim_disable = False + lines_to_del_to_del = [] - for (ctx_keys, line) in lines_to_del: + index = -1 + for ctx_keys, line in lines_to_del: + index = index + 1 if ctx_keys[0].startswith("interface") and line and line == "ip pim": pim_disable = True + # no ip msdp peer <> does not accept source so strip it off. + if line and line.startswith("ip msdp peer "): + pim_msdp_peer = re.search(r"ip msdp peer (\S+) source (\S+)", line) + if pim_msdp_peer: + source_sub_str = "source %s" % pim_msdp_peer.group(2) + new_line = line.replace(source_sub_str, "").strip() + lines_to_del.remove((ctx_keys, line)) + lines_to_del.insert(index, (ctx_keys, new_line)) + if pim_disable: - for (ctx_keys, line) in lines_to_del: + for ctx_keys, line in lines_to_del: if ( ctx_keys[0].startswith("interface") and line - and line.startswith("ip pim ") + and (line.startswith("ip pim ") or line.startswith("ip multicast ")) ): - lines_to_del.remove((ctx_keys, line)) + lines_to_del_to_del.append((ctx_keys, line)) + + for ctx_keys, line in lines_to_del_to_del: + lines_to_del.remove((ctx_keys, line)) return (lines_to_add, lines_to_del) def delete_move_lines(lines_to_add, lines_to_del): - lines_to_add, lines_to_del = bgp_delete_move_lines(lines_to_add, lines_to_del) lines_to_add, lines_to_del = pim_delete_move_lines(lines_to_add, lines_to_del) @@ -1089,18 +1181,41 @@ def delete_move_lines(lines_to_add, lines_to_del): def ignore_delete_re_add_lines(lines_to_add, lines_to_del): - # Quite possibly the most confusing (while accurate) variable names in history lines_to_add_to_del = [] lines_to_del_to_del = [] - for (ctx_keys, line) in lines_to_del: + index = -1 + for ctx_keys, line in lines_to_del: deleted = False + # no form of route-map description command only + # accept 'no description', replace 'no description blah' + # to just 'no description'. + index = index + 1 + if ( + ctx_keys[0].startswith("route-map") + and line + and line.startswith("description ") + ): + lines_to_del.remove((ctx_keys, line)) + lines_to_del.insert(index, (ctx_keys, "description")) + + # interface x ; description blah + # no form of description does not accept any argument, + # strip arg before rendering + if ( + ctx_keys[0].startswith("interface ") + and line + and line.startswith("description ") + ): + lines_to_del.remove((ctx_keys, line)) + lines_to_del.insert(index, (ctx_keys, "description")) + # If there is a change in the segment routing block ranges, do it # in-place, to avoid requesting spurious label chunks which might fail if line and "segment-routing global-block" in line: - for (add_key, add_line) in lines_to_add: + for add_key, add_line in lines_to_add: if ( ctx_keys[0] == add_key[0] and add_line @@ -1111,7 +1226,6 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): continue if ctx_keys[0].startswith("router bgp") and line: - if line.startswith("neighbor "): # BGP changed how it displays swpX peers that are part of peer-group. Older # versions of frr would display these on separate lines: @@ -1130,10 +1244,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_peergroup = re.search( - "neighbor (\S+) interface peer-group (\S+)", line + r"neighbor (\S+) interface peer-group (\S+)", line ) re_swpx_int_v6only_peergroup = re.search( - "neighbor (\S+) interface v6only peer-group (\S+)", line + r"neighbor (\S+) interface v6only peer-group (\S+)", line ) if re_swpx_int_peergroup or re_swpx_int_v6only_peergroup: @@ -1190,10 +1304,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if re_nbr_bfd_timers: nbr = re_nbr_bfd_timers.group(1) - bfd_nbr = "neighbor %s" % nbr + bfd_nbr = r"neighbor %s" % nbr bfd_search_string = bfd_nbr + r" bfd (\S+) (\S+) (\S+)" - for (ctx_keys, add_line) in lines_to_add: + for ctx_keys, add_line in lines_to_add: if ctx_keys[0].startswith("router bgp"): re_add_nbr_bfd_timers = re.search( bfd_search_string, add_line @@ -1215,15 +1329,15 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # they actually match and if we are going from a very old style # command such that the neighbor command is under the `router # bgp ..` node that we need to handle that appropriately - re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line) + re_nbr_rm = re.search(r"neighbor(.*)route-map(.*)(in|out)$", line) if re_nbr_rm: adjust_for_bgp_node = 0 neighbor_name = re_nbr_rm.group(1) rm_name_del = re_nbr_rm.group(2) dir = re_nbr_rm.group(3) - search = "neighbor%sroute-map(.*)%s" % (neighbor_name, dir) + search = r"neighbor%sroute-map(.*)%s" % (neighbor_name, dir) save_line = "EMPTY" - for (ctx_keys_al, add_line) in lines_to_add: + for ctx_keys_al, add_line in lines_to_add: if ctx_keys_al[0].startswith("router bgp"): if add_line: rm_match = re.search(search, add_line) @@ -1243,7 +1357,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys_al, line)) if adjust_for_bgp_node == 1: - for (ctx_keys_dl, dl_line) in lines_to_del: + for ctx_keys_dl, dl_line in lines_to_del: if ( ctx_keys_dl[0].startswith("router bgp") and len(ctx_keys_dl) > 1 @@ -1274,10 +1388,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_remoteas = re.search( - "neighbor (\S+) interface remote-as (\S+)", line + r"neighbor (\S+) interface remote-as (\S+)", line ) re_swpx_int_v6only_remoteas = re.search( - "neighbor (\S+) interface v6only remote-as (\S+)", line + r"neighbor (\S+) interface v6only remote-as (\S+)", line ) if re_swpx_int_remoteas or re_swpx_int_v6only_remoteas: @@ -1317,7 +1431,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # unnecessary session resets. if "multipath-relax" in line: re_asrelax_new = re.search( - "^bgp\s+bestpath\s+as-path\s+multipath-relax$", line + r"^bgp\s+bestpath\s+as-path\s+multipath-relax$", line ) old_asrelax_cmd = "bgp bestpath as-path multipath-relax no-as-set" found_asrelax_old = line_exist(lines_to_add, ctx_keys, old_asrelax_cmd) @@ -1342,7 +1456,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # the new syntax. This causes an unnecessary 'no import-table' followed # by the same old 'ip import-table' which causes perturbations in # announced routes leading to traffic blackholes. Fix this issue. - re_importtbl = re.search("^ip\s+import-table\s+(\d+)$", ctx_keys[0]) + re_importtbl = re.search(r"^ip\s+import-table\s+(\d+)$", ctx_keys[0]) if re_importtbl: table_num = re_importtbl.group(1) for ctx in lines_to_add: @@ -1363,7 +1477,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # access-list FOO seq 5 permit 2.2.2.2/32 # ipv6 access-list BAR seq 5 permit 2:2:2::2/128 re_acl_pfxlst = re.search( - "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_acl_pfxlst: @@ -1396,7 +1510,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # bgp large-community-list standard llist seq 5 permit 65001:65001:1 # bgp extcommunity-list standard elist seq 5 permit soo 123:123 re_bgp_lists = re.search( - "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_lists: @@ -1419,15 +1533,43 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_add.append((add_cmd, None)) lines_to_del_to_del.append((ctx_keys, None)) + # bgp as-path access-list can be specified without a seq number. + # However, the running config always + # adds `seq X` (sequence number). So, ignore such lines as well. + # Examples: + # bgp as-path access-list important_internet_bgp_as_numbers seq 30 permit _40841_" + re_bgp_as_path = re.search( + r"^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + ctx_keys[0], + ) + if re_bgp_as_path: + found = False + tmpline = ( + re_bgp_as_path.group(1) + + re_bgp_as_path.group(2) + + re_bgp_as_path.group(3) + + re_bgp_as_path.group(4) + + re_bgp_as_path.group(6) + + re_bgp_as_path.group(7) + ) + for ctx in lines_to_add: + if ctx[0][0] == tmpline: + lines_to_del_to_del.append((ctx_keys, None)) + lines_to_add_to_del.append(((tmpline,), None)) + found = True + if found is False: + add_cmd = ("no " + ctx_keys[0],) + lines_to_add.append((add_cmd, None)) + lines_to_del_to_del.append((ctx_keys, None)) + if ( len(ctx_keys) == 3 and ctx_keys[0].startswith("router bgp") and ctx_keys[1] == "address-family l2vpn evpn" and ctx_keys[2].startswith("vni") ): - re_route_target = ( - re.search("^route-target import (.*)$", line) + re.search(r"^route-target import (.*)$", line) if line is not None else False ) @@ -1501,19 +1643,18 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys, line)) lines_to_add_to_del.append((tmp_ctx_keys, line)) - for (ctx_keys, line) in lines_to_del_to_del: + for ctx_keys, line in lines_to_del_to_del: try: lines_to_del.remove((ctx_keys, line)) except ValueError: pass - for (ctx_keys, line) in lines_to_add_to_del: + for ctx_keys, line in lines_to_add_to_del: try: lines_to_add.remove((ctx_keys, line)) except ValueError: pass - return (lines_to_add, lines_to_del) @@ -1524,8 +1665,7 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del): """ lines_to_del_to_del = [] - for (ctx_keys, line) in lines_to_del: - + for ctx_keys, line in lines_to_del: # The integrated-vtysh-config one is technically "no"able but if we did # so frr-reload would stop working so do not let the user shoot # themselves in the foot by removing this. @@ -1546,7 +1686,7 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del): log.info('"%s" cannot be removed' % (ctx_keys[-1],)) lines_to_del_to_del.append((ctx_keys, line)) - for (ctx_keys, line) in lines_to_del_to_del: + for ctx_keys, line in lines_to_del_to_del: lines_to_del.remove((ctx_keys, line)) return (lines_to_add, lines_to_del) @@ -1566,13 +1706,12 @@ def compare_context_objects(newconf, running): pcclist_to_del = [] candidates_to_add = [] delete_bgpd = False - area_stub_no_sum = "area (\S+) stub no-summary" + area_stub_no_sum = r"area (\S+) stub no-summary" deleted_keychains = [] # Find contexts that are in newconf but not in running # Find contexts that are in running but not in newconf - for (running_ctx_keys, running_ctx) in iteritems(running.contexts): - + for running_ctx_keys, running_ctx in iteritems(running.contexts): if running_ctx_keys in newconf.contexts: newconf_ctx = newconf.contexts[running_ctx_keys] @@ -1593,7 +1732,6 @@ def compare_context_objects(newconf, running): lines_to_del.append((running_ctx_keys, new_del_line)) if running_ctx_keys not in newconf.contexts: - # We check that the len is 1 here so that we only look at ('router bgp 10') # and not ('router bgp 10', 'address-family ipv4 unicast'). The # latter could cause a false delete_bgpd positive if ipv4 unicast is in @@ -1603,9 +1741,11 @@ def compare_context_objects(newconf, running): lines_to_del.append((running_ctx_keys, None)) # We cannot do 'no interface' or 'no vrf' in FRR, and so deal with it - elif running_ctx_keys[0].startswith("interface") or running_ctx_keys[ - 0 - ].startswith("vrf"): + elif ( + running_ctx_keys[0].startswith("interface") + or running_ctx_keys[0].startswith("vrf") + or running_ctx_keys[0].startswith("router pim") + ): for line in running_ctx.lines: lines_to_del.append((running_ctx_keys, line)) @@ -1764,14 +1904,12 @@ def compare_context_objects(newconf, running): # Find the lines within each context to add # Find the lines within each context to del - for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts): - + for newconf_ctx_keys, newconf_ctx in iteritems(newconf.contexts): if newconf_ctx_keys in running.contexts: running_ctx = running.contexts[newconf_ctx_keys] for line in newconf_ctx.lines: if line not in running_ctx.dlines: - # candidate paths can only be added after the policy and segment list, # so add them to a separate array that is going to be appended at the end if ( @@ -1789,10 +1927,8 @@ def compare_context_objects(newconf, running): if line not in newconf_ctx.dlines: lines_to_del.append((newconf_ctx_keys, line)) - for (newconf_ctx_keys, newconf_ctx) in iteritems(newconf.contexts): - + for newconf_ctx_keys, newconf_ctx in iteritems(newconf.contexts): if newconf_ctx_keys not in running.contexts: - # candidate paths can only be added after the policy and segment list, # so add them to a separate array that is going to be appended at the end if ( @@ -2027,7 +2163,6 @@ def compare_context_objects(newconf, running): reload_ok = False if args.test: - # Create a Config object from the running config running = Config(vtysh) @@ -2043,8 +2178,7 @@ def compare_context_objects(newconf, running): print("\nLines To Delete") print("===============") - for (ctx_keys, line) in lines_to_del: - + for ctx_keys, line in lines_to_del: if line == "!": continue @@ -2070,8 +2204,7 @@ def compare_context_objects(newconf, running): print("\nLines To Add") print("============") - for (ctx_keys, line) in lines_to_add: - + for ctx_keys, line in lines_to_add: if line == "!": continue @@ -2159,8 +2292,7 @@ def compare_context_objects(newconf, running): # apply to other scenarios as well where configuring FOO adds BAR # to the config. if lines_to_del and x == 0: - for (ctx_keys, line) in lines_to_del: - + for ctx_keys, line in lines_to_del: if line == "!": continue @@ -2190,12 +2322,11 @@ def compare_context_objects(newconf, running): vtysh(["configure"] + cmd, stdouts) except VtyshException: - # - Pull the last entry from cmd (this would be # 'no ip ospf authentication message-digest 1.1.1.1' in # our example above # - Split that last entry by whitespace and drop the last word - log.info("Failed to execute %s", " ".join(cmd)) + log.error("Failed to execute %s", " ".join(cmd)) last_arg = cmd[-1].split(" ") if len(last_arg) <= 2: @@ -2218,8 +2349,7 @@ def compare_context_objects(newconf, running): if lines_to_add: lines_to_configure = [] - for (ctx_keys, line) in lines_to_add: - + for ctx_keys, line in lines_to_add: if line == "!": continue diff --git a/tools/frr.in b/tools/frr.in index cd24a96054c3..94c15d5de389 100755 --- a/tools/frr.in +++ b/tools/frr.in @@ -14,11 +14,11 @@ # PATH=/bin:/usr/bin:/sbin:/usr/sbin -D_PATH="@CFG_SBIN@" # /usr/lib/frr -C_PATH="@CFG_SYSCONF@" # /etc/frr -V_PATH="@CFG_STATE@" # /var/run/frr -B_PATH="@CFG_BIN@" -VTYSH="@vtysh_bin@" # /usr/bin/vtysh +D_PATH="@e_sbindir@" # /usr/lib/frr +C_PATH="@e_frr_sysconfdir@" # /etc/frr +V_PATH="@e_frr_runstatedir@" # /var/run/frr +B_PATH="@e_bindir@" +VTYSH="@e_vtysh_bin@" # /usr/bin/vtysh FRR_USER="@enable_user@" # frr FRR_GROUP="@enable_group@" # frr FRR_VTY_GROUP="@enable_vty_group@" # frrvty diff --git a/tools/frr.service.in b/tools/frr.service.in index 1e958dd93e3d..b52ee3f4258b 100644 --- a/tools/frr.service.in +++ b/tools/frr.service.in @@ -17,10 +17,10 @@ WatchdogSec=60s RestartSec=5 Restart=always LimitNOFILE=1024 -PIDFile=@CFG_STATE@/watchfrr.pid -ExecStart=@CFG_SBIN@/frrinit.sh start -ExecStop=@CFG_SBIN@/frrinit.sh stop -ExecReload=@CFG_SBIN@/frrinit.sh reload +PIDFile=@e_frr_runstatedir@/watchfrr.pid +ExecStart=@e_sbindir@/frrinit.sh start +ExecStop=@e_sbindir@/frrinit.sh stop +ExecReload=@e_sbindir@/frrinit.sh reload [Install] WantedBy=multi-user.target diff --git a/tools/frr@.service.in b/tools/frr@.service.in index 85408a0cc7ea..c8a2d3ba83ce 100644 --- a/tools/frr@.service.in +++ b/tools/frr@.service.in @@ -17,10 +17,10 @@ WatchdogSec=60s RestartSec=5 Restart=always LimitNOFILE=1024 -PIDFile=@CFG_STATE@/%I/watchfrr.pid -ExecStart=@CFG_SBIN@/frrinit.sh start %I -ExecStop=@CFG_SBIN@/frrinit.sh stop %I -ExecReload=@CFG_SBIN@/frrinit.sh reload %I +PIDFile=@e_frr_runstatedir@/%I/watchfrr.pid +ExecStart=@e_sbindir@/frrinit.sh start %I +ExecStop=@e_sbindir@/frrinit.sh stop %I +ExecReload=@e_sbindir@/frrinit.sh reload %I [Install] WantedBy=multi-user.target diff --git a/tools/frr_babeltrace.py b/tools/frr_babeltrace.py index 4d974ad356f8..9832568b3736 100755 --- a/tools/frr_babeltrace.py +++ b/tools/frr_babeltrace.py @@ -157,6 +157,46 @@ def parse_frr_bgp_evpn_mh_local_es_evi_del_zrecv(event): parse_event(event, field_parsers) +def parse_frr_bgp_evpn_mh_es_evi_vtep_add(event): + """ + bgp evpn remote ead evi remote vtep add; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi, + "vtep": print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_es_evi_vtep_del(event): + """ + bgp evpn remote ead evi remote vtep del; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi, + "vtep": print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_local_ead_es_evi_route_upd(event): + """ + bgp evpn local ead evi vtep; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi, + "vtep": print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_local_ead_es_evi_route_del(event): + """ + bgp evpn local ead evi vtep del; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi, + "vtep": print_net_ipv4_addr} + + parse_event(event, field_parsers) + def parse_frr_bgp_evpn_local_vni_add_zrecv(event): """ bgp evpn local-vni parser; raw format - @@ -205,6 +245,24 @@ def parse_frr_bgp_evpn_local_macip_del_zrecv(event): parse_event(event, field_parsers) +def parse_frr_bgp_evpn_advertise_type5(event): + """ + local originated type-5 route + """ + field_parsers = {"ip": print_ip_addr, + "rmac": print_mac, + "vtep": print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_withdraw_type5(event): + """ + local originated type-5 route withdraw + """ + field_parsers = {"ip": print_ip_addr} + + parse_event(event, field_parsers) + ############################ evpn parsers - end *############################# def main(): @@ -225,6 +283,14 @@ def main(): parse_frr_bgp_evpn_mh_local_es_evi_add_zrecv, "frr_bgp:evpn_mh_local_es_evi_del_zrecv": parse_frr_bgp_evpn_mh_local_es_evi_del_zrecv, + "frr_bgp:evpn_mh_es_evi_vtep_add": + parse_frr_bgp_evpn_mh_es_evi_vtep_add, + "frr_bgp:evpn_mh_es_evi_vtep_del": + parse_frr_bgp_evpn_mh_es_evi_vtep_del, + "frr_bgp:evpn_mh_local_ead_es_evi_route_upd": + parse_frr_bgp_evpn_mh_local_ead_es_evi_route_upd, + "frr_bgp:evpn_mh_local_ead_es_evi_route_del": + parse_frr_bgp_evpn_mh_local_ead_es_evi_route_del, "frr_bgp:evpn_local_vni_add_zrecv": parse_frr_bgp_evpn_local_vni_add_zrecv, "frr_bgp:evpn_local_l3vni_add_zrecv": @@ -233,6 +299,10 @@ def main(): parse_frr_bgp_evpn_local_macip_add_zrecv, "frr_bgp:evpn_local_macip_del_zrecv": parse_frr_bgp_evpn_local_macip_del_zrecv, + "frr_bgp:evpn_advertise_type5": + parse_frr_bgp_evpn_advertise_type5, + "frr_bgp:evpn_withdraw_type5": + parse_frr_bgp_evpn_withdraw_type5, } # get the trace path from the first command line argument diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 00b63a78e2bc..44d41956b3a3 100755 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -14,18 +14,18 @@ # not perform any action. Note there is an "exit 1" if the main config # file does not exist. # -# This script should be installed in @CFG_SBIN@/frrcommon.sh +# This script should be installed in @e_sbindir@/frrcommon.sh # FRR_PATHSPACE is passed in from watchfrr suffix="${FRR_PATHSPACE:+/${FRR_PATHSPACE}}" nsopt="${FRR_PATHSPACE:+-N ${FRR_PATHSPACE}}" PATH=/bin:/usr/bin:/sbin:/usr/sbin -D_PATH="@CFG_SBIN@" # /usr/lib/frr -C_PATH="@CFG_SYSCONF@${suffix}" # /etc/frr -V_PATH="@CFG_STATE@${suffix}" # /var/run/frr -B_PATH="@CFG_BIN@" -VTYSH="@vtysh_bin@" # /usr/bin/vtysh +D_PATH="@e_sbindir@" # /usr/lib/frr +C_PATH="@e_frr_sysconfdir@${suffix}" # /etc/frr +V_PATH="@e_frr_runstatedir@${suffix}" # /var/run/frr +B_PATH="@e_bindir@" +VTYSH="@e_vtysh_bin@" # /usr/bin/vtysh FRR_USER="@enable_user@" # frr FRR_GROUP="@enable_group@" # frr FRR_VTY_GROUP="@enable_vty_group@" # frrvty diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in index 428d57c55b3d..178d18d43780 100644 --- a/tools/frrinit.sh.in +++ b/tools/frrinit.sh.in @@ -37,7 +37,7 @@ self="`dirname $0`" if [ -r "$self/frrcommon.sh" ]; then . "$self/frrcommon.sh" else - . "@CFG_SBIN@/frrcommon.sh" + . "@e_sbindir@/frrcommon.sh" fi case "$1" in diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c index 4e2c2d3ba9c2..963741e4798f 100644 --- a/tools/gcc-plugins/frr-format.c +++ b/tools/gcc-plugins/frr-format.c @@ -66,6 +66,8 @@ static GTY(()) tree local_pid_t_node; static GTY(()) tree local_uid_t_node; static GTY(()) tree local_gid_t_node; static GTY(()) tree local_time_t_node; +static GTY(()) tree local_suseconds_t_node; +static GTY(()) tree local_suseconds64_t_node; static GTY(()) tree local_socklen_t_node; static GTY(()) tree local_in_addr_t_node; @@ -85,6 +87,8 @@ static struct type_special { { &local_uid_t_node, NULL, &local_uid_t_node, }, { &local_gid_t_node, NULL, &local_gid_t_node, }, { &local_time_t_node, NULL, &local_time_t_node, }, + { &local_suseconds_t_node, NULL, &local_suseconds_t_node, }, + { &local_suseconds64_t_node, NULL, &local_suseconds64_t_node, }, { NULL, NULL, NULL, } }; @@ -4176,6 +4180,8 @@ handle_finish_parse (void *event_data, void *data) setup_type ("uid_t", &local_uid_t_node); setup_type ("gid_t", &local_gid_t_node); setup_type ("time_t", &local_time_t_node); + setup_type ("__suseconds_t", &local_suseconds_t_node); + setup_type ("__suseconds64_t", &local_suseconds64_t_node); setup_type ("socklen_t", &local_socklen_t_node); setup_type ("in_addr_t", &local_in_addr_t_node); diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index 5b778a158556..a87981136357 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -7,6 +7,7 @@ #define REALLY_NEED_PLAIN_GETOPT 1 #include +#include #include @@ -25,67 +26,70 @@ static void __attribute__((noreturn)) usage(int status) static struct nb_callback_info { int operation; bool optional; + bool need_config_write; char return_type[32]; char return_value[32]; char arguments[128]; } nb_callbacks[] = { { - .operation = NB_OP_CREATE, + .operation = NB_CB_CREATE, + .need_config_write = true, .return_type = "int ", .return_value = "NB_OK", .arguments = "struct nb_cb_create_args *args", }, { - .operation = NB_OP_MODIFY, + .operation = NB_CB_MODIFY, + .need_config_write = true, .return_type = "int ", .return_value = "NB_OK", .arguments = "struct nb_cb_modify_args *args", }, { - .operation = NB_OP_DESTROY, + .operation = NB_CB_DESTROY, .return_type = "int ", .return_value = "NB_OK", .arguments = "struct nb_cb_destroy_args *args", }, { - .operation = NB_OP_MOVE, + .operation = NB_CB_MOVE, .return_type = "int ", .return_value = "NB_OK", .arguments = "struct nb_cb_move_args *args", }, { - .operation = NB_OP_APPLY_FINISH, + .operation = NB_CB_APPLY_FINISH, .optional = true, .return_type = "void ", .return_value = "", .arguments = "struct nb_cb_apply_finish_args *args", }, { - .operation = NB_OP_GET_ELEM, + .operation = NB_CB_GET_ELEM, .return_type = "struct yang_data *", .return_value = "NULL", .arguments = "struct nb_cb_get_elem_args *args", }, { - .operation = NB_OP_GET_NEXT, + .operation = NB_CB_GET_NEXT, .return_type = "const void *", .return_value = "NULL", .arguments = "struct nb_cb_get_next_args *args", }, { - .operation = NB_OP_GET_KEYS, + .operation = NB_CB_GET_KEYS, .return_type = "int ", .return_value = "NB_OK", .arguments = "struct nb_cb_get_keys_args *args", }, { - .operation = NB_OP_LOOKUP_ENTRY, + .operation = NB_CB_LOOKUP_ENTRY, .return_type = "const void *", .return_value = "NULL", .arguments = "struct nb_cb_lookup_entry_args *args", }, { - .operation = NB_OP_RPC, + .operation = NB_CB_RPC, .return_type = "int ", .return_value = "NB_OK", .arguments = "struct nb_cb_rpc_args *args", @@ -96,6 +100,16 @@ static struct nb_callback_info { }, }; +/* + * Special-purpose info block for the cli-config-write callback. This + * is different enough from the config-oriented callbacks that it doesn't + * really fit in the array above. + */ +static struct nb_callback_info nb_config_write = { + .return_type = "void ", + .arguments = "struct vty *vty, const struct lyd_node *dnode, bool show_defaults", +}; + static void replace_hyphens_by_underscores(char *str) { char *p; @@ -106,7 +120,7 @@ static void replace_hyphens_by_underscores(char *str) } static void generate_callback_name(const struct lysc_node *snode, - enum nb_operation operation, char *buffer, + enum nb_cb_operation operation, char *buffer, size_t size) { struct list *snodes; @@ -128,7 +142,38 @@ static void generate_callback_name(const struct lysc_node *snode, strlcat(buffer, snode->name, size); strlcat(buffer, "_", size); } - strlcat(buffer, nb_operation_name(operation), size); + strlcat(buffer, nb_cb_operation_name(operation), size); + list_delete(&snodes); + + replace_hyphens_by_underscores(buffer); +} + +static void generate_config_write_cb_name(const struct lysc_node *snode, + char *buffer, size_t size) +{ + struct list *snodes; + struct listnode *ln; + + buffer[0] = '\0'; + + snodes = list_new(); + for (; snode; snode = snode->parent) { + /* Skip schema-only snodes. */ + if (CHECK_FLAG(snode->nodetype, LYS_USES | LYS_CHOICE | LYS_CASE + | LYS_INPUT + | LYS_OUTPUT)) + continue; + + listnode_add_head(snodes, (void *)snode); + } + + for (ALL_LIST_ELEMENTS_RO(snodes, ln, snode)) { + strlcat(buffer, snode->name, size); + strlcat(buffer, "_", size); + } + + strlcat(buffer, "cli_write", size); + list_delete(&snodes); replace_hyphens_by_underscores(buffer); @@ -140,8 +185,16 @@ static void generate_prototype(const struct nb_callback_info *ncinfo, printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments); } +static void generate_config_write_prototype(const struct nb_callback_info *ncinfo, + const char *cb_name) +{ + printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments); +} + static int generate_prototypes(const struct lysc_node *snode, void *arg) { + bool need_config_write = true; + switch (snode->nodetype) { case LYS_CONTAINER: case LYS_LEAF: @@ -159,12 +212,21 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg) char cb_name[BUFSIZ]; if (cb->optional - || !nb_operation_is_valid(cb->operation, snode)) + || !nb_cb_operation_is_valid(cb->operation, snode)) continue; generate_callback_name(snode, cb->operation, cb_name, sizeof(cb_name)); generate_prototype(cb, cb_name); + + if (cb->need_config_write && need_config_write) { + generate_config_write_cb_name(snode, cb_name, + sizeof(cb_name)); + generate_config_write_prototype(&nb_config_write, + cb_name); + + need_config_write = false; + } } return YANG_ITER_CONTINUE; @@ -177,10 +239,10 @@ static void generate_callback(const struct nb_callback_info *ncinfo, ncinfo->return_type, cb_name, ncinfo->arguments); switch (ncinfo->operation) { - case NB_OP_CREATE: - case NB_OP_MODIFY: - case NB_OP_DESTROY: - case NB_OP_MOVE: + case NB_CB_CREATE: + case NB_CB_MODIFY: + case NB_CB_DESTROY: + case NB_CB_MOVE: printf("\tswitch (args->event) {\n" "\tcase NB_EV_VALIDATE:\n" "\tcase NB_EV_PREPARE:\n" @@ -200,9 +262,22 @@ static void generate_callback(const struct nb_callback_info *ncinfo, printf("\treturn %s;\n}\n\n", ncinfo->return_value); } +static void generate_config_write_callback(const struct nb_callback_info *ncinfo, + const char *cb_name) +{ + printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "", + ncinfo->return_type, cb_name, ncinfo->arguments); + + /* Add a comment, since these callbacks may not all be needed. */ + printf("\t/* TODO: this cli callback is optional; the cli output may not need to be done at each node. */\n"); + + printf("}\n\n"); +} + static int generate_callbacks(const struct lysc_node *snode, void *arg) { bool first = true; + bool need_config_write = true; switch (snode->nodetype) { case LYS_CONTAINER: @@ -221,7 +296,7 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg) char cb_name[BUFSIZ]; if (cb->optional - || !nb_operation_is_valid(cb->operation, snode)) + || !nb_cb_operation_is_valid(cb->operation, snode)) continue; if (first) { @@ -240,6 +315,15 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg) generate_callback_name(snode, cb->operation, cb_name, sizeof(cb_name)); generate_callback(cb, cb_name); + + if (cb->need_config_write && need_config_write) { + generate_config_write_cb_name(snode, cb_name, + sizeof(cb_name)); + generate_config_write_callback(&nb_config_write, + cb_name); + + need_config_write = false; + } } return YANG_ITER_CONTINUE; @@ -248,6 +332,10 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg) static int generate_nb_nodes(const struct lysc_node *snode, void *arg) { bool first = true; + char cb_name[BUFSIZ]; + char xpath[XPATH_MAXLEN]; + bool config_pass = *(bool *)arg; + bool need_config_write = true; switch (snode->nodetype) { case LYS_CONTAINER: @@ -261,31 +349,53 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg) return YANG_ITER_CONTINUE; } + /* We generate two types of structs currently; behavior is a little + * different between the types. + */ for (struct nb_callback_info *cb = &nb_callbacks[0]; cb->operation != -1; cb++) { - char cb_name[BUFSIZ]; if (cb->optional - || !nb_operation_is_valid(cb->operation, snode)) + || !nb_cb_operation_is_valid(cb->operation, snode)) continue; - if (first) { - char xpath[XPATH_MAXLEN]; + if (config_pass) { + if (first) { + yang_snode_get_path(snode, YANG_PATH_DATA, xpath, + sizeof(xpath)); - yang_snode_get_path(snode, YANG_PATH_DATA, xpath, - sizeof(xpath)); + printf("\t\t{\n" + "\t\t\t.xpath = \"%s\",\n", + xpath); + printf("\t\t\t.cbs = {\n"); + first = false; + } - printf("\t\t{\n" - "\t\t\t.xpath = \"%s\",\n", - xpath); - printf("\t\t\t.cbs = {\n"); - first = false; - } + generate_callback_name(snode, cb->operation, cb_name, + sizeof(cb_name)); + printf("\t\t\t\t.%s = %s,\n", + nb_cb_operation_name(cb->operation), + cb_name); + } else if (cb->need_config_write && need_config_write) { + if (first) { + yang_snode_get_path(snode, + YANG_PATH_DATA, + xpath, + sizeof(xpath)); + + printf("\t\t{\n" + "\t\t\t.xpath = \"%s\",\n", + xpath); + printf("\t\t\t.cbs = {\n"); + first = false; + } - generate_callback_name(snode, cb->operation, cb_name, - sizeof(cb_name)); - printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation), - cb_name); + generate_config_write_cb_name(snode, cb_name, + sizeof(cb_name)); + printf("\t\t\t\t.cli_show = %s,\n", cb_name); + + need_config_write = false; + } } if (!first) { @@ -303,6 +413,7 @@ int main(int argc, char *argv[]) char module_name_underscores[64]; struct stat st; int opt; + bool config_pass; while ((opt = getopt(argc, argv, "hp:s")) != -1) { switch (opt) { @@ -348,13 +459,18 @@ int main(int argc, char *argv[]) module = yang_module_find(argv[0]); if (!module) /* Non-native FRR module (e.g. modules from unit tests). */ - module = yang_module_load(argv[0]); + module = yang_module_load(argv[0], NULL); yang_init_loading_complete(); /* Create a nb_node for all YANG schema nodes. */ nb_nodes_create(); + /* Emit bare-bones license line (and fool the checkpatch regex + * that triggers a warning). + */ + printf("// SPDX-" "License-Identifier: GPL-2.0-or-later\n\n"); + /* Generate callback prototypes. */ if (!static_cbs) { printf("/* prototypes */\n"); @@ -369,13 +485,38 @@ int main(int argc, char *argv[]) sizeof(module_name_underscores)); replace_hyphens_by_underscores(module_name_underscores); - /* Generate frr_yang_module_info array. */ + /* + * We're going to generate two structs here, two arrays of callbacks: + * first one with config-handling callbacks, then a second struct with + * config-output-oriented callbacks. + */ + + /* Generate frr_yang_module_info array, with config-handling callbacks */ + config_pass = true; printf("/* clang-format off */\n" - "const struct frr_yang_module_info %s_info = {\n" + "const struct frr_yang_module_info %s_nb_info = {\n" "\t.name = \"%s\",\n" "\t.nodes = {\n", module_name_underscores, module->name); - yang_snodes_iterate(module->info, generate_nb_nodes, 0, NULL); + yang_snodes_iterate(module->info, generate_nb_nodes, 0, &config_pass); + + /* Emit terminator element */ + printf("\t\t{\n" + "\t\t\t.xpath = NULL,\n" + "\t\t},\n"); + printf("\t}\n" + "};\n"); + + /* Generate second array, with output-oriented callbacks. */ + config_pass = false; + printf("\n/* clang-format off */\n" + "const struct frr_yang_module_info %s_cli_info = {\n" + "\t.name = \"%s\",\n" + "\t.nodes = {\n", + module_name_underscores, module->name); + yang_snodes_iterate(module->info, generate_nb_nodes, 0, &config_pass); + + /* Emit terminator element */ printf("\t\t{\n" "\t\t\t.xpath = NULL,\n" "\t\t},\n"); diff --git a/tools/gen_yang_deviations.c b/tools/gen_yang_deviations.c index fc9f55bcbc3d..251643c69ebb 100644 --- a/tools/gen_yang_deviations.c +++ b/tools/gen_yang_deviations.c @@ -55,7 +55,7 @@ int main(int argc, char *argv[]) yang_init(false, false); /* Load YANG module. */ - module = yang_module_load(argv[0]); + module = yang_module_load(argv[0], NULL); /* Generate deviations. */ yang_snodes_iterate(module->info, generate_yang_deviation, 0, NULL); diff --git a/tools/indent.py b/tools/indent.py index fe9eb7c2526b..dac7d3f04b66 100755 --- a/tools/indent.py +++ b/tools/indent.py @@ -34,13 +34,13 @@ def wrap_file(fn): ci = subprocess.Popen( ["clang-format"], stdin=subprocess.PIPE, stdout=subprocess.PIPE ) - stdout, ign = ci.communicate(text) + stdout, ign = ci.communicate(text.encode("utf-8")) ci.wait() if ci.returncode != 0: raise IOError("clang-format returned %d" % (ci.returncode)) # remove the bits we inserted above - final = clean_re.sub("", stdout) + final = clean_re.sub("", stdout.decode("utf-8")) tmpname = fn + ".indent" with open(tmpname, "w") as ofd: diff --git a/tools/valgrind.supp b/tools/valgrind.supp index da3d4a8d6d7b..d2cb4118de8f 100644 --- a/tools/valgrind.supp +++ b/tools/valgrind.supp @@ -23,6 +23,15 @@ fun:cap_init fun:zprivs_caps_init } +{ + + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:getgrouplist + fun:zprivs_init + fun:frr_init +} { Memcheck:Leak diff --git a/tools/watchfrr.sh.in b/tools/watchfrr.sh.in index 712f962a0ae5..31279f6db111 100644 --- a/tools/watchfrr.sh.in +++ b/tools/watchfrr.sh.in @@ -5,7 +5,7 @@ # internally by watchfrr to start the protocol daemons with the appropriate # options. # -# This script should be installed in @CFG_SBIN@/watchfrr.sh +# This script should be installed in @e_sbindir@/watchfrr.sh log_success_msg() { : @@ -27,7 +27,7 @@ self="`dirname $0`" if [ -r "$self/frrcommon.sh" ]; then . "$self/frrcommon.sh" else - . "@CFG_SBIN@/frrcommon.sh" + . "@e_sbindir@/frrcommon.sh" fi frrcommon_main "$@" diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index b14a6ecc473f..017387924c7f 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -700,10 +700,9 @@ static int vrrp_bind_to_primary_connected(struct vrrp_router *r) */ ifp = r->family == AF_INET ? r->vr->ifp : r->mvl_ifp; - struct listnode *ln; struct connected *c = NULL; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, ln, c)) + frr_each (if_connected, ifp->connected, c) if (c->address->family == r->family) { if (r->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6)) @@ -1171,9 +1170,15 @@ static int vrrp_socket(struct vrrp_router *r) r->vr->vrid, family2str(r->family)); /* Join Rx socket to VRRP IPv4 multicast group */ - assert(listhead(r->vr->ifp->connected)); - struct connected *c = listhead(r->vr->ifp->connected)->data; - struct in_addr v4 = c->address->u.prefix4; + struct connected *c; + struct in_addr v4; + + frr_each (if_connected, r->vr->ifp->connected, c) + if (c->address->family == AF_INET) + break; + + assert(c); + v4 = c->address->u.prefix4; ret = setsockopt_ipv4_multicast(r->sock_rx, IP_ADD_MEMBERSHIP, v4, htonl(VRRP_MCASTV4_GROUP), @@ -1703,7 +1708,6 @@ int vrrp_event(struct vrrp_router *r, int event) */ static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router *r) { - struct listnode *ln; struct connected *c = NULL; bool is_v6_ll; @@ -1714,7 +1718,7 @@ static void vrrp_autoconfig_autoaddrupdate(struct vrrp_router *r) VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM "Setting Virtual IP list to match IPv4 addresses on %s", r->vr->vrid, family2str(r->family), r->mvl_ifp->name); - for (ALL_LIST_ELEMENTS_RO(r->mvl_ifp->connected, ln, c)) { + frr_each (if_connected, r->mvl_ifp->connected, c) { is_v6_ll = (c->address->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6)); if (c->address->family == r->family && !is_v6_ll) { diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c index 5245c7468924..e9af3d92f5d8 100644 --- a/vrrpd/vrrp_main.c +++ b/vrrpd/vrrp_main.c @@ -107,16 +107,20 @@ static const struct frr_yang_module_info *const vrrp_yang_modules[] = { &frr_vrrpd_info, }; -#define VRRP_VTY_PORT 2619 - -FRR_DAEMON_INFO(vrrpd, VRRP, .vty_port = VRRP_VTY_PORT, - .proghelp = "Virtual Router Redundancy Protocol", - .signals = vrrp_signals, - .n_signals = array_size(vrrp_signals), - .privs = &vrrp_privs, - .yang_modules = vrrp_yang_modules, - .n_yang_modules = array_size(vrrp_yang_modules), +/* clang-format off */ +FRR_DAEMON_INFO(vrrpd, VRRP, + .vty_port = VRRP_VTY_PORT, + .proghelp = "Virtual Router Redundancy Protocol", + + .signals = vrrp_signals, + .n_signals = array_size(vrrp_signals), + + .privs = &vrrp_privs, + + .yang_modules = vrrp_yang_modules, + .n_yang_modules = array_size(vrrp_yang_modules), ); +/* clang-format on */ int main(int argc, char **argv, char **envp) { diff --git a/vrrpd/vrrp_northbound.c b/vrrpd/vrrp_northbound.c index 1f8da4cf2090..2947a416d8b9 100644 --- a/vrrpd/vrrp_northbound.c +++ b/vrrpd/vrrp_northbound.c @@ -27,8 +27,8 @@ static int lib_interface_vrrp_vrrp_group_create(struct nb_cb_create_args *args) uint8_t version = 3; struct vrrp_vrouter *vr; - vrid = yang_dnode_get_uint8(args->dnode, "./virtual-router-id"); - version = yang_dnode_get_enum(args->dnode, "./version"); + vrid = yang_dnode_get_uint8(args->dnode, "virtual-router-id"); + version = yang_dnode_get_enum(args->dnode, "version"); switch (args->event) { case NB_EV_VALIDATE: diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 9971df58a3aa..fd6cbc8b6740 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -62,11 +62,11 @@ DEFPY_YANG(vrrp_vrid, void cli_show_vrrp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const char *vrid = yang_dnode_get_string(dnode, "./virtual-router-id"); - const char *ver = yang_dnode_get_string(dnode, "./version"); + const char *vrid = yang_dnode_get_string(dnode, "virtual-router-id"); + const char *ver = yang_dnode_get_string(dnode, "version"); vty_out(vty, " vrrp %s", vrid); - if (show_defaults || !yang_dnode_is_default(dnode, "./version")) + if (show_defaults || !yang_dnode_is_default(dnode, "version")) vty_out(vty, " version %s", ver); vty_out(vty, "\n"); } @@ -200,7 +200,11 @@ DEFPY_YANG(vrrp_ip, VRRP_IP_STR) { int op = no ? NB_OP_DESTROY : NB_OP_CREATE; - nb_cli_enqueue_change(vty, "./v4/virtual-address", op, ip_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./v4/virtual-address[.='%s']", ip_str); + + nb_cli_enqueue_change(vty, xpath, op, NULL); return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } @@ -228,7 +232,11 @@ DEFPY_YANG(vrrp_ip6, VRRP_IP_STR) { int op = no ? NB_OP_DESTROY : NB_OP_CREATE; - nb_cli_enqueue_change(vty, "./v6/virtual-address", op, ipv6_str); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "./v6/virtual-address[.='%s']", ipv6_str); + + nb_cli_enqueue_change(vty, xpath, op, NULL); return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index 6d753d2e4764..009432b217c3 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -36,11 +36,10 @@ static void vrrp_zebra_debug_if_dump_address(struct interface *ifp, const char *func) { struct connected *ifc; - struct listnode *node; DEBUGD(&vrrp_dbg_zebra, "%s: interface %s addresses:", func, ifp->name); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { struct prefix *p = ifc->address; DEBUGD(&vrrp_dbg_zebra, "%s: interface %s address %pFX %s", @@ -183,8 +182,10 @@ static zclient_handler *const vrrp_handlers[] = { void vrrp_zebra_init(void) { - if_zapi_callbacks(vrrp_ifp_create, vrrp_ifp_up, - vrrp_ifp_down, vrrp_ifp_destroy); + hook_register_prio(if_real, 0, vrrp_ifp_create); + hook_register_prio(if_up, 0, vrrp_ifp_up); + hook_register_prio(if_down, 0, vrrp_ifp_down); + hook_register_prio(if_unreal, 0, vrrp_ifp_destroy); /* Socket for receiving updates from Zebra daemon */ zclient = zclient_new(master, &zclient_options_default, vrrp_handlers, diff --git a/vtysh/.gitignore b/vtysh/.gitignore index 09e90e51d2ed..9cbd248f2f72 100644 --- a/vtysh/.gitignore +++ b/vtysh/.gitignore @@ -1,6 +1,6 @@ vtysh vtysh_cmd.c -vtysh_daemons.h +vtysh_cmd.*.c # does not exist anymore - remove 2023-10-04 or so extract.pl diff --git a/vtysh/subdir.am b/vtysh/subdir.am index a1b81f598a0e..d39987eb83c8 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -17,9 +17,6 @@ vtysh_vtysh_SOURCES = \ vtysh/vtysh_user.c \ vtysh/vtysh_config.c \ # end -nodist_vtysh_vtysh_SOURCES = \ - vtysh/vtysh_cmd.c \ - # end noinst_HEADERS += \ vtysh/vtysh.h \ @@ -29,13 +26,3 @@ noinst_HEADERS += \ vtysh_vtysh_LDADD = lib/libfrr.la $(LIBCAP) $(LIBREADLINE) $(LIBS) $(LIBPAM) EXTRA_DIST += vtysh/daemons.pl - -BUILT_SOURCES += vtysh/vtysh_daemons.h - -# force vtysh_daemons.h -$(vtysh_vtysh_OBJECTS): vtysh/vtysh_daemons.h - -CLEANFILES += vtysh/vtysh_daemons.h -vtysh/vtysh_daemons.h: - @$(MKDIR_P) vtysh - $(PERL) $(top_srcdir)/vtysh/daemons.pl $(vtysh_daemons) > vtysh/vtysh_daemons.h diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 113a15c172ef..e483b1a575a1 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -5,6 +5,9 @@ #include +#include +#include + #include #include #include @@ -28,7 +31,7 @@ #include "network.h" #include "filter.h" #include "vtysh/vtysh.h" -#include "vtysh/vtysh_daemons.h" +#include "lib/vtysh_daemons.h" #include "log.h" #include "vrf.h" #include "libfrr.h" @@ -36,7 +39,6 @@ #include "frrstr.h" #include "json.h" #include "ferr.h" -#include "bgpd/bgp_vty.h" DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy"); @@ -1159,14 +1161,12 @@ static char **new_completion(const char *text, int start, int end) } /* Vty node structures. */ -#ifdef HAVE_BGPD static struct cmd_node bgp_node = { .name = "bgp", .node = BGP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BGPD */ static struct cmd_node rip_node = { .name = "rip", @@ -1175,7 +1175,6 @@ static struct cmd_node rip_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_ISISD static struct cmd_node isis_node = { .name = "isis", .node = ISIS_NODE, @@ -1203,16 +1202,13 @@ static struct cmd_node isis_srv6_node_msd_node = { .parent_node = ISIS_SRV6_NODE, .prompt = "%s(config-router-srv6-node-msd)# ", }; -#endif /* HAVE_ISISD */ -#ifdef HAVE_FABRICD static struct cmd_node openfabric_node = { .name = "openfabric", .node = OPENFABRIC_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_FABRICD */ static struct cmd_node interface_node = { .name = "interface", @@ -1235,7 +1231,6 @@ static struct cmd_node segment_routing_node = { .prompt = "%s(config-sr)# ", }; -#if defined(HAVE_PATHD) static struct cmd_node sr_traffic_eng_node = { .name = "sr traffic-eng", .node = SR_TRAFFIC_ENG_NODE, @@ -1291,7 +1286,6 @@ static struct cmd_node pcep_pce_config_node = { .parent_node = PCEP_NODE, .prompt = "%s(pcep-sr-te-pcep-pce-config)# ", }; -#endif /* HAVE_PATHD */ static struct cmd_node vrf_node = { .name = "vrf", @@ -1335,14 +1329,40 @@ static struct cmd_node srv6_loc_node = { .prompt = "%s(config-srv6-locator)# ", }; -#ifdef HAVE_PBRD +static struct cmd_node srv6_encap_node = { + .name = "srv6-encap", + .node = SRV6_ENCAP_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-encap)# " +}; + +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + static struct cmd_node pbr_map_node = { .name = "pbr-map", .node = PBRMAP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-pbr-map)# ", }; -#endif /* HAVE_PBRD */ static struct cmd_node zebra_node = { .name = "zebra", @@ -1351,7 +1371,6 @@ static struct cmd_node zebra_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_BGPD static struct cmd_node bgp_vpnv4_node = { .name = "bgp vpnv4", .node = BGP_VPNV4_NODE, @@ -1447,7 +1466,13 @@ static struct cmd_node bgp_ipv6l_node = { .no_xpath = true, }; -#ifdef ENABLE_BGP_VNC +static struct cmd_node bgp_rtc_node = { + .name = "bgp rtc", + .node = BGP_RTC_NODE, + .parent_node = BGP_NODE, + .prompt = "%s(config-router-af-rtc)# ", +}; + static struct cmd_node bgp_vnc_defaults_node = { .name = "bgp vnc defaults", .node = BGP_VNC_DEFAULTS_NODE, @@ -1475,7 +1500,6 @@ static struct cmd_node bgp_vnc_l2_group_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-vnc-l2-group)# ", }; -#endif /* ENABLE_BGP_VNC */ static struct cmd_node bmp_node = { .name = "bmp", @@ -1490,34 +1514,27 @@ static struct cmd_node bgp_srv6_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-srv6)# ", }; -#endif /* HAVE_BGPD */ -#ifdef HAVE_OSPFD static struct cmd_node ospf_node = { .name = "ospf", .node = OSPF_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_OSPFD */ -#ifdef HAVE_EIGRPD static struct cmd_node eigrp_node = { .name = "eigrp", .node = EIGRP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_EIGRPD */ -#ifdef HAVE_BABELD static struct cmd_node babel_node = { .name = "babel", .node = BABEL_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BABELD */ static struct cmd_node ripng_node = { .name = "ripng", @@ -1526,16 +1543,13 @@ static struct cmd_node ripng_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_OSPF6D static struct cmd_node ospf6_node = { .name = "ospf6", .node = OSPF6_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-ospf6)# ", }; -#endif /* HAVE_OSPF6D */ -#ifdef HAVE_LDPD static struct cmd_node ldp_node = { .name = "ldp", .node = LDP_NODE, @@ -1584,7 +1598,6 @@ static struct cmd_node ldp_pseudowire_node = { .parent_node = LDP_L2VPN_NODE, .prompt = "%s(config-l2vpn-pw)# ", }; -#endif /* HAVE_LDPD */ static struct cmd_node keychain_node = { .name = "keychain", @@ -1605,19 +1618,22 @@ struct cmd_node link_params_node = { .node = LINK_PARAMS_NODE, .parent_node = INTERFACE_NODE, .prompt = "%s(config-link-params)# ", - .no_xpath = true, }; -#ifdef HAVE_BGPD static struct cmd_node rpki_node = { .name = "rpki", .node = RPKI_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-rpki)# ", }; -#endif /* HAVE_BGPD */ -#if HAVE_BFDD > 0 +static struct cmd_node rpki_vrf_node = { + .name = "rpki", + .node = RPKI_VRF_NODE, + .parent_node = VRF_NODE, + .prompt = "%s(config-vrf-rpki)# ", +}; + static struct cmd_node bfd_node = { .name = "bfd", .node = BFD_NODE, @@ -1638,7 +1654,20 @@ static struct cmd_node bfd_profile_node = { .parent_node = BFD_NODE, .prompt = "%s(config-bfd-profile)# ", }; -#endif /* HAVE_BFDD */ + +static struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", +}; + +static struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", +}; /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -1691,6 +1720,39 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, srv6_encap, srv6_encap_cmd, + "encapsulation", + "Segment Routing SRv6 encapsulation\n") +{ + vty->node = SRV6_ENCAP_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_formats, srv6_sid_formats_cmd, "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f3216_usid, srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + vty->node = SRV6_SID_FORMAT_USID_F3216_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f4024_uncompressed, srv6_sid_format_f4024_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + vty->node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_BGPD DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, "router bgp [ASNUM [ VIEWVRFNAME] [as-notation ]]", @@ -1758,6 +1820,14 @@ DEFUNSH(VTYSH_BGPD, address_family_flowspecv6, address_family_flowspecv6_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BGPD, address_family_rtc, address_family_rtc_cmd, + "address-family ipv4 rt-constraint", + "Enter Address Family command mode\n" BGP_AF_STR BGP_AF_MODIFIER_STR) +{ + vty->node = BGP_RTC_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BGPD, address_family_ipv4_multicast, address_family_ipv4_multicast_cmd, "address-family ipv4 multicast", "Enter Address Family command mode\n" @@ -1836,7 +1906,10 @@ DEFUNSH(VTYSH_BGPD, "rpki", "Enable rpki and enter rpki configuration mode\n") { - vty->node = RPKI_NODE; + if (vty->node == CONFIG_NODE) + vty->node = RPKI_NODE; + else + vty->node = RPKI_VRF_NODE; return CMD_SUCCESS; } @@ -1976,7 +2049,7 @@ DEFUNSH(VTYSH_KEYS, key, key_cmd, "key (0-2147483647)", } #ifdef HAVE_RIPD -DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip [vrf NAME]", +DEFUNSH(VTYSH_MGMTD, router_rip, router_rip_cmd, "router rip [vrf NAME]", ROUTER_STR "RIP\n" VRF_CMD_HELP_STR) { vty->node = RIP_NODE; @@ -1985,7 +2058,7 @@ DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip [vrf NAME]", #endif /* HAVE_RIPD */ #ifdef HAVE_RIPNGD -DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng [vrf NAME]", +DEFUNSH(VTYSH_MGMTD, router_ripng, router_ripng_cmd, "router ripng [vrf NAME]", ROUTER_STR "RIPng\n" VRF_CMD_HELP_STR) { vty->node = RIPNG_NODE; @@ -2273,7 +2346,7 @@ DEFUNSH(VTYSH_AFFMAP, no_affinity_map, vtysh_no_affinity_map_cmd, return CMD_SUCCESS; } -DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd, +DEFUNSH(VTYSH_RMAP_CONFIG, vtysh_route_map, vtysh_route_map_cmd, "route-map RMAP_NAME (1-65535)", "Create route-map or enter route-map command mode\n" "Route map tag\n" @@ -2340,6 +2413,30 @@ DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, } #endif /* HAVE_BFDD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, router_pim, router_pim_cmd, + "router pim [vrf NAME]", + ROUTER_STR + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, router_pim6, router_pim6_cmd, + "router pim6 [vrf NAME]", + ROUTER_STR + "Start PIMv6 configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM6_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIM6D*/ + DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty", "Configure a terminal line\n" "Virtual terminal\n") @@ -2366,8 +2463,8 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_disable, vtysh_disable_cmd, "disable", DEFUNSH(VTYSH_REALLYALL, vtysh_config_terminal, vtysh_config_terminal_cmd, "configure [terminal [file-lock]]", "Configuration from vty interface\n" - "Configuration with locked datastores\n" - "Configuration terminal\n") + "Configuration terminal\n" + "Configuration with locked datastores\n") { vty->node = CONFIG_NODE; return CMD_SUCCESS; @@ -2384,17 +2481,6 @@ static int vtysh_exit(struct vty *vty) if (cnode->parent_node) vty->node = cnode->parent_node; - if (vty->node == CONFIG_NODE) { - /* resync in case one of the daemons is somewhere else */ - vtysh_execute("end"); - /* NOTE: a rather expensive thing to do, can we avoid it? */ - - if (vty->vtysh_file_locked) - vtysh_execute("configure terminal file-lock"); - else - vtysh_execute("configure terminal"); - } - return CMD_SUCCESS; } @@ -2414,13 +2500,12 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_quit_all, vtysh_quit_all_cmd, "quit", DEFUNSH(VTYSH_BGPD, exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { - if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE - || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE - || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE - || vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE - || vty->node == BGP_EVPN_NODE - || vty->node == BGP_FLOWSPECV4_NODE - || vty->node == BGP_FLOWSPECV6_NODE) + if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || + vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || + vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || + vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE || + vty->node == BGP_EVPN_NODE || vty->node == BGP_FLOWSPECV4_NODE || + vty->node == BGP_FLOWSPECV6_NODE || vty->node == BGP_RTC_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -2491,14 +2576,39 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_loc_config, exit_srv6_loc_config_cmd, "exit", return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, exit_srv6_encap, exit_srv6_encap_cmd, "exit", + "Exit from SRv6-encapsulation configuration mode\n") +{ + if (vty->node == SRV6_ENCAP_NODE) + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_formats, exit_srv6_sid_formats_cmd, "exit", + "Exit from SRv6 SID formats configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMATS_NODE) + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_format, exit_srv6_sid_format_cmd, + "exit", "Exit from SRv6 SID format configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMAT_USID_F3216_NODE || + vty->node == SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE) + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_RIPD -DEFUNSH(VTYSH_RIPD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit", +DEFUNSH(VTYSH_MGMTD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit", "Exit current mode and down to previous mode\n") { return vtysh_exit(vty); } -DEFUNSH(VTYSH_RIPD, vtysh_quit_ripd, vtysh_quit_ripd_cmd, "quit", +DEFUNSH(VTYSH_MGMTD, vtysh_quit_ripd, vtysh_quit_ripd_cmd, "quit", "Exit current mode and down to previous mode\n") { return vtysh_exit_ripd(self, vty, argc, argv); @@ -2506,26 +2616,26 @@ DEFUNSH(VTYSH_RIPD, vtysh_quit_ripd, vtysh_quit_ripd_cmd, "quit", #endif /* HAVE_RIPD */ #ifdef HAVE_RIPNGD -DEFUNSH(VTYSH_RIPNGD, vtysh_exit_ripngd, vtysh_exit_ripngd_cmd, "exit", +DEFUNSH(VTYSH_MGMTD, vtysh_exit_ripngd, vtysh_exit_ripngd_cmd, "exit", "Exit current mode and down to previous mode\n") { return vtysh_exit(vty); } -DEFUNSH(VTYSH_RIPNGD, vtysh_quit_ripngd, vtysh_quit_ripngd_cmd, "quit", +DEFUNSH(VTYSH_MGMTD, vtysh_quit_ripngd, vtysh_quit_ripngd_cmd, "quit", "Exit current mode and down to previous mode\n") { return vtysh_exit_ripngd(self, vty, argc, argv); } #endif /* HAVE_RIPNGD */ -DEFUNSH(VTYSH_RMAP, vtysh_exit_rmap, vtysh_exit_rmap_cmd, "exit", +DEFUNSH(VTYSH_RMAP_CONFIG, vtysh_exit_rmap, vtysh_exit_rmap_cmd, "exit", "Exit current mode and down to previous mode\n") { return vtysh_exit(vty); } -DEFUNSH(VTYSH_RMAP, vtysh_quit_rmap, vtysh_quit_rmap_cmd, "quit", +DEFUNSH(VTYSH_RMAP_CONFIG, vtysh_quit_rmap, vtysh_quit_rmap_cmd, "quit", "Exit current mode and down to previous mode\n") { return vtysh_exit_rmap(self, vty, argc, argv); @@ -2739,6 +2849,34 @@ DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit", } #endif /* HAVE_PATHD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, vtysh_exit_pimd, vtysh_exit_pimd_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIMD, vtysh_quit_pimd, vtysh_quit_pimd_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pimd(self, vty, argc, argv); +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, vtysh_exit_pim6d, vtysh_exit_pim6d_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIM6D, vtysh_quit_pim6d, vtysh_quit_pim6d_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pim6d(self, vty, argc, argv); +} +#endif /* HAVE_PIM6D */ + DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -2901,35 +3039,35 @@ static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc, return ret; } -DEFUN (vtysh_show_thread_timer, - vtysh_show_thread_timer_cmd, - "show thread timers", +DEFUN (vtysh_show_event_timer, + vtysh_show_event_timer_cmd, + "show event timers", SHOW_STR - "Thread information\n" + "Event information\n" "Show all timers and how long they have in the system\n") { - return show_per_daemon(vty, argv, argc, "Thread timers for %s:\n"); + return show_per_daemon(vty, argv, argc, "Event timers for %s:\n"); } -DEFUN (vtysh_show_poll, - vtysh_show_poll_cmd, - "show thread poll", +DEFUN (vtysh_show_event_poll, + vtysh_show_event_poll_cmd, + "show event poll", SHOW_STR - "Thread information\n" - "Thread Poll Information\n") + "Event information\n" + "Event Poll Information\n") { - return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n"); + return show_per_daemon(vty, argv, argc, "Event statistics for %s:\n"); } -DEFUN (vtysh_show_thread, - vtysh_show_thread_cmd, - "show thread cpu [FILTER]", +DEFUN (vtysh_show_event, + vtysh_show_event_cpu_cmd, + "show event cpu [FILTER]", SHOW_STR - "Thread information\n" - "Thread CPU usage\n" + "Event information\n" + "Event CPU usage\n" "Display filter (rwtexb)\n") { - return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n"); + return show_per_daemon(vty, argv, argc, "Event statistics for %s:\n"); } DEFUN (vtysh_show_work_queues, @@ -2952,14 +3090,22 @@ DEFUN (vtysh_show_work_queues_daemon, return show_one_daemon(vty, argv, argc - 1, argv[argc - 1]->text); } -DEFUNSH(VTYSH_ZEBRA, vtysh_link_params, vtysh_link_params_cmd, "link-params", +DEFUNSH(VTYSH_MGMTD, vtysh_link_params, vtysh_link_params_cmd, "link-params", LINK_PARAMS_STR) { vty->node = LINK_PARAMS_NODE; return CMD_SUCCESS; } -DEFUNSH(VTYSH_ZEBRA, exit_link_params, exit_link_params_cmd, "exit-link-params", +DEFUNSH_HIDDEN(VTYSH_MGMTD, no_link_params_enable, no_link_params_enable_cmd, + "no enable", NO_STR "Disable link parameters on this interface\n") +{ + if (vty->node == LINK_PARAMS_NODE) + vty->node = INTERFACE_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_MGMTD, exit_link_params, exit_link_params_cmd, "exit-link-params", "Exit from Link Params configuration node\n") { if (vty->node == LINK_PARAMS_NODE) @@ -2967,7 +3113,7 @@ DEFUNSH(VTYSH_ZEBRA, exit_link_params, exit_link_params_cmd, "exit-link-params", return CMD_SUCCESS; } -DEFUNSH(VTYSH_ZEBRA, vtysh_exit_link_params, vtysh_exit_link_params_cmd, "exit", +DEFUNSH(VTYSH_MGMTD, vtysh_exit_link_params, vtysh_exit_link_params_cmd, "exit", "Exit current mode and down to previous mode\n") { if (vty->node == LINK_PARAMS_NODE) @@ -2975,7 +3121,7 @@ DEFUNSH(VTYSH_ZEBRA, vtysh_exit_link_params, vtysh_exit_link_params_cmd, "exit", return CMD_SUCCESS; } -DEFUNSH(VTYSH_ZEBRA, vtysh_quit_link_params, vtysh_quit_link_params_cmd, "quit", +DEFUNSH(VTYSH_MGMTD, vtysh_quit_link_params, vtysh_quit_link_params_cmd, "quit", "Exit current mode and down to previous mode\n") { return vtysh_exit_link_params(self, vty, argc, argv); @@ -3057,7 +3203,7 @@ DEFUN (vtysh_show_error_code, } /* Northbound. */ -DEFUN_HIDDEN (show_config_running, +DEFUN (show_config_running, show_config_running_cmd, "show configuration running\ [ [translate WORD]]\ @@ -3133,7 +3279,7 @@ DEFUNSH(VTYSH_ALL, debug_nb, debug_nb_cmd, "[no] debug northbound\ [<\ - callbacks [{configuration|state|rpc}]\ + callbacks [{configuration|state|rpc|notify}]\ |notifications\ |events\ |libyang\ @@ -3146,6 +3292,7 @@ DEFUNSH(VTYSH_ALL, debug_nb, "State\n" "RPC\n" "Notifications\n" + "Notifications\n" "Events\n" "libyang debugging\n") { @@ -3380,6 +3527,316 @@ DEFUN (vtysh_show_running_config, return vtysh_write_terminal(self, vty, argc, argv); } +static void show_route_map_send(const char *route_map, bool json) +{ + unsigned int i; + bool first = true; + char command_line[128]; + + snprintf(command_line, sizeof(command_line), "do show route-map "); + if (route_map) + strlcat(command_line, route_map, sizeof(command_line)); + if (json) + strlcat(command_line, " json", sizeof(command_line)); + + if (json) + vty_out(vty, "{"); + + for (i = 0; i < array_size(vtysh_client); i++) { + const struct vtysh_client *client = &vtysh_client[i]; + bool is_connected = true; + + if (!CHECK_FLAG(client->flag, VTYSH_RMAP_SHOW)) + continue; + + for (; client; client = client->next) + if (client->fd < 0) + is_connected = false; + + if (!is_connected) + continue; + + if (json && !first) + vty_out(vty, ","); + else + first = false; + + if (json) + vty_out(vty, "\"%s\":", vtysh_client[i].name); + + vtysh_client_execute_name(vtysh_client[i].name, command_line); + } + + if (json) + vty_out(vty, "}\n"); +} + +DEFPY (show_route_map, + show_route_map_cmd, + "show route-map [WORD]$route_map [json]$json", + SHOW_STR + "route-map information\n" + "route-map name\n" + JSON_STR) +{ + show_route_map_send(route_map, !!json); + + return CMD_SUCCESS; +} + +static void show_prefix_list_send(afi_t afi, const char *prefix_list, + const char *seq, enum display_type dtype, + bool json) +{ + unsigned int i; + bool first = true; + char command_line[128]; + + if (afi == AFI_IP) + snprintf(command_line, sizeof(command_line), + "do show ip prefix-list "); + else if (afi == AFI_IP6) + snprintf(command_line, sizeof(command_line), + "do show ipv6 prefix-list "); + if (dtype == detail_display) + strlcat(command_line, "detail ", sizeof(command_line)); + else if (dtype == summary_display) + strlcat(command_line, "summary ", sizeof(command_line)); + if (prefix_list) + strlcat(command_line, prefix_list, sizeof(command_line)); + if (dtype == sequential_display) { + strlcat(command_line, " seq ", sizeof(command_line)); + strlcat(command_line, seq, sizeof(command_line)); + } + if (json) + strlcat(command_line, " json", sizeof(command_line)); + + if (json) + vty_out(vty, "{"); + + for (i = 0; i < array_size(vtysh_client); i++) { + const struct vtysh_client *client = &vtysh_client[i]; + bool is_connected = true; + + if (!CHECK_FLAG(client->flag, VTYSH_PREFIX_LIST_SHOW)) + continue; + + for (; client; client = client->next) + if (client->fd < 0) + is_connected = false; + + if (!is_connected) + continue; + + if (json && !first) + vty_out(vty, ","); + else + first = false; + + if (json) + vty_out(vty, "\"%s\":", vtysh_client[i].name); + + vtysh_client_execute_name(vtysh_client[i].name, command_line); + } + + if (json) + vty_out(vty, "}\n"); +} + +DEFPY (show_ip_prefix_list, + show_ip_prefix_list_cmd, + "show ip prefix-list [PREFIXLIST4_NAME$name [seq$dseq (1-4294967295)$arg]] [json$uj]", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + JSON_STR) +{ + enum display_type dtype = normal_display; + + if (dseq) + dtype = sequential_display; + + show_prefix_list_send(AFI_IP, name, arg_str, dtype, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ip_prefix_list_summary, + show_ip_prefix_list_summary_cmd, + "show ip prefix-list summary [PREFIXLIST4_NAME$name] [json$uj]", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Summary of prefix lists\n" + "Name of a prefix list\n" + JSON_STR) +{ + show_prefix_list_send(AFI_IP, name, NULL, summary_display, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ip_prefix_list_detail, + show_ip_prefix_list_detail_cmd, + "show ip prefix-list detail [PREFIXLIST4_NAME$name] [json$uj]", + SHOW_STR + IP_STR + PREFIX_LIST_STR + "Detail of prefix lists\n" + "Name of a prefix list\n" + JSON_STR) +{ + show_prefix_list_send(AFI_IP, name, NULL, detail_display, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_prefix_list, + show_ipv6_prefix_list_cmd, + "show ipv6 prefix-list [PREFIXLIST6_NAME$name [seq$dseq (1-4294967295)$arg]] [json$uj]", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Name of a prefix list\n" + "sequence number of an entry\n" + "Sequence number\n" + JSON_STR) +{ + enum display_type dtype = normal_display; + + if (dseq) + dtype = sequential_display; + + show_prefix_list_send(AFI_IP6, name, arg_str, dtype, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_prefix_list_summary, + show_ipv6_prefix_list_summary_cmd, + "show ipv6 prefix-list summary [PREFIXLIST6_NAME$name] [json$uj]", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Summary of prefix lists\n" + "Name of a prefix list\n" + JSON_STR) +{ + show_prefix_list_send(AFI_IP6, name, NULL, summary_display, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_prefix_list_detail, + show_ipv6_prefix_list_detail_cmd, + "show ipv6 prefix-list detail [PREFIXLIST6_NAME$name] [json$uj]", + SHOW_STR + IPV6_STR + PREFIX_LIST_STR + "Detail of prefix lists\n" + "Name of a prefix list\n" + JSON_STR) +{ + show_prefix_list_send(AFI_IP6, name, NULL, detail_display, !!uj); + return CMD_SUCCESS; +} + +static void show_access_list_send(afi_t afi, const char *access_list, bool json) +{ + unsigned int i; + bool first = true; + char command_line[128]; + + if (afi == AFI_IP) + snprintf(command_line, sizeof(command_line), + "do show ip access-list "); + else if (afi == AFI_IP6) + snprintf(command_line, sizeof(command_line), + "do show ipv6 access-list "); + if (access_list) + strlcat(command_line, access_list, sizeof(command_line)); + if (json) { + strlcat(command_line, " json", sizeof(command_line)); + vty_out(vty, "{"); + } + + for (i = 0; i < array_size(vtysh_client); i++) { + const struct vtysh_client *client = &vtysh_client[i]; + bool is_connected = true; + + if (!CHECK_FLAG(client->flag, VTYSH_ACCESS_LIST_SHOW)) + continue; + + for (; client; client = client->next) + if (client->fd < 0) + is_connected = false; + + if (!is_connected) + continue; + + if (json && !first) + vty_out(vty, ","); + else + first = false; + + if (json) + vty_out(vty, "\"%s\":", vtysh_client[i].name); + + vtysh_client_execute_name(vtysh_client[i].name, command_line); + } + + if (json) + vty_out(vty, "}\n"); +} + +DEFPY (show_ip_access_list, + show_ip_access_list_cmd, + "show ip access-list [json$uj]", + SHOW_STR + IP_STR + "List IP access lists\n" + JSON_STR) +{ + show_access_list_send(AFI_IP, NULL, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ip_access_list_name, + show_ip_access_list_name_cmd, + "show ip access-list ACCESSLIST4_NAME$name [json$uj]", + SHOW_STR + IP_STR + "List IP access lists\n" + "IP access-list name\n" + JSON_STR) +{ + show_access_list_send(AFI_IP, name, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_access_list, + show_ipv6_access_list_cmd, + "show ipv6 access-list [json$uj]", + SHOW_STR + IPV6_STR + "List IPv6 access lists\n" + JSON_STR) +{ + show_access_list_send(AFI_IP6, NULL, !!uj); + return CMD_SUCCESS; +} + +DEFPY (show_ipv6_access_list_name, + show_ipv6_access_list_name_cmd, + "show ipv6 access-list ACCESSLIST6_NAME$name [json$uj]", + SHOW_STR + IPV6_STR + "List IPv6 access lists\n" + "IPv6 access-list name\n" + JSON_STR) +{ + show_access_list_send(AFI_IP6, name, !!uj); + return CMD_SUCCESS; +} + DEFUN (vtysh_integrated_config, vtysh_integrated_config_cmd, "service integrated-vtysh-config", @@ -3404,8 +3861,8 @@ DEFUN (no_vtysh_integrated_config, static void backup_config_file(const char *fbackup) { char *integrate_sav = NULL; - size_t integrate_sav_sz = strlen(fbackup) + strlen(CONF_BACKUP_EXT) + 1; + integrate_sav = malloc(integrate_sav_sz); strlcpy(integrate_sav, fbackup, integrate_sav_sz); strlcat(integrate_sav, CONF_BACKUP_EXT, integrate_sav_sz); @@ -4114,71 +4571,6 @@ DEFUN (vtysh_traceroute6, return CMD_SUCCESS; } -#if CONFDATE > 20240201 -CPP_NOTICE("Remove HAVE_SHELL_ACCESS and it's documentation"); -#endif -#if defined(HAVE_SHELL_ACCESS) -DEFUN (vtysh_telnet, - vtysh_telnet_cmd, - "telnet WORD", - "Open a telnet connection\n" - "IP address or hostname of a remote system\n") -{ - execute_command("telnet", 1, argv[1]->arg, NULL); - return CMD_SUCCESS; -} - -DEFUN (vtysh_telnet_port, - vtysh_telnet_port_cmd, - "telnet WORD PORT", - "Open a telnet connection\n" - "IP address or hostname of a remote system\n" - "TCP Port number\n") -{ - execute_command("telnet", 2, argv[1]->arg, argv[2]->arg); - return CMD_SUCCESS; -} - -DEFUN (vtysh_ssh, - vtysh_ssh_cmd, - "ssh WORD", - "Open an ssh connection\n" - "[user@]host\n") -{ - execute_command("ssh", 1, argv[1]->arg, NULL); - return CMD_SUCCESS; -} - -DEFUN (vtysh_start_shell, - vtysh_start_shell_cmd, - "start-shell", - "Start UNIX shell\n") -{ - execute_command("sh", 0, NULL, NULL); - return CMD_SUCCESS; -} - -DEFUN (vtysh_start_bash, - vtysh_start_bash_cmd, - "start-shell bash", - "Start UNIX shell\n" - "Start bash\n") -{ - execute_command("bash", 0, NULL, NULL); - return CMD_SUCCESS; -} - -DEFUN (vtysh_start_zsh, - vtysh_start_zsh_cmd, - "start-shell zsh", - "Start UNIX shell\n" - "Start Z shell\n") -{ - execute_command("zsh", 0, NULL, NULL); - return CMD_SUCCESS; -} -#endif - DEFUN (config_list, config_list_cmd, "list [permutations]", @@ -4543,15 +4935,88 @@ void vtysh_init_vty(void) cmd_init(0); cmd_variable_handler_register(vtysh_var_handler); + install_node(&bgp_node); + install_node(&babel_node); + install_node(&bgp_vpnv4_node); + install_node(&bgp_vpnv6_node); + install_node(&bgp_flowspecv4_node); + install_node(&bgp_flowspecv6_node); + install_node(&bgp_ipv4_node); + install_node(&bgp_ipv4m_node); + install_node(&bgp_ipv4l_node); + install_node(&bgp_ipv6_node); + install_node(&bgp_ipv6m_node); + install_node(&bgp_ipv6l_node); + install_node(&bgp_vrf_policy_node); + install_node(&bgp_vnc_defaults_node); + install_node(&bgp_vnc_nve_group_node); + install_node(&bgp_vnc_l2_group_node); + install_node(&bgp_evpn_node); + install_node(&bgp_evpn_vni_node); + install_node(&bgp_rtc_node); + install_node(&rpki_node); + install_node(&bmp_node); + install_node(&bgp_srv6_node); + install_node(&rip_node); + install_node(&ripng_node); + install_node(&ospf_node); + install_node(&ospf6_node); + install_node(&ldp_node); + install_node(&ldp_ipv4_node); + install_node(&ldp_ipv6_node); + install_node(&ldp_ipv4_iface_node); + install_node(&ldp_ipv6_iface_node); + install_node(&ldp_l2vpn_node); + install_node(&ldp_pseudowire_node); + install_node(&eigrp_node); + install_node(&isis_node); + install_node(&isis_flex_algo_node); + install_node(&isis_srv6_node); + install_node(&isis_srv6_node_msd_node); + install_node(&openfabric_node); + install_node(&pbr_map_node); + install_node(&bfd_node); + install_node(&bfd_peer_node); + install_node(&bfd_profile_node); + install_node(&segment_routing_node); + install_node(&sr_traffic_eng_node); + install_node(&srte_segment_list_node); + install_node(&srte_policy_node); + install_node(&srte_candidate_dyn_node); + install_node(&pcep_node); + install_node(&pcep_pcc_node); + install_node(&pcep_pce_node); + install_node(&pcep_pce_config_node); + install_node(&keychain_node); + install_node(&keychain_key_node); + install_node(&nh_group_node); + install_node(&zebra_node); + install_node(&interface_node); + install_node(&pim_node); + install_node(&pim6_node); + install_node(&link_params_node); + install_node(&pw_node); + install_node(&vrf_node); + install_node(&rpki_vrf_node); + install_node(&rmap_node); + install_node(&vty_node); + install_node(&srv6_node); + install_node(&srv6_locs_node); + install_node(&srv6_loc_node); + install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); + + vtysh_init_cmd(); + /* bgpd */ #ifdef HAVE_BGPD - install_node(&bgp_node); install_element(CONFIG_NODE, &router_bgp_cmd); install_element(BGP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_vpnv4_node); install_element(BGP_NODE, &address_family_ipv4_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); @@ -4561,7 +5026,6 @@ void vtysh_init_vty(void) install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV4_NODE, &exit_address_family_cmd); - install_node(&bgp_vpnv6_node); install_element(BGP_NODE, &address_family_ipv6_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv6_cmd); @@ -4571,56 +5035,48 @@ void vtysh_init_vty(void) install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV6_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv4_node); install_element(BGP_NODE, &address_family_flowspecv4_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv6_node); install_element(BGP_NODE, &address_family_flowspecv6_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4_node); install_element(BGP_NODE, &address_family_ipv4_cmd); install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4m_node); install_element(BGP_NODE, &address_family_ipv4_multicast_cmd); install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4l_node); install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd); install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4L_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6_node); install_element(BGP_NODE, &address_family_ipv6_cmd); install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6m_node); install_element(BGP_NODE, &address_family_ipv6_multicast_cmd); install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6l_node); install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); @@ -4628,28 +5084,24 @@ void vtysh_init_vty(void) install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); #if defined(ENABLE_BGP_VNC) - install_node(&bgp_vrf_policy_node); install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); - install_node(&bgp_vnc_defaults_node); install_element(BGP_NODE, &vnc_defaults_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_nve_group_node); install_element(BGP_NODE, &vnc_nve_group_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_l2_group_node); install_element(BGP_NODE, &vnc_l2_group_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd); @@ -4657,33 +5109,34 @@ void vtysh_init_vty(void) install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd); #endif - install_node(&bgp_evpn_node); install_element(BGP_NODE, &address_family_evpn_cmd); install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); - install_node(&bgp_evpn_vni_node); install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); - install_node(&rpki_node); + install_element(BGP_NODE, &address_family_rtc_cmd); + install_element(BGP_RTC_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_RTC_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_RTC_NODE, &vtysh_end_all_cmd); + install_element(BGP_RTC_NODE, &exit_address_family_cmd); + install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); - install_node(&bmp_node); install_element(BGP_NODE, &bmp_targets_cmd); install_element(BMP_NODE, &bmp_exit_cmd); install_element(BMP_NODE, &bmp_quit_cmd); install_element(BMP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_srv6_node); install_element(BGP_NODE, &bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd); @@ -4691,7 +5144,6 @@ void vtysh_init_vty(void) #endif /* HAVE_BGPD */ /* ripd */ - install_node(&rip_node); #ifdef HAVE_RIPD install_element(CONFIG_NODE, &router_rip_cmd); install_element(RIP_NODE, &vtysh_exit_ripd_cmd); @@ -4700,7 +5152,6 @@ void vtysh_init_vty(void) #endif /* HAVE_RIPD */ /* ripngd */ - install_node(&ripng_node); #ifdef HAVE_RIPNGD install_element(CONFIG_NODE, &router_ripng_cmd); install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd); @@ -4710,7 +5161,6 @@ void vtysh_init_vty(void) /* ospfd */ #ifdef HAVE_OSPFD - install_node(&ospf_node); install_element(CONFIG_NODE, &router_ospf_cmd); install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd); install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd); @@ -4719,7 +5169,6 @@ void vtysh_init_vty(void) /* ospf6d */ #ifdef HAVE_OSPF6D - install_node(&ospf6_node); install_element(CONFIG_NODE, &router_ospf6_cmd); install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd); install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd); @@ -4728,45 +5177,38 @@ void vtysh_init_vty(void) /* ldpd */ #if defined(HAVE_LDPD) - install_node(&ldp_node); install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd); install_element(LDP_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_node); install_element(LDP_NODE, &ldp_address_family_ipv4_cmd); install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_node); install_element(LDP_NODE, &ldp_address_family_ipv6_cmd); install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_iface_node); install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_iface_node); install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_l2vpn_node); install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd); - install_node(&ldp_pseudowire_node); install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd); @@ -4775,7 +5217,6 @@ void vtysh_init_vty(void) /* eigrpd */ #ifdef HAVE_EIGRPD - install_node(&eigrp_node); install_element(CONFIG_NODE, &router_eigrp_cmd); install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd); install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd); @@ -4784,7 +5225,6 @@ void vtysh_init_vty(void) /* babeld */ #ifdef HAVE_BABELD - install_node(&babel_node); install_element(CONFIG_NODE, &router_babel_cmd); install_element(BABEL_NODE, &vtysh_exit_babeld_cmd); install_element(BABEL_NODE, &vtysh_quit_babeld_cmd); @@ -4793,25 +5233,21 @@ void vtysh_init_vty(void) /* isisd */ #ifdef HAVE_ISISD - install_node(&isis_node); install_element(CONFIG_NODE, &router_isis_cmd); install_element(ISIS_NODE, &vtysh_exit_isisd_cmd); install_element(ISIS_NODE, &vtysh_quit_isisd_cmd); install_element(ISIS_NODE, &vtysh_end_all_cmd); - install_node(&isis_flex_algo_node); install_element(ISIS_NODE, &isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_exit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_quit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node); install_element(ISIS_NODE, &isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE, &vtysh_exit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_quit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node_msd_node); install_element(ISIS_SRV6_NODE_MSD_NODE, &vtysh_exit_isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE_MSD_NODE, @@ -4821,7 +5257,6 @@ void vtysh_init_vty(void) /* fabricd */ #ifdef HAVE_FABRICD - install_node(&openfabric_node); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd); install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd); @@ -4830,7 +5265,6 @@ void vtysh_init_vty(void) /* pbrd */ #ifdef HAVE_PBRD - install_node(&pbr_map_node); install_element(CONFIG_NODE, &vtysh_pbr_map_cmd); install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd); install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd); @@ -4840,37 +5274,28 @@ void vtysh_init_vty(void) /* bfdd */ #if HAVE_BFDD > 0 - install_node(&bfd_node); install_element(CONFIG_NODE, &bfd_enter_cmd); install_element(BFD_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_NODE, &vtysh_end_all_cmd); - install_node(&bfd_peer_node); install_element(BFD_NODE, &bfd_peer_enter_cmd); install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_end_all_cmd); - install_node(&bfd_profile_node); install_element(BFD_NODE, &bfd_profile_enter_cmd); install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd); #endif /* HAVE_BFDD */ - install_node(&segment_routing_node); install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd); #if defined(HAVE_PATHD) - install_node(&sr_traffic_eng_node); - install_node(&srte_segment_list_node); - install_node(&srte_policy_node); - install_node(&srte_candidate_dyn_node); - install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd); install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd); install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd); @@ -4891,11 +5316,6 @@ void vtysh_init_vty(void) install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd); - install_node(&pcep_node); - install_node(&pcep_pcc_node); - install_node(&pcep_pce_node); - install_node(&pcep_pce_config_node); - install_element(PCEP_NODE, &vtysh_exit_pathd_cmd); install_element(PCEP_NODE, &vtysh_quit_pathd_cmd); install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd); @@ -4918,14 +5338,12 @@ void vtysh_init_vty(void) #endif /* HAVE_PATHD */ /* keychain */ - install_node(&keychain_node); install_element(CONFIG_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd); - install_node(&keychain_key_node); install_element(KEYCHAIN_NODE, &key_cmd); install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd); @@ -4933,7 +5351,6 @@ void vtysh_init_vty(void) install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); /* nexthop-group */ - install_node(&nh_group_node); install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd); install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); @@ -4941,44 +5358,60 @@ void vtysh_init_vty(void) install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd); /* zebra and all */ - install_node(&zebra_node); - - install_node(&interface_node); install_element(CONFIG_NODE, &vtysh_interface_cmd); install_element(INTERFACE_NODE, &vtysh_end_all_cmd); install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); - install_node(&link_params_node); + /* pimd */ +#ifdef HAVE_PIMD + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(PIM_NODE, &vtysh_exit_pimd_cmd); + install_element(PIM_NODE, &vtysh_quit_pimd_cmd); + install_element(PIM_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIMD */ + + /* pim6d */ +#ifdef HAVE_PIM6D + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIM6D */ + install_element(INTERFACE_NODE, &vtysh_link_params_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); install_element(LINK_PARAMS_NODE, &vtysh_end_all_cmd); install_element(LINK_PARAMS_NODE, &vtysh_exit_link_params_cmd); install_element(LINK_PARAMS_NODE, &vtysh_quit_link_params_cmd); - install_node(&pw_node); install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); install_element(PW_NODE, &vtysh_end_all_cmd); install_element(PW_NODE, &vtysh_exit_pseudowire_cmd); install_element(PW_NODE, &vtysh_quit_pseudowire_cmd); - install_node(&vrf_node); install_element(CONFIG_NODE, &vtysh_vrf_cmd); install_element(VRF_NODE, &exit_vrf_config_cmd); install_element(VRF_NODE, &vtysh_end_all_cmd); install_element(VRF_NODE, &vtysh_exit_vrf_cmd); install_element(VRF_NODE, &vtysh_quit_vrf_cmd); +#ifdef HAVE_BGPD + install_element(VRF_NODE, &rpki_cmd); + install_element(RPKI_VRF_NODE, &rpki_exit_cmd); + install_element(RPKI_VRF_NODE, &rpki_quit_cmd); + install_element(RPKI_VRF_NODE, &vtysh_end_all_cmd); +#endif + install_element(CONFIG_NODE, &vtysh_affinity_map_cmd); install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd); - install_node(&rmap_node); install_element(CONFIG_NODE, &vtysh_route_map_cmd); install_element(RMAP_NODE, &vtysh_exit_rmap_cmd); install_element(RMAP_NODE, &vtysh_quit_rmap_cmd); install_element(RMAP_NODE, &vtysh_end_all_cmd); - install_node(&vty_node); install_element(CONFIG_NODE, &vtysh_line_vty_cmd); install_element(VTY_NODE, &vtysh_exit_line_vty_cmd); install_element(VTY_NODE, &vtysh_quit_line_vty_cmd); @@ -5011,25 +5444,54 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_end_all_cmd); /* SRv6 Data-plane */ - install_node(&srv6_node); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_NODE, &exit_srv6_config_cmd); install_element(SRV6_NODE, &vtysh_end_all_cmd); + install_element(SRV6_NODE, &srv6_encap_cmd); - install_node(&srv6_locs_node); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd); - install_node(&srv6_loc_node); install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd); install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); + install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); + install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_f4024_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd); + install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &vtysh_end_all_cmd); + install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd); + install_element(ENABLE_NODE, &show_route_map_cmd); + install_element(ENABLE_NODE, &show_ip_prefix_list_cmd); + install_element(ENABLE_NODE, &show_ip_prefix_list_summary_cmd); + install_element(ENABLE_NODE, &show_ip_prefix_list_detail_cmd); + install_element(ENABLE_NODE, &show_ipv6_prefix_list_cmd); + install_element(ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd); + install_element(ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element(ENABLE_NODE, &show_ip_access_list_cmd); + install_element(ENABLE_NODE, &show_ip_access_list_name_cmd); + install_element(ENABLE_NODE, &show_ipv6_access_list_cmd); + install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd); + /* "write terminal" command. */ install_element(ENABLE_NODE, &vtysh_write_terminal_cmd); @@ -5059,16 +5521,6 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &vtysh_mtrace_cmd); install_element(VIEW_NODE, &vtysh_ping6_cmd); install_element(VIEW_NODE, &vtysh_traceroute6_cmd); -#if defined(HAVE_SHELL_ACCESS) - install_element(VIEW_NODE, &vtysh_telnet_cmd); - install_element(VIEW_NODE, &vtysh_telnet_port_cmd); - install_element(VIEW_NODE, &vtysh_ssh_cmd); -#endif -#if defined(HAVE_SHELL_ACCESS) - install_element(ENABLE_NODE, &vtysh_start_shell_cmd); - install_element(ENABLE_NODE, &vtysh_start_bash_cmd); - install_element(ENABLE_NODE, &vtysh_start_zsh_cmd); -#endif /* debugging */ install_element(VIEW_NODE, &vtysh_show_error_code_cmd); @@ -5095,9 +5547,9 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &vtysh_show_modules_cmd); install_element(VIEW_NODE, &vtysh_show_work_queues_cmd); install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); - install_element(VIEW_NODE, &vtysh_show_thread_cmd); - install_element(VIEW_NODE, &vtysh_show_poll_cmd); - install_element(VIEW_NODE, &vtysh_show_thread_timer_cmd); + install_element(VIEW_NODE, &vtysh_show_event_cpu_cmd); + install_element(VIEW_NODE, &vtysh_show_event_poll_cmd); + install_element(VIEW_NODE, &vtysh_show_event_timer_cmd); /* Logging */ install_element(VIEW_NODE, &vtysh_show_logging_cmd); diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 65733ca61b4c..b1d57aa3c221 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -49,21 +49,48 @@ extern struct event_loop *master; VTYSH_PIM6D | VTYSH_NHRPD | VTYSH_EIGRPD | VTYSH_BABELD | \ VTYSH_SHARPD | VTYSH_PBRD | VTYSH_STATICD | VTYSH_BFDD | \ VTYSH_FABRICD | VTYSH_VRRPD | VTYSH_PATHD | VTYSH_MGMTD -#define VTYSH_ACL VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_PIM6D|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA -#define VTYSH_AFFMAP VTYSH_ZEBRA | VTYSH_ISISD -#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD -#define VTYSH_INTERFACE_SUBSET \ +#define VTYSH_ACL_CONFIG \ + VTYSH_BFDD | VTYSH_BABELD | VTYSH_BGPD | VTYSH_EIGRPD | VTYSH_ISISD | \ + VTYSH_FABRICD | VTYSH_LDPD | VTYSH_NHRPD | VTYSH_OSPF6D | \ + VTYSH_OSPFD | VTYSH_PBRD | VTYSH_PIMD | VTYSH_PIM6D | \ + VTYSH_VRRPD | VTYSH_MGMTD +#define VTYSH_ACL_SHOW \ + VTYSH_BFDD | VTYSH_BABELD | VTYSH_BGPD | VTYSH_EIGRPD | VTYSH_ISISD | \ + VTYSH_FABRICD | VTYSH_LDPD | VTYSH_NHRPD | VTYSH_OSPF6D | \ + VTYSH_OSPFD | VTYSH_PBRD | VTYSH_PIMD | VTYSH_PIM6D | \ + VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_VRRPD | VTYSH_ZEBRA + +#define VTYSH_AFFMAP VTYSH_ISISD | VTYSH_MGMTD +#define VTYSH_RMAP_CONFIG \ + VTYSH_OSPFD | VTYSH_OSPF6D | VTYSH_BGPD | VTYSH_ISISD | \ + VTYSH_PIMD | VTYSH_EIGRPD | VTYSH_FABRICD | VTYSH_MGMTD +#define VTYSH_RMAP_SHOW \ + VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \ + VTYSH_BGPD | VTYSH_ISISD | VTYSH_PIMD | VTYSH_EIGRPD | \ + VTYSH_FABRICD +#define VTYSH_ACCESS_LIST_SHOW \ + VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \ + VTYSH_BGPD | VTYSH_ISISD | VTYSH_PIMD | VTYSH_EIGRPD | \ + VTYSH_FABRICD +#define VTYSH_PREFIX_LIST_SHOW \ VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D | \ + VTYSH_BGPD | VTYSH_ISISD | VTYSH_PIMD | VTYSH_EIGRPD | \ + VTYSH_FABRICD +#define VTYSH_INTERFACE_SUBSET \ + VTYSH_OSPFD | VTYSH_OSPF6D | \ VTYSH_ISISD | VTYSH_PIMD | VTYSH_PIM6D | VTYSH_NHRPD | \ VTYSH_EIGRPD | VTYSH_BABELD | VTYSH_PBRD | VTYSH_FABRICD | \ - VTYSH_VRRPD + VTYSH_VRRPD | VTYSH_MGMTD #define VTYSH_INTERFACE VTYSH_INTERFACE_SUBSET | VTYSH_BGPD -#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_MGMTD -#define VTYSH_KEYS VTYSH_RIPD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD +#define VTYSH_VRF VTYSH_INTERFACE_SUBSET | VTYSH_BGPD +#define VTYSH_KEYS VTYSH_MGMTD | VTYSH_EIGRPD | VTYSH_OSPF6D | VTYSH_OSPFD /* Daemons who can process nexthop-group configs */ #define VTYSH_NH_GROUP VTYSH_PBRD|VTYSH_SHARPD #define VTYSH_SR VTYSH_ZEBRA|VTYSH_PATHD #define VTYSH_DPDK VTYSH_ZEBRA +#define VTYSH_MGMT_BACKEND \ + VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_STATICD | VTYSH_ZEBRA +#define VTYSH_MGMT_FRONTEND VTYSH_MGMTD enum vtysh_write_integrated { WRITE_INTEGRATED_UNSPECIFIED, @@ -71,7 +98,17 @@ enum vtysh_write_integrated { WRITE_INTEGRATED_YES }; +enum display_type { + normal_display, + summary_display, + detail_display, + sequential_display, + longer_display, + first_match_display +}; + extern enum vtysh_write_integrated vtysh_write_integrated; +extern enum display_type display_type; extern char frr_config[]; extern char vtydir[]; diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index ae64d5128369..8f7cd84818c6 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -315,11 +315,20 @@ void vtysh_config_parse_line(void *arg, const char *line) } else if (!strncmp(line, " ip mroute", strlen(" ip mroute"))) { config_add_line_uniq_end(config->line, line); + } else if ((strncmp(line, " rpki", strlen(" rpki")) == + 0) && + config->index == VRF_NODE) { + config_add_line(config->line, line); + config->index = RPKI_VRF_NODE; } else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE || config->index == VTY_NODE) config_add_line_uniq(config->line, line); - else if (config->index == NH_GROUP_NODE) { + else if (config->index == RPKI_VRF_NODE && + strncmp(line, " exit", strlen(" exit")) == 0) { + config_add_line(config->line, line); + config->index = VRF_NODE; + } else if (config->index == NH_GROUP_NODE) { if (strncmp(line, " resilient", strlen(" resilient")) == 0) config_add_line_head(config->line, @@ -455,6 +464,12 @@ void vtysh_config_parse_line(void *arg, const char *line) else if (strncmp(line, "debug resolver", strlen("debug resolver")) == 0) config = config_get(RESOLVER_DEBUG_NODE, line); + else if (strncmp(line, "debug mgmt client frontend", + strlen("debug mgmt client frontend")) == 0) + config = config_get(MGMT_FE_DEBUG_NODE, line); + else if (strncmp(line, "debug mgmt client backend", + strlen("debug mgmt client backend")) == 0) + config = config_get(MGMT_BE_DEBUG_NODE, line); else if (strncmp(line, "debug", strlen("debug")) == 0) config = config_get(DEBUG_NODE, line); else if (strncmp(line, "password", strlen("password")) == 0 @@ -482,6 +497,11 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(BFD_NODE, line); else if (strncmp(line, "rpki", strlen("rpki")) == 0) config = config_get(RPKI_NODE, line); + else if (strncmp(line, "router pim", strlen("router pim")) == 0) + config = config_get(PIM_NODE, line); + else if (strncmp(line, "router pim6", strlen("router pim6")) == + 0) + config = config_get(PIM6_NODE, line); else { if (strncmp(line, "log", strlen("log")) == 0 || strncmp(line, "hostname", strlen("hostname")) == 0 || @@ -601,8 +621,13 @@ static int vtysh_read_file(FILE *confp, bool dry_run) vty->node = CONFIG_NODE; vtysh_execute_no_pager("enable"); - vtysh_execute_no_pager("conf term file-lock"); - vty->vtysh_file_locked = true; + /* + * When reading the config, we need to wait until the lock is acquired. + * If we ignore the failure and continue without the lock, the config + * will be fully ignored. + */ + while (vtysh_execute_no_pager("conf term file-lock") == CMD_WARNING_CONFIG_FAILED) + usleep(100000); if (!dry_run) vtysh_execute_no_pager("XFRR_start_configuration"); @@ -614,7 +639,6 @@ static int vtysh_read_file(FILE *confp, bool dry_run) vtysh_execute_no_pager("XFRR_end_configuration"); vtysh_execute_no_pager("end"); - vty->vtysh_file_locked = false; vtysh_execute_no_pager("disable"); vty_close(vty); diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 20254fcd537c..64198132cc64 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -5,6 +5,9 @@ #include +#include +#include +#include #include #include #include @@ -221,7 +224,9 @@ static struct event *vtysh_rl_read_thread; static void vtysh_rl_read(struct event *thread) { - event_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO, + bool *suppress_warnings = EVENT_ARG(thread); + + event_add_read(master, vtysh_rl_read, suppress_warnings, STDIN_FILENO, &vtysh_rl_read_thread); rl_callback_read_char(); } @@ -230,11 +235,12 @@ static void vtysh_rl_read(struct event *thread) static void vtysh_rl_run(void) { struct event thread; + bool suppress_warnings = true; master = event_master_create(NULL); rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback); - event_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO, + event_add_read(master, vtysh_rl_read, &suppress_warnings, STDIN_FILENO, &vtysh_rl_read_thread); while (!vtysh_loop_exited && event_fetch(master, &thread)) @@ -359,8 +365,7 @@ int main(int argc, char **argv, char **env) strlcpy(sysconfdir, frr_sysconfdir, sizeof(sysconfdir)); - frr_init_vtydir(); - strlcpy(vtydir, frr_vtydir, sizeof(vtydir)); + strlcpy(vtydir, frr_runstatedir, sizeof(vtydir)); /* Option handling. */ while (1) { @@ -484,7 +489,6 @@ int main(int argc, char **argv, char **env) /* Make vty structure and register commands. */ vtysh_init_vty(); - vtysh_init_cmd(); vtysh_user_init(); vtysh_config_init(); diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index 89199da1af79..acc612c0a858 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -6,6 +6,11 @@ */ #include + +#include +#include +#include + #include "frrevent.h" #include #include @@ -27,6 +32,8 @@ #include "watchfrr.h" #include "watchfrr_errors.h" +#include "lib/config_paths.h" + #ifndef MIN #define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y)) #endif @@ -115,7 +122,7 @@ static struct global_state { int numdown; /* # of daemons that are not UP or UNRESPONSIVE */ } gs = { .phase = PHASE_INIT, - .vtydir = frr_vtydir, + .vtydir = frr_runstatedir, .period = 1000 * DEFAULT_PERIOD, .timeout = DEFAULT_TIMEOUT, .restart_timeout = DEFAULT_RESTART_TIMEOUT, @@ -292,11 +299,11 @@ Otherwise, the interval is doubled (but capped at the -M value).\n\n", passing command-line arguments with embedded spaces.\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n", - frr_vtydir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, LOG_DEBUG, - DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, + frr_runstatedir, DEFAULT_LOGLEVEL, LOG_EMERG, LOG_DEBUG, + LOG_DEBUG, DEFAULT_MIN_RESTART, DEFAULT_MAX_RESTART, DEFAULT_OPERATIONAL_TIMEOUT, DEFAULT_PERIOD, DEFAULT_TIMEOUT, DEFAULT_RESTART_TIMEOUT, DEFAULT_RESTART_CMD, DEFAULT_START_CMD, - DEFAULT_STOP_CMD, frr_vtydir); + DEFAULT_STOP_CMD, frr_runstatedir); } static pid_t run_background(char *shell_cmd) @@ -600,6 +607,9 @@ static void daemon_restarting_operational(struct event *thread) static void daemon_down(struct daemon *dmn, const char *why) { + if (dmn->ignore_timeout) + return; + if (IS_UP(dmn) || (dmn->state == DAEMON_INIT)) flog_err(EC_WATCHFRR_CONNECTION, "%s state -> down : %s", dmn->name, why); @@ -720,7 +730,7 @@ static void daemon_send_ready(int exitcode) frr_detach(); - snprintf(started, sizeof(started), "%s/%s", frr_vtydir, + snprintf(started, sizeof(started), "%s/%s", frr_runstatedir, "watchfrr.started"); fp = fopen(started, "w"); if (fp) @@ -908,7 +918,7 @@ static void phase_check(void) "Phased restart: all routing daemon stop jobs have completed."); set_phase(PHASE_WAITING_DOWN); - /*FALLTHRU*/ + fallthrough; case PHASE_WAITING_DOWN: if (gs.numdown + IS_UP(gs.special) < gs.numdaemons) break; @@ -918,7 +928,7 @@ static void phase_check(void) 1); set_phase(PHASE_ZEBRA_RESTART_PENDING); - /*FALLTHRU*/ + fallthrough; case PHASE_ZEBRA_RESTART_PENDING: if (gs.special->restart.pid) break; @@ -927,7 +937,7 @@ static void phase_check(void) gs.special->name); set_phase(PHASE_WAITING_ZEBRA_UP); - /*FALLTHRU*/ + fallthrough; case PHASE_WAITING_ZEBRA_UP: if (!IS_UP(gs.special)) break; @@ -1344,19 +1354,20 @@ static struct frr_signal_t watchfrr_signals[] = { }, }; +/* clang-format off */ FRR_DAEMON_INFO(watchfrr, WATCHFRR, - .flags = FRR_NO_PRIVSEP | FRR_NO_TCPVTY | FRR_LIMITED_CLI - | FRR_NO_CFG_PID_DRY | FRR_NO_ZCLIENT - | FRR_DETACH_LATER, + .flags = FRR_NO_PRIVSEP | FRR_NO_TCPVTY | FRR_LIMITED_CLI + | FRR_NO_CFG_PID_DRY | FRR_NO_ZCLIENT | FRR_DETACH_LATER, - .printhelp = printhelp, - .copyright = "Copyright 2004 Andrew J. Schorr", + .printhelp = printhelp, + .copyright = "Copyright 2004 Andrew J. Schorr", - .signals = watchfrr_signals, - .n_signals = array_size(watchfrr_signals), + .signals = watchfrr_signals, + .n_signals = array_size(watchfrr_signals), - .privs = &watchfrr_privs, + .privs = &watchfrr_privs, ); +/* clang-format on */ #define DEPRECATED_OPTIONS "aAezR:" diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c index 3afc76761d3e..95a7962ec6c4 100644 --- a/watchfrr/watchfrr_vty.c +++ b/watchfrr/watchfrr_vty.c @@ -6,6 +6,8 @@ */ #include + +#include #include #include "memory.h" @@ -16,6 +18,8 @@ #include "watchfrr.h" +#include "lib/config_paths.h" + pid_t integrated_write_pid; static int integrated_result_fd; diff --git a/yang/confd/confd.frr-ripd.yang b/yang/confd/confd.frr-ripd.yang deleted file mode 100644 index 7bbe54cca9db..000000000000 --- a/yang/confd/confd.frr-ripd.yang +++ /dev/null @@ -1,24 +0,0 @@ -module confd.frr-ripd { - namespace "urn:dummy"; - prefix "dummy"; - - import tailf-common { - prefix tailf; - } - import frr-ripd { - prefix frr-ripd; - } - - tailf:annotate-module "frr-ripd" { - tailf:annotate-statement "container[name='ripd']" { - tailf:annotate-statement "list[name='instance']" { - tailf:annotate-statement "container[name='state']" { - tailf:callpoint "state"; - } - } - } - tailf:annotate-statement "rpc[name='clear-rip-route']" { - tailf:actionpoint "actionpoint"; - } - } -} diff --git a/yang/confd/confd.frr-ripngd.yang b/yang/confd/confd.frr-ripngd.yang deleted file mode 100644 index 83383fb4544b..000000000000 --- a/yang/confd/confd.frr-ripngd.yang +++ /dev/null @@ -1,24 +0,0 @@ -module confd.frr-ripngd { - namespace "urn:dummy"; - prefix "dummy"; - - import tailf-common { - prefix tailf; - } - import frr-ripngd { - prefix frr-ripngd; - } - - tailf:annotate-module "frr-ripngd" { - tailf:annotate-statement "container[name='ripngd']" { - tailf:annotate-statement "list[name='instance']" { - tailf:annotate-statement "container[name='state']" { - tailf:callpoint "state"; - } - } - } - tailf:annotate-statement "rpc[name='clear-ripng-route']" { - tailf:actionpoint "actionpoint"; - } - } -} diff --git a/yang/frr-affinity-map.yang b/yang/frr-affinity-map.yang index c4377e62467f..f1d9e447381f 100644 --- a/yang/frr-affinity-map.yang +++ b/yang/frr-affinity-map.yang @@ -53,12 +53,22 @@ module frr-affinity-map { "Initial revision"; } + typedef affinity-map-ref { + type leafref { + path "/frr-affinity-map:lib/frr-affinity-map:affinity-maps/frr-affinity-map:affinity-map/frr-affinity-map:name"; + require-instance true; + } + description + "Reference to an affinity map"; + } + container lib { container affinity-maps { description "Affinity Mapping Table"; list affinity-map { key "name"; + unique "value"; description "Affinity Mapping configuration"; leaf name { @@ -69,6 +79,7 @@ module frr-affinity-map { "Affinity Name"; } leaf value { + mandatory true; type uint16 { range "0..1023"; } diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index ffba42b53b9a..02ed9214599f 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -16,9 +16,6 @@ module frr-bfdd { import frr-vrf { prefix frr-vrf; } - import frr-route-types { - prefix frr-route-types; - } organization "FRRouting"; contact diff --git a/yang/frr-bgp-common-multiprotocol.yang b/yang/frr-bgp-common-multiprotocol.yang index c22bdf996473..72e9d0197d5b 100644 --- a/yang/frr-bgp-common-multiprotocol.yang +++ b/yang/frr-bgp-common-multiprotocol.yang @@ -204,5 +204,15 @@ submodule frr-bgp-common-multiprotocol { description "IPv6 flowspec configuration options."; } + + container ipv4-rtc { + when "derived-from-or-self(../afi-safi-name, 'frr-rt:ipv4-rtc')" { + description + "Include this container for ipv4-rtc specific + configuration."; + } + description + "IPv4 RTC configuration options."; + } } } diff --git a/yang/frr-bgp-neighbor.yang b/yang/frr-bgp-neighbor.yang index 5a4c37974f40..b199ab94694b 100644 --- a/yang/frr-bgp-neighbor.yang +++ b/yang/frr-bgp-neighbor.yang @@ -76,7 +76,7 @@ submodule frr-bgp-neighbor { leaf enforce-first-as { type boolean; - default "false"; + default "true"; description "When set to 'true' it will enforce the first AS for EBGP routes."; } diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index 05fe57c7d7cc..abfb14c23cec 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -379,6 +379,7 @@ identity set-extcommunity-color { grouping extcommunity-non-transitive-types { leaf two-octet-as-specific { type boolean; + default false; description "Non-Transitive Two-Octet AS-Specific Extended Community"; } @@ -541,7 +542,7 @@ identity set-extcommunity-color { augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:rmap-match-condition/frr-route-map:match-condition" { case local-preference { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-local-preference')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-local-preference')"; leaf local-preference { type uint32 { range "0..4294967295"; @@ -550,21 +551,21 @@ identity set-extcommunity-color { } case alias { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-alias')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-alias')"; leaf alias { type string; } } case script { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-script')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-script')"; leaf script { type string; } } case origin { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-origin')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-origin')"; leaf origin { type enumeration { enum "egp" { @@ -587,7 +588,7 @@ identity set-extcommunity-color { } case rpki { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:rpki')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:rpki')"; leaf rpki { type enumeration { enum "invalid" { @@ -633,7 +634,7 @@ identity set-extcommunity-color { } case probability { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:probability')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:probability')"; leaf probability { type uint8 { range "0..100"; @@ -642,14 +643,14 @@ identity set-extcommunity-color { } case source-vrf { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:source-vrf')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:source-vrf')"; leaf source-vrf { type string; } } case peer { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:peer')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:peer')"; choice peer { description "Value of the peer"; @@ -688,10 +689,10 @@ identity set-extcommunity-color { } case access-list-name { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:mac-address-list') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:as-path-list') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:ip-route-source') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:ip-route-source-prefix-list')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:mac-address-list') or " + + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:as-path-list') or " + + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:ip-route-source') or " + + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:ip-route-source-prefix-list')"; description "Access-list name"; leaf list-name { @@ -700,7 +701,7 @@ identity set-extcommunity-color { } case evpn-default-route { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:evpn-default-route')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:evpn-default-route')"; description "Match default EVPN type-5 route"; leaf evpn-default-route { @@ -709,7 +710,7 @@ identity set-extcommunity-color { } case evpn-vni { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:evpn-vni')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:evpn-vni')"; description "Match eVPN VNI"; leaf evpn-vni { @@ -720,7 +721,7 @@ identity set-extcommunity-color { } case evpn-route-type { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:evpn-route-type')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:evpn-route-type')"; description "Match eVPN route-type"; leaf evpn-route-type { @@ -755,7 +756,7 @@ identity set-extcommunity-color { } case evpn-rd { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:evpn-rd')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:evpn-rd')"; description "Match eVPN route-distinguisher"; leaf route-distinguisher { @@ -764,11 +765,12 @@ identity set-extcommunity-color { } case comm-list-name { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-community') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-large-community') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-extcommunity')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-community') or " + + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-large-community') or " + + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-extcommunity')"; container comm-list { leaf comm-list-name { + mandatory true; type bgp-filter:bgp-list-name; } @@ -777,11 +779,18 @@ identity set-extcommunity-color { description "Do exact matching of communities"; } + + leaf comm-list-name-any { + type boolean; + description + "Do matching of any community"; + } + } } case ipv4-address { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:ipv4-nexthop')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:ipv4-nexthop')"; leaf ipv4-address { type inet:ipv4-address; description @@ -790,7 +799,7 @@ identity set-extcommunity-color { } case ipv6-address { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:ipv6-nexthop')"; + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:ipv6-nexthop')"; leaf ipv6-address { type inet:ipv6-address; description @@ -808,7 +817,7 @@ identity set-extcommunity-color { augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { case distance { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:distance')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:distance')"; leaf distance { type uint8 { range "1..255"; @@ -817,7 +826,7 @@ identity set-extcommunity-color { } case extcommunity-none { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-none')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-none')"; description "Value of the BGP extended community attribute"; leaf extcommunity-none { @@ -827,7 +836,7 @@ identity set-extcommunity-color { } case extcommunity-rt { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-rt')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-rt')"; description "Value of the ext-community"; leaf extcommunity-rt { @@ -849,7 +858,7 @@ identity set-extcommunity-color { } case extcommunity-soo { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-soo')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-soo')"; description "Value of the ext-community"; leaf extcommunity-soo { @@ -860,19 +869,19 @@ identity set-extcommunity-color { } case extcommunity-lb { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-lb')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-lb')"; container extcommunity-lb { description "Value of the ext-community."; leaf lb-type { + mandatory true; type frr-bgp-route-map:extcommunity-lb-type; } leaf bandwidth { when "../lb-type = 'explicit-bandwidth'"; - type uint16 { - range "1..25600"; - } + mandatory true; + type uint32; description "Bandwidth value in Mbps"; } @@ -881,7 +890,7 @@ identity set-extcommunity-color { } case extcommunity-color { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-color')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-color')"; description "Value of the ext-community"; leaf extcommunity-color { @@ -894,7 +903,7 @@ identity set-extcommunity-color { } case ipv4-address { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:ipv4-vpn-address')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:ipv4-vpn-address')"; description "Set the IPv4 address"; leaf ipv4-address { @@ -903,15 +912,15 @@ identity set-extcommunity-color { } case ipv4-nexthop { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-ipv4-nexthop')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-ipv4-nexthop')"; leaf ipv4-nexthop { type string; } } case ipv6-address { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:ipv6-nexthop-global') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:ipv6-vpn-address')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:ipv6-nexthop-global') or " + + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:ipv6-vpn-address')"; description "Set the IPv6 address"; leaf ipv6-address { @@ -920,15 +929,15 @@ identity set-extcommunity-color { } case preference { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:ipv6-prefer-global') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:ipv6-peer-address')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:ipv6-prefer-global') or " + + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:ipv6-peer-address')"; leaf preference { type boolean; } } case label-index { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:label-index')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:label-index')"; leaf label-index { type uint32 { range "0..1048560"; @@ -937,14 +946,14 @@ identity set-extcommunity-color { } case local-pref { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-local-preference')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-local-preference')"; leaf local-pref { type string; } } case weight { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:weight')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:weight')"; leaf weight { type uint32 { range "0..4294967295"; @@ -953,7 +962,7 @@ identity set-extcommunity-color { } case origin { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-origin')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-origin')"; leaf origin { type enumeration { enum "egp" { @@ -976,14 +985,14 @@ identity set-extcommunity-color { } case originator-id { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:originator-id')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:originator-id')"; leaf originator-id { type inet:ipv4-address; } } case table { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:table')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:table')"; leaf table { type uint32 { range "1..4294967295"; @@ -992,7 +1001,7 @@ identity set-extcommunity-color { } case atomic-aggregate { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:atomic-aggregate')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:atomic-aggregate')"; leaf atomic-aggregate { type empty; } @@ -1008,7 +1017,7 @@ identity set-extcommunity-color { } case as-path-prepend { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:as-path-prepend')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:as-path-prepend')"; choice as-path-prepend { description "Value of the BGP AS-path attribute"; @@ -1033,7 +1042,7 @@ identity set-extcommunity-color { } case as-path-exclude { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:as-path-exclude')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:as-path-exclude')"; leaf exclude-as-path { type string; description @@ -1042,7 +1051,7 @@ identity set-extcommunity-color { } case as-path-replace { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:as-path-replace')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:as-path-replace')"; leaf replace-as-path { type string; description @@ -1051,7 +1060,7 @@ identity set-extcommunity-color { } case community { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-community')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-community')"; choice community { description "Value of the BGP community attribute"; @@ -1074,7 +1083,7 @@ identity set-extcommunity-color { } case large-community { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-large-community')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-large-community')"; choice large-community { description "Value of the BGP large-community attribute"; @@ -1097,16 +1106,18 @@ identity set-extcommunity-color { } case aggregator { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:aggregator')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:aggregator')"; container aggregator { leaf aggregator-asn { type asn-type; + mandatory true; description "ASN of the aggregator"; } leaf aggregator-address { type inet:ipv4-address; + mandatory true; description "IPv4 address of the aggregator"; } @@ -1114,9 +1125,9 @@ identity set-extcommunity-color { } case comm-list-name { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:comm-list-delete') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:large-comm-list-delete') or " - + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:comm-list-delete') or " + + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:large-comm-list-delete') or " + + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:extended-comm-list-delete')"; leaf comm-list-name { type bgp-filter:bgp-list-name; @@ -1144,7 +1155,7 @@ identity set-extcommunity-color { } case l3vpn-nexthop-encapsulation { when - "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-l3vpn-nexthop-encapsulation')"; description "Accept L3VPN traffic over other than LSP encapsulation"; diff --git a/yang/frr-bgp.yang b/yang/frr-bgp.yang index b34fd43e78de..07ed4bcc765c 100644 --- a/yang/frr-bgp.yang +++ b/yang/frr-bgp.yang @@ -819,6 +819,17 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/neighbor/afi-safis/afi-safi/ipv4-rtc" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-unicast" { uses structure-neighbor-group-add-paths; @@ -1090,6 +1101,16 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-rtc" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-unicast" { uses structure-neighbor-group-add-paths; @@ -1366,4 +1387,14 @@ module frr-bgp { uses structure-neighbor-group-filter-config; } + + augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-rtc" { + uses structure-neighbor-route-reflector; + + uses structure-neighbor-route-server; + + uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; + } } diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index e9071c897199..d3d9db2f62a3 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -22,6 +22,9 @@ module frr-eigrpd { import frr-route-types { prefix frr-route-types; } + import frr-filter { + prefix frr-filter; + } organization "FRRouting"; contact @@ -72,7 +75,7 @@ module frr-eigrpd { typedef autonomous-system { description "Administrative domain identification for a network"; type uint16 { - range 1..65535; + range "1..65535"; } } @@ -224,6 +227,8 @@ module frr-eigrpd { type inet:ipv4-address; } + uses frr-filter:distribute-list-group; + list redistribute { description "Redistribute routes learned from other routing protocols"; diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang index a1946d834240..9b65fcc0255a 100644 --- a/yang/frr-filter.yang +++ b/yang/frr-filter.yang @@ -10,6 +10,9 @@ module frr-filter { import ietf-yang-types { prefix yang; } + import frr-interface { + prefix frr-interface; + } organization "FRRouting"; contact @@ -45,35 +48,95 @@ module frr-filter { revision 2019-07-04 { description "Initial revision"; + reference "FRRouting"; } /* * Types. */ typedef access-list-name { - description "Access list name formatting"; type string { length 1..128; } + description "Access list name formatting"; } typedef access-list-sequence { - description "Access list sequence number"; type uint32 { range "1..4294967295"; } + description "Access list sequence number"; } typedef access-list-action { - description "Access list return action on match"; type enumeration { enum deny { - description "Deny an entry"; value 0; + description "Deny an entry"; } enum permit { - description "Accept an entry"; value 1; + description "Accept an entry"; + } + } + description "Access list return action on match"; + } + + typedef access-list-ref { + type leafref { + path "/frr-filter:lib/frr-filter:access-list/frr-filter:name"; + require-instance false; + } + description "IPv4 or IPv6 access list reference"; + } + + typedef prefix-list-ref { + type leafref { + path "/frr-filter:lib/frr-filter:prefix-list/frr-filter:name"; + require-instance false; + } + description "IPv4 or IPv6 prefix list reference"; + } + + /* + * Grouping. + */ + grouping distribute-list-group { + description "Distribute list grouping"; + list distribute-list { + key "interface"; + description "Distribute list configuration"; + + leaf interface { + type union { + type frr-interface:interface-ref; + type empty; + } + description + "Interface to attach list to or empty for global."; + } + + container in { + description "Inbound filter list"; + leaf access-list { + type access-list-ref; + description "inbound access list"; + } + leaf prefix-list { + type prefix-list-ref; + description "inbound prefix list"; + } + } + container out { + description "Outbound filter list"; + leaf access-list { + type access-list-ref; + description "outbound access list"; + } + leaf prefix-list { + type prefix-list-ref; + description "outbound prefix list"; + } } } } @@ -82,77 +145,74 @@ module frr-filter { * Configuration data. */ container lib { + description "Filter library"; list access-list { - description "Access list instance"; - key "type name"; + description "Access list instance"; leaf type { - description "Access list content type"; type enumeration { enum ipv4 { - description "Internet Protocol address version 4"; - value 0; - } - enum ipv6 { - description "Internet Protocol address version 6"; - value 1; + value 0; + description "Internet Protocol address version 4"; + } + enum ipv6 { + value 1; + description "Internet Protocol address version 6"; } enum mac { - description "Media Access Control address"; value 2; + description "Media Access Control address"; } } + description "Access list content type"; } leaf name { - description "Access list name"; type access-list-name; + description "Access list name"; } leaf remark { - description "Access list remark"; type string; + description "Access list remark"; } list entry { - description "Access list entry"; - key "sequence"; - + description "Access list entry"; leaf sequence { - description "Access list sequence value"; type access-list-sequence; + description "Access list sequence value"; } - leaf action { - description "Access list action on match"; type access-list-action; mandatory true; + description "Access list action on match"; } choice value { - description "Access list value to match"; mandatory true; + description "Access list value to match"; case ipv4-prefix { when "../type = 'ipv4'"; choice style { - description "Access list entry style selection: zebra or cisco."; mandatory true; + description "Access list entry style selection: zebra or cisco."; case zebra { leaf ipv4-prefix { - description "Configure IPv4 prefix to match"; type inet:ipv4-prefix; mandatory true; + description "Configure IPv4 prefix to match"; } leaf ipv4-exact-match { - description "Exact match of prefix"; type boolean; default false; + description "Exact match of prefix"; } } case cisco { @@ -160,19 +220,20 @@ module frr-filter { description "Source value to match"; leaf host { - description "Host to match"; type inet:ipv4-address; + description "Host to match"; } container network { + description "Network to match"; leaf address { + type inet:ipv4-address; mandatory true; description "Network address part."; - type inet:ipv4-address; } leaf mask { + type inet:ipv4-address; mandatory true; description "Network mask/wildcard part."; - type inet:ipv4-address; } } leaf source-any { @@ -180,8 +241,8 @@ module frr-filter { * Was `any`, however it conflicts with `any` leaf * outside this choice. */ - description "Match any"; type empty; + description "Match any"; } } @@ -189,24 +250,25 @@ module frr-filter { description "Destination value to match"; leaf destination-host { - description "Host to match"; type inet:ipv4-address; + description "Host to match"; } container destination-network { + description "Destination network to match"; leaf address { + type inet:ipv4-address; mandatory true; description "Network address part."; - type inet:ipv4-address; } leaf mask { + type inet:ipv4-address; mandatory true; description "Network mask/wildcard part."; - type inet:ipv4-address; } } leaf destination-any { - description "Match any"; type empty; + description "Match any"; } } } @@ -216,29 +278,29 @@ module frr-filter { when "../type = 'ipv6'"; leaf ipv6-prefix { - description "Configure IPv6 prefix to match"; type inet:ipv6-prefix; mandatory true; + description "Configure IPv6 prefix to match"; } leaf ipv6-exact-match { - description "Exact match of prefix"; type boolean; default false; + description "Exact match of prefix"; } } case mac { when "../type = 'mac'"; leaf mac { - description "Configure MAC address to match"; type yang:mac-address; + description "Configure MAC address to match"; } } case any { leaf any { - description "Match anything"; type empty; + description "Match anything"; } } } @@ -246,108 +308,104 @@ module frr-filter { } list prefix-list { - description "Prefix list instance"; - key "type name"; - + description "Prefix list instance"; leaf type { - description "Prefix list type"; type enumeration { enum ipv4 { - description "Internet Protocol address version 4"; value 0; + description "Internet Protocol address version 4"; } enum ipv6 { - description "Internet Protocol address version 6"; value 1; + description "Internet Protocol address version 6"; } } + description "Prefix list type"; } leaf name { - description "Prefix list name"; type access-list-name; + description "Prefix list name"; } leaf remark { - description "Prefix list user description"; type string; + description "Prefix list user description"; } list entry { - description "Prefix list entry"; - key "sequence"; - + description "Prefix list entry"; leaf sequence { - description "Prefix list sequence value"; type access-list-sequence; + description "Prefix list sequence value"; } leaf action { - description "Prefix list action on match"; type access-list-action; mandatory true; + description "Prefix list action on match"; } choice value { - description "Prefix list value to match"; mandatory true; + description "Prefix list value to match"; case ipv4-prefix { leaf ipv4-prefix { - description "Configure IPv4 prefix to match"; type inet:ipv4-prefix; mandatory true; + description "Configure IPv4 prefix to match"; } leaf ipv4-prefix-length-greater-or-equal { - description - "Specifies if matching prefixes with length greater than - or equal to value"; type uint8 { range "0..32"; } + description + "Specifies if matching prefixes with length greater than + or equal to value"; } leaf ipv4-prefix-length-lesser-or-equal { - description - "Specifies if matching prefixes with length lesser than - or equal to value"; type uint8 { range "0..32"; } + description + "Specifies if matching prefixes with length lesser than + or equal to value"; } } case ipv6-prefix { leaf ipv6-prefix { - description "Configure IPv6 prefix to match"; type inet:ipv6-prefix; mandatory true; + description "Configure IPv6 prefix to match"; } leaf ipv6-prefix-length-greater-or-equal { - description - "Specifies if matching prefixes with length greater than - or equal to value"; type uint8 { range "0..128"; } + description + "Specifies if matching prefixes with length greater than + or equal to value"; } leaf ipv6-prefix-length-lesser-or-equal { - description - "Specifies if matching prefixes with length lesser than - or equal to value"; type uint8 { range "0..128"; } + description + "Specifies if matching prefixes with length lesser than + or equal to value"; } } case any { leaf any { - description "Match anything"; type empty; + description "Match anything"; } } } diff --git a/yang/frr-gmp.yang b/yang/frr-gmp.yang index c8a05a2bdba7..e6a1f7f640bb 100644 --- a/yang/frr-gmp.yang +++ b/yang/frr-gmp.yang @@ -147,10 +147,10 @@ module frr-gmp { expected packet loss on a network."; } - list static-group { + list join-group { key "group-addr source-addr"; description - "A static multicast route, (*,G) or (S,G). + "A static GMP join, (*,G) or (S,G). The version of IGMP must be 3 to support (S,G)."; leaf group-addr { @@ -164,6 +164,23 @@ module frr-gmp { "Multicast source address."; } } + + list static-group { + key "group-addr source-addr"; + description + "A static multicast group without GMP, (*,G) or (S,G)."; + + leaf group-addr { + type rt-types:ip-multicast-group-address; + description + "Multicast group address."; + } + leaf source-addr { + type inet:ip-address; + description + "Multicast source address."; + } + } } // interface-config-attributes /* diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index 012c96b6007b..fc5a29090876 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -241,17 +241,18 @@ module frr-interface { } leaf mtu { - type uint16; + type uint32; description - "The size of the largest IPV4 packet that the interface - will send and receive."; + "The size of the largest IPV4 packet that the interface will send. + Normally this will never be larger than 65535; however, some devices + (e.g., vrf) can have larger values"; } leaf mtu6 { type uint32; description "The size of the largest IPV6 packet that the interface - will send and receive."; + will send."; } leaf speed { diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 5d7c739c05d2..60914b0be961 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -685,7 +685,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-1 metric for this IS-IS circuit."; @@ -695,7 +695,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide'"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-2 metric for this IS-IS circuit."; diff --git a/yang/frr-ospf-route-map.yang b/yang/frr-ospf-route-map.yang index ad7ba5c1ba2f..6e7c85dc962a 100644 --- a/yang/frr-ospf-route-map.yang +++ b/yang/frr-ospf-route-map.yang @@ -32,7 +32,7 @@ module frr-ospf-route-map { augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { case metric-type { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'metric-type')"; + when "derived-from-or-self(../frr-route-map:action, 'metric-type')"; leaf metric-type { type enumeration { enum "type-1" { diff --git a/yang/frr-ospf6-route-map.yang b/yang/frr-ospf6-route-map.yang index e5d4969d45d8..7e2e56de0f13 100644 --- a/yang/frr-ospf6-route-map.yang +++ b/yang/frr-ospf6-route-map.yang @@ -38,7 +38,7 @@ module frr-ospf6-route-map { augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { case ipv6-address { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'forwarding-address')"; + when "derived-from-or-self(../frr-route-map:action, 'forwarding-address')"; leaf ipv6-address { type inet:ipv6-address; } diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index e9b3f675073d..6a6c52185ddb 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -5,6 +5,10 @@ module frr-pim { prefix frr-pim; + import frr-filter { + prefix frr-filter; + } + import frr-interface { prefix frr-interface; } @@ -118,6 +122,37 @@ module frr-pim { } } + grouping msdp-authentication { + description + "MSDP authentication options."; + + leaf authentication-type { + type enumeration { + enum None { + value 0; + description + "No authentication."; + } + enum MD5 { + value 1; + description + "Use MD5 digest."; + } + } + default None; + description + "Authentication method."; + } + + leaf authentication-key { + when "../authentication-type = 'MD5'"; + mandatory true; + type string; + description + "Authentication key."; + } + } + grouping global-pim-config-attributes { description "A grouping defining per address family pim global attributes"; @@ -267,6 +302,20 @@ module frr-pim { description "MSDP source IP address."; } + + leaf sa-filter-in { + type frr-filter:access-list-name; + description + "Access list name used to filter the incoming SAs exchanged."; + } + + leaf sa-filter-out { + type frr-filter:access-list-name; + description + "Access list name used to filter the outgoing SAs exchanged."; + } + + uses msdp-authentication; } container mlag { @@ -422,9 +471,7 @@ module frr-pim { } leaf dr-priority { - type uint32 { - range "1..max"; - } + type uint32; default 1; description "DR (Designated Router) priority"; diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang index 5f85a4cabc1b..d65ee489633f 100644 --- a/yang/frr-ripd.yang +++ b/yang/frr-ripd.yang @@ -16,6 +16,9 @@ module frr-ripd { import frr-bfdd { prefix frr-bfdd; } + import frr-filter { + prefix frr-filter; + } import frr-interface { prefix frr-interface; } @@ -258,6 +261,9 @@ module frr-ripd { "A list of interfaces where the sending of RIP packets is enabled."; } + + uses frr-filter:distribute-list-group; + list redistribute { key "protocol"; description @@ -380,9 +386,9 @@ module frr-ripd { } leaf default-bfd-profile { + type frr-bfdd:profile-ref; description "Use this BFD profile for all peers by default."; - type frr-bfdd:profile-ref; } /* @@ -691,12 +697,13 @@ module frr-ripd { container bfd-monitoring { presence "Present if BFD is configured for RIP peers in this interface."; + description "Configure BFD use in RIPD"; leaf enable { type boolean; + default false; description "Enable/disable BFD monitoring."; - default false; } leaf profile { diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang index 4aeaf3640075..383b45fa4a51 100644 --- a/yang/frr-ripngd.yang +++ b/yang/frr-ripngd.yang @@ -13,6 +13,9 @@ module frr-ripngd { import frr-if-rmap { prefix frr-if-rmap; } + import frr-filter { + prefix frr-filter; + } import frr-interface { prefix frr-interface; } @@ -63,6 +66,7 @@ module frr-ripngd { description "Changed interface references to use frr-interface:interface-ref typedef"; + reference "FRRouting"; } revision 2018-11-27 { description @@ -72,6 +76,7 @@ module frr-ripngd { } container ripngd { + description "ripng routing instance data"; /* * Routing instance configuration. */ @@ -169,15 +174,18 @@ module frr-ripngd { "A list of interfaces where the sending of RIPng packets is disabled."; } + + uses frr-filter:distribute-list-group; + list redistribute { key "protocol"; description "Redistributes routes learned from other routing protocols."; leaf protocol { type frr-route-types:frr-route-types-v6; + must '. != "ripng"'; description "Routing protocol."; - must '. != "ripng"'; } leaf route-map { type frr-route-map:route-map-ref; @@ -330,6 +338,7 @@ module frr-ripngd { * Per-interface configuration data */ augment "/frr-interface:lib/frr-interface:interface" { + description "RIPng interface augmentation."; container ripng { description "RIPng interface parameters."; diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 7cb13b60f2fc..c875a6ec7f05 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -268,7 +268,7 @@ module frr-route-map { when "derived-from-or-self(../condition, 'match-tag')"; leaf tag { type uint32 { - range "1..4294967295"; + range "0..4294967295"; } } } @@ -360,16 +360,16 @@ module frr-route-map { case set-min-metric { when "derived-from-or-self(../action, 'set-min-metric')"; - choice minimun-metric-value { + choice minimum-metric-value { description - "Mimimum metric to set or use"; + "Minimum metric to set or use"; case min-metric { leaf min-metric { type uint32 { range "0..4294967295"; } description - "Use the following mimumn metric value"; + "Use the following minimum metric value"; } } } diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang index 728607cabe64..aa676cebc203 100644 --- a/yang/frr-route-types.yang +++ b/yang/frr-route-types.yang @@ -54,44 +54,47 @@ module frr-route-types { enum connected { value 2; } - enum static { + enum local { value 3; } - enum rip { + enum static { value 4; } + enum rip { + value 5; + } enum ospf { - value 6; + value 7; } enum isis { - value 8; + value 9; } enum bgp { - value 9; + value 10; } enum eigrp { - value 11; + value 12; } enum nhrp { - value 12; + value 13; } enum table { - value 15; + value 16; } enum vnc { - value 17; + value 18; } enum vnc-direct { - value 18; + value 19; } enum babel { - value 22; + value 23; } enum sharp { - value 23; + value 24; } enum openfabric { - value 26; + value 27; } } } @@ -104,41 +107,44 @@ module frr-route-types { enum connected { value 2; } - enum static { + enum local { value 3; } + enum static { + value 4; + } enum ripng { - value 5; + value 6; } enum ospf6 { - value 7; + value 8; } enum isis { - value 8; + value 9; } enum bgp { - value 9; + value 10; } enum nhrp { - value 12; + value 13; } enum table { - value 15; + value 16; } enum vnc { - value 17; + value 18; } enum vnc-direct { - value 18; + value 19; } enum babel { - value 22; + value 23; } enum sharp { - value 23; + value 24; } enum openfabric { - value 26; + value 27; } } } diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang index b304c241a41c..78abef168068 100644 --- a/yang/frr-routing.yang +++ b/yang/frr-routing.yang @@ -172,6 +172,13 @@ module frr-routing { } + identity ipv4-rtc { + base afi-safi-type; + description + "This identity represents the ipv4-rtc address family."; + } + + identity control-plane-protocol { description "Base identity from which control-plane protocol identities are diff --git a/yang/frr-test-module.yang b/yang/frr-test-module.yang index d6e718824068..dcf204a95656 100644 --- a/yang/frr-test-module.yang +++ b/yang/frr-test-module.yang @@ -80,6 +80,41 @@ module frr-test-module { } } } + action ping { + input { + leaf data { + type string; + } + } + output { + leaf vrf { + type string; + } + // can't use the same name in input and output + // because of a bug in libyang < 2.1.148 + leaf data-out { + type string; + } + } + } + } + } + choice achoice { + description "a choice statement"; + case case1 { + leaf c1value { + type uint8; + description "A uint8 value for case 1"; + } + } + case case2 { + container c2cont { + description "case 2 container"; + leaf c2value { + type uint32; + description "A uint32 value for case 2"; + } + } } } } diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 3c6e45126a16..1c7d1c8ef4dc 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -81,6 +81,16 @@ module frr-zebra { "Initial revision."; } + feature ipv6-router-advertisements { + description + "Support for IPv6 Router Advertisements."; + } + + feature ptm-bfd { + description + "Using an external PTM daemon that implements BFD."; + } + typedef unix-timestamp { type uint32; units "seconds"; @@ -135,16 +145,16 @@ module frr-zebra { "Zebra interface type bond."; } - identity zif-bond-slave { + identity zif-macvlan { base zebra-interface-type; description - "Zebra interface type bond slave."; + "Zebra interface type macvlan."; } - identity zif-macvlan { + identity zif-gre { base zebra-interface-type; description - "Zebra interface type macvlan."; + "Zebra interface type gre."; } /* @@ -616,6 +626,7 @@ module frr-zebra { leaf table-id { type uint32; + default "254"; description "Routing Table id (default id - 254)."; } @@ -1935,19 +1946,23 @@ module frr-zebra { description "Extends interface model with Zebra-related parameters."; container zebra { - list ip-addrs { - key "address-family ip-prefix"; + list ipv4-addrs { + key "ip prefix-length"; description - "IP prefixes for an interface."; - uses frr-rt:address-family { + "The list of configured IPv4 addresses on the interface."; + + leaf ip { + type inet:ipv4-address-no-zone; description - "Address family of the RIB."; + "The IPv4 address on the interface."; } - leaf ip-prefix { - type inet:ip-prefix; + leaf prefix-length { + type uint8 { + range "0..32"; + } description - "IP address prefix."; + "The length of the subnet prefix."; } leaf label { @@ -1955,12 +1970,57 @@ module frr-zebra { description "Optional string label for the address."; } + } + + list ipv4-p2p-addrs { + key "ip peer-ip peer-prefix-length"; + description + "The list of configured peer-to-peer IPv4 addresses on the interface."; - leaf ip4-peer { - when "derived-from-or-self(../address-family, 'frr-rt:ipv4')"; - type inet:ipv4-prefix; + leaf ip { + type inet:ipv4-address-no-zone; description - "Peer prefix, for peer-to-peer interfaces."; + "The IPv4 address on the interface."; + } + + leaf peer-ip { + type inet:ipv4-address-no-zone; + description + "Peer address."; + } + + leaf peer-prefix-length { + type uint8 { + range "0..32"; + } + description + "The length of the peer subnet prefix."; + } + + leaf label { + type string; + description + "Optional string label for the address."; + } + } + + list ipv6-addrs { + key "ip prefix-length"; + description + "The list of configured IPv6 addresses on the interface."; + + leaf ip { + type inet:ipv6-address-no-zone; + description + "The IPv6 address on the interface."; + } + + leaf prefix-length { + type uint8 { + range "0..128"; + } + description + "The length of the subnet prefix."; } } @@ -1972,11 +2032,12 @@ module frr-zebra { leaf link-detect { type boolean; + default "true"; description "Link-detection for the interface."; } - leaf shutdown { + leaf enabled { type boolean; description "Interface admin status."; @@ -1990,14 +2051,69 @@ module frr-zebra { leaf bandwidth { type uint32 { - range "1..100000"; + range "1..1000000"; } + units "megabits/sec"; description "Link bandwidth informational parameter, in megabits."; } container link-params { + presence "Activates link parameters on this interface."; description "link-params for Traffic-Engineering (TE) use in IGP extensions."; + leaf metric { + type uint32; + description + "Link metric for MPLS-TE purpose."; + } + leaf max-bandwidth { + type rt-types:bandwidth-ieee-float32; + description + "Maximum bandwidth."; + } + leaf max-reservable-bandwidth { + type rt-types:bandwidth-ieee-float32; + description + "Maximum reservable bandwidth."; + } + container unreserved-bandwidths { + description + "All unreserved bandwidths."; + list unreserved-bandwidth { + key "priority"; + leaf priority { + type uint8 { + range "0 .. 7"; + } + description + "Priority from 0 to 7."; + } + leaf unreserved-bandwidth { + type rt-types:bandwidth-ieee-float32; + mandatory true; + description + "Unreserved bandwidth."; + } + description + "List of unreserved bandwidths for different + priorities."; + } + } + leaf residual-bandwidth { + type rt-types:bandwidth-ieee-float32; + description + "Unidirectional residual bandwidth."; + } + leaf available-bandwidth { + type rt-types:bandwidth-ieee-float32; + description + "Unidirectional available bandwidth."; + } + leaf utilized-bandwidth { + type rt-types:bandwidth-ieee-float32; + description + "Unidirectional utilized bandwidth."; + } choice admin-group-mode { description "Admin-group mode"; case legacy { @@ -2011,8 +2127,11 @@ module frr-zebra { case affinity { container affinities { leaf-list affinity { - type string; + type frr-affinity-map:affinity-map-ref; max-elements "256"; + must '../../affinity-mode != "standard" or /frr-affinity-map:lib/frr-affinity-map:affinity-maps/frr-affinity-map:affinity-map[frr-affinity-map:name=current()]/frr-affinity-map:value < 32' { + error-message "Affinity bit-position must be less than 32 when used with standard affinity mode"; + } description "Array of Attribute Names"; } @@ -2041,9 +2160,526 @@ module frr-zebra { } } } + container neighbor { + description "Remote ASBR information (RFC 5316 & RFC 5392)"; + presence "Activates neighbor information on this interface."; + leaf remote-as { + type inet:as-number; + mandatory true; + description + "Remote AS Number (RFC 5316 & RFC 5392)"; + } + leaf ipv4-remote-id { + type inet:ipv4-address; + mandatory true; + description + "IPv4 Remote ASBR ID (RFC 5316 & RFC 5392)"; + } + } + leaf delay { + type uint32 { + range "0..16777215"; + } + description + "Average Unidirectional Link Delay"; + } + container min-max-delay { + description + "Min/Max Unidirectional Link Delay"; + presence "Activates min/max delay."; + leaf delay-min { + type uint32 { + range "0..16777215"; + } + must '. <= ../../delay' { + error-message "Min delay must be less than or equal to delay"; + } + mandatory true; + description + "Min Delay"; + } + leaf delay-max { + type uint32 { + range "0..16777215"; + } + must '. >= ../../delay' { + error-message "Max delay must be greater than or equal to delay"; + } + mandatory true; + description + "Max Delay"; + } + } + leaf delay-variation { + type uint32 { + range "0..16777215"; + } + description + "Unidirectional Delay Variation"; + } + leaf packet-loss { + type decimal64 { + fraction-digits 6; + range "0..50.331642"; + } + description + "Unidirectional Link Packet Loss"; + } // TODO -- other link-params options // for (experimental/partial TE use in IGP extensions) } + container evpn-mh { + description "EVPN multihoming configuration"; + choice esi-choice { + description "ESI type"; + container type-0 { + leaf esi { + type yang:hex-string { + length "29"; + } + description + "10-octet ESI."; + } + } + container type-3 { + leaf system-mac { + type yang:mac-address; + description + "System MAC address."; + } + leaf local-discriminator { + type uint32 { + range "1..16777215"; + } + description + "Local discriminator."; + } + } + } + leaf df-preference { + type uint16; + default "32767"; + description + "Preference value used for DF election."; + } + leaf bypass { + type boolean; + default "false"; + description + "Bypass mode."; + } + leaf uplink { + type boolean; + default "false"; + description + "Uplink to the VxLAN core."; + } + } + container ipv6-router-advertisements { + if-feature "ipv6-router-advertisements"; + description + "Support for IPv6 Router Advertisements."; + leaf send-advertisements { + type boolean; + default "false"; + description + "A flag indicating whether or not the router sends + periodic Router Advertisements and responds to + Router Solicitations."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvSendAdvertisements"; + } + leaf max-rtr-adv-interval { + type uint32 { + range "70..1800000"; + } + units "milliseconds"; + default "600000"; + description + "The maximum time allowed between sending unsolicited + multicast Router Advertisements from the interface."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - MaxRtrAdvInterval + RFC 6275: Mobility Support in IPv6"; + } + // Setting this value is not yet supported by the actual code. + /* + leaf min-rtr-adv-interval { + type uint32 { + range "30..1350000"; + } + units "milliseconds"; + must ". <= 0.75 * ../max-rtr-adv-interval" { + description + "The value MUST NOT be greater than 75% of + 'max-rtr-adv-interval'."; + } + description + "The minimum time allowed between sending unsolicited + multicast Router Advertisements from the interface. + + The default value to be used operationally if this + leaf is not configured is determined as follows: + + - if max-rtr-adv-interval >= 9 seconds, the default + value is 0.33 * max-rtr-adv-interval; + + - otherwise, it is 0.75 * max-rtr-adv-interval."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - MaxRtrAdvInterval + RFC 6275: Mobility Support in IPv6"; + } + */ + leaf managed-flag { + type boolean; + default "false"; + description + "The value to be placed in the 'Managed address + configuration' flag field in the Router + Advertisement."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvManagedFlag"; + } + leaf other-config-flag { + type boolean; + default "false"; + description + "The value to be placed in the 'Other configuration' + flag field in the Router Advertisement."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvOtherConfigFlag"; + } + leaf home-agent-flag { + type boolean; + default "false"; + description + "The value to be placed in the 'Home Agent' + flag field in the Router Advertisement."; + reference + "RFC 6275: Mobility Support in IPv6"; + } + leaf link-mtu { + type uint32; + default "0"; + description + "The value to be placed in MTU options sent by the + router. A value of zero indicates that no MTU options + are sent."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvLinkMTU"; + } + leaf reachable-time { + type uint32 { + range "0..3600000"; + } + units "milliseconds"; + default "0"; + description + "The value to be placed in the Reachable Time field in + the Router Advertisement messages sent by the router. + A value of zero means unspecified (by this router)."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvReachableTime"; + } + leaf retrans-timer { + type uint32; + units "milliseconds"; + default "0"; + description + "The value to be placed in the Retrans Timer field in + the Router Advertisement messages sent by the router. + A value of zero means unspecified (by this router)."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvRetransTimer"; + } + leaf cur-hop-limit { + type uint8; + description + "The value to be placed in the Cur Hop Limit field in + the Router Advertisement messages sent by the router. + A value of zero means unspecified (by this router). + + If this parameter is not configured, the device SHOULD + use the IANA-specified value for the default IPv4 + Time to Live (TTL) parameter that was in effect at the + time of implementation."; + reference + "RFC 3232: Assigned Numbers: RFC 1700 is Replaced by + an On-line Database + RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvCurHopLimit + IANA: IP Parameters + (https://www.iana.org/assignments/ip-parameters)"; + } + leaf default-lifetime { + type uint16 { + range "0..9000"; + } + units "seconds"; + must ". = 0 or . * 1000 >= ../max-rtr-adv-interval" { + description + "The value MUST NOT be less than max-rtr-adv-interval."; + } + description + "The value to be placed in the Router Lifetime field of + Router Advertisements sent from the interface, in + seconds. It MUST be either zero or between + max-rtr-adv-interval and 9000 seconds. A value of zero + indicates that the router is not to be used as a + default router. These limits may be overridden by + specific documents that describe how IPv6 operates over + different link layers. + + If this parameter is not configured, the device SHOULD + use a value of 3 * max-rtr-adv-interval."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvDefaultLifetime"; + } + leaf fast-retransmit { + type boolean; + default "true"; + description + "Allow sending unsolicited multicast Router Advertisements + more frequently than once every 3 seconds as required by + RFC 4861."; + } + leaf advertisement-interval-option { + type boolean; + default "false"; + description + "Enable sending the Advertisement Interval Option in + Router Advertisements."; + reference + "RFC 6275: Mobility Support in IPv6"; + } + leaf home-agent-preference { + type uint16; + description + "The value to be placed in the Home Agent Preference + field in the Router Advertisement messages sent by the + router."; + reference + "RFC 6275: Mobility Support in IPv6"; + } + leaf home-agent-lifetime { + type uint16; + description + "The value to be placed in the Home Agent Lifetime + field in the Router Advertisement messages sent by the + router."; + reference + "RFC 6275: Mobility Support in IPv6"; + } + leaf default-router-preference { + type enumeration { + enum high { + value 1; /* 01 */ + description + "High preference."; + } + enum medium { + value 0; /* 00 */ + description + "Medium preference."; + } + enum low { + value 3; /* 11 */ + description + "Low preference."; + } + } + default "medium"; + description + "The value to be placed in the Default Router + Preference field in the Router Advertisement messages + sent by the router."; + reference + "RFC 4191: Default Router Preferences and More-Specific + Routes"; + } + container prefix-list { + description + "Support for prefixes to be placed in Prefix + Information options in Router Advertisement messages + sent from the interface. + + Prefixes that are advertised by default but do not + have their entries in the child 'prefix' list are + advertised with the default values of all parameters. + + The link-local prefix SHOULD NOT be included in the + list of advertised prefixes."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 (IPv6) + - AdvPrefixList"; + list prefix { + key "prefix-spec"; + description + "Support for an advertised prefix entry."; + leaf prefix-spec { + type inet:ipv6-prefix; + description + "IPv6 address prefix."; + } + // FRR doesn't support 'no-advertise'. Keeping the code + // here for future reference. + /* + choice control-adv-prefixes { + default "advertise"; + description + "Either (1) the prefix is explicitly removed from the + set of advertised prefixes or (2) the parameters with + which the prefix is advertised are specified (default + case)."; + leaf no-advertise { + type empty; + description + "The prefix will not be advertised. + + This can be used for removing the prefix from + the default set of advertised prefixes."; + } + case advertise { + */ + leaf valid-lifetime { + type uint32; + units "seconds"; + default "2592000"; + description + "The value to be placed in the Valid Lifetime + in the Prefix Information option. The + designated value of all 1's (0xffffffff) + represents infinity."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 + (IPv6) - AdvValidLifetime"; + } + leaf on-link-flag { + type boolean; + default "true"; + description + "The value to be placed in the on-link flag + ('L-bit') field in the Prefix Information + option."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 + (IPv6) - AdvOnLinkFlag"; + } + leaf preferred-lifetime { + type uint32; + units "seconds"; + must ". <= ../valid-lifetime" { + description + "This value MUST NOT be greater than + valid-lifetime."; + } + default "604800"; + description + "The value to be placed in the Preferred + Lifetime in the Prefix Information option. + The designated value of all 1's (0xffffffff) + represents infinity."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 + (IPv6) - AdvPreferredLifetime"; + } + leaf autonomous-flag { + type boolean; + default "true"; + description + "The value to be placed in the Autonomous Flag + field in the Prefix Information option."; + reference + "RFC 4861: Neighbor Discovery for IP version 6 + (IPv6) - AdvAutonomousFlag"; + } + leaf router-address-flag { + type boolean; + default "false"; + description + "The value to be placed in the Router Address + flag field in the Prefix Information option."; + reference + "RFC 6275: Mobility Support in IPv6"; + } + /* + } + } + */ + // This is closing brackets for `case advertise` and + // `choice control-adv-prefixes`. + } + } + container rdnss { + description + "A list of recursive DNS server addresses that are placed + in Recursive DNS Server (RDNSS) options in Router + Advertisement messages sent from the interface."; + reference + "RFC 8106: IPv6 Router Advertisement Options for DNS + Configuration"; + list rdnss-address { + key "address"; + description + "Recursive DNS server address."; + leaf address { + type inet:ipv6-address; + description + "IPv6 address of a recursive DNS server."; + } + leaf lifetime { + type uint32; + units "seconds"; + description + "The value that is placed in the Lifetime field in the + RDNSS option. The designated value of all 1's + (0xffffffff) represents infinity."; + } + } + } + container dnssl { + description + "A list of domain names that are placed in DNS Search List (DNSSL) + options in Router Advertisement messages sent from the interface."; + reference + "RFC 8106: IPv6 Router Advertisement Options for DNS + Configuration"; + list dnssl-domain { + key "domain"; + description + "Domain name for the search list."; + leaf domain { + type inet:domain-name; + description + "Domain name for the search list."; + } + leaf lifetime { + type uint32; + units "seconds"; + description + "The value that is placed in the Lifetime field in the + DNSSL option. The designated value of all 1's + (0xffffffff) represents infinity."; + } + } + } + } + leaf ptm-enable { + if-feature ptm-bfd; + type boolean; + default "true"; + description + "Enable PTM on the interface."; + } container state { config false; description @@ -2098,6 +2734,12 @@ module frr-zebra { description "The VNI multicast group for BUM traffic."; } + + leaf bond { + type frr-interface:interface-ref; + description + "The bond interface this interface belongs to."; + } } } } @@ -2108,6 +2750,112 @@ module frr-zebra { container zebra { description "Zebra's vrf specific configuration and operational model."; + + leaf router-id { + type yang:dotted-quad; + description + "A 32-bit number in the form of a dotted quad that is used by + some routing protocols identifying a router."; + } + + leaf ipv6-router-id { + type inet:ipv6-address-no-zone; + description + "A 128-bit number in the form of an IPv6 address that is used by + some routing protocols identifying a router."; + } + + list filter-protocol { + key "afi-safi protocol"; + description + "Filter routing info exchanged between zebra and protocol."; + leaf afi-safi { + type identityref { + base frr-rt:afi-safi-type; + } + description + "AFI-SAFI type."; + } + leaf protocol { + // This should be identityref to frr-rt:control-plane-protocol someday + type string; + description + "The protocol to filter."; + } + leaf route-map { + type frr-route-map:route-map-ref; + mandatory true; + description + "A route-map to filter routes."; + } + } + + list filter-nht { + key "afi-safi protocol"; + description + "Filter next hop tracking route resolution."; + leaf afi-safi { + type identityref { + base frr-rt:afi-safi-type; + } + description + "AFI-SAFI type."; + } + leaf protocol { + // This should be identityref to frr-rt:control-plane-protocol someday + type string; + description + "The protocol to filter."; + } + leaf route-map { + type frr-route-map:route-map-ref; + mandatory true; + description + "A route-map to filter nexthops."; + } + } + + leaf resolve-via-default { + type boolean; + description + "Resolve IPv4 nexthops via the default route. This is true by default + for traditional profile and false by default for datacenter profile. + Removing the leaf sets it back to the default value for the profile."; + } + + leaf ipv6-resolve-via-default { + type boolean; + description + "Resolve IPv4 nexthops via the default route. This is true by default + for traditional profile and false by default for datacenter profile. + Removing the leaf sets it back to the default value for the profile."; + } + + container netns { + description + "Configuration for netns VRF backend."; + container table-range { + presence "Activates table-range configuration."; + description + "The range of tables to use for this netns."; + leaf start { + type uint32; + mandatory true; + description + "The first table to use."; + } + leaf end { + type uint32; + mandatory true; + must ". >= ../start" { + error-message "End table must be greater than or equal to start table"; + } + description + "The last table to use."; + } + } + } + uses ribs; uses vrf-vni-mapping; @@ -2213,6 +2961,22 @@ module frr-zebra { description "Limit on the number of updates queued to the dataplane subsystem."; } + leaf ptm-enable { + if-feature ptm-bfd; + type boolean; + default "false"; + description + "Enable PTM globally."; + } + leaf route-map-delay { + type uint32 { + range "0..600"; + } + units "seconds"; + default "5"; + description + "Time to wait before route-map updates are processed."; + } /* * Debug options */ diff --git a/yang/ietf/frr-deviations-ietf-key-chain.yang b/yang/ietf/frr-deviations-ietf-key-chain.yang new file mode 100644 index 000000000000..aa6a41f8841c --- /dev/null +++ b/yang/ietf/frr-deviations-ietf-key-chain.yang @@ -0,0 +1,29 @@ +module frr-deviations-ietf-key-chain { + yang-version 1.1; + namespace "http://frrouting.org/yang/frr-deviations-ietf-key-chain"; + prefix frr-deviations-ietf-key-chain; + + import ietf-key-chain { + prefix kc; + } + + organization + "FRRouting"; + contact + "FRR Users List: + FRR Development List: "; + description + "This module defines deviation statements for the ietf-key-chain + module."; + + revision 2024-03-03 { + description "Initial revision."; + reference "RFC 8177: YANG Data Model for Key Chains"; + } + + deviation /kc:key-chains/kc:key-chain/kc:key/kc:crypto-algorithm { + deviate replace { + mandatory false; + } + } +} diff --git a/yang/ietf/frr-deviations-ietf-routing.yang b/yang/ietf/frr-deviations-ietf-routing.yang index 15ceb6b92918..5c0ae30beadc 100644 --- a/yang/ietf/frr-deviations-ietf-routing.yang +++ b/yang/ietf/frr-deviations-ietf-routing.yang @@ -6,6 +6,9 @@ module frr-deviations-ietf-routing { import ietf-routing { prefix ietf-routing; } + import ietf-rip { + prefix ietf-rip; + } organization "FRRouting"; diff --git a/yang/ietf/ietf-bgp-types.yang b/yang/ietf/ietf-bgp-types.yang index 9c7a6af76c52..ed64b78ad6c6 100644 --- a/yang/ietf/ietf-bgp-types.yang +++ b/yang/ietf/ietf-bgp-types.yang @@ -333,7 +333,7 @@ module ietf-bgp-types { // TODO: needs more work to make this more precise given the // variability of extended community attribute specifications // 8-octet value: - // 2 octects + // 2 octets // 6 octets type union { diff --git a/yang/ietf/ietf-key-chain.yang b/yang/ietf/ietf-key-chain.yang new file mode 100644 index 000000000000..445d1994a5ac --- /dev/null +++ b/yang/ietf/ietf-key-chain.yang @@ -0,0 +1,382 @@ +module ietf-key-chain { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-key-chain"; + prefix key-chain; + + import ietf-yang-types { + prefix yang; + } + import ietf-netconf-acm { + prefix nacm; + } + + organization + "IETF RTGWG - Routing Area Working Group"; + contact + "WG Web: + WG List: + + Editor: Acee Lindem + + Yingzhen Qu + + Derek Yeung + + Ing-Wher Chen + + Jeffrey Zhang + "; + + description + "This YANG module defines the generic configuration + data for key chains. It is intended that the module + will be extended by vendors to define vendor-specific + key chain configuration parameters. + + Copyright (c) 2017 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8177; + see the RFC itself for full legal notices."; + + reference "RFC 8177"; + + revision 2017-06-15 { + description + "Initial RFC Revision"; + reference "RFC 8177: YANG Data Model for Key Chains"; + } + + feature hex-key-string { + description + "Support hexadecimal key string."; + } + + feature accept-tolerance { + description + "Support the tolerance or acceptance limit."; + } + + feature independent-send-accept-lifetime { + description + "Support for independent send and accept key lifetimes."; + } + + feature crypto-hmac-sha-1-12 { + description + "Support for TCP HMAC-SHA-1 12-byte digest hack."; + } + + feature cleartext { + description + "Support for cleartext algorithm. Usage is + NOT RECOMMENDED."; + } + + feature aes-cmac-prf-128 { + description + "Support for AES Cipher-based Message Authentication + Code Pseudorandom Function."; + } + + feature aes-key-wrap { + description + "Support for Advanced Encryption Standard (AES) Key Wrap."; + } + + feature replay-protection-only { + description + "Provide replay protection without any authentication + as required by protocols such as Bidirectional + Forwarding Detection (BFD)."; + } + identity crypto-algorithm { + description + "Base identity of cryptographic algorithm options."; + } + + identity hmac-sha-1-12 { + base crypto-algorithm; + if-feature "crypto-hmac-sha-1-12"; + description + "The HMAC-SHA1-12 algorithm."; + } + + identity aes-cmac-prf-128 { + base crypto-algorithm; + if-feature "aes-cmac-prf-128"; + description + "The AES-CMAC-PRF-128 algorithm - required by + RFC 5926 for TCP-AO key derivation functions."; + } + + identity md5 { + base crypto-algorithm; + description + "The MD5 algorithm."; + } + + identity sha-1 { + base crypto-algorithm; + description + "The SHA-1 algorithm."; + } + + identity hmac-sha-1 { + base crypto-algorithm; + description + "HMAC-SHA-1 authentication algorithm."; + } + + identity hmac-sha-256 { + base crypto-algorithm; + description + "HMAC-SHA-256 authentication algorithm."; + } + + identity hmac-sha-384 { + base crypto-algorithm; + description + "HMAC-SHA-384 authentication algorithm."; + } + + identity hmac-sha-512 { + base crypto-algorithm; + description + "HMAC-SHA-512 authentication algorithm."; + } + + identity cleartext { + base crypto-algorithm; + if-feature "cleartext"; + description + "cleartext."; + } + + identity replay-protection-only { + base crypto-algorithm; + if-feature "replay-protection-only"; + description + "Provide replay protection without any authentication as + required by protocols such as Bidirectional Forwarding + Detection (BFD)."; + } + + typedef key-chain-ref { + type leafref { + path + "/key-chain:key-chains/key-chain:key-chain/key-chain:name"; + } + description + "This type is used by data models that need to reference + configured key chains."; + } + + grouping lifetime { + description + "Key lifetime specification."; + choice lifetime { + default "always"; + description + "Options for specifying key accept or send lifetimes"; + case always { + leaf always { + type empty; + description + "Indicates key lifetime is always valid."; + } + } + case start-end-time { + leaf start-date-time { + type yang:date-and-time; + description + "Start time."; + } + choice end-time { + default "infinite"; + description + "End-time setting."; + case infinite { + leaf no-end-time { + type empty; + description + "Indicates key lifetime end-time is infinite."; + } + } + case duration { + leaf duration { + type uint32 { + range "1..2147483646"; + } + units "seconds"; + description + "Key lifetime duration, in seconds"; + } + } + case end-date-time { + leaf end-date-time { + type yang:date-and-time; + description + "End time."; + } + } + } + } + } + } + + container key-chains { + description + "All configured key-chains on the device."; + list key-chain { + key "name"; + description + "List of key-chains."; + leaf name { + type string; + description + "Name of the key-chain."; + } + leaf description { + type string; + description + "A description of the key-chain"; + } + container accept-tolerance { + if-feature "accept-tolerance"; + description + "Tolerance for key lifetime acceptance (seconds)."; + leaf duration { + type uint32; + units "seconds"; + default "0"; + description + "Tolerance range, in seconds."; + } + } + leaf last-modified-timestamp { + type yang:date-and-time; + config false; + description + "Timestamp of the most recent update to the key-chain"; + } + list key { + key "key-id"; + description + "Single key in key chain."; + leaf key-id { + type uint64; + description + "Numeric value uniquely identifying the key"; + } + container lifetime { + description + "Specify a key's lifetime."; + choice lifetime { + description + "Options for specification of send and accept + lifetimes."; + case send-and-accept-lifetime { + description + "Send and accept key have the same lifetime."; + container send-accept-lifetime { + description + "Single lifetime specification for both + send and accept lifetimes."; + uses lifetime; + } + } + case independent-send-accept-lifetime { + if-feature "independent-send-accept-lifetime"; + description + "Independent send and accept key lifetimes."; + container send-lifetime { + description + "Separate lifetime specification for send + lifetime."; + uses lifetime; + } + container accept-lifetime { + description + "Separate lifetime specification for accept + lifetime."; + uses lifetime; + } + } + } + } + leaf crypto-algorithm { + type identityref { + base crypto-algorithm; + } + mandatory true; + description + "Cryptographic algorithm associated with key."; + } + container key-string { + description + "The key string."; + nacm:default-deny-all; + choice key-string-style { + description + "Key string styles"; + case keystring { + leaf keystring { + type string; + description + "Key string in ASCII format."; + } + } + case hexadecimal { + if-feature "hex-key-string"; + leaf hexadecimal-string { + type yang:hex-string; + description + "Key in hexadecimal string format. When compared + to ASCII, specification in hexadecimal affords + greater key entropy with the same number of + internal key-string octets. Additionally, it + discourages usage of well-known words or + numbers."; + } + } + } + } + leaf send-lifetime-active { + type boolean; + config false; + description + "Indicates if the send lifetime of the + key-chain key is currently active."; + } + leaf accept-lifetime-active { + type boolean; + config false; + description + "Indicates if the accept lifetime of the + key-chain key is currently active."; + } + } + } + container aes-key-wrap { + if-feature "aes-key-wrap"; + description + "AES Key Wrap encryption for key-chain key-strings. The + encrypted key-strings are encoded as hexadecimal key + strings using the hex-key-string leaf."; + leaf enable { + type boolean; + default "false"; + description + "Enable AES Key Wrap encryption."; + } + } + } +} diff --git a/yang/ietf/ietf-netconf-acm.yang b/yang/ietf/ietf-netconf-acm.yang new file mode 100644 index 000000000000..f7e02f280ef9 --- /dev/null +++ b/yang/ietf/ietf-netconf-acm.yang @@ -0,0 +1,464 @@ +module ietf-netconf-acm { + + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"; + + prefix nacm; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: + WG List: + + Author: Andy Bierman + + + Author: Martin Bjorklund + "; + + description + "Network Configuration Access Control Model. + + Copyright (c) 2012 - 2018 IETF Trust and the persons + identified as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD + License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8341; see + the RFC itself for full legal notices."; + + revision 2018-02-14 { + description + "Added support for YANG 1.1 actions and notifications tied to + data nodes. Clarified how NACM extensions can be used by + other data models."; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + revision 2012-02-22 { + description + "Initial version."; + reference + "RFC 6536: Network Configuration Protocol (NETCONF) + Access Control Model"; + } + + /* + * Extension statements + */ + + extension default-deny-write { + description + "Used to indicate that the data model node + represents a sensitive security system parameter. + + If present, the NETCONF server will only allow the designated + 'recovery session' to have write access to the node. An + explicit access control rule is required for all other users. + + If the NACM module is used, then it must be enabled (i.e., + /nacm/enable-nacm object equals 'true'), or this extension + is ignored. + + The 'default-deny-write' extension MAY appear within a data + definition statement. It is ignored otherwise."; + } + + extension default-deny-all { + description + "Used to indicate that the data model node + controls a very sensitive security system parameter. + + If present, the NETCONF server will only allow the designated + 'recovery session' to have read, write, or execute access to + the node. An explicit access control rule is required for all + other users. + + If the NACM module is used, then it must be enabled (i.e., + /nacm/enable-nacm object equals 'true'), or this extension + is ignored. + + The 'default-deny-all' extension MAY appear within a data + definition statement, 'rpc' statement, or 'notification' + statement. It is ignored otherwise."; + } + + /* + * Derived types + */ + + typedef user-name-type { + type string { + length "1..max"; + } + description + "General-purpose username string."; + } + + typedef matchall-string-type { + type string { + pattern '\*'; + } + description + "The string containing a single asterisk '*' is used + to conceptually represent all possible values + for the particular leaf using this data type."; + } + + typedef access-operations-type { + type bits { + bit create { + description + "Any protocol operation that creates a + new data node."; + } + bit read { + description + "Any protocol operation or notification that + returns the value of a data node."; + } + bit update { + description + "Any protocol operation that alters an existing + data node."; + } + bit delete { + description + "Any protocol operation that removes a data node."; + } + bit exec { + description + "Execution access to the specified protocol operation."; + } + } + description + "Access operation."; + } + + typedef group-name-type { + type string { + length "1..max"; + pattern '[^\*].*'; + } + description + "Name of administrative group to which + users can be assigned."; + } + + typedef action-type { + type enumeration { + enum permit { + description + "Requested action is permitted."; + } + enum deny { + description + "Requested action is denied."; + } + } + description + "Action taken by the server when a particular + rule matches."; + } + + typedef node-instance-identifier { + type yang:xpath1.0; + description + "Path expression used to represent a special + data node, action, or notification instance-identifier + string. + + A node-instance-identifier value is an + unrestricted YANG instance-identifier expression. + All the same rules as an instance-identifier apply, + except that predicates for keys are optional. If a key + predicate is missing, then the node-instance-identifier + represents all possible server instances for that key. + + This XML Path Language (XPath) expression is evaluated in the + following context: + + o The set of namespace declarations are those in scope on + the leaf element where this type is used. + + o The set of variable bindings contains one variable, + 'USER', which contains the name of the user of the + current session. + + o The function library is the core function library, but + note that due to the syntax restrictions of an + instance-identifier, no functions are allowed. + + o The context node is the root node in the data tree. + + The accessible tree includes actions and notifications tied + to data nodes."; + } + + /* + * Data definition statements + */ + + container nacm { + nacm:default-deny-all; + + description + "Parameters for NETCONF access control model."; + + leaf enable-nacm { + type boolean; + default "true"; + description + "Enables or disables all NETCONF access control + enforcement. If 'true', then enforcement + is enabled. If 'false', then enforcement + is disabled."; + } + + leaf read-default { + type action-type; + default "permit"; + description + "Controls whether read access is granted if + no appropriate rule is found for a + particular read request."; + } + + leaf write-default { + type action-type; + default "deny"; + description + "Controls whether create, update, or delete access + is granted if no appropriate rule is found for a + particular write request."; + } + + leaf exec-default { + type action-type; + default "permit"; + description + "Controls whether exec access is granted if no appropriate + rule is found for a particular protocol operation request."; + } + + leaf enable-external-groups { + type boolean; + default "true"; + description + "Controls whether the server uses the groups reported by the + NETCONF transport layer when it assigns the user to a set of + NACM groups. If this leaf has the value 'false', any group + names reported by the transport layer are ignored by the + server."; + } + + leaf denied-operations { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request was denied."; + } + + leaf denied-data-writes { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request to alter + a configuration datastore was denied."; + } + + leaf denied-notifications { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that + a notification was dropped for a subscription because + access to the event type was denied."; + } + + container groups { + description + "NETCONF access control groups."; + + list group { + key name; + + description + "One NACM group entry. This list will only contain + configured entries, not any entries learned from + any transport protocols."; + + leaf name { + type group-name-type; + description + "Group name associated with this entry."; + } + + leaf-list user-name { + type user-name-type; + description + "Each entry identifies the username of + a member of the group associated with + this entry."; + } + } + } + + list rule-list { + key name; + ordered-by user; + description + "An ordered collection of access control rules."; + + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule-list."; + } + leaf-list group { + type union { + type matchall-string-type; + type group-name-type; + } + description + "List of administrative groups that will be + assigned the associated access rights + defined by the 'rule' list. + + The string '*' indicates that all groups apply to the + entry."; + } + + list rule { + key name; + ordered-by user; + description + "One access control rule. + + Rules are processed in user-defined order until a match is + found. A rule matches if 'module-name', 'rule-type', and + 'access-operations' match the request. If a rule + matches, the 'action' leaf determines whether or not + access is granted."; + + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule."; + } + + leaf module-name { + type union { + type matchall-string-type; + type string; + } + default "*"; + description + "Name of the module associated with this rule. + + This leaf matches if it has the value '*' or if the + object being accessed is defined in the module with the + specified module name."; + } + choice rule-type { + description + "This choice matches if all leafs present in the rule + match the request. If no leafs are present, the + choice matches all requests."; + case protocol-operation { + leaf rpc-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if + its value equals the requested protocol operation + name."; + } + } + case notification { + leaf notification-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if its + value equals the requested notification name."; + } + } + + case data-node { + leaf path { + type node-instance-identifier; + mandatory true; + description + "Data node instance-identifier associated with the + data node, action, or notification controlled by + this rule. + + Configuration data or state data + instance-identifiers start with a top-level + data node. A complete instance-identifier is + required for this type of path value. + + The special value '/' refers to all possible + datastore contents."; + } + } + } + + leaf access-operations { + type union { + type matchall-string-type; + type access-operations-type; + } + default "*"; + description + "Access operations associated with this rule. + + This leaf matches if it has the value '*' or if the + bit corresponding to the requested operation is set."; + } + + leaf action { + type action-type; + mandatory true; + description + "The access control action associated with the + rule. If a rule has been determined to match a + particular request, then this object is used + to determine whether to permit or deny the + request."; + } + + leaf comment { + type string; + description + "A textual description of the access rule."; + } + } + } + } +} diff --git a/yang/ietf/ietf-netconf-with-defaults.yang b/yang/ietf/ietf-netconf-with-defaults.yang new file mode 100644 index 000000000000..05ff399fd722 --- /dev/null +++ b/yang/ietf/ietf-netconf-with-defaults.yang @@ -0,0 +1,139 @@ +module ietf-netconf-with-defaults { + + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"; + + prefix ncwd; + + import ietf-netconf { prefix nc; } + + organization + "IETF NETCONF (Network Configuration Protocol) Working Group"; + + contact + "WG Web: + + WG List: + + WG Chair: Bert Wijnen + + + WG Chair: Mehmet Ersue + + + Editor: Andy Bierman + + + Editor: Balazs Lengyel + "; + + description + "This module defines an extension to the NETCONF protocol + that allows the NETCONF client to control how default + values are handled by the server in particular NETCONF + operations. + + Copyright (c) 2011 IETF Trust and the persons identified as + the document authors. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6243; see + the RFC itself for full legal notices."; + + revision 2011-06-01 { + description + "Initial version."; + reference + "RFC 6243: With-defaults Capability for NETCONF"; + } + + typedef with-defaults-mode { + description + "Possible modes to report default data."; + reference + "RFC 6243; Section 3."; + type enumeration { + enum report-all { + description + "All default data is reported."; + reference + "RFC 6243; Section 3.1"; + } + enum report-all-tagged { + description + "All default data is reported. + Any nodes considered to be default data + will contain a 'default' XML attribute, + set to 'true' or '1'."; + reference + "RFC 6243; Section 3.4"; + } + enum trim { + description + "Values are not reported if they contain the default."; + reference + "RFC 6243; Section 3.2"; + } + enum explicit { + description + "Report values that contain the definition of + explicitly set data."; + reference + "RFC 6243; Section 3.3"; + } + } + } + + grouping with-defaults-parameters { + description + "Contains the parameter for control + of defaults in NETCONF retrieval operations."; + + leaf with-defaults { + description + "The explicit defaults processing mode requested."; + reference + "RFC 6243; Section 4.5.1"; + + type with-defaults-mode; + } + } + + // extending the get-config operation + augment /nc:get-config/nc:input { + description + "Adds the parameter to the + input of the NETCONF operation."; + reference + "RFC 6243; Section 4.5.1"; + + uses with-defaults-parameters; + } + + // extending the get operation + augment /nc:get/nc:input { + description + "Adds the parameter to + the input of the NETCONF operation."; + reference + "RFC 6243; Section 4.5.1"; + + uses with-defaults-parameters; + } + + // extending the copy-config operation + augment /nc:copy-config/nc:input { + description + "Adds the parameter to + the input of the NETCONF operation."; + reference + "RFC 6243; Section 4.5.1"; + + uses with-defaults-parameters; + } +} diff --git a/yang/ietf/ietf-netconf.yang b/yang/ietf/ietf-netconf.yang new file mode 100644 index 000000000000..93927f1c80e5 --- /dev/null +++ b/yang/ietf/ietf-netconf.yang @@ -0,0 +1,933 @@ +module ietf-netconf { + + // the namespace for NETCONF XML definitions is unchanged + // from RFC 4741, which this document replaces + namespace "urn:ietf:params:xml:ns:netconf:base:1.0"; + + prefix nc; + + import ietf-inet-types { + prefix inet; + } + + import ietf-netconf-acm { prefix nacm; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: Bert Wijnen + + + WG Chair: Mehmet Ersue + + + Editor: Martin Bjorklund + + + Editor: Juergen Schoenwaelder + + + Editor: Andy Bierman + "; + description + "NETCONF Protocol Data Types and Protocol Operations. + + Copyright (c) 2011 IETF Trust and the persons identified as + the document authors. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6241; see + the RFC itself for full legal notices."; + + revision 2011-06-01 { + description + "Initial revision; + 2013-09-29: Updated to include NACM attributes, + as specified in RFC 6536: sec 3.2.5 and 3.2.8"; + reference + "RFC 6241: Network Configuration Protocol"; + } + + extension get-filter-element-attributes { + description + "If this extension is present within an 'anyxml' + statement named 'filter', which must be conceptually + defined within the RPC input section for the + and protocol operations, then the + following unqualified XML attribute is supported + within the element, within a or + protocol operation: + + type : optional attribute with allowed + value strings 'subtree' and 'xpath'. + If missing, the default value is 'subtree'. + + If the 'xpath' feature is supported, then the + following unqualified XML attribute is + also supported: + + select: optional attribute containing a + string representing an XPath expression. + The 'type' attribute must be equal to 'xpath' + if this attribute is present."; + } + + // NETCONF capabilities defined as features + feature writable-running { + description + "NETCONF :writable-running capability; + If the server advertises the :writable-running + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.2"; + } + + feature candidate { + description + "NETCONF :candidate capability; + If the server advertises the :candidate + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.3"; + } + + feature confirmed-commit { + if-feature candidate; + description + "NETCONF :confirmed-commit:1.1 capability; + If the server advertises the :confirmed-commit:1.1 + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + + reference "RFC 6241, Section 8.4"; + } + + feature rollback-on-error { + description + "NETCONF :rollback-on-error capability; + If the server advertises the :rollback-on-error + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.5"; + } + + feature validate { + description + "NETCONF :validate:1.1 capability; + If the server advertises the :validate:1.1 + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.6"; + } + + feature startup { + description + "NETCONF :startup capability; + If the server advertises the :startup + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.7"; + } + + feature url { + description + "NETCONF :url capability; + If the server advertises the :url + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.8"; + } + + feature xpath { + description + "NETCONF :xpath capability; + If the server advertises the :xpath + capability for a session, then this feature must + also be enabled for that session. Otherwise, + this feature must not be enabled."; + reference "RFC 6241, Section 8.9"; + } + + // NETCONF Simple Types + + typedef session-id-type { + type uint32 { + range "1..max"; + } + description + "NETCONF Session Id"; + } + + typedef session-id-or-zero-type { + type uint32; + description + "NETCONF Session Id or Zero to indicate none"; + } + typedef error-tag-type { + type enumeration { + enum in-use { + description + "The request requires a resource that + already is in use."; + } + enum invalid-value { + description + "The request specifies an unacceptable value for one + or more parameters."; + } + enum too-big { + description + "The request or response (that would be generated) is + too large for the implementation to handle."; + } + enum missing-attribute { + description + "An expected attribute is missing."; + } + enum bad-attribute { + description + "An attribute value is not correct; e.g., wrong type, + out of range, pattern mismatch."; + } + enum unknown-attribute { + description + "An unexpected attribute is present."; + } + enum missing-element { + description + "An expected element is missing."; + } + enum bad-element { + description + "An element value is not correct; e.g., wrong type, + out of range, pattern mismatch."; + } + enum unknown-element { + description + "An unexpected element is present."; + } + enum unknown-namespace { + description + "An unexpected namespace is present."; + } + enum access-denied { + description + "Access to the requested protocol operation or + data model is denied because authorization failed."; + } + enum lock-denied { + description + "Access to the requested lock is denied because the + lock is currently held by another entity."; + } + enum resource-denied { + description + "Request could not be completed because of + insufficient resources."; + } + enum rollback-failed { + description + "Request to roll back some configuration change (via + rollback-on-error or operations) + was not completed for some reason."; + + } + enum data-exists { + description + "Request could not be completed because the relevant + data model content already exists. For example, + a 'create' operation was attempted on data that + already exists."; + } + enum data-missing { + description + "Request could not be completed because the relevant + data model content does not exist. For example, + a 'delete' operation was attempted on + data that does not exist."; + } + enum operation-not-supported { + description + "Request could not be completed because the requested + operation is not supported by this implementation."; + } + enum operation-failed { + description + "Request could not be completed because the requested + operation failed for some reason not covered by + any other error condition."; + } + enum partial-operation { + description + "This error-tag is obsolete, and SHOULD NOT be sent + by servers conforming to this document."; + } + enum malformed-message { + description + "A message could not be handled because it failed to + be parsed correctly. For example, the message is not + well-formed XML or it uses an invalid character set."; + } + } + description "NETCONF Error Tag"; + reference "RFC 6241, Appendix A"; + } + + typedef error-severity-type { + type enumeration { + enum error { + description "Error severity"; + } + enum warning { + description "Warning severity"; + } + } + description "NETCONF Error Severity"; + reference "RFC 6241, Section 4.3"; + } + + typedef edit-operation-type { + type enumeration { + enum merge { + description + "The configuration data identified by the + element containing this attribute is merged + with the configuration at the corresponding + level in the configuration datastore identified + by the target parameter."; + } + enum replace { + description + "The configuration data identified by the element + containing this attribute replaces any related + configuration in the configuration datastore + identified by the target parameter. If no such + configuration data exists in the configuration + datastore, it is created. Unlike a + operation, which replaces the + entire target configuration, only the configuration + actually present in the config parameter is affected."; + } + enum create { + description + "The configuration data identified by the element + containing this attribute is added to the + configuration if and only if the configuration + data does not already exist in the configuration + datastore. If the configuration data exists, an + element is returned with an + value of 'data-exists'."; + } + enum delete { + description + "The configuration data identified by the element + containing this attribute is deleted from the + configuration if and only if the configuration + data currently exists in the configuration + datastore. If the configuration data does not + exist, an element is returned with + an value of 'data-missing'."; + } + enum remove { + description + "The configuration data identified by the element + containing this attribute is deleted from the + configuration if the configuration + data currently exists in the configuration + datastore. If the configuration data does not + exist, the 'remove' operation is silently ignored + by the server."; + } + } + default "merge"; + description "NETCONF 'operation' attribute values"; + reference "RFC 6241, Section 7.2"; + } + + // NETCONF Standard Protocol Operations + + rpc get-config { + description + "Retrieve all or part of a specified configuration."; + + reference "RFC 6241, Section 7.1"; + + input { + container source { + description + "Particular configuration to retrieve."; + + choice config-source { + mandatory true; + description + "The configuration to retrieve."; + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source. + This is optional-to-implement on the server because + not all servers will support filtering for this + datastore."; + } + } + } + + anyxml filter { + description + "Subtree or XPath filter to use."; + nc:get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the source datastore subset that matched + the filter criteria (if any). An empty data container + indicates that the request did not produce any results."; + } + } + } + + rpc edit-config { + description + "The operation loads all or part of a specified + configuration to the specified target configuration."; + + reference "RFC 6241, Section 7.2"; + + input { + container target { + description + "Particular configuration to edit."; + + choice config-target { + mandatory true; + description + "The configuration target."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + if-feature writable-running; + type empty; + description + "The running configuration is the config source."; + } + } + } + + leaf default-operation { + type enumeration { + enum merge { + description + "The default operation is merge."; + } + enum replace { + description + "The default operation is replace."; + } + enum none { + description + "There is no default operation."; + } + } + default "merge"; + description + "The default operation to use."; + } + + leaf test-option { + if-feature validate; + type enumeration { + enum test-then-set { + description + "The server will test and then set if no errors."; + } + enum set { + description + "The server will set without a test first."; + } + + enum test-only { + description + "The server will only test and not set, even + if there are no errors."; + } + } + default "test-then-set"; + description + "The test option to use."; + } + + leaf error-option { + type enumeration { + enum stop-on-error { + description + "The server will stop on errors."; + } + enum continue-on-error { + description + "The server may continue on errors."; + } + enum rollback-on-error { + description + "The server will roll back on errors. + This value can only be used if the 'rollback-on-error' + feature is supported."; + } + } + default "stop-on-error"; + description + "The error option to use."; + } + + choice edit-content { + mandatory true; + description + "The content for the edit operation."; + + anyxml config { + description + "Inline Config content."; + } + leaf url { + if-feature url; + type inet:uri; + description + "URL-based config content."; + } + } + } + } + + rpc copy-config { + description + "Create or replace an entire configuration datastore with the + contents of another complete configuration datastore."; + + reference "RFC 6241, Section 7.3"; + + input { + container target { + description + "Particular configuration to copy to."; + + choice config-target { + mandatory true; + description + "The configuration target of the copy operation."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + if-feature writable-running; + type empty; + description + "The running configuration is the config target. + This is optional-to-implement on the server."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config target."; + } + } + } + + container source { + description + "Particular configuration to copy from."; + + choice config-source { + mandatory true; + description + "The configuration source for the copy operation."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config source."; + } + anyxml config { + description + "Inline Config content: element. Represents + an entire configuration datastore, not + a subset of the running datastore."; + } + } + } + } + } + + rpc delete-config { + nacm:default-deny-all; + description + "Delete a configuration datastore."; + + reference "RFC 6241, Section 7.4"; + + input { + container target { + description + "Particular configuration to delete."; + + choice config-target { + mandatory true; + description + "The configuration target to delete."; + + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config target."; + } + } + } + } + } + + rpc lock { + description + "The lock operation allows the client to lock the configuration + system of a device."; + + reference "RFC 6241, Section 7.5"; + + input { + container target { + description + "Particular configuration to lock."; + + choice config-target { + mandatory true; + description + "The configuration target to lock."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + type empty; + description + "The running configuration is the config target."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + } + } + } + } + + rpc unlock { + description + "The unlock operation is used to release a configuration lock, + previously obtained with the 'lock' operation."; + + reference "RFC 6241, Section 7.6"; + + input { + container target { + description + "Particular configuration to unlock."; + + choice config-target { + mandatory true; + description + "The configuration target to unlock."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config target."; + } + leaf running { + type empty; + description + "The running configuration is the config target."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config target."; + } + } + } + } + } + + rpc get { + description + "Retrieve running configuration and device state information."; + + reference "RFC 6241, Section 7.7"; + + input { + anyxml filter { + description + "This parameter specifies the portion of the system + configuration and state data to retrieve."; + nc:get-filter-element-attributes; + } + } + + output { + anyxml data { + description + "Copy of the running datastore subset and/or state + data that matched the filter criteria (if any). + An empty data container indicates that the request did not + produce any results."; + } + } + } + + rpc close-session { + description + "Request graceful termination of a NETCONF session."; + + reference "RFC 6241, Section 7.8"; + } + + rpc kill-session { + nacm:default-deny-all; + description + "Force the termination of a NETCONF session."; + + reference "RFC 6241, Section 7.9"; + + input { + leaf session-id { + type session-id-type; + mandatory true; + description + "Particular session to kill."; + } + } + } + + rpc commit { + if-feature candidate; + + description + "Commit the candidate configuration as the device's new + current configuration."; + + reference "RFC 6241, Section 8.3.4.1"; + + input { + leaf confirmed { + if-feature confirmed-commit; + type empty; + description + "Requests a confirmed commit."; + reference "RFC 6241, Section 8.3.4.1"; + } + + leaf confirm-timeout { + if-feature confirmed-commit; + type uint32 { + range "1..max"; + } + units "seconds"; + default "600"; // 10 minutes + description + "The timeout interval for a confirmed commit."; + reference "RFC 6241, Section 8.3.4.1"; + } + + leaf persist { + if-feature confirmed-commit; + type string; + description + "This parameter is used to make a confirmed commit + persistent. A persistent confirmed commit is not aborted + if the NETCONF session terminates. The only way to abort + a persistent confirmed commit is to let the timer expire, + or to use the operation. + + The value of this parameter is a token that must be given + in the 'persist-id' parameter of or + operations in order to confirm or cancel + the persistent confirmed commit. + + The token should be a random string."; + reference "RFC 6241, Section 8.3.4.1"; + } + + leaf persist-id { + if-feature confirmed-commit; + type string; + description + "This parameter is given in order to commit a persistent + confirmed commit. The value must be equal to the value + given in the 'persist' parameter to the operation. + If it does not match, the operation fails with an + 'invalid-value' error."; + reference "RFC 6241, Section 8.3.4.1"; + } + + } + } + + rpc discard-changes { + if-feature candidate; + + description + "Revert the candidate configuration to the current + running configuration."; + reference "RFC 6241, Section 8.3.4.2"; + } + + rpc cancel-commit { + if-feature confirmed-commit; + description + "This operation is used to cancel an ongoing confirmed commit. + If the confirmed commit is persistent, the parameter + 'persist-id' must be given, and it must match the value of the + 'persist' parameter."; + reference "RFC 6241, Section 8.4.4.1"; + + input { + leaf persist-id { + type string; + description + "This parameter is given in order to cancel a persistent + confirmed commit. The value must be equal to the value + given in the 'persist' parameter to the operation. + If it does not match, the operation fails with an + 'invalid-value' error."; + } + } + } + + rpc validate { + if-feature validate; + + description + "Validates the contents of the specified configuration."; + + reference "RFC 6241, Section 8.6.4.1"; + + input { + container source { + description + "Particular configuration to validate."; + + choice config-source { + mandatory true; + description + "The configuration source to validate."; + + leaf candidate { + if-feature candidate; + type empty; + description + "The candidate configuration is the config source."; + } + leaf running { + type empty; + description + "The running configuration is the config source."; + } + leaf startup { + if-feature startup; + type empty; + description + "The startup configuration is the config source."; + } + leaf url { + if-feature url; + type inet:uri; + description + "The URL-based configuration is the config source."; + } + anyxml config { + description + "Inline Config content: element. Represents + an entire configuration datastore, not + a subset of the running datastore."; + } + } + } + } + } +} diff --git a/yang/subdir.am b/yang/subdir.am index eb17c38dbc01..71aa04087858 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -35,9 +35,14 @@ dist_yangmodels_DATA += yang/frr-bgp-route-map.yang dist_yangmodels_DATA += yang/frr-vrf.yang dist_yangmodels_DATA += yang/frr-route-types.yang dist_yangmodels_DATA += yang/frr-routing.yang +dist_yangmodels_DATA += yang/ietf/frr-deviations-ietf-key-chain.yang dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang dist_yangmodels_DATA += yang/ietf/ietf-interfaces.yang dist_yangmodels_DATA += yang/ietf/ietf-bgp-types.yang +dist_yangmodels_DATA += yang/ietf/ietf-key-chain.yang +dist_yangmodels_DATA += yang/ietf/ietf-netconf-acm.yang +dist_yangmodels_DATA += yang/ietf/ietf-netconf.yang +dist_yangmodels_DATA += yang/ietf/ietf-netconf-with-defaults.yang if BFDD dist_yangmodels_DATA += yang/frr-bfdd.yang @@ -101,31 +106,4 @@ endif CLEANFILES += \ yang/*.c \ yang/ietf/*.c \ - yang/confd/*.c \ # - -if CONFD - -SUBMODULES = $(shell cd $(top_srcdir); grep -l belongs-to $(dist_yangmodels_DATA)) -EXCLUDED_MODULES = $(SUBMODULES) yang/frr-module-translator.yang -YANG_MODULES = $(filter-out $(EXCLUDED_MODULES),$(dist_yangmodels_DATA)) - -fxsdir = $(sysconfdir)/confd -fxs_DATA = $(YANG_MODULES:.yang=.fxs) - -SUFFIXES += .fxs -CLEANFILES += $(fxs_DATA) - -AM_V_CONFDC = $(AM_V_CONFDC_@AM_V@) -AM_V_CONFDC_ = $(AM_V_CONFDC_@AM_DEFAULT_V@) -AM_V_CONFDC_0 = @echo " CONFDC " $@; - -CONFDC_FLAGS = --yangpath $(srcdir)/yang --yangpath $(srcdir)/yang/ietf - -yang/%.fxs: yang/%.yang yang/confd/confd.%.yang - $(AM_V_CONFDC)$(CONFDC) $(CONFDC_FLAGS) -c -o $@ -a $(srcdir)/yang/confd/confd.$*.yang -- $< - -yang/%.fxs: yang/%.yang - $(AM_V_CONFDC)$(CONFDC) $(CONFDC_FLAGS) -c -o $@ -- $< - -endif diff --git a/zebra/.gitignore b/zebra/.gitignore index 41a86e7d753a..f10240db4394 100644 --- a/zebra/.gitignore +++ b/zebra/.gitignore @@ -1,3 +1,4 @@ zebra zebra.conf client +fpm_listener diff --git a/zebra/connected.c b/zebra/connected.c index ee0823f56f45..974a1c17a292 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -48,7 +48,7 @@ static void connected_withdraw(struct connected *ifc) UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { - listnode_delete(ifc->ifp->connected, ifc); + if_connected_del(ifc->ifp->connected, ifc); connected_free(&ifc); } } @@ -65,7 +65,7 @@ static void connected_announce(struct interface *ifp, struct connected *ifc) UNSET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED); } - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); /* Update interface address information to protocol daemon. */ if (ifc->address->family == AF_INET) @@ -84,9 +84,8 @@ struct connected *connected_check(struct interface *ifp, { const struct prefix *p = pu.p; struct connected *ifc; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) + frr_each (if_connected, ifp->connected, ifc) if (prefix_same(ifc->address, p)) return ifc; @@ -101,9 +100,8 @@ struct connected *connected_check_ptp(struct interface *ifp, const struct prefix *p = pu.p; const struct prefix *d = du.p; struct connected *ifc; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { if (!prefix_same(ifc->address, p)) continue; if (!CONNECTED_PEER(ifc) && !d) @@ -182,18 +180,19 @@ static void connected_update(struct interface *ifp, struct connected *ifc) void connected_up(struct interface *ifp, struct connected *ifc) { afi_t afi; - struct prefix p; + struct prefix p, plocal; struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, .vrf_id = ifp->vrf->vrf_id, + .weight = 1, }; struct zebra_vrf *zvrf; uint32_t metric; uint32_t flags = 0; uint32_t count = 0; - struct listnode *cnode; struct connected *c; + bool install_local = true; zvrf = ifp->vrf->info; if (!zvrf) { @@ -210,6 +209,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN); prefix_copy(&p, CONNECTED_PREFIX(ifc)); + prefix_copy(&plocal, ifc->address); /* Apply mask to the network. */ apply_mask(&p); @@ -224,6 +224,8 @@ void connected_up(struct interface *ifp, struct connected *ifc) */ if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) return; + + plocal.prefixlen = IPV4_MAX_BITLEN; break; case AFI_IP6: #ifndef GNU_LINUX @@ -231,6 +233,11 @@ void connected_up(struct interface *ifp, struct connected *ifc) if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) return; #endif + + if (IN6_IS_ADDR_LINKLOCAL(&plocal.u.prefix6)) + install_local = false; + + plocal.prefixlen = IPV6_MAX_BITLEN; break; case AFI_UNSPEC: case AFI_L2VPN: @@ -262,7 +269,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) * for all the addresses on an interface that * resolve to the same network and mask */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix cp; prefix_copy(&cp, CONNECTED_PREFIX(c)); @@ -276,13 +283,24 @@ void connected_up(struct interface *ifp, struct connected *ifc) return; } - rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); - rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, - false); + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, + zvrf->table_id, metric, 0, 0, 0, false); + } + + if (install_local) { + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_LOCAL, + 0, flags, &plocal, NULL, &nh, 0, zvrf->table_id, 0, 0, + 0, 0, false); + rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, flags, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -368,7 +386,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, void connected_down(struct interface *ifp, struct connected *ifc) { afi_t afi; - struct prefix p; + struct prefix p, plocal; struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, @@ -376,8 +394,8 @@ void connected_down(struct interface *ifp, struct connected *ifc) }; struct zebra_vrf *zvrf; uint32_t count = 0; - struct listnode *cnode; struct connected *c; + bool remove_local = true; zvrf = ifp->vrf->info; if (!zvrf) { @@ -403,6 +421,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) } prefix_copy(&p, CONNECTED_PREFIX(ifc)); + prefix_copy(&plocal, ifc->address); /* Apply mask to the network. */ apply_mask(&p); @@ -417,10 +436,18 @@ void connected_down(struct interface *ifp, struct connected *ifc) */ if (prefix_ipv4_any((struct prefix_ipv4 *)&p)) return; + + plocal.prefixlen = IPV4_MAX_BITLEN; break; case AFI_IP6: if (IN6_IS_ADDR_UNSPECIFIED(&p.u.prefix6)) return; + + plocal.prefixlen = IPV6_MAX_BITLEN; + + if (IN6_IS_ADDR_LINKLOCAL(&plocal.u.prefix6)) + remove_local = false; + break; case AFI_UNSPEC: case AFI_L2VPN: @@ -439,7 +466,7 @@ void connected_down(struct interface *ifp, struct connected *ifc) * allow the deletion when are removing the last * one. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix cp; prefix_copy(&cp, CONNECTED_PREFIX(c)); @@ -457,11 +484,25 @@ void connected_down(struct interface *ifp, struct connected *ifc) * Same logic as for connected_up(): push the changes into the * head. */ - rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, - 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + + rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_CONNECT, 0, 0, &p, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + } + + if (remove_local) { + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, 0, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); - rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, - 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false); + rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, + ZEBRA_ROUTE_LOCAL, 0, 0, &plocal, NULL, &nh, 0, + zvrf->table_id, 0, 0, false); + } /* Schedule LSP forwarding entries for processing, if appropriate. */ if (zvrf->vrf->vrf_id == VRF_DEFAULT) { @@ -616,9 +657,8 @@ void connected_delete_ipv6(struct interface *ifp, int connected_is_unnumbered(struct interface *ifp) { struct connected *connected; - struct listnode *node; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) && connected->address->family == AF_INET) return CHECK_FLAG(connected->flags, diff --git a/zebra/debug.c b/zebra/debug.c index 68bedaf0578a..cf1701be1938 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -7,6 +7,7 @@ #include #include "command.h" #include "debug.h" +#include "mgmt_be_client.h" #include "zebra/debug_clippy.c" @@ -846,4 +847,7 @@ void zebra_debug_init(void) install_element(CONFIG_NODE, &no_debug_zebra_pbr_cmd); install_element(CONFIG_NODE, &debug_zebra_mlag_cmd); install_element(CONFIG_NODE, &debug_zebra_evpn_mh_cmd); + + /* Init mgmtd backend client debug commands. */ + mgmt_be_client_lib_vty_init(); } diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index df0b5aae7bb6..037d0b6237d2 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -534,6 +534,12 @@ const char *rtm_rta2str(int type) return "NH_ID"; case RTA_EXPIRES: return "EXPIRES"; + case RTA_VIA: + return "VIA"; + case RTA_ENCAP_TYPE: + return "RTA_ENCAP_TYPE"; + case RTA_ENCAP: + return "RTA_ENCAP"; default: return "UNKNOWN"; } @@ -983,6 +989,7 @@ static void nllink_dump(struct ifinfomsg *ifi, size_t msglen) zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, plen, rta_type, rta_type2str(rta_type)); switch (rta_type) { + case IFLA_IFNAME: case IFLA_IFALIAS: if (plen == 0) { zlog_debug(" invalid length"); diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index fc140b07a34d..411155167f64 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -52,7 +52,7 @@ void zd_dpdk_stat_show(struct vty *vty) static void zd_dpdk_flow_stat_show(struct vty *vty, int in_ifindex, intptr_t dp_flow_ptr) { - struct rte_flow_action_count count = {.shared = 0, .id = 0}; + struct rte_flow_action_count count = { .id = 0 }; const struct rte_flow_action actions[] = { { .type = RTE_FLOW_ACTION_TYPE_COUNT, @@ -105,8 +105,7 @@ static int zd_dpdk_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg) ifp = if_lookup_by_name_vrf(rule->ifname, vrf); if (ifp) - zd_dpdk_flow_stat_show(vty, ifp->ifindex, - zaction->dp_flow_ptr); + zd_dpdk_flow_stat_show(vty, ifp->ifindex, zaction->dp_flow_ptr); } return HASHWALK_CONTINUE; } @@ -153,8 +152,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) zlog_debug( "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; in_port %d missing\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, - unique, in_ifindex); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, in_ifindex); return; } @@ -163,8 +161,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE_DPDK_DETAIL) zlog_debug( "PBR dpdk flow create ifname %s seq %d pri %u unique %d failed; out_port %d missing\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, - unique, out_ifindex); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, out_ifindex); return; } @@ -180,7 +177,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) memset(&ip, 0, sizeof(ip)); memset(&ip_mask, 0, sizeof(ip_mask)); - if (filter_bm & PBR_FILTER_SRC_IP) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_IP)) { const struct prefix *src_ip; src_ip = dplane_ctx_rule_get_src_ip(ctx); @@ -188,7 +185,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) masklen2ip(src_ip->prefixlen, &tmp_mask); ip_mask.hdr.src_addr = tmp_mask.s_addr; } - if (filter_bm & PBR_FILTER_DST_IP) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_IP)) { const struct prefix *dst_ip; dst_ip = dplane_ctx_rule_get_dst_ip(ctx); @@ -196,7 +193,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) masklen2ip(dst_ip->prefixlen, &tmp_mask); ip_mask.hdr.dst_addr = tmp_mask.s_addr; } - if (filter_bm & PBR_FILTER_IP_PROTOCOL) { + if (CHECK_FLAG(filter_bm, PBR_FILTER_IP_PROTOCOL)) { ip.hdr.next_proto_id = dplane_ctx_rule_get_ipproto(ctx); ip_mask.hdr.next_proto_id = UINT8_MAX; } @@ -206,17 +203,15 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) items[item_cnt].last = NULL; ++item_cnt; - if ((filter_bm & (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) { + if (CHECK_FLAG(filter_bm, (PBR_FILTER_SRC_PORT | PBR_FILTER_DST_PORT))) { memset(&udp, 0, sizeof(udp)); memset(&udp_mask, 0, sizeof(udp_mask)); - if (filter_bm & PBR_FILTER_SRC_PORT) { - udp.hdr.src_port = - RTE_BE16(dplane_ctx_rule_get_src_port(ctx)); + if (CHECK_FLAG(filter_bm, PBR_FILTER_SRC_PORT)) { + udp.hdr.src_port = RTE_BE16(dplane_ctx_rule_get_src_port(ctx)); udp_mask.hdr.src_port = UINT16_MAX; } - if (filter_bm & PBR_FILTER_DST_PORT) { - udp.hdr.dst_port = - RTE_BE16(dplane_ctx_rule_get_dst_port(ctx)); + if (CHECK_FLAG(filter_bm, PBR_FILTER_DST_PORT)) { + udp.hdr.dst_port = RTE_BE16(dplane_ctx_rule_get_dst_port(ctx)); udp_mask.hdr.dst_port = UINT16_MAX; } items[item_cnt].type = RTE_FLOW_ITEM_TYPE_UDP; @@ -273,8 +268,7 @@ static void zd_dpdk_rule_add(struct zebra_dplane_ctx *ctx) } else { zlog_warn( "PBR dpdk flow create failed ifname %s seq %d pri %u unique %d; rc %d\n", - dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, - error.type); + dplane_ctx_rule_get_ifname(ctx), seq, pri, unique, error.type); } } @@ -504,9 +498,11 @@ static void zd_dpdk_port_show_entry(struct zd_dpdk_port *dport, struct vty *vty, if (detail) { vty_out(vty, "DPDK port: %u\n", dport->port_id); vty_out(vty, " Device: %s\n", - dev_info->device ? dev_info->device->name : "-"); + dev_info->device ? rte_dev_name(dev_info->device) : "-"); vty_out(vty, " Driver: %s\n", - dev_info->driver_name ? dev_info->driver_name : "-"); + dev_info->driver_name ? rte_driver_name(rte_dev_driver( + dev_info->device)) + : "-"); vty_out(vty, " Interface: %s (%d)\n", ifindex2ifname(dev_info->if_index, VRF_DEFAULT), dev_info->if_index); @@ -516,9 +512,8 @@ static void zd_dpdk_port_show_entry(struct zd_dpdk_port *dport, struct vty *vty, dev_info->switch_info.port_id); vty_out(vty, "\n"); } else { - vty_out(vty, "%-4u %-16s %-16s %-16d %s,%u,%u\n", - dport->port_id, - dev_info->device ? dev_info->device->name : "-", + vty_out(vty, "%-4u %-16s %-16s %-16d %s,%u,%u\n", dport->port_id, + dev_info->device ? rte_dev_name(dev_info->device) : "-", ifindex2ifname(dev_info->if_index, VRF_DEFAULT), dev_info->if_index, dev_info->switch_info.name, dev_info->switch_info.domain_id, @@ -562,7 +557,7 @@ void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, int detail) for (count = 0; count < RTE_MAX_ETHPORTS; ++count) { dport = &dpdk_ctx->dpdk_ports[count]; - if (dport->flags & ZD_DPDK_PORT_FLAG_INITED) + if (CHECK_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED)) zd_dpdk_port_show_entry(dport, vty, detail); } } @@ -592,31 +587,31 @@ static void zd_dpdk_port_init(void) dport = &dpdk_ctx->dpdk_ports[count]; count++; dport->port_id = port_id; - dport->flags |= ZD_DPDK_PORT_FLAG_PROBED; + SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_PROBED); dev_info = &dport->dev_info; if (rte_eth_dev_info_get(port_id, dev_info) < 0) { zlog_warn("failed to get dev info for %u, %s", port_id, rte_strerror(rte_errno)); continue; } - dport->flags |= ZD_DPDK_PORT_FLAG_INITED; + SET_FLAG(dport->flags, ZD_DPDK_PORT_FLAG_INITED); if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug( - "port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u", - port_id, - dev_info->device ? dev_info->device->name : "-", - dev_info->if_index, dev_info->switch_info.name, - dev_info->switch_info.domain_id, - dev_info->switch_info.port_id); + zlog_debug("port %u, dev %s, ifI %d, sw_name %s, sw_domain %u, sw_port %u", + port_id, + dev_info->device + ? rte_dev_name(dev_info->device) + : "-", + dev_info->if_index, + dev_info->switch_info.name, + dev_info->switch_info.domain_id, + dev_info->switch_info.port_id); if (rte_flow_isolate(port_id, 1, &error)) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) zlog_debug( - "Flow isolate on port %u failed %d\n", - port_id, error.type); + "Flow isolate on port %u failed %d", port_id, error.type); } else { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("Flow isolate on port %u\n", - port_id); + zlog_debug("Flow isolate on port %u", port_id); } rc = rte_eth_dev_start(port_id); if (rc) { @@ -625,8 +620,7 @@ static void zd_dpdk_port_init(void) continue; } if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("DPDK port %d started in promiscuous mode ", - port_id); + zlog_debug("DPDK port %d started in promiscuous mode ", port_id); } if (!count) { @@ -639,13 +633,12 @@ static void zd_dpdk_port_init(void) static int zd_dpdk_init(void) { int rc; - static const char *argv[] = {(char *)"/usr/lib/frr/zebra", - (char *)"--"}; + static const char *argv[] = {(char *)"/usr/lib/frr/zebra", (char *)"--"}; zd_dpdk_vty_init(); frr_with_privs (&zserv_privs) { - rc = rte_eal_init(array_size(argv), argv); + rc = rte_eal_init(array_size(argv), (char **)argv); } if (rc < 0) { zlog_warn("EAL init failed %s", rte_strerror(rte_errno)); @@ -674,8 +667,7 @@ static int zd_dpdk_finish(struct zebra_dplane_provider *prov, bool early) if (early) { if (IS_ZEBRA_DEBUG_DPLANE_DPDK) - zlog_debug("%s early finish", - dplane_provider_get_name(prov)); + zlog_debug("%s early finish", dplane_provider_get_name(prov)); return 0; } diff --git a/zebra/dpdk/zebra_dplane_dpdk.h b/zebra/dpdk/zebra_dplane_dpdk.h index e5a3dbebab29..ece72d9efbe5 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.h +++ b/zebra/dpdk/zebra_dplane_dpdk.h @@ -20,4 +20,6 @@ extern void zd_dpdk_port_show(struct vty *vty, uint16_t port_id, bool uj, extern void zd_dpdk_stat_show(struct vty *vty); extern void zd_dpdk_vty_init(void); +extern struct zebra_privs_t zserv_privs; + #endif diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 2a8792523188..09080aa6164d 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -19,6 +19,9 @@ #include #include "lib/zebra.h" + +#include + #include "lib/json.h" #include "lib/libfrr.h" #include "lib/frratomic.h" @@ -27,22 +30,28 @@ #include "lib/network.h" #include "lib/ns.h" #include "lib/frr_pthread.h" +#include "lib/termtable.h" #include "zebra/debug.h" #include "zebra/interface.h" #include "zebra/zebra_dplane.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_router.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" -#include "zebra/debug.h" #include "fpm/fpm.h" +#include "zebra/dplane_fpm_nl_clippy.c" + #define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK -#define SOUTHBOUND_DEFAULT_PORT 2620 + +/* + * Time in seconds that if the other end is not responding + * something terrible has gone wrong. Let's fix that. + */ +#define DPLANE_FPM_NL_WEDGIE_TIME 15 /** * FPM header: @@ -90,6 +99,7 @@ struct fpm_nl_ctx { struct event *t_event; struct event *t_nhg; struct event *t_dequeue; + struct event *t_wedged; /* zebra events. */ struct event *t_lspreset; @@ -124,8 +134,6 @@ struct fpm_nl_ctx { /* Amount of data plane context processed. */ _Atomic uint32_t dplane_contexts; - /* Amount of data plane contexts enqueued. */ - _Atomic uint32_t ctxqueue_len; /* Peak amount of data plane contexts enqueued. */ _Atomic uint32_t ctxqueue_len_peak; @@ -207,7 +215,7 @@ DEFUN(fpm_set_address, fpm_set_address_cmd, memset(sin, 0, sizeof(*sin)); sin->sin_family = AF_INET; sin->sin_port = - port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT); + port ? htons(port) : htons(FPM_DEFAULT_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin->sin_len = sizeof(*sin); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ @@ -225,7 +233,7 @@ DEFUN(fpm_set_address, fpm_set_address_cmd, sin6 = (struct sockaddr_in6 *)&gfnc->addr; memset(sin6, 0, sizeof(*sin6)); sin6->sin6_family = AF_INET6; - sin6->sin6_port = port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT); + sin6->sin6_port = port ? htons(port) : htons(FPM_DEFAULT_PORT); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN sin6->sin6_len = sizeof(*sin6); #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ @@ -313,12 +321,86 @@ DEFUN(fpm_reset_counters, fpm_reset_counters_cmd, return CMD_SUCCESS; } +DEFPY(fpm_show_status, + fpm_show_status_cmd, + "show fpm status [json]$json", + SHOW_STR FPM_STR "FPM status\n" JSON_STR) +{ + struct json_object *j; + bool connected; + uint16_t port; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + char buf[BUFSIZ]; + + connected = gfnc->socket > 0 ? true : false; + + switch (gfnc->addr.ss_family) { + case AF_INET: + sin = (struct sockaddr_in *)&gfnc->addr; + snprintfrr(buf, sizeof(buf), "%pI4", &sin->sin_addr); + port = ntohs(sin->sin_port); + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)&gfnc->addr; + snprintfrr(buf, sizeof(buf), "%pI6", &sin6->sin6_addr); + port = ntohs(sin6->sin6_port); + break; + default: + strlcpy(buf, "Unknown", sizeof(buf)); + port = FPM_DEFAULT_PORT; + break; + } + + if (json) { + j = json_object_new_object(); + + json_object_boolean_add(j, "connected", connected); + json_object_boolean_add(j, "useNHG", gfnc->use_nhg); + json_object_boolean_add(j, "useRouteReplace", + gfnc->use_route_replace); + json_object_boolean_add(j, "disabled", gfnc->disabled); + json_object_string_add(j, "address", buf); + json_object_int_add(j, "port", port); + + vty_json(vty, j); + } else { + struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + char *out; + + ttable_rowseps(table, 0, BOTTOM, true, '-'); + ttable_add_row(table, "Address to connect to|%s", buf); + ttable_add_row(table, "Port|%u", port); + ttable_add_row(table, "Connected|%s", connected ? "Yes" : "No"); + ttable_add_row(table, "Use Nexthop Groups|%s", + gfnc->use_nhg ? "Yes" : "No"); + ttable_add_row(table, "Use Route Replace Semantics|%s", + gfnc->use_route_replace ? "Yes" : "No"); + ttable_add_row(table, "Disabled|%s", + gfnc->disabled ? "Yes" : "No"); + + out = ttable_dump(table, "\n"); + vty_out(vty, "%s\n", out); + XFREE(MTYPE_TMP, out); + + ttable_del(table); + } + + return CMD_SUCCESS; +} + DEFUN(fpm_show_counters, fpm_show_counters_cmd, "show fpm counters", SHOW_STR FPM_STR "FPM statistic counters\n") { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + vty_out(vty, "%30s\n%30s\n", "FPM counters", "============"); #define SHOW_COUNTER(label, counter) \ @@ -332,8 +414,7 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, SHOW_COUNTER("Connection errors", gfnc->counters.connection_errors); SHOW_COUNTER("Data plane items processed", gfnc->counters.dplane_contexts); - SHOW_COUNTER("Data plane items enqueued", - gfnc->counters.ctxqueue_len); + SHOW_COUNTER("Data plane items enqueued", curr_queue_len); SHOW_COUNTER("Data plane items queue peak", gfnc->counters.ctxqueue_len_peak); SHOW_COUNTER("Buffer full hits", gfnc->counters.buffer_full); @@ -352,6 +433,12 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, "FPM statistic counters\n" JSON_STR) { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + struct json_object *jo; jo = json_object_new_object(); @@ -365,8 +452,7 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, gfnc->counters.connection_errors); json_object_int_add(jo, "data-plane-contexts", gfnc->counters.dplane_contexts); - json_object_int_add(jo, "data-plane-contexts-queue", - gfnc->counters.ctxqueue_len); + json_object_int_add(jo, "data-plane-contexts-queue", curr_queue_len); json_object_int_add(jo, "data-plane-contexts-queue-peak", gfnc->counters.ctxqueue_len_peak); json_object_int_add(jo, "buffer-full-hits", gfnc->counters.buffer_full); @@ -392,7 +478,7 @@ static int fpm_write_config(struct vty *vty) written = 1; sin = (struct sockaddr_in *)&gfnc->addr; vty_out(vty, "fpm address %pI4", &sin->sin_addr); - if (sin->sin_port != htons(SOUTHBOUND_DEFAULT_PORT)) + if (sin->sin_port != htons(FPM_DEFAULT_PORT)) vty_out(vty, " port %d", ntohs(sin->sin_port)); vty_out(vty, "\n"); @@ -401,7 +487,7 @@ static int fpm_write_config(struct vty *vty) written = 1; sin6 = (struct sockaddr_in6 *)&gfnc->addr; vty_out(vty, "fpm address %pI6", &sin6->sin6_addr); - if (sin6->sin6_port != htons(SOUTHBOUND_DEFAULT_PORT)) + if (sin6->sin6_port != htons(FPM_DEFAULT_PORT)) vty_out(vty, " port %d", ntohs(sin6->sin6_port)); vty_out(vty, "\n"); @@ -574,14 +660,6 @@ static void fpm_read(struct event *t) hdr_available_bytes = fpm.msg_len - FPM_MSG_HDR_LEN; available_bytes -= hdr_available_bytes; - /* Sanity check: must be at least header size. */ - if (hdr->nlmsg_len < sizeof(*hdr)) { - zlog_warn( - "%s: [seq=%u] invalid message length %u (< %zu)", - __func__, hdr->nlmsg_seq, hdr->nlmsg_len, - sizeof(*hdr)); - continue; - } if (hdr->nlmsg_len > fpm.msg_len) { zlog_warn( "%s: Received a inner header length of %u that is greater than the fpm total length of %u", @@ -611,6 +689,14 @@ static void fpm_read(struct event *t) switch (hdr->nlmsg_type) { case RTM_NEWROUTE: + /* Sanity check: need at least route msg header size. */ + if (hdr->nlmsg_len < sizeof(struct rtmsg)) { + zlog_warn("%s: [seq=%u] invalid message length %u (< %zu)", + __func__, hdr->nlmsg_seq, + hdr->nlmsg_len, sizeof(struct rtmsg)); + break; + } + ctx = dplane_ctx_alloc(); dplane_ctx_route_init(ctx, DPLANE_OP_ROUTE_NOTIFY, NULL, NULL); @@ -859,7 +945,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) if (op == DPLANE_OP_ROUTE_DELETE) break; - /* FALL THROUGH */ + fallthrough; case DPLANE_OP_ROUTE_INSTALL: rv = netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len], @@ -969,6 +1055,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_TC_FILTER_ADD: case DPLANE_OP_TC_FILTER_DELETE: case DPLANE_OP_TC_FILTER_UPDATE: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: break; @@ -1364,6 +1451,18 @@ static void fpm_rmac_reset(struct event *t) &fnc->t_rmacwalk); } +static void fpm_process_wedged(struct event *t) +{ + struct fpm_nl_ctx *fnc = EVENT_ARG(t); + + zlog_warn("%s: Connection unable to write to peer for over %u seconds, resetting", + __func__, DPLANE_FPM_NL_WEDGIE_TIME); + + atomic_fetch_add_explicit(&fnc->counters.connection_errors, 1, + memory_order_relaxed); + FPM_RECONNECT(fnc); +} + static void fpm_process_queue(struct event *t) { struct fpm_nl_ctx *fnc = EVENT_ARG(t); @@ -1372,8 +1471,14 @@ static void fpm_process_queue(struct event *t) uint64_t processed_contexts = 0; while (true) { + size_t writeable_amount; + + frr_with_mutex (&fnc->obuf_mutex) { + writeable_amount = STREAM_WRITEABLE(fnc->obuf); + } + /* No space available yet. */ - if (STREAM_WRITEABLE(fnc->obuf) < NL_PKT_BUF_SIZE) { + if (writeable_amount < NL_PKT_BUF_SIZE) { no_bufs = true; break; } @@ -1396,8 +1501,6 @@ static void fpm_process_queue(struct event *t) /* Account the processed entries. */ processed_contexts++; - atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1, - memory_order_relaxed); dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(fnc->prov, ctx); @@ -1408,9 +1511,13 @@ static void fpm_process_queue(struct event *t) processed_contexts, memory_order_relaxed); /* Re-schedule if we ran out of buffer space */ - if (no_bufs) - event_add_timer(fnc->fthread->master, fpm_process_queue, fnc, 0, + if (no_bufs) { + event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); + event_add_timer(fnc->fthread->master, fpm_process_wedged, fnc, + DPLANE_FPM_NL_WEDGIE_TIME, &fnc->t_wedged); + } else + EVENT_OFF(fnc->t_wedged); /* * Let the dataplane thread know if there are items in the @@ -1567,7 +1674,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) struct zebra_dplane_ctx *ctx; struct fpm_nl_ctx *fnc; int counter, limit; - uint64_t cur_queue, peak_queue = 0, stored_peak_queue; + uint64_t cur_queue = 0, peak_queue = 0, stored_peak_queue; fnc = dplane_provider_get_data(prov); limit = dplane_provider_get_work_limit(prov); @@ -1581,20 +1688,12 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) * anyway. */ if (fnc->socket != -1 && fnc->connecting == false) { - /* - * Update the number of queued contexts *before* - * enqueueing, to ensure counter consistency. - */ - atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len, - 1, memory_order_relaxed); - frr_with_mutex (&fnc->ctxqueue_mutex) { dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx); + cur_queue = + dplane_ctx_queue_count(&fnc->ctxqueue); } - cur_queue = atomic_load_explicit( - &fnc->counters.ctxqueue_len, - memory_order_relaxed); if (peak_queue < cur_queue) peak_queue = cur_queue; continue; @@ -1611,10 +1710,8 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) atomic_store_explicit(&fnc->counters.ctxqueue_len_peak, peak_queue, memory_order_relaxed); - if (atomic_load_explicit(&fnc->counters.ctxqueue_len, - memory_order_relaxed) - > 0) - event_add_timer(fnc->fthread->master, fpm_process_queue, fnc, 0, + if (cur_queue > 0) + event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); /* Ensure dataplane thread is rescheduled if we hit the work limit */ @@ -1639,6 +1736,7 @@ static int fpm_nl_new(struct event_loop *tm) zlog_debug("%s register status: %d", prov_name, rv); install_node(&fpm_node); + install_element(ENABLE_NODE, &fpm_show_status_cmd); install_element(ENABLE_NODE, &fpm_show_counters_cmd); install_element(ENABLE_NODE, &fpm_show_counters_json_cmd); install_element(ENABLE_NODE, &fpm_reset_counters_cmd); diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c new file mode 100644 index 000000000000..7d84c706d408 --- /dev/null +++ b/zebra/fpm_listener.c @@ -0,0 +1,814 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" +#include +#include +#include + +#ifdef GNU_LINUX +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rt_netlink.h" +#include "fpm/fpm.h" +#include "lib/libfrr.h" + +XREF_SETUP(); + +struct glob { + int server_sock; + int sock; + bool reflect; + bool dump_hex; +}; + +struct glob glob_space; +struct glob *glob = &glob_space; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +/* + * get_print_buf + */ +static char * +get_print_buf(size_t *buf_len) +{ + static char print_bufs[16][128]; + static int counter; + + counter++; + if (counter >= 16) + counter = 0; + + *buf_len = 128; + return &print_bufs[counter][0]; +} + +/* + * create_listen_sock + */ +static int create_listen_sock(int port, int *sock_p) +{ + int sock; + struct sockaddr_in addr; + int reuse; + + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) { + fprintf(stderr, "Failed to create socket: %s\n", strerror(errno)); + return 0; + } + + reuse = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < + 0) { + fprintf(stderr, "Failed to set reuse addr option: %s\n", + strerror(errno)); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf(stderr, "Failed to bind to port %d: %s\n", port, strerror(errno)); + close(sock); + return 0; + } + + if (listen(sock, 5)) { + fprintf(stderr, "Failed to listen on socket: %s\n", strerror(errno)); + close(sock); + return 0; + } + + *sock_p = sock; + return 1; +} + +/* + * accept_conn + */ +static int accept_conn(int listen_sock) +{ + int sock; + struct sockaddr_in client_addr = { 0 }; + unsigned int client_len; + + while (1) { + char buf[120]; + + fprintf(stdout, "Waiting for client connection...\n"); + client_len = sizeof(client_addr); + sock = accept(listen_sock, (struct sockaddr *)&client_addr, + &client_len); + + if (sock >= 0) { + fprintf(stdout, "Accepted client %s\n", + inet_ntop(AF_INET, &client_addr.sin_addr, buf, sizeof(buf))); + return sock; + } + fprintf(stderr, "Failed to accept socket: %s\n", strerror(errno)); + } +} + +/* + * read_fpm_msg + */ +static fpm_msg_hdr_t * +read_fpm_msg(char *buf, size_t buf_len) +{ + char *cur, *end; + long need_len, bytes_read, have_len; + fpm_msg_hdr_t *hdr; + int reading_full_msg; + + end = buf + buf_len; + cur = buf; + hdr = (fpm_msg_hdr_t *)buf; + + while (1) { + reading_full_msg = 0; + + have_len = cur - buf; + + if (have_len < (long)FPM_MSG_HDR_LEN) { + need_len = FPM_MSG_HDR_LEN - have_len; + } else { + need_len = fpm_msg_len(hdr) - have_len; + assert(need_len >= 0 && need_len <= (end - cur)); + + if (!need_len) + return hdr; + + reading_full_msg = 1; + } + + bytes_read = read(glob->sock, cur, need_len); + + if (bytes_read == 0) { + fprintf(stdout, + "Socket closed as that read returned 0\n"); + return NULL; + } + + if (bytes_read < 0) { + fprintf(stderr, "Error reading from socket: %s\n", + strerror(errno)); + return NULL; + } + + cur += bytes_read; + + if (bytes_read < need_len) { + fprintf(stderr, + "Read %lu bytes but expected to read %lu bytes instead\n", + bytes_read, need_len); + return NULL; + } + + if (reading_full_msg) + return hdr; + + if (!fpm_msg_ok(hdr, buf_len)) { + assert(0); + fprintf(stderr, "Malformed fpm message\n"); + return NULL; + } + } +} + +/* + * netlink_msg_type_to_s + */ +static const char * +netlink_msg_type_to_s(uint16_t type) +{ + switch (type) { + + case RTM_NEWROUTE: + return "New route"; + + case RTM_DELROUTE: + return "Del route"; + + case RTM_NEWNEXTHOP: + return "New Nexthop Group"; + + case RTM_DELNEXTHOP: + return "Del Nexthop Group"; + + default: + return "Unknown"; + } +} + +/* + * netlink_prot_to_s + */ +static const char * +netlink_prot_to_s(unsigned char prot) +{ + switch (prot) { + + case RTPROT_KERNEL: + return "Kernel"; + + case RTPROT_BOOT: + return "Boot"; + + case RTPROT_STATIC: + return "Static"; + + case RTPROT_ZEBRA: + return "Zebra"; + + case RTPROT_DHCP: + return "Dhcp"; + + case RTPROT_BGP: + return "BGP"; + + case RTPROT_ISIS: + return "ISIS"; + + case RTPROT_OSPF: + return "OSPF"; + + case RTPROT_RIP: + return "RIP"; + + case RTPROT_RIPNG: + return "RIPNG"; + + case RTPROT_BABEL: + return "BABEL"; + + case RTPROT_NHRP: + return "NHRP"; + + case RTPROT_EIGRP: + return "EIGRP"; + + case RTPROT_SHARP: + return "SHARP"; + + case RTPROT_PBR: + return "PBR"; + + case RTPROT_ZSTATIC: + return "Static"; + + default: + return "Unknown"; + } +} + +#define MAX_NHS 16 + +struct netlink_nh { + struct rtattr *gateway; + int if_index; + uint16_t encap_type; + uint32_t vxlan_vni; +}; + +struct netlink_msg_ctx { + struct nlmsghdr *hdr; + + /* + * Stuff pertaining to route messages. + */ + struct rtmsg *rtmsg; + struct rtattr *rtattrs[RTA_MAX + 1]; + + /* + * Nexthops. + */ + struct netlink_nh nhs[MAX_NHS]; + unsigned long num_nhs; + + struct rtattr *dest; + struct rtattr *src; + int *metric; + unsigned int *nhgid; + + const char *err_msg; +}; + +/* + * netlink_msg_ctx_init + */ +static inline void netlink_msg_ctx_init(struct netlink_msg_ctx *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * netlink_msg_ctx_set_err + */ +static inline void netlink_msg_ctx_set_err(struct netlink_msg_ctx *ctx, + const char *err_msg) +{ + if (ctx->err_msg) + return; + + ctx->err_msg = err_msg; +} + +/* + * parse_rtattrs_ + */ +static int parse_rtattrs_(struct rtattr *rta, size_t len, struct rtattr **rtas, + uint16_t num_rtas, const char **err_msg) +{ + memset(rtas, 0, num_rtas * sizeof(rtas[0])); + + for (; len > 0; rta = RTA_NEXT(rta, len)) { + uint16_t type = rta->rta_type & NLA_TYPE_MASK; + + if (!RTA_OK(rta, len)) { + *err_msg = "Malformed rta"; + return 0; + } + + if (type >= num_rtas) { + warn("Unknown rtattr type %d", rta->rta_type); + continue; + } + + rtas[type] = rta; + } + + return 1; +} + +/* + * parse_rtattrs + */ +static int parse_rtattrs(struct netlink_msg_ctx *ctx, struct rtattr *rta, + size_t len) +{ + const char *err_msg; + + err_msg = NULL; + + if (!parse_rtattrs_(rta, len, ctx->rtattrs, ARRAY_SIZE(ctx->rtattrs), + &err_msg)) { + netlink_msg_ctx_set_err(ctx, err_msg); + return 0; + } + + return 1; +} + +/* + * netlink_msg_ctx_add_nh + */ +static int netlink_msg_ctx_add_nh(struct netlink_msg_ctx *ctx, int if_index, + struct rtattr *gateway, uint16_t encap_type, + uint32_t vxlan_vni) +{ + struct netlink_nh *nh; + + if (ctx->num_nhs + 1 >= ARRAY_SIZE(ctx->nhs)) { + warn("Too many next hops"); + return 0; + } + nh = &ctx->nhs[ctx->num_nhs]; + ctx->num_nhs++; + + nh->gateway = gateway; + nh->if_index = if_index; + + nh->encap_type = encap_type; + nh->vxlan_vni = vxlan_vni; + return 1; +} + +/* + * parse_multipath_attr + */ +static int parse_multipath_attr(struct netlink_msg_ctx *ctx, + struct rtattr *mpath_rtattr) +{ + int len; + struct rtnexthop *rtnh; + struct rtattr *rtattrs[RTA_MAX + 1]; + struct rtattr *tb[RTA_MAX + 1]; + struct rtattr *gateway; + const char *err_msg; + + rtnh = RTA_DATA(mpath_rtattr); + len = RTA_PAYLOAD(mpath_rtattr); + + for (; len > 0; + len -= NLMSG_ALIGN(rtnh->rtnh_len), rtnh = RTNH_NEXT(rtnh)) { + uint32_t vxlan_vni; + uint16_t encap_type; + + if (!RTNH_OK(rtnh, len)) { + netlink_msg_ctx_set_err(ctx, "Malformed nh"); + return 0; + } + + if (rtnh->rtnh_len <= sizeof(*rtnh)) { + netlink_msg_ctx_set_err(ctx, "NH len too small"); + return 0; + } + + /* + * Parse attributes included in the nexthop. + */ + err_msg = NULL; + if (!parse_rtattrs_(RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh), rtattrs, + ARRAY_SIZE(rtattrs), &err_msg)) { + netlink_msg_ctx_set_err(ctx, err_msg); + return 0; + } + + gateway = rtattrs[RTA_GATEWAY]; + memset(tb, 0, sizeof(tb)); + if (rtattrs[RTA_ENCAP]) { + parse_rtattrs_(RTA_DATA(rtattrs[RTA_ENCAP]), + rtattrs[RTA_ENCAP]->rta_len - + sizeof(struct rtattr), + tb, ARRAY_SIZE(tb), &err_msg); + } + + if (rtattrs[RTA_ENCAP_TYPE]) + encap_type = + *(uint16_t *)RTA_DATA(rtattrs[RTA_ENCAP_TYPE]); + else + encap_type = 0; + + if (tb[0]) + vxlan_vni = *(uint32_t *)RTA_DATA(tb[0]); + else + vxlan_vni = 0; + + netlink_msg_ctx_add_nh(ctx, rtnh->rtnh_ifindex, gateway, + encap_type, vxlan_vni); + } + + return 1; +} + +/* + * parse_route_msg + */ +static int parse_route_msg(struct netlink_msg_ctx *ctx) +{ + int len; + struct rtattr **rtattrs, *rtattr, *gateway, *oif; + int if_index; + + ctx->rtmsg = NLMSG_DATA(ctx->hdr); + + len = ctx->hdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + if (len < 0) { + netlink_msg_ctx_set_err(ctx, "Bad message length"); + return 0; + } + + if (!parse_rtattrs(ctx, RTM_RTA(ctx->rtmsg), len)) + return 0; + + rtattrs = ctx->rtattrs; + + ctx->dest = rtattrs[RTA_DST]; + ctx->src = rtattrs[RTA_PREFSRC]; + + rtattr = rtattrs[RTA_PRIORITY]; + if (rtattr) + ctx->metric = (int *)RTA_DATA(rtattr); + + rtattr = rtattrs[RTA_NH_ID]; + if (rtattr) + ctx->nhgid = (unsigned int *)RTA_DATA(rtattr); + + gateway = rtattrs[RTA_GATEWAY]; + oif = rtattrs[RTA_OIF]; + if (gateway || oif) { + struct rtattr *tb[RTA_MAX + 1] = { 0 }; + uint16_t encap_type = 0; + uint32_t vxlan_vni = 0; + + if_index = 0; + if (oif) + if_index = *((int *)RTA_DATA(oif)); + + + if (rtattrs[RTA_ENCAP]) { + const char *err_msg; + + parse_rtattrs_(RTA_DATA(rtattrs[RTA_ENCAP]), + rtattrs[RTA_ENCAP]->rta_len - + sizeof(struct rtattr), + tb, ARRAY_SIZE(tb), &err_msg); + } + + if (rtattrs[RTA_ENCAP_TYPE]) + encap_type = + *(uint16_t *)RTA_DATA(rtattrs[RTA_ENCAP_TYPE]); + + if (tb[0]) + vxlan_vni = *(uint32_t *)RTA_DATA(tb[0]); + + netlink_msg_ctx_add_nh(ctx, if_index, gateway, encap_type, + vxlan_vni); + } + + rtattr = rtattrs[RTA_MULTIPATH]; + if (rtattr) + parse_multipath_attr(ctx, rtattr); + + return 1; +} + +/* + * addr_to_s + */ +static const char * +addr_to_s(unsigned char family, void *addr) +{ + size_t buf_len; + char *buf; + + buf = get_print_buf(&buf_len); + + return inet_ntop(family, addr, buf, buf_len); +} + +/* + * netlink_msg_ctx_print + */ +static int netlink_msg_ctx_snprint(struct netlink_msg_ctx *ctx, char *buf, + size_t buf_len) +{ + struct nlmsghdr *hdr; + struct rtmsg *rtmsg; + struct netlink_nh *nh; + char *cur, *end; + unsigned long i; + + hdr = ctx->hdr; + rtmsg = ctx->rtmsg; + + cur = buf; + end = buf + buf_len; + + cur += snprintf(cur, end - cur, "%s %s/%d, Prot: %s(%u)", + netlink_msg_type_to_s(hdr->nlmsg_type), + addr_to_s(rtmsg->rtm_family, RTA_DATA(ctx->dest)), + rtmsg->rtm_dst_len, + netlink_prot_to_s(rtmsg->rtm_protocol), + rtmsg->rtm_protocol); + + if (ctx->metric) + cur += snprintf(cur, end - cur, ", Metric: %d", *ctx->metric); + + if (ctx->nhgid) + cur += snprintf(cur, end - cur, ", nhgid: %u", *ctx->nhgid); + for (i = 0; i < ctx->num_nhs; i++) { + cur += snprintf(cur, end - cur, "\n "); + nh = &ctx->nhs[i]; + + if (nh->gateway) { + cur += snprintf(cur, end - cur, " %s", + addr_to_s(rtmsg->rtm_family, + RTA_DATA(nh->gateway))); + } + + if (nh->if_index) { + cur += snprintf(cur, end - cur, " via interface %d", + nh->if_index); + } + + if (nh->encap_type) + cur += snprintf(cur, end - cur, + ", Encap Type: %u Vxlan vni %u", + nh->encap_type, nh->vxlan_vni); + } + + return cur - buf; +} + +/* + * print_netlink_msg_ctx + */ +static void print_netlink_msg_ctx(struct netlink_msg_ctx *ctx) +{ + char buf[1024]; + + netlink_msg_ctx_snprint(ctx, buf, sizeof(buf)); + printf("%s\n", buf); +} + +static void fpm_listener_hexdump(const void *mem, size_t len) +{ + char line[64]; + const uint8_t *src = mem; + const uint8_t *end = src + len; + + if (!glob->dump_hex) + return; + + if (len == 0) { + printf("%016lx: (zero length / no data)\n", (long)src); + return; + } + + while (src < end) { + struct fbuf fb = { + .buf = line, + .pos = line, + .len = sizeof(line), + }; + const uint8_t *lineend = src + 8; + uint32_t line_bytes = 0; + + printf("%016lx: ", (long)src); + + while (src < lineend && src < end) { + printf("%02x ", *src++); + line_bytes++; + } + if (line_bytes < 8) + printf("%*s", (8 - line_bytes) * 3, ""); + + src -= line_bytes; + while (src < lineend && src < end && fb.pos < fb.buf + fb.len) { + uint8_t byte = *src++; + + if (isprint(byte)) + *fb.pos++ = byte; + else + *fb.pos++ = '.'; + } + printf("\n"); + } +} + +/* + * parse_netlink_msg + */ +static void parse_netlink_msg(char *buf, size_t buf_len, fpm_msg_hdr_t *fpm) +{ + struct netlink_msg_ctx ctx_space, *ctx; + struct nlmsghdr *hdr; + unsigned int len; + + fpm_listener_hexdump(buf, buf_len); + ctx = &ctx_space; + + hdr = (struct nlmsghdr *)buf; + len = buf_len; + for (; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) { + + netlink_msg_ctx_init(ctx); + ctx->hdr = hdr; + + switch (hdr->nlmsg_type) { + + case RTM_DELROUTE: + case RTM_NEWROUTE: + + parse_route_msg(ctx); + if (ctx->err_msg) { + fprintf(stderr, + "Error parsing route message: %s\n", + ctx->err_msg); + } + + print_netlink_msg_ctx(ctx); + + if (glob->reflect && hdr->nlmsg_type == RTM_NEWROUTE && + ctx->rtmsg->rtm_protocol > RTPROT_STATIC) { + printf(" Route %s(%u) reflecting back\n", + netlink_prot_to_s( + ctx->rtmsg->rtm_protocol), + ctx->rtmsg->rtm_protocol); + ctx->rtmsg->rtm_flags |= RTM_F_OFFLOAD; + write(glob->sock, fpm, fpm_msg_len(fpm)); + } + break; + + default: + fprintf(stdout, + "Ignoring netlink message - Type: %s(%d)\n", + netlink_msg_type_to_s(hdr->nlmsg_type), + hdr->nlmsg_type); + } + } +} + +/* + * process_fpm_msg + */ +static void process_fpm_msg(fpm_msg_hdr_t *hdr) +{ + fprintf(stdout, "FPM message - Type: %d, Length %d\n", hdr->msg_type, + ntohs(hdr->msg_len)); + + if (hdr->msg_type != FPM_MSG_TYPE_NETLINK) { + fprintf(stderr, "Unknown fpm message type %u\n", hdr->msg_type); + return; + } + + parse_netlink_msg(fpm_msg_data(hdr), fpm_msg_data_len(hdr), hdr); +} + +/* + * fpm_serve + */ +static void fpm_serve(void) +{ + char buf[FPM_MAX_MSG_LEN * 4]; + fpm_msg_hdr_t *hdr; + + while (1) { + + hdr = read_fpm_msg(buf, sizeof(buf)); + if (!hdr) + return; + + process_fpm_msg(hdr); + } +} + +int main(int argc, char **argv) +{ + pid_t daemon; + int r; + bool fork_daemon = false; + + memset(glob, 0, sizeof(*glob)); + + while ((r = getopt(argc, argv, "rdv")) != -1) { + switch (r) { + case 'r': + glob->reflect = true; + break; + case 'd': + fork_daemon = true; + break; + case 'v': + glob->dump_hex = true; + break; + } + } + + if (fork_daemon) { + daemon = fork(); + + if (daemon) + exit(0); + } + + if (!create_listen_sock(FPM_DEFAULT_PORT, &glob->server_sock)) + exit(1); + + /* + * Server forever. + */ + while (1) { + glob->sock = accept_conn(glob->server_sock); + fpm_serve(); + fprintf(stdout, "Done serving client"); + } +} +#else + +int main(int argc, char **argv) +{ + fprintf(stderr, "This program only works on linux"); + exit(-1); +} +#endif diff --git a/zebra/ge_netlink.c b/zebra/ge_netlink.c new file mode 100644 index 000000000000..e7d2e6b12ad3 --- /dev/null +++ b/zebra/ge_netlink.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Generic Netlink functions. + * Copyright (C) 2022, Carmine Scarpitta + */ + +#include + +#ifdef HAVE_NETLINK + +/* The following definition is to workaround an issue in the Linux kernel + * header files with redefinition of 'struct in6_addr' in both + * netinet/in.h and linux/in6.h. + * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html + */ +#define _LINUX_IN6_H + +#include +#include +#include + +#include "lib/ns.h" +#include "zebra/ge_netlink.h" +#include "zebra/debug.h" +#include "zebra/kernel_netlink.h" +#include "zebra/zebra_router.h" +#include "zebra/zebra_srv6.h" + + +/** + * This file provides an implementation of the functionality exposed by the + * kernel through the Generic Netlink mechanism. + * + * Supported features include the ability to configure the source address used + * for SRv6 encapsulation ('sr tunsrc' in kernel terminology). + * + * At the time of writing this code, the kernel does not send us any asynchronous + * notifications when someone changes the 'sr tunsrc' under us. As a result, we + * are currently unable to detect when the source address changes and update the + * SRv6 encapsulation source address configured in zebra. + * + * In the future, when the kernel supports async notifications, the implementation + * can be improved by listening on the Generic Netlink socket and adding a handler + * to process/parse incoming 'sr tunsrc' change messages and update the SRv6 zebra + * configuration with the new encap source address. + */ + + +/* + * Numeric family identifier used to configure SRv6 internal parameters through Generic Netlink. + */ +static int16_t seg6_genl_family = -1; + +static int genl_parse_getfamily(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + int len; + struct rtattr *tb[CTRL_ATTR_MAX + 1]; + struct genlmsghdr *ghdr = NLMSG_DATA(h); + struct rtattr *attrs; + const char *family; + + if (h->nlmsg_type != GENL_ID_CTRL) { + zlog_err( + "Not a controller message, nlmsg_len=%d nlmsg_type=0x%x", + h->nlmsg_len, h->nlmsg_type); + return 0; + } + + len = h->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) { + zlog_err( + "Message received from netlink is of a broken size %d %zu", + h->nlmsg_len, (size_t)NLMSG_LENGTH(GENL_HDRLEN)); + return -1; + } + + if (ghdr->cmd != CTRL_CMD_NEWFAMILY) { + zlog_err("Unknown controller command %d", ghdr->cmd); + return -1; + } + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + netlink_parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); + + if (tb[CTRL_ATTR_FAMILY_ID] == NULL) { + zlog_err("Missing family id TLV"); + return -1; + } + + if (tb[CTRL_ATTR_FAMILY_NAME] == NULL) { + zlog_err("Missing family name TLV"); + return -1; + } + + family = (char *)RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]); + + if (strmatch(family, "SEG6")) + seg6_genl_family = + *(int16_t *)RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]); + else { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_err("Unsupported Generic Netlink family '%s'", + family); + return -1; + } + + return 0; +} + +int genl_resolve_family(const char *family) +{ + struct zebra_ns *zns; + struct genl_request req; + + memset(&req, 0, sizeof(req)); + + zns = zebra_ns_lookup(NS_DEFAULT); + + req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = GENL_ID_CTRL; + + req.n.nlmsg_pid = zns->ge_netlink_cmd.snl.nl_pid; + + req.g.cmd = CTRL_CMD_GETFAMILY; + req.g.version = 0; + + if (!nl_attr_put(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, family, + strlen(family) + 1)) + return -1; + + return ge_netlink_talk(genl_parse_getfamily, &req.n, zns, false); +} + +/* + * sr tunsrc change via netlink interface, using a dataplane context object + * + * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer + * otherwise the number of bytes written to buf. + */ +ssize_t netlink_sr_tunsrc_set_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + struct nlsock *nl; + const struct in6_addr *tunsrc_addr; + struct genl_request *req = buf; + + if (seg6_genl_family < 0) { + zlog_err( + "Failed to set SRv6 source address: kernel does not support 'SEG6' Generic Netlink family."); + return -1; + } + + tunsrc_addr = dplane_ctx_get_srv6_encap_srcaddr(ctx); + if (!tunsrc_addr) + return -1; + + if (buflen < sizeof(*req)) + return 0; + + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + + /* Prepare Netlink request to set tunsrc addr */ + req->n.nlmsg_type = seg6_genl_family; + req->n.nlmsg_pid = nl->snl.nl_pid; + + req->g.cmd = cmd; + req->g.version = SEG6_GENL_VERSION; + + switch (cmd) { + case SEG6_CMD_SET_TUNSRC: + if (!nl_attr_put(&req->n, buflen, SEG6_ATTR_DST, tunsrc_addr, + sizeof(struct in6_addr))) + return 0; + break; + default: + zlog_err("Unsupported command (%u)", cmd); + return -1; + } + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + +ssize_t netlink_sr_tunsrc_set_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + enum dplane_op_e op; + int cmd = 0; + + op = dplane_ctx_get_op(ctx); + + /* Call to netlink layer based on type of operation */ + if (op == DPLANE_OP_SRV6_ENCAP_SRCADDR_SET) { + /* Validate */ + if (dplane_ctx_get_srv6_encap_srcaddr(ctx) == NULL) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "sr tunsrc set failed: SRv6 encap source address not set"); + return -1; + } + + cmd = SEG6_CMD_SET_TUNSRC; + } else { + /* Invalid op */ + zlog_err("Context received for kernel sr tunsrc update with incorrect OP code (%u)", + op); + return -1; + } + + return netlink_sr_tunsrc_set_msg_encode(cmd, ctx, buf, buflen); +} + +enum netlink_msg_status +netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op; + struct zebra_ns *zns; + struct genl_request req; + + op = dplane_ctx_get_op(ctx); + assert(op == DPLANE_OP_SRV6_ENCAP_SRCADDR_SET); + + netlink_sr_tunsrc_set_msg_encoder(ctx, &req, sizeof(req)); + + zns = zebra_ns_lookup(dplane_ctx_get_ns_sock(ctx)); + + return ge_netlink_talk(netlink_talk_filter, &req.n, zns, false); +} + +/** + * netlink_sr_tunsrc_reply_read() - Read in SR tunsrc reply from the kernel + * + * @h: Netlink message header + * @ns_id: Namspace id + * @startup: Are we reading under startup conditions? + * + * Return: Result status + */ +int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup) +{ + int len; + struct genlmsghdr *ghdr; + struct rtattr *tb[SEG6_ATTR_MAX + 1] = {}; + struct rtattr *attrs; + + if (h->nlmsg_type != seg6_genl_family) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) { + zlog_warn("%s: Message received from netlink is of a broken size %d %zu", + __func__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(GENL_HDRLEN)); + return -1; + } + + ghdr = NLMSG_DATA(h); + + if (ghdr->cmd != SEG6_CMD_GET_TUNSRC) + return 0; + + attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); + netlink_parse_rtattr(tb, SEG6_ATTR_MAX, attrs, len); + + if (tb[SEG6_ATTR_DST] == NULL) { + zlog_err("Missing tunsrc addr"); + return -1; + } + + zebra_srv6_encap_src_addr_set( + (struct in6_addr *)RTA_DATA(tb[SEG6_ATTR_DST])); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: SRv6 encap source address received from kernel: '%pI6'", + __func__, + (struct in6_addr *)RTA_DATA(tb[SEG6_ATTR_DST])); + + return 0; +} + +/** + * netlink_request_sr_tunsrc() - Request SR tunsrc from the kernel + * @zns: Zebra namespace + * + * Return: Result status + */ +static int netlink_request_sr_tunsrc(struct zebra_ns *zns) +{ + struct genl_request req; + + if (zns->ge_netlink_cmd.sock < 0) + return -1; + + if (seg6_genl_family < 0) { + zlog_err( + "Failed to get SRv6 encap source address: kernel does not support 'SEG6' Generic Netlink family."); + return -1; + } + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = seg6_genl_family; + req.g.cmd = SEG6_CMD_GET_TUNSRC; + req.g.version = SEG6_GENL_VERSION; + + return netlink_request(&zns->ge_netlink_cmd, &req); +} + +/** + * SR tunsrc read function using netlink interface. Only called + * on bootstrap time. + */ +int netlink_sr_tunsrc_read(struct zebra_ns *zns) +{ + int ret; + struct zebra_dplane_info dp_info; + + if (zns->ge_netlink_cmd.sock < 0) + return -1; + + /* Capture info in intermediate info struct */ + dp_info.ns_id = zns->ns_id; + dp_info.is_cmd = true; + dp_info.sock = zns->ge_netlink_cmd.sock; + dp_info.seq = zns->ge_netlink_cmd.seq; + + /* Get SR tunsrc. */ + ret = netlink_request_sr_tunsrc(zns); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_sr_tunsrc_reply_read, + &zns->ge_netlink_cmd, &dp_info, 0, true); + if (ret < 0) + return ret; + + return 0; +} + +void ge_netlink_init(struct zebra_ns *zns) +{ + if (zns->ge_netlink_cmd.sock < 0) + return; + + /* + * Resolves the 'seg6' Generic Netlink family name to the corresponding numeric family identifier. + * This will give us the numeric family identifier required to send 'seg6' commands to the kernel + * over the Generic Netlink socket. 'seg6' commands are used to configure SRv6 internal parameters + * such as the address to use as source for encapsulated packets. + */ + if (genl_resolve_family("SEG6")) + zlog_warn( + "Kernel does not support 'SEG6' Generic Netlink family. Any attempt to set the encapsulation parameters under the SRv6 configuration will fail"); + + /** + * Retrieve the actual SRv6 encap source address from the kernel + * (default namespace) and save it to zebra SRv6 config + */ + if (zns->ns_id == NS_DEFAULT) + netlink_sr_tunsrc_read(zns); +} + +#endif /* HAVE_NETLINK */ diff --git a/zebra/ge_netlink.h b/zebra/ge_netlink.h new file mode 100644 index 000000000000..20d09116c00a --- /dev/null +++ b/zebra/ge_netlink.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Header file exported by ge_netlink.c to zebra. + * Copyright (C) 2022, Carmine Scarpitta + */ + +#ifndef _ZEBRA_GE_NETLINK_H +#define _ZEBRA_GE_NETLINK_H + +#include "zebra_dplane.h" + +#ifdef HAVE_NETLINK + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Generic Netlink request message */ +struct genl_request { + struct nlmsghdr n; + struct genlmsghdr g; + char buf[1024]; +}; + +extern int genl_resolve_family(const char *family); +extern ssize_t netlink_sr_tunsrc_set_msg_encode(int cmd, + struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen); +extern ssize_t netlink_sr_tunsrc_set_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen); +struct nl_batch; +extern enum netlink_msg_status +netlink_put_sr_tunsrc_set_msg(struct nl_batch *bth, + struct zebra_dplane_ctx *ctx); + +int netlink_sr_tunsrc_reply_read(struct nlmsghdr *h, ns_id_t ns_id, int startup); +int netlink_sr_tunsrc_read(struct zebra_ns *zns); + +extern void ge_netlink_init(struct zebra_ns *zns); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_NETLINK */ + +#endif /* _ZEBRA_GE_NETLINK_H */ diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index b3cf86512258..688a7f6e332f 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -5,6 +5,7 @@ */ #include +#include #ifdef OPEN_BSD @@ -295,6 +296,8 @@ void interface_list(struct zebra_ns *zns) /proc/net/if_inet6. */ ifaddr_proc_ipv6(); #endif /* HAVE_PROC_NET_IF_INET6 */ + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); } #endif /* OPEN_BSD */ diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 61a8c6a78a0e..32335198733b 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -17,6 +17,8 @@ #define _LINUX_IF_H #define _LINUX_IP_H +#include +#include #include #include #include @@ -215,6 +217,8 @@ static void netlink_determine_zebra_iftype(const char *kind, *zif_type = ZEBRA_IF_VETH; else if (strcmp(kind, "bond") == 0) *zif_type = ZEBRA_IF_BOND; + else if (strcmp(kind, "team") == 0) + *zif_type = ZEBRA_IF_BOND; else if (strcmp(kind, "gre") == 0) *zif_type = ZEBRA_IF_GRE; } @@ -257,6 +261,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) int sd; int rc; const char *ifname = interface->name; + uint32_t ret; if (error) *error = 0; @@ -281,7 +286,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) ifname, errno, safe_strerror(errno)); /* no vrf socket creation may probably mean vrf issue */ if (error) - *error = -1; + *error = INTERFACE_SPEED_ERROR_READ; return 0; } /* Get the current link state for the interface */ @@ -295,14 +300,20 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) ifname, errno, safe_strerror(errno)); /* no device means interface unreachable */ if (errno == ENODEV && error) - *error = -1; + *error = INTERFACE_SPEED_ERROR_READ; ecmd.speed_hi = 0; ecmd.speed = 0; } close(sd); - return ((uint32_t)ecmd.speed_hi << 16) | ecmd.speed; + ret = ((uint32_t)ecmd.speed_hi << 16) | ecmd.speed; + if (ret == UINT32_MAX) { + if (error) + *error = INTERFACE_SPEED_ERROR_UNKNOWN; + ret = 0; + } + return ret; } uint32_t kernel_get_speed(struct interface *ifp, int *error) @@ -998,68 +1009,13 @@ static ssize_t netlink_intf_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, op = dplane_ctx_get_op(ctx); - switch (op) { - case DPLANE_OP_INTF_UPDATE: + if (op == DPLANE_OP_INTF_UPDATE) cmd = RTM_SETLINK; - break; - case DPLANE_OP_INTF_INSTALL: + else if (op == DPLANE_OP_INTF_INSTALL) cmd = RTM_NEWLINK; - break; - case DPLANE_OP_INTF_DELETE: + else if (op == DPLANE_OP_INTF_DELETE) cmd = RTM_DELLINK; - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: + else { flog_err( EC_ZEBRA_NHG_FIB_UPDATE, "Context received for kernel interface update with incorrect OP code (%u)", @@ -1474,6 +1430,9 @@ int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, if (kernel_flags & IFA_F_SECONDARY) dplane_ctx_intf_set_secondary(ctx); + if (kernel_flags & IFA_F_NOPREFIXROUTE) + dplane_ctx_intf_set_noprefixroute(ctx); + /* Label */ if (tb[IFA_LABEL]) { label = (char *)RTA_DATA(tb[IFA_LABEL]); @@ -1514,7 +1473,6 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifi = NLMSG_DATA(h); - /* assume if not default zns, then new VRF */ if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_debug("%s: wrong kernel message %s", __func__, @@ -1622,6 +1580,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) zlog_debug( "RTM_NEWLINK for interface %s(%u) without MTU set", name, ifi->ifi_index); + dplane_ctx_fini(&ctx); return 0; } dplane_ctx_set_ifp_mtu(ctx, *(int *)RTA_DATA(tb[IFLA_MTU])); diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index ae292689ed30..28cbb0415a5c 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -6,6 +6,8 @@ #include +#include + #if !defined(GNU_LINUX) && !defined(OPEN_BSD) #include "if.h" @@ -126,6 +128,8 @@ void interface_list(struct zebra_ns *zns) /* Free sysctl buffer. */ XFREE(MTYPE_TMP, ref); + + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_INTERFACES_READ); } #endif /* !defined(GNU_LINUX) && !defined(OPEN_BSD) */ diff --git a/zebra/interface.c b/zebra/interface.c index 92ae8a9dc5e5..03b710e1a0f9 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -18,7 +18,6 @@ #include "log.h" #include "zclient.h" #include "vrf.h" -#include "lib/northbound_cli.h" #include "zebra/rtadv.h" #include "zebra_ns.h" @@ -33,7 +32,6 @@ #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_evpn_mh.h" @@ -44,8 +42,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information"); DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), (vty, ifp)); -DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), - (vty, ifp)); DEFINE_MTYPE(ZEBRA, ZIF_DESC, "Intf desc"); @@ -65,7 +61,7 @@ static void if_zebra_speed_update(struct event *thread) * interfaces not available. * note that loopback & virtual interfaces can return 0 as speed */ - if (error < 0) + if (error == INTERFACE_SPEED_ERROR_READ) return; if (new_speed != ifp->speed) { @@ -76,7 +72,7 @@ static void if_zebra_speed_update(struct event *thread) changed = true; } - if (changed || new_speed == UINT32_MAX) { + if (changed || error == INTERFACE_SPEED_ERROR_UNKNOWN) { #define SPEED_UPDATE_SLEEP_TIME 5 #define SPEED_UPDATE_COUNT_MAX (4 * 60 / SPEED_UPDATE_SLEEP_TIME) /* @@ -91,7 +87,7 @@ static void if_zebra_speed_update(struct event *thread) * to not update the system to keep track of that. This * is far simpler to just stop trying after 4 minutes */ - if (new_speed == UINT32_MAX && + if (error == INTERFACE_SPEED_ERROR_UNKNOWN && zif->speed_update_count == SPEED_UPDATE_COUNT_MAX) return; @@ -111,17 +107,6 @@ static void zebra_if_node_destroy(route_table_delegate_t *delegate, route_node_destroy(delegate, table, node); } -static void zebra_if_nhg_dependents_free(struct zebra_if *zebra_if) -{ - nhg_connected_tree_free(&zebra_if->nhg_dependents); -} - -static void zebra_if_nhg_dependents_init(struct zebra_if *zebra_if) -{ - nhg_connected_tree_init(&zebra_if->nhg_dependents); -} - - route_table_delegate_t zebra_if_table_delegate = { .create_node = route_node_create, .destroy_node = zebra_if_node_destroy}; @@ -136,11 +121,11 @@ static int if_zebra_new_hook(struct interface *ifp) zebra_if->multicast = IF_ZEBRA_DATA_UNSPEC; zebra_if->mpls_config = IF_ZEBRA_DATA_UNSPEC; - zebra_if->shutdown = IF_ZEBRA_DATA_OFF; + zebra_if->shutdown = IF_ZEBRA_DATA_UNSPEC; zebra_if->link_nsid = NS_UNKNOWN; - zebra_if_nhg_dependents_init(zebra_if); + nhg_connected_tree_init(&zebra_if->nhg_dependents); zebra_ptm_if_init(zebra_if); @@ -148,6 +133,8 @@ static int if_zebra_new_hook(struct interface *ifp) rtadv_if_init(zebra_if); + zebra_evpn_mh_if_init(zebra_if); + memset(&zebra_if->neigh_mac[0], 0, 6); /* Initialize installed address chains tree. */ @@ -171,18 +158,13 @@ static int if_zebra_new_hook(struct interface *ifp) return 0; } -static void if_nhg_dependents_check_valid(struct nhg_hash_entry *nhe) -{ - zebra_nhg_check_valid(nhe); -} - static void if_down_nhg_dependents(const struct interface *ifp) { struct nhg_connected *rb_node_dep = NULL; struct zebra_if *zif = (struct zebra_if *)ifp->info; frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) - if_nhg_dependents_check_valid(rb_node_dep->nhe); + zebra_nhg_check_valid(rb_node_dep->nhe); } static void if_nhg_dependents_release(const struct interface *ifp) @@ -192,7 +174,11 @@ static void if_nhg_dependents_release(const struct interface *ifp) frr_each(nhg_connected_tree, &zif->nhg_dependents, rb_node_dep) { rb_node_dep->nhe->ifp = NULL; /* Null it out */ - if_nhg_dependents_check_valid(rb_node_dep->nhe); + zebra_nhg_check_valid(rb_node_dep->nhe); + if (CHECK_FLAG(rb_node_dep->nhe->flags, + NEXTHOP_GROUP_KEEP_AROUND) && + rb_node_dep->nhe->refcnt == 1) + zebra_nhg_decrement_ref(rb_node_dep->nhe); } } @@ -227,7 +213,7 @@ static int if_zebra_delete_hook(struct interface *ifp) zebra_evpn_mac_ifp_del(ifp); if_nhg_dependents_release(ifp); - zebra_if_nhg_dependents_free(zebra_if); + nhg_connected_tree_free(&zebra_if->nhg_dependents); XFREE(MTYPE_ZIF_DESC, zebra_if->desc); @@ -489,12 +475,11 @@ void if_flags_update(struct interface *ifp, uint64_t newflags) address. */ void if_addr_wakeup(struct interface *ifp) { - struct listnode *node, *nnode; struct connected *ifc; struct prefix *p; enum zebra_dplane_result dplane_res; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) { + frr_each_safe (if_connected, ifp->connected, ifc) { p = ifc->address; if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED) @@ -637,32 +622,24 @@ void if_add_update(struct interface *ifp) /* Install connected routes corresponding to an interface. */ static void if_install_connected(struct interface *ifp) { - struct listnode *node; - struct listnode *next; struct connected *ifc; - if (ifp->connected) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, next, ifc)) { - if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) - zebra_interface_address_add_update(ifp, ifc); + frr_each (if_connected, ifp->connected, ifc) { + if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) + zebra_interface_address_add_update(ifp, ifc); - connected_up(ifp, ifc); - } + connected_up(ifp, ifc); } } /* Uninstall connected routes corresponding to an interface. */ static void if_uninstall_connected(struct interface *ifp) { - struct listnode *node; - struct listnode *next; struct connected *ifc; - if (ifp->connected) { - for (ALL_LIST_ELEMENTS(ifp->connected, node, next, ifc)) { - zebra_interface_address_delete_update(ifp, ifc); - connected_down(ifp, ifc); - } + frr_each_safe (if_connected, ifp->connected, ifc) { + zebra_interface_address_delete_update(ifp, ifc); + connected_down(ifp, ifc); } } @@ -670,20 +647,15 @@ static void if_uninstall_connected(struct interface *ifp) /* TODO - Check why IPv4 handling here is different from install or if_down */ static void if_delete_connected(struct interface *ifp) { - struct connected *ifc; + struct connected *ifc, *ifc_next; struct prefix cp; struct route_node *rn; struct zebra_if *zebra_if; - struct listnode *node; - struct listnode *last = NULL; zebra_if = ifp->info; - if (!ifp->connected) - return; - - while ((node = (last ? last->next : listhead(ifp->connected)))) { - ifc = listgetdata(node); + for (ifc = if_connected_first(ifp->connected); ifc; ifc = ifc_next) { + ifc_next = if_connected_next(ifp->connected, ifc); cp = *CONNECTED_PREFIX(ifc); apply_mask(&cp); @@ -732,11 +704,15 @@ static void if_delete_connected(struct interface *ifp) * (unconditionally). */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { - listnode_delete(ifp->connected, + if (ifc == ifc_next) + ifc_next = if_connected_next( + ifp->connected, ifc); + + if_connected_del(ifp->connected, + ifc); connected_free(&ifc); - } else - last = node; + } } /* Free chain list and respective route node. */ @@ -751,14 +727,10 @@ static void if_delete_connected(struct interface *ifp) UNSET_FLAG(ifc->conf, ZEBRA_IFC_REAL); UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - last = node; - else { - listnode_delete(ifp->connected, ifc); + if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { + if_connected_del(ifp->connected, ifc); connected_free(&ifc); } - } else { - last = node; } } } @@ -853,7 +825,7 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) if_down_del_nbr_connected(ifp); /* Send out notification on interface VRF change. */ - /* This is to issue an UPDATE or a DELETE, as appropriate. */ + /* This is to issue a DELETE, as appropriate. */ zebra_interface_vrf_update_del(ifp, vrf_id); if (if_is_vrf(ifp)) @@ -974,47 +946,6 @@ static void if_down_del_nbr_connected(struct interface *ifp) } } -void if_nhg_dependents_add(struct interface *ifp, struct nhg_hash_entry *nhe) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe); - } -} - -void if_nhg_dependents_del(struct interface *ifp, struct nhg_hash_entry *nhe) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe); - } -} - -unsigned int if_nhg_dependents_count(const struct interface *ifp) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - return nhg_connected_tree_count(&zif->nhg_dependents); - } - - return 0; -} - - -bool if_nhg_dependents_is_empty(const struct interface *ifp) -{ - if (ifp->info) { - struct zebra_if *zif = (struct zebra_if *)ifp->info; - - return nhg_connected_tree_is_empty(&zif->nhg_dependents); - } - - return false; -} - /* Interface is up. */ void if_up(struct interface *ifp, bool install_connected) { @@ -1042,6 +973,14 @@ void if_up(struct interface *ifp, bool install_connected) if (install_connected) if_install_connected(ifp); + /* + * Interface associated NHG's have been deleted on + * interface down events, now that this interface + * is coming back up, let's resync the zebra -> dplane + * nhg's so that they can be continued to be used. + */ + zebra_interface_nhg_reinstall(ifp); + /* Handle interface up for specific types for EVPN. Non-VxLAN interfaces * are checked to see if (remote) neighbor entries need to be installed * on them for ARP suppression. @@ -1068,6 +1007,8 @@ void if_up(struct interface *ifp, bool install_connected) event_add_timer(zrouter.master, if_zebra_speed_update, ifp, 0, &zif->speed_update); event_ignore_late_timer(zif->speed_update); + + if_addr_wakeup(ifp); } /* Interface goes down. We have to manage different behavior of based @@ -1331,6 +1272,9 @@ static void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx, if (dplane_ctx_intf_is_secondary(ctx)) SET_FLAG(flags, ZEBRA_IFA_SECONDARY); + if (dplane_ctx_intf_is_noprefixroute(ctx)) + SET_FLAG(flags, ZEBRA_IFA_NOPREFIXROUTE); + /* Label? */ if (dplane_ctx_intf_has_label(ctx)) label = dplane_ctx_get_intf_label(ctx); @@ -1538,23 +1482,27 @@ static void interface_vrf_change(enum dplane_op_e op, ifindex_t ifindex, "DPLANE_OP_INTF_UPDATE for VRF %s(%u) table %u", name, ifindex, tableid); - if (!vrf_lookup_by_id((vrf_id_t)ifindex)) { - vrf_id_t exist_id; + /* + * For a given tableid, if there already exists a vrf and it + * is different from the current vrf to be operated, then there + * is a misconfiguration and zebra will exit. + */ + vrf_id_t exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); - exist_id = zebra_vrf_lookup_by_table(tableid, ns_id); - if (exist_id != VRF_DEFAULT) { - vrf = vrf_lookup_by_id(exist_id); + if (exist_id != VRF_DEFAULT) { + vrf = vrf_lookup_by_id(exist_id); - if (vrf) - flog_err(EC_ZEBRA_VRF_MISCONFIGURED, - "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", - name, ifindex, vrf->name, - vrf->vrf_id); - else - flog_err(EC_ZEBRA_VRF_NOT_FOUND, - "VRF %s id %u does not exist", - name, ifindex); + if (!vrf_lookup_by_id((vrf_id_t)ifindex) && !vrf) { + flog_err(EC_ZEBRA_VRF_NOT_FOUND, + "VRF %s id %u does not exist", name, + ifindex); + exit(-1); + } + if (vrf && strcmp(name, vrf->name)) { + flog_err(EC_ZEBRA_VRF_MISCONFIGURED, + "VRF %s id %u table id overlaps existing vrf %s(%d), misconfiguration exiting", + name, ifindex, vrf->name, vrf->vrf_id); exit(-1); } } @@ -1711,8 +1659,10 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, uint32_t rc_bitfield) { struct zebra_if *zif = ifp->info; - bool old_protodown; + bool old_protodown, reason_extern; + reason_extern = !!CHECK_FLAG(zif->protodown_rc, + ZEBRA_PROTODOWN_EXTERNAL); /* * Set our reason code to note it wasn't us. * If the reason we got from the kernel is ONLY frr though, don't @@ -1728,8 +1678,8 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, return; if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_DPLANE) - zlog_debug("interface %s dplane change, protodown %s", - ifp->name, protodown ? "on" : "off"); + zlog_debug("interface %s dplane change, protodown %s curr reason_extern %u", + ifp->name, protodown ? "on" : "off", reason_extern); /* Set protodown, respectively */ COND_FLAG(zif->flags, ZIF_FLAG_PROTODOWN, protodown); @@ -1754,6 +1704,13 @@ static void interface_if_protodown(struct interface *ifp, bool protodown, return; } + if (!protodown && reason_extern) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("bond member %s has protodown reason external and clear the reason, skip reinstall.", + ifp->name); + return; + } + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "bond mbr %s reinstate protodown %s in the dplane", @@ -1800,6 +1757,9 @@ interface_bridge_vxlan_vlan_vni_map_update(struct zebra_dplane_ctx *ctx, vlanid_t vid; int i; + if (vniarray == NULL) + return; + memset(&vni_start, 0, sizeof(vni_start)); memset(&vni_end, 0, sizeof(vni_end)); @@ -2295,15 +2255,10 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) ifp = if_lookup_by_index_per_ns(zns, ifindex); - switch (op) { - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: + if (op == DPLANE_OP_INTF_ADDR_ADD || op == DPLANE_OP_INTF_ADDR_DEL) { zebra_if_addr_update_ctx(ctx, ifp); - break; - - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: + } else if (op == DPLANE_OP_INTF_INSTALL || + op == DPLANE_OP_INTF_UPDATE || op == DPLANE_OP_INTF_DELETE) { /* * Queued from the dplane means it is something * that we need to handle( create/delete the @@ -2313,62 +2268,8 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) zebra_if_dplane_ifp_handling(ctx); else zebra_if_update_ctx(ctx, ifp); - break; - - case DPLANE_OP_INTF_NETCONFIG: + } else if (op == DPLANE_OP_INTF_NETCONFIG) { zebra_if_netconf_update_ctx(ctx, ifp, ifindex); - break; - - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_NONE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: - break; /* should never hit here */ } } @@ -2407,6 +2308,12 @@ static void connected_dump_vty(struct vty *vty, json_object *json, else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY)) vty_out(vty, " secondary"); + if (json) + json_object_boolean_add(json_addr, "noPrefixRoute", + CHECK_FLAG(connected->flags, ZEBRA_IFA_NOPREFIXROUTE)); + else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_NOPREFIXROUTE)) + vty_out(vty, " noprefixroute"); + if (json) json_object_boolean_add( json_addr, "unnumbered", @@ -2556,34 +2463,27 @@ static void ifs_dump_brief_vty(struct vty *vty, struct vrf *vrf) } uint32_t v6_list_size = 0; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) && (connected->address->family == AF_INET6)) v6_list_size++; } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && !CHECK_FLAG(connected->flags, - ZEBRA_IFA_SECONDARY) - && (connected->address->family == AF_INET6)) { + frr_each (if_connected, ifp->connected, connected) { + if (!CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY) && + (connected->address->family == AF_INET6)) { p = connected->address; - /* Don't print link local pfx */ - if (!IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) { - if (first_pfx_printed) { - /* padding to prepare row only - * for ip addr */ - vty_out(vty, "%-40s", ""); - if (v6_list_size > 1) - vty_out(vty, "+ "); - vty_out(vty, "%pFX\n", p); - } else { - if (v6_list_size > 1) - vty_out(vty, "+ "); - vty_out(vty, "%pFX\n", p); - } - first_pfx_printed = true; - break; + if (first_pfx_printed) { + vty_out(vty, "%-40s", ""); + if (v6_list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%pFX\n", p); + } else { + if (v6_list_size > 1) + vty_out(vty, "+ "); + vty_out(vty, "%pFX\n", p); } + first_pfx_printed = true; + break; } } if (!first_pfx_printed) @@ -2595,7 +2495,6 @@ static void ifs_dump_brief_vty(struct vty *vty, struct vrf *vrf) static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf) { struct connected *connected; - struct listnode *node; struct interface *ifp; FOR_ALL_INTERFACES (vrf, ifp) { @@ -2611,13 +2510,8 @@ static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf) json_addrs = json_object_new_array(); json_object_object_add(json_if, "addresses", json_addrs); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && !CHECK_FLAG(connected->flags, - ZEBRA_IFA_SECONDARY) - && !(connected->address->family == AF_INET6 - && IN6_IS_ADDR_LINKLOCAL( - &connected->address->u.prefix6))) { + frr_each (if_connected, ifp->connected, connected) { + if (!CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY)) { char buf[PREFIX2STR_BUFFER]; json_array_string_add( @@ -2824,9 +2718,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) connected_dump_vty(vty, NULL, connected); } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && (connected->address->family == AF_INET6)) + frr_each (if_connected, ifp->connected, connected) { + if (connected->address->family == AF_INET6) connected_dump_vty(vty, NULL, connected); } @@ -2958,8 +2851,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) " Link Delay Variation %u (micro-sec.)\n", iflp->delay_var); if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) - vty_out(vty, " Link Packet Loss %g (in %%)\n", - iflp->pkt_loss); + vty_out(vty, " Link Packet Loss %f (in %%)\n", + (double)iflp->pkt_loss * LOSS_PRECISION); if (IS_PARAM_SET(iflp, LP_AVA_BW)) vty_out(vty, " Available Bandwidth %g (Byte/s)\n", iflp->ava_bw); @@ -3133,7 +3026,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_object_string_add(json_if, "lastLinkDown", zebra_if->down_last); - zebra_ptm_show_status(vty, json, ifp); + zebra_ptm_show_status(vty, json_if, ifp); json_object_string_add(json_if, "vrfName", ifp->vrf->name); @@ -3201,9 +3094,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, connected_dump_vty(vty, json_addrs, connected); } - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && (connected->address->family == AF_INET6)) + frr_each (if_connected, ifp->connected, connected) { + if (connected->address->family == AF_INET6) connected_dump_vty(vty, json_addrs, connected); } @@ -3360,7 +3252,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, iflp->delay_var); if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) json_object_double_add(json_te, "linkPacketLoss", - iflp->pkt_loss); + (double)iflp->pkt_loss * + LOSS_PRECISION); if (IS_PARAM_SET(iflp, LP_AVA_BW)) json_object_double_add(json_te, "availableBandwidth", iflp->ava_bw); @@ -3744,63 +3637,43 @@ DEFUN (show_interface_desc_vrf_all, return CMD_SUCCESS; } -int if_multicast_set(struct interface *ifp) +void if_arp(struct interface *ifp, bool enable) { - struct zebra_if *if_data; + int ret; - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - if (if_set_flags(ifp, IFF_MULTICAST) < 0) { - zlog_debug("Can't set multicast flag on interface %s", - ifp->name); - return -1; - } - if_refresh(ifp); + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) + return; + + if (enable) + ret = if_unset_flags(ifp, IFF_NOARP); + else + ret = if_set_flags(ifp, IFF_NOARP); + + if (ret < 0) { + zlog_debug("Can't %sset noarp flag on interface %s", + enable ? "" : "un", ifp->name); + return; } - if_data = ifp->info; - if_data->multicast = IF_ZEBRA_DATA_ON; - return 0; + if_refresh(ifp); } -DEFUN (multicast, - multicast_cmd, - "multicast", - "Set multicast flag to interface\n") +int if_multicast_set(struct interface *ifp) { - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; struct zebra_if *if_data; if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - ret = if_set_flags(ifp, IFF_MULTICAST); - if (ret < 0) { - vty_out(vty, "Can't set multicast flag\n"); - return CMD_WARNING_CONFIG_FAILED; + if (if_set_flags(ifp, IFF_MULTICAST) < 0) { + zlog_debug("Can't set multicast flag on interface %s", + ifp->name); + return -1; } if_refresh(ifp); } if_data = ifp->info; if_data->multicast = IF_ZEBRA_DATA_ON; - return CMD_SUCCESS; -} - -DEFPY (mpls, - mpls_cmd, - "[no] mpls ", - NO_STR - MPLS_STR - "Set mpls to be on for the interface\n" - "Set mpls to be off for the interface\n") -{ - if (!no) - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls", - NB_OP_CREATE, on ? "true" : "false"); - else - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls", - NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); + return 0; } int if_multicast_unset(struct interface *ifp) @@ -3821,30 +3694,6 @@ int if_multicast_unset(struct interface *ifp) return 0; } -DEFUN (no_multicast, - no_multicast_cmd, - "no multicast", - NO_STR - "Unset multicast flag to interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; - struct zebra_if *if_data; - - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - ret = if_unset_flags(ifp, IFF_MULTICAST); - if (ret < 0) { - vty_out(vty, "Can't unset multicast flag\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if_refresh(ifp); - } - if_data = ifp->info; - if_data->multicast = IF_ZEBRA_DATA_OFF; - - return CMD_SUCCESS; -} - int if_linkdetect(struct interface *ifp, bool detect) { int if_was_operative; @@ -3868,30 +3717,6 @@ int if_linkdetect(struct interface *ifp, bool detect) return 0; } -DEFUN(linkdetect, linkdetect_cmd, "link-detect", - "Enable link detection on interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - if_linkdetect(ifp, true); - - return CMD_SUCCESS; -} - - -DEFUN (no_linkdetect, - no_linkdetect_cmd, - "no link-detect", - NO_STR - "Disable link detection on interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - if_linkdetect(ifp, false); - - return CMD_SUCCESS; -} - int if_shutdown(struct interface *ifp) { struct zebra_if *if_data; @@ -3911,31 +3736,6 @@ int if_shutdown(struct interface *ifp) return 0; } -DEFUN (shutdown_if, - shutdown_if_cmd, - "shutdown", - "Shutdown the selected interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; - struct zebra_if *if_data; - - if (ifp->ifindex != IFINDEX_INTERNAL) { - /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */ - rtadv_stop_ra(ifp); - ret = if_unset_flags(ifp, IFF_UP); - if (ret < 0) { - vty_out(vty, "Can't shutdown interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if_refresh(ifp); - } - if_data = ifp->info; - if_data->shutdown = IF_ZEBRA_DATA_ON; - - return CMD_SUCCESS; -} - int if_no_shutdown(struct interface *ifp) { struct zebra_if *if_data; @@ -3960,997 +3760,69 @@ int if_no_shutdown(struct interface *ifp) return 0; } -DEFUN (no_shutdown_if, - no_shutdown_if_cmd, - "no shutdown", - NO_STR - "Shutdown the selected interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - int ret; - struct zebra_if *if_data; - - if (ifp->ifindex != IFINDEX_INTERNAL) { - ret = if_set_flags(ifp, IFF_UP | IFF_RUNNING); - if (ret < 0) { - vty_out(vty, "Can't up interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if_refresh(ifp); - - /* Some addresses (in particular, IPv6 addresses on Linux) get - * removed when the interface goes down. They need to be - * readded. - */ - if_addr_wakeup(ifp); - } - - if_data = ifp->info; - if_data->shutdown = IF_ZEBRA_DATA_OFF; - - return CMD_SUCCESS; -} - -DEFUN (bandwidth_if, - bandwidth_if_cmd, - "bandwidth (1-100000)", - "Set bandwidth informational parameter\n" - "Bandwidth in megabits\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - unsigned int bandwidth; - - bandwidth = strtol(argv[idx_number]->arg, NULL, 10); - - /* bandwidth range is <1-100000> */ - if (bandwidth < 1 || bandwidth > 100000) { - vty_out(vty, "Bandwidth is invalid\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ifp->bandwidth = bandwidth; - - /* force protocols to recalculate routes due to cost change */ - if (if_is_operative(ifp)) - zebra_interface_up_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_bandwidth_if, - no_bandwidth_if_cmd, - "no bandwidth [(1-100000)]", - NO_STR - "Set bandwidth informational parameter\n" - "Bandwidth in megabits\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - ifp->bandwidth = 0; - - /* force protocols to recalculate routes due to cost change */ - if (if_is_operative(ifp)) - zebra_interface_up_update(ifp); - - return CMD_SUCCESS; -} - - -struct cmd_node link_params_node = { - .name = "link-params", - .node = LINK_PARAMS_NODE, - .parent_node = INTERFACE_NODE, - .prompt = "%s(config-link-params)# ", - .no_xpath = true, -}; - -static void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, - uint32_t type, uint32_t value) +void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, + uint32_t type, uint32_t value) { /* Update field as needed */ if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) { *field = value; SET_PARAM(ifp->link_params, type); - - /* force protocols to update LINK STATE due to parameters change - */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); } } -static void link_param_cmd_set_float(struct interface *ifp, float *field, - uint32_t type, float value) -{ +void link_param_cmd_set_float(struct interface *ifp, float *field, + uint32_t type, float value) +{ /* Update field as needed */ if (IS_PARAM_UNSET(ifp->link_params, type) || *field != value) { *field = value; SET_PARAM(ifp->link_params, type); - - /* force protocols to update LINK STATE due to parameters change - */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); } } -static void link_param_cmd_unset(struct interface *ifp, uint32_t type) +void link_param_cmd_unset(struct interface *ifp, uint32_t type) { if (ifp->link_params == NULL) return; /* Unset field */ UNSET_PARAM(ifp->link_params, type); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); } -DEFUN_NOSH (link_params, - link_params_cmd, - "link-params", - LINK_PARAMS_STR) +void if_ip_address_install(struct interface *ifp, struct prefix *prefix, + const char *label, struct prefix *pp) { - /* vty->qobj_index stays the same @ interface pointer */ - vty->node = LINK_PARAMS_NODE; - - return CMD_SUCCESS; -} - -DEFUN_NOSH (exit_link_params, - exit_link_params_cmd, - "exit-link-params", - "Exit from Link Params configuration mode\n") -{ - if (vty->node == LINK_PARAMS_NODE) - vty->node = INTERFACE_NODE; - return CMD_SUCCESS; -} - -/* Specific Traffic Engineering parameters commands */ -DEFUN (link_params_enable, - link_params_enable_cmd, - "enable", - "Activate link parameters on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); + struct zebra_if *if_data; + struct connected *ifc; - /* This command could be issue at startup, when activate MPLS TE */ - /* on a new interface or after a ON / OFF / ON toggle */ - /* In all case, TE parameters are reset to their default factory */ - if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) - zlog_debug( - "Link-params: enable TE link parameters on interface %s", - ifp->name); + if_data = ifp->info; - if (!if_link_params_get(ifp)) - if_link_params_enable(ifp); + ifc = connected_check_ptp(ifp, prefix, pp); + if (!ifc) { + ifc = connected_new(); + ifc->ifp = ifp; - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); + /* Address. */ + ifc->address = prefix_new(); + prefix_copy(ifc->address, prefix); - return CMD_SUCCESS; -} + if (pp) { + SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); + ifc->destination = prefix_new(); + prefix_copy(ifc->destination, pp); + } -DEFUN (no_link_params_enable, - no_link_params_enable_cmd, - "no enable", - NO_STR - "Disable link parameters on this interface\n") -{ - char xpath[XPATH_MAXLEN]; - int ret; - VTY_DECLVAR_CONTEXT(interface, ifp); + /* Label. */ + if (label) + ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); - if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS) - zlog_debug("MPLS-TE: disable TE link parameters on interface %s", - ifp->name); + /* Add to linked list. */ + if_connected_add_tail(ifp->connected, ifc); + } - if_link_params_free(ifp); - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities", - ifp->name); - if (yang_dnode_exists(running_config->dnode, xpath)) - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - ret = nb_cli_apply_changes(vty, NULL); - - if (ret != CMD_SUCCESS) - return ret; - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -/* STANDARD TE metrics */ -DEFUN (link_params_metric, - link_params_metric_cmd, - "metric (0-4294967295)", - "Link metric for MPLS-TE purpose\n" - "Metric value in decimal\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - uint32_t metric; - - metric = strtoul(argv[idx_number]->arg, NULL, 10); - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update TE metric if needed */ - link_param_cmd_set_uint32(ifp, &iflp->te_metric, LP_TE_METRIC, metric); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_metric, - no_link_params_metric_cmd, - "no metric", - NO_STR - "Disable Link Metric on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset TE Metric */ - link_param_cmd_unset(ifp, LP_TE_METRIC); - - return CMD_SUCCESS; -} - -DEFUN (link_params_maxbw, - link_params_maxbw_cmd, - "max-bw BANDWIDTH", - "Maximum bandwidth that can be used\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_maxbw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that Maximum bandwidth is not lower than other bandwidth - * parameters */ - if (iflp && ((bw <= iflp->max_rsv_bw) || (bw <= iflp->unrsv_bw[0]) || - (bw <= iflp->unrsv_bw[1]) || (bw <= iflp->unrsv_bw[2]) || - (bw <= iflp->unrsv_bw[3]) || (bw <= iflp->unrsv_bw[4]) || - (bw <= iflp->unrsv_bw[5]) || (bw <= iflp->unrsv_bw[6]) || - (bw <= iflp->unrsv_bw[7]) || (bw <= iflp->ava_bw) || - (bw <= iflp->res_bw) || (bw <= iflp->use_bw))) { - vty_out(vty, - "Maximum Bandwidth could not be lower than others bandwidth\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Maximum Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->max_bw, LP_MAX_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (link_params_max_rsv_bw, - link_params_max_rsv_bw_cmd, - "max-rsv-bw BANDWIDTH", - "Maximum bandwidth that may be reserved\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_max_rsv_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Maximum Reservable Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (link_params_unrsv_bw, - link_params_unrsv_bw_cmd, - "unrsv-bw (0-7) BANDWIDTH", - "Unreserved bandwidth at each priority level\n" - "Priority\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_number = 1; - int idx_bandwidth = 2; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - int priority; - float bw; - - /* We don't have to consider about range check here. */ - if (sscanf(argv[idx_number]->arg, "%d", &priority) != 1) { - vty_out(vty, "link_params_unrsv_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_unrsv_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Unreserved Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, - bw); - - return CMD_SUCCESS; -} - -DEFPY_YANG(link_params_admin_grp, link_params_admin_grp_cmd, - "admin-grp BITPATTERN", - "Administrative group membership\n" - "32-bit Hexadecimal value (e.g. 0xa1)\n") -{ - char xpath[XPATH_MAXLEN]; - int idx_bitpattern = 1; - unsigned long value; - char value_str[11]; - - VTY_DECLVAR_CONTEXT(interface, ifp); - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities", - ifp->name); - if (yang_dnode_exists(running_config->dnode, xpath)) { - vty_out(vty, - "cannot use the admin-grp command when affinity is set\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (sscanf(argv[idx_bitpattern]->arg, "0x%lx", &value) != 1) { - vty_out(vty, "link_params_admin_grp: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - if (value > 0xFFFFFFFF) { - vty_out(vty, "value must be not be superior to 0xFFFFFFFF\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - snprintf(value_str, sizeof(value_str), "%ld", value); - - nb_cli_enqueue_change( - vty, "./frr-zebra:zebra/link-params/legacy-admin-group", - NB_OP_MODIFY, value_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG(no_link_params_admin_grp, no_link_params_admin_grp_cmd, - "no admin-grp", - NO_STR "Disable Administrative group membership on this interface\n") -{ - nb_cli_enqueue_change( - vty, "./frr-zebra:zebra/link-params/legacy-admin-group", - NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -/* RFC5392 & RFC5316: INTER-AS */ -DEFUN (link_params_inter_as, - link_params_inter_as_cmd, - "neighbor A.B.C.D as (1-4294967295)", - "Configure remote ASBR information (Neighbor IP address and AS number)\n" - "Remote IP address in dot decimal A.B.C.D\n" - "Remote AS number\n" - "AS number in the range <1-4294967295>\n") -{ - int idx_ipv4 = 1; - int idx_number = 3; - - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - struct in_addr addr; - uint32_t as; - - if (!inet_aton(argv[idx_ipv4]->arg, &addr)) { - vty_out(vty, "Please specify Router-Addr by A.B.C.D\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - as = strtoul(argv[idx_number]->arg, NULL, 10); - - /* Update Remote IP and Remote AS fields if needed */ - if (IS_PARAM_UNSET(iflp, LP_RMT_AS) || iflp->rmt_as != as - || iflp->rmt_ip.s_addr != addr.s_addr) { - - iflp->rmt_as = as; - iflp->rmt_ip.s_addr = addr.s_addr; - SET_PARAM(iflp, LP_RMT_AS); - - /* force protocols to update LINK STATE due to parameters change - */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - } - return CMD_SUCCESS; -} - -DEFUN (no_link_params_inter_as, - no_link_params_inter_as_cmd, - "no neighbor", - NO_STR - "Remove Neighbor IP address and AS number for Inter-AS TE\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - - if (!iflp) - return CMD_SUCCESS; - - /* Reset Remote IP and AS neighbor */ - iflp->rmt_as = 0; - iflp->rmt_ip.s_addr = 0; - UNSET_PARAM(iflp, LP_RMT_AS); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -/* RFC7471: OSPF Traffic Engineering (TE) Metric extensions & - * draft-ietf-isis-metric-extensions-07.txt */ -DEFUN (link_params_delay, - link_params_delay_cmd, - "delay (0-16777215) [min (0-16777215) max (0-16777215)]", - "Unidirectional Average Link Delay\n" - "Average delay in micro-second as decimal (0...16777215)\n" - "Minimum delay\n" - "Minimum delay in micro-second as decimal (0...16777215)\n" - "Maximum delay\n" - "Maximum delay in micro-second as decimal (0...16777215)\n") -{ - /* Get and Check new delay values */ - uint32_t delay = 0, low = 0, high = 0; - delay = strtoul(argv[1]->arg, NULL, 10); - if (argc == 6) { - low = strtoul(argv[3]->arg, NULL, 10); - high = strtoul(argv[5]->arg, NULL, 10); - } - - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - uint8_t update = 0; - - if (argc == 2) { - /* - * Check new delay value against old Min and Max delays if set - * - * RFC 7471 Section 4.2.7: - * It is possible for min delay and max delay to be - * the same value. - * - * Therefore, it is also allowed that the average - * delay be equal to the min delay or max delay. - */ - if (iflp && IS_PARAM_SET(iflp, LP_MM_DELAY) && - (delay < iflp->min_delay || delay > iflp->max_delay)) { - vty_out(vty, - "Average delay should be in range Min (%d) - Max (%d) delay\n", - iflp->min_delay, iflp->max_delay); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update delay if value is not set or change */ - if (IS_PARAM_UNSET(iflp, LP_DELAY) || iflp->av_delay != delay) { - iflp->av_delay = delay; - SET_PARAM(iflp, LP_DELAY); - update = 1; - } - /* Unset Min and Max delays if already set */ - if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { - iflp->min_delay = 0; - iflp->max_delay = 0; - UNSET_PARAM(iflp, LP_MM_DELAY); - update = 1; - } - } else { - /* - * Check new delays value coherency. See above note - * regarding average delay equal to min/max allowed - */ - if (delay < low || delay > high) { - vty_out(vty, - "Average delay should be in range Min (%d) - Max (%d) delay\n", - low, high); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Delays if needed */ - if (IS_PARAM_UNSET(iflp, LP_DELAY) - || IS_PARAM_UNSET(iflp, LP_MM_DELAY) - || iflp->av_delay != delay || iflp->min_delay != low - || iflp->max_delay != high) { - iflp->av_delay = delay; - SET_PARAM(iflp, LP_DELAY); - iflp->min_delay = low; - iflp->max_delay = high; - SET_PARAM(iflp, LP_MM_DELAY); - update = 1; - } - } - - /* force protocols to update LINK STATE due to parameters change */ - if (update == 1 && if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_delay, - no_link_params_delay_cmd, - "no delay", - NO_STR - "Disable Unidirectional Average, Min & Max Link Delay on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - - if (!iflp) - return CMD_SUCCESS; - - /* Unset Delays */ - iflp->av_delay = 0; - UNSET_PARAM(iflp, LP_DELAY); - iflp->min_delay = 0; - iflp->max_delay = 0; - UNSET_PARAM(iflp, LP_MM_DELAY); - - /* force protocols to update LINK STATE due to parameters change */ - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - - return CMD_SUCCESS; -} - -DEFUN (link_params_delay_var, - link_params_delay_var_cmd, - "delay-variation (0-16777215)", - "Unidirectional Link Delay Variation\n" - "delay variation in micro-second as decimal (0...16777215)\n") -{ - int idx_number = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - uint32_t value; - - value = strtoul(argv[idx_number]->arg, NULL, 10); - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Delay Variation if needed */ - link_param_cmd_set_uint32(ifp, &iflp->delay_var, LP_DELAY_VAR, value); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_delay_var, - no_link_params_delay_var_cmd, - "no delay-variation", - NO_STR - "Disable Unidirectional Delay Variation on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Delay Variation */ - link_param_cmd_unset(ifp, LP_DELAY_VAR); - - return CMD_SUCCESS; -} - -DEFUN (link_params_pkt_loss, - link_params_pkt_loss_cmd, - "packet-loss PERCENTAGE", - "Unidirectional Link Packet Loss\n" - "percentage of total traffic by 0.000003% step and less than 50.331642%\n") -{ - int idx_percentage = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float fval; - - if (sscanf(argv[idx_percentage]->arg, "%g", &fval) != 1) { - vty_out(vty, "link_params_pkt_loss: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - if (fval > MAX_PKT_LOSS) - fval = MAX_PKT_LOSS; - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Packet Loss if needed */ - link_param_cmd_set_float(ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_pkt_loss, - no_link_params_pkt_loss_cmd, - "no packet-loss", - NO_STR - "Disable Unidirectional Link Packet Loss on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Packet Loss */ - link_param_cmd_unset(ifp, LP_PKT_LOSS); - - return CMD_SUCCESS; -} - -DEFUN (link_params_res_bw, - link_params_res_bw_cmd, - "res-bw BANDWIDTH", - "Unidirectional Residual Bandwidth\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_res_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Residual Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Residual Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->res_bw, LP_RES_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_res_bw, - no_link_params_res_bw_cmd, - "no res-bw", - NO_STR - "Disable Unidirectional Residual Bandwidth on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Residual Bandwidth */ - link_param_cmd_unset(ifp, LP_RES_BW); - - return CMD_SUCCESS; -} - -DEFUN (link_params_ava_bw, - link_params_ava_bw_cmd, - "ava-bw BANDWIDTH", - "Unidirectional Available Bandwidth\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_ava_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Available Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Residual Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->ava_bw, LP_AVA_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_ava_bw, - no_link_params_ava_bw_cmd, - "no ava-bw", - NO_STR - "Disable Unidirectional Available Bandwidth on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Available Bandwidth */ - link_param_cmd_unset(ifp, LP_AVA_BW); - - return CMD_SUCCESS; -} - -DEFUN (link_params_use_bw, - link_params_use_bw_cmd, - "use-bw BANDWIDTH", - "Unidirectional Utilised Bandwidth\n" - "Bytes/second (IEEE floating point format)\n") -{ - int idx_bandwidth = 1; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct if_link_params *iflp = if_link_params_get(ifp); - float bw; - - if (sscanf(argv[idx_bandwidth]->arg, "%g", &bw) != 1) { - vty_out(vty, "link_params_use_bw: fscanf: %s\n", - safe_strerror(errno)); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Check that bandwidth is not greater than maximum bandwidth parameter - */ - if (iflp && bw > iflp->max_bw) { - vty_out(vty, - "Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)\n", - iflp->max_bw); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!iflp) - iflp = if_link_params_enable(ifp); - - /* Update Utilized Bandwidth if needed */ - link_param_cmd_set_float(ifp, &iflp->use_bw, LP_USE_BW, bw); - - return CMD_SUCCESS; -} - -DEFUN (no_link_params_use_bw, - no_link_params_use_bw_cmd, - "no use-bw", - NO_STR - "Disable Unidirectional Utilised Bandwidth on this interface\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - - /* Unset Utilised Bandwidth */ - link_param_cmd_unset(ifp, LP_USE_BW); - - return CMD_SUCCESS; -} - -static int ag_change(struct vty *vty, int argc, struct cmd_token **argv, - const char *xpath, bool no, int start_idx) -{ - for (int i = start_idx; i < argc; i++) - nb_cli_enqueue_change(vty, xpath, - no ? NB_OP_DESTROY : NB_OP_CREATE, - argv[i]->arg); - return nb_cli_apply_changes(vty, NULL); -} - -/* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity - */ -DEFPY_YANG(link_params_affinity, link_params_affinity_cmd, - "[no] affinity NAME...", - NO_STR - "Interface affinities\n" - "Affinity names\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - char xpath[XPATH_MAXLEN]; - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/legacy-admin-group", - ifp->name); - if (yang_dnode_exists(running_config->dnode, xpath)) { - vty_out(vty, - "cannot use the affinity command when admin-grp is set\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return ag_change(vty, argc, argv, - "./frr-zebra:zebra/link-params/affinities/affinity", - no, no ? 2 : 1); -} - - -/* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity-mode - */ -DEFPY_YANG(link_params_affinity_mode, link_params_affinity_mode_cmd, - "affinity-mode $affmode", - "Interface affinity mode\n" - "Standard Admin-Group only RFC3630,5305,5329 (default)\n" - "Extended Admin-Group only RFC7308\n" - "Standard and extended Admin-Group format\n") -{ - const char *xpath = "./frr-zebra:zebra/link-params/affinity-mode"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, affmode); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG(no_link_params_affinity_mode, no_link_params_affinity_mode_cmd, - "no affinity-mode []", - NO_STR - "Interface affinity mode\n" - "Standard Admin-Group only RFC3630,5305,5329 (default)\n" - "Extended Admin-Group only RFC7308\n" - "Standard and extended Admin-Group format\n") -{ - const char *xpath = "./frr-zebra:zebra/link-params/affinity-mode"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "standard"); - - return nb_cli_apply_changes(vty, NULL); -} - -static int ag_iter_cb(const struct lyd_node *dnode, void *arg) -{ - struct vty *vty = (struct vty *)arg; - - vty_out(vty, " %s", yang_dnode_get_string(dnode, ".")); - return YANG_ITER_CONTINUE; -} - -void cli_show_legacy_admin_group(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) -{ - if (!yang_dnode_exists(dnode, "./legacy-admin-group")) - return; - - vty_out(vty, " admin-group 0x%x\n", - yang_dnode_get_uint32(dnode, "./legacy-admin-group")); -} - -void cli_show_affinity_mode(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) -{ - enum affinity_mode affinity_mode = yang_dnode_get_enum(dnode, "."); - - if (affinity_mode == AFFINITY_MODE_STANDARD) - vty_out(vty, " affinity-mode standard\n"); - else if (affinity_mode == AFFINITY_MODE_BOTH) - vty_out(vty, " affinity-mode both\n"); -} - -void cli_show_affinity(struct vty *vty, const struct lyd_node *dnode, - bool show_defaults) -{ - if (!yang_dnode_exists(dnode, "./affinity")) - return; - - vty_out(vty, " affinity"); - yang_dnode_iterate(ag_iter_cb, vty, dnode, "./affinity"); - vty_out(vty, "\n"); -} - -int if_ip_address_install(struct interface *ifp, struct prefix *prefix, - const char *label, struct prefix *pp) -{ - struct zebra_if *if_data; - struct prefix_ipv4 lp; - struct prefix_ipv4 *p; - struct connected *ifc; - enum zebra_dplane_result dplane_res; - - if_data = ifp->info; - - lp.family = prefix->family; - lp.prefix = prefix->u.prefix4; - lp.prefixlen = prefix->prefixlen; - apply_mask_ipv4(&lp); - - ifc = connected_check_ptp(ifp, &lp, pp ? pp : NULL); - if (!ifc) { - ifc = connected_new(); - ifc->ifp = ifp; - - /* Address. */ - p = prefix_ipv4_new(); - *p = lp; - ifc->address = (struct prefix *)p; - - if (pp) { - SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); - p = prefix_ipv4_new(); - *p = *(struct prefix_ipv4 *)pp; - ifc->destination = (struct prefix *)p; - } - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); - - /* Add to linked list. */ - listnode_add(ifp->connected, ifc); - } - - /* This address is configured from zebra. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); + /* This address is configured from zebra. */ + if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) + SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); /* In case of this route need to install kernel. */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) && @@ -4962,13 +3834,7 @@ int if_ip_address_install(struct interface *ifp, struct prefix *prefix, if_refresh(ifp); } - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - zlog_debug( - "dplane can't set interface IP address: %s.", - dplane_res2str(dplane_res)); - return NB_ERR; - } + dplane_intf_addr_set(ifp, ifc); SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the @@ -4976,407 +3842,50 @@ int if_ip_address_install(struct interface *ifp, struct prefix *prefix, * from the kernel has been received. * It will also be added to the subnet chain list, then. */ } - - return 0; } -static int ip_address_install(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) +void if_ip_address_uninstall(struct interface *ifp, struct prefix *prefix, + struct prefix *pp) { - struct zebra_if *if_data; - struct prefix_ipv4 lp, pp; struct connected *ifc; - struct prefix_ipv4 *p; - int ret; - enum zebra_dplane_result dplane_res; - - if_data = ifp->info; - - ret = str2prefix_ipv4(addr_str, &lp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ipv4_martian(&lp.prefix)) { - vty_out(vty, "%% Invalid address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (peer_str) { - if (lp.prefixlen != IPV4_MAX_BITLEN) { - vty_out(vty, - "%% Local prefix length for P-t-P address must be /32\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = str2prefix_ipv4(peer_str, &pp); - if (ret <= 0) { - vty_out(vty, "%% Malformed peer address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL); - if (!ifc) { - ifc = connected_new(); - ifc->ifp = ifp; - - /* Address. */ - p = prefix_ipv4_new(); - *p = lp; - ifc->address = (struct prefix *)p; - - if (peer_str) { - SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); - p = prefix_ipv4_new(); - *p = pp; - ifc->destination = (struct prefix *)p; - } - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); - - /* Add to linked list. */ - listnode_add(ifp->connected, ifc); - } - - /* This address is configured from zebra. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - - /* In case of this route need to install kernel. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) && - CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && - !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) { - /* Some system need to up the interface to set IP address. */ - if (!if_is_up(ifp)) { - if_set_flags(ifp, IFF_UP | IFF_RUNNING); - if_refresh(ifp); - } - - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't set interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } - - SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* The address will be advertised to zebra clients when the - * notification - * from the kernel has been received. - * It will also be added to the subnet chain list, then. */ - } - - return CMD_SUCCESS; -} - -int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix) -{ - struct connected *ifc = NULL; - enum zebra_dplane_result dplane_res; - - if (prefix->family == AF_INET) { - /* Check current interface address. */ - ifc = connected_check_ptp(ifp, prefix, NULL); - if (!ifc) { - zlog_debug("interface %s Can't find address", - ifp->name); - return -1; - } - } else if (prefix->family == AF_INET6) { - /* Check current interface address. */ - ifc = connected_check(ifp, prefix); - } + ifc = connected_check_ptp(ifp, prefix, pp); + assert(ifc); - if (!ifc) { - zlog_debug("interface %s Can't find address", ifp->name); - return -1; - } UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); + if_connected_del(ifp->connected, ifc); connected_free(&ifc); - return CMD_WARNING_CONFIG_FAILED; + return; } /* This is real route. */ - dplane_res = dplane_intf_addr_unset(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - zlog_debug("Can't unset interface IP address: %s.", - dplane_res2str(dplane_res)); - return -1; - } - UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - - return 0; -} - -static int ip_address_uninstall(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) -{ - struct prefix_ipv4 lp, pp; - struct connected *ifc; - int ret; - enum zebra_dplane_result dplane_res; - - /* Convert to prefix structure. */ - ret = str2prefix_ipv4(addr_str, &lp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (peer_str) { - if (lp.prefixlen != IPV4_MAX_BITLEN) { - vty_out(vty, - "%% Local prefix length for P-t-P address must be /32\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = str2prefix_ipv4(peer_str, &pp); - if (ret <= 0) { - vty_out(vty, "%% Malformed peer address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - /* Check current interface address. */ - ifc = connected_check_ptp(ifp, &lp, peer_str ? &pp : NULL); - if (!ifc) { - vty_out(vty, "%% Can't find address\n"); - return CMD_WARNING_CONFIG_FAILED; - } + dplane_intf_addr_unset(ifp, ifc); - /* This is not configured address. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - return CMD_WARNING_CONFIG_FAILED; - - UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - - /* This is not real address or interface is not active. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) - || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); - connected_free(&ifc); - return CMD_WARNING_CONFIG_FAILED; - } - - /* This is real route. */ - dplane_res = dplane_intf_addr_unset(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't unset interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* we will receive a kernel notification about this route being removed. - * this will trigger its removal from the connected list. */ - return CMD_SUCCESS; -} - -DEFUN (ip_address, - ip_address_cmd, - "ip address A.B.C.D/M", - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n") -{ - int idx_ipv4_prefixlen = 2; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_install(vty, ifp, argv[idx_ipv4_prefixlen]->arg, NULL, - NULL); -} - -DEFUN (no_ip_address, - no_ip_address_cmd, - "no ip address A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP Address (e.g. 10.0.0.1/8)\n") -{ - int idx_ipv4_prefixlen = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_uninstall(vty, ifp, argv[idx_ipv4_prefixlen]->arg, - NULL, NULL); -} - -DEFUN(ip_address_peer, - ip_address_peer_cmd, - "ip address A.B.C.D peer A.B.C.D/M", - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "Local IP (e.g. 10.0.0.1) for P-t-P address\n" - "Specify P-t-P address\n" - "Peer IP address (e.g. 10.0.0.1/8)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_install(vty, ifp, argv[2]->arg, argv[4]->arg, NULL); -} - -DEFUN(no_ip_address_peer, - no_ip_address_peer_cmd, - "no ip address A.B.C.D peer A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "Local IP (e.g. 10.0.0.1) for P-t-P address\n" - "Specify P-t-P address\n" - "Peer IP address (e.g. 10.0.0.1/8)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_uninstall(vty, ifp, argv[3]->arg, argv[5]->arg, NULL); -} - -#ifdef HAVE_NETLINK -DEFUN (ip_address_label, - ip_address_label_cmd, - "ip address A.B.C.D/M label LINE", - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n" - "Label of this address\n" - "Label\n") -{ - int idx_ipv4_prefixlen = 2; - int idx_line = 4; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_install(vty, ifp, argv[idx_ipv4_prefixlen]->arg, NULL, - argv[idx_line]->arg); -} - -DEFUN (no_ip_address_label, - no_ip_address_label_cmd, - "no ip address A.B.C.D/M label LINE", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n" - "Label of this address\n" - "Label\n") -{ - int idx_ipv4_prefixlen = 3; - int idx_line = 5; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ip_address_uninstall(vty, ifp, argv[idx_ipv4_prefixlen]->arg, - NULL, argv[idx_line]->arg); } -#endif /* HAVE_NETLINK */ -int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix, - const char *label) +void if_ipv6_address_install(struct interface *ifp, struct prefix *prefix) { struct zebra_if *if_data; - struct prefix_ipv6 cp; struct connected *ifc; - struct prefix_ipv6 *p; - enum zebra_dplane_result dplane_res; - - if_data = ifp->info; - - cp.family = prefix->family; - cp.prefixlen = prefix->prefixlen; - cp.prefix = prefix->u.prefix6; - apply_mask_ipv6(&cp); - - ifc = connected_check(ifp, (struct prefix *)&cp); - if (!ifc) { - ifc = connected_new(); - ifc->ifp = ifp; - - /* Address. */ - p = prefix_ipv6_new(); - *p = cp; - ifc->address = (struct prefix *)p; - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); - - /* Add to linked list. */ - listnode_add(ifp->connected, ifc); - } - - /* This address is configured from zebra. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - - /* In case of this route need to install kernel. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) && - CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && - !(if_data && if_data->shutdown == IF_ZEBRA_DATA_ON)) { - /* Some system need to up the interface to set IP address. */ - if (!if_is_up(ifp)) { - if_set_flags(ifp, IFF_UP | IFF_RUNNING); - if_refresh(ifp); - } - - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - zlog_debug( - "dplane can't set interface IP address: %s.", - dplane_res2str(dplane_res)); - return NB_ERR; - } - - SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* The address will be advertised to zebra clients when the - * notification - * from the kernel has been received. */ - } - - return 0; -} - -static int ipv6_address_install(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) -{ - struct zebra_if *if_data; - struct prefix_ipv6 cp; - struct connected *ifc; - struct prefix_ipv6 *p; - int ret; - enum zebra_dplane_result dplane_res; if_data = ifp->info; - ret = str2prefix_ipv6(addr_str, &cp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (ipv6_martian(&cp.prefix)) { - vty_out(vty, "%% Invalid address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ifc = connected_check(ifp, (struct prefix *)&cp); + ifc = connected_check(ifp, prefix); if (!ifc) { ifc = connected_new(); ifc->ifp = ifp; /* Address. */ - p = prefix_ipv6_new(); - *p = cp; - ifc->address = (struct prefix *)p; - - /* Label. */ - if (label) - ifc->label = XSTRDUP(MTYPE_CONNECTED_LABEL, label); + ifc->address = prefix_new(); + prefix_copy(ifc->address, prefix); /* Add to linked list. */ - listnode_add(ifp->connected, ifc); + if_connected_add_tail(ifp->connected, ifc); } /* This address is configured from zebra. */ @@ -5393,265 +3902,36 @@ static int ipv6_address_install(struct vty *vty, struct interface *ifp, if_refresh(ifp); } - dplane_res = dplane_intf_addr_set(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't set interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } + dplane_intf_addr_set(ifp, ifc); SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); /* The address will be advertised to zebra clients when the * notification * from the kernel has been received. */ } - - return CMD_SUCCESS; -} - -/* Return true if an ipv6 address is configured on ifp */ -int ipv6_address_configured(struct interface *ifp) -{ - struct connected *connected; - struct listnode *node; - - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) - if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL) - && (connected->address->family == AF_INET6)) - return 1; - - return 0; } -static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) +void if_ipv6_address_uninstall(struct interface *ifp, struct prefix *prefix) { - struct prefix_ipv6 cp; struct connected *ifc; - int ret; - enum zebra_dplane_result dplane_res; - - /* Convert to prefix structure. */ - ret = str2prefix_ipv6(addr_str, &cp); - if (ret <= 0) { - vty_out(vty, "%% Malformed address \n"); - return CMD_WARNING_CONFIG_FAILED; - } - /* Check current interface address. */ - ifc = connected_check(ifp, (struct prefix *)&cp); - if (!ifc) { - vty_out(vty, "%% Can't find address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - /* This is not configured address. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) - return CMD_WARNING_CONFIG_FAILED; + ifc = connected_check(ifp, prefix); + assert(ifc); UNSET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); /* This is not real address or interface is not active. */ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); + if_connected_del(ifp->connected, ifc); connected_free(&ifc); - return CMD_WARNING_CONFIG_FAILED; + return; } /* This is real route. */ - dplane_res = dplane_intf_addr_unset(ifp, ifc); - if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) { - vty_out(vty, "%% Can't unset interface IP address: %s.\n", - dplane_res2str(dplane_res)); - return CMD_WARNING_CONFIG_FAILED; - } + dplane_intf_addr_unset(ifp, ifc); UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED); - /* This information will be propagated to the zclients when the - * kernel notification is received. */ - return CMD_SUCCESS; -} - -DEFUN (ipv6_address, - ipv6_address_cmd, - "ipv6 address X:X::X:X/M", - "Interface IPv6 config commands\n" - "Set the IP address of an interface\n" - "IPv6 address (e.g. 3ffe:506::1/48)\n") -{ - int idx_ipv6_prefixlen = 2; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ipv6_address_install(vty, ifp, argv[idx_ipv6_prefixlen]->arg, - NULL, NULL); -} - -DEFUN (no_ipv6_address, - no_ipv6_address_cmd, - "no ipv6 address X:X::X:X/M", - NO_STR - "Interface IPv6 config commands\n" - "Set the IP address of an interface\n" - "IPv6 address (e.g. 3ffe:506::1/48)\n") -{ - int idx_ipv6_prefixlen = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - return ipv6_address_uninstall(vty, ifp, argv[idx_ipv6_prefixlen]->arg, - NULL, NULL); -} - -static int link_params_config_write(struct vty *vty, struct interface *ifp) -{ - const struct lyd_node *dnode; - char xpath[XPATH_MAXLEN]; - int i; - - if ((ifp == NULL) || !HAS_LINK_PARAMS(ifp)) - return -1; - - struct if_link_params *iflp = ifp->link_params; - - vty_out(vty, " link-params\n"); - vty_out(vty, " enable\n"); - if (IS_PARAM_SET(iflp, LP_TE_METRIC) && iflp->te_metric != ifp->metric) - vty_out(vty, " metric %u\n", iflp->te_metric); - if (IS_PARAM_SET(iflp, LP_MAX_BW) && iflp->max_bw != iflp->default_bw) - vty_out(vty, " max-bw %g\n", iflp->max_bw); - if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW) - && iflp->max_rsv_bw != iflp->default_bw) - vty_out(vty, " max-rsv-bw %g\n", iflp->max_rsv_bw); - if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) { - for (i = 0; i < 8; i++) - if (iflp->unrsv_bw[i] != iflp->default_bw) - vty_out(vty, " unrsv-bw %d %g\n", i, - iflp->unrsv_bw[i]); - } - - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params", - ifp->name); - dnode = yang_dnode_get(running_config->dnode, xpath); - if (dnode) - nb_cli_show_dnode_cmds(vty, dnode, false); - - if (IS_PARAM_SET(iflp, LP_DELAY)) { - vty_out(vty, " delay %u", iflp->av_delay); - if (IS_PARAM_SET(iflp, LP_MM_DELAY)) { - vty_out(vty, " min %u", iflp->min_delay); - vty_out(vty, " max %u", iflp->max_delay); - } - vty_out(vty, "\n"); - } - if (IS_PARAM_SET(iflp, LP_DELAY_VAR)) - vty_out(vty, " delay-variation %u\n", iflp->delay_var); - if (IS_PARAM_SET(iflp, LP_PKT_LOSS)) - vty_out(vty, " packet-loss %g\n", iflp->pkt_loss); - if (IS_PARAM_SET(iflp, LP_AVA_BW)) - vty_out(vty, " ava-bw %g\n", iflp->ava_bw); - if (IS_PARAM_SET(iflp, LP_RES_BW)) - vty_out(vty, " res-bw %g\n", iflp->res_bw); - if (IS_PARAM_SET(iflp, LP_USE_BW)) - vty_out(vty, " use-bw %g\n", iflp->use_bw); - if (IS_PARAM_SET(iflp, LP_RMT_AS)) - vty_out(vty, " neighbor %pI4 as %u\n", &iflp->rmt_ip, - iflp->rmt_as); - - vty_out(vty, " exit-link-params\n"); - return 0; -} - -static int if_config_write(struct vty *vty) -{ - struct vrf *vrf; - struct interface *ifp; - - zebra_ptm_write(vty); - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - FOR_ALL_INTERFACES (vrf, ifp) { - struct zebra_if *if_data; - struct listnode *addrnode; - struct connected *ifc; - struct prefix *p; - - if_data = ifp->info; - - if_vty_config_start(vty, ifp); - - if (if_data) { - if (if_data->shutdown == IF_ZEBRA_DATA_ON) - vty_out(vty, " shutdown\n"); - - zebra_ptm_if_write(vty, if_data); - } - - if (ifp->desc) - vty_out(vty, " description %s\n", ifp->desc); - - /* Assign bandwidth here to avoid unnecessary interface - flap - while processing config script */ - if (ifp->bandwidth != 0) - vty_out(vty, " bandwidth %u\n", ifp->bandwidth); - - if (!CHECK_FLAG(ifp->status, - ZEBRA_INTERFACE_LINKDETECTION)) - vty_out(vty, " no link-detect\n"); - - for (ALL_LIST_ELEMENTS_RO(ifp->connected, addrnode, - ifc)) { - if (CHECK_FLAG(ifc->conf, - ZEBRA_IFC_CONFIGURED)) { - char buf[INET6_ADDRSTRLEN]; - p = ifc->address; - vty_out(vty, " ip%s address %s", - p->family == AF_INET ? "" - : "v6", - inet_ntop(p->family, - &p->u.prefix, buf, - sizeof(buf))); - if (CONNECTED_PEER(ifc)) { - p = ifc->destination; - vty_out(vty, " peer %s", - inet_ntop(p->family, - &p->u.prefix, - buf, - sizeof(buf))); - } - vty_out(vty, "/%d", p->prefixlen); - - if (ifc->label) - vty_out(vty, " label %s", - ifc->label); - - vty_out(vty, "\n"); - } - } - - if (if_data) { - if (if_data->multicast != IF_ZEBRA_DATA_UNSPEC) - vty_out(vty, " %smulticast\n", - if_data->multicast == - IF_ZEBRA_DATA_ON - ? "" - : "no "); - - if (if_data->mpls_config == IF_ZEBRA_DATA_ON) - vty_out(vty, " mpls enable\n"); - else if (if_data->mpls_config == - IF_ZEBRA_DATA_OFF) - vty_out(vty, " mpls disable\n"); - } - - hook_call(zebra_if_config_wr, vty, ifp); - zebra_evpn_mh_if_write(vty, ifp); - link_params_config_write(vty, ifp); - - if_vty_config_end(vty); - } - return 0; } /* Allocate and initialize interface vector. */ @@ -5661,15 +3941,6 @@ void zebra_if_init(void) hook_register_prio(if_add, 0, if_zebra_new_hook); hook_register_prio(if_del, 0, if_zebra_delete_hook); - /* Install configuration write function. */ - if_cmd_init(if_config_write); - install_node(&link_params_node); - /* - * This is *intentionally* setting this to NULL, signaling - * that interface creation for zebra acts differently - */ - if_zapi_callbacks(NULL, NULL, NULL, NULL); - install_element(VIEW_NODE, &show_interface_cmd); install_element(VIEW_NODE, &show_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_interface_name_vrf_cmd); @@ -5677,55 +3948,4 @@ void zebra_if_init(void) install_element(ENABLE_NODE, &show_interface_desc_cmd); install_element(ENABLE_NODE, &show_interface_desc_vrf_all_cmd); - install_element(INTERFACE_NODE, &multicast_cmd); - install_element(INTERFACE_NODE, &no_multicast_cmd); - install_element(INTERFACE_NODE, &mpls_cmd); - install_element(INTERFACE_NODE, &linkdetect_cmd); - install_element(INTERFACE_NODE, &no_linkdetect_cmd); - install_element(INTERFACE_NODE, &shutdown_if_cmd); - install_element(INTERFACE_NODE, &no_shutdown_if_cmd); - install_element(INTERFACE_NODE, &bandwidth_if_cmd); - install_element(INTERFACE_NODE, &no_bandwidth_if_cmd); - install_element(INTERFACE_NODE, &ip_address_cmd); - install_element(INTERFACE_NODE, &no_ip_address_cmd); - install_element(INTERFACE_NODE, &ip_address_peer_cmd); - install_element(INTERFACE_NODE, &no_ip_address_peer_cmd); - install_element(INTERFACE_NODE, &ipv6_address_cmd); - install_element(INTERFACE_NODE, &no_ipv6_address_cmd); -#ifdef HAVE_NETLINK - install_element(INTERFACE_NODE, &ip_address_label_cmd); - install_element(INTERFACE_NODE, &no_ip_address_label_cmd); -#endif /* HAVE_NETLINK */ - install_element(INTERFACE_NODE, &link_params_cmd); - install_default(LINK_PARAMS_NODE); - install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); - install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_metric_cmd); - install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_admin_grp_cmd); - install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_inter_as_cmd); - install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_delay_cmd); - install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_delay_var_cmd); - install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_pkt_loss_cmd); - install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_ava_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_res_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_use_bw_cmd); - install_element(LINK_PARAMS_NODE, &link_params_affinity_cmd); - install_element(LINK_PARAMS_NODE, &link_params_affinity_mode_cmd); - install_element(LINK_PARAMS_NODE, &no_link_params_affinity_mode_cmd); - install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); - - /* setup EVPN MH elements */ - zebra_evpn_interface_init(); } diff --git a/zebra/interface.h b/zebra/interface.h index 3b6799549b42..8d19c1838fbf 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -201,6 +201,9 @@ struct zebra_if { ifindex_t link_ifindex; struct interface *link; +#define INTERFACE_SPEED_ERROR_READ -1 +#define INTERFACE_SPEED_ERROR_UNKNOWN -2 + uint8_t speed_update_count; struct event *speed_update; @@ -218,8 +221,6 @@ struct zebra_if { DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), (vty, ifp)); -DECLARE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), - (vty, ifp)); #define IS_ZEBRA_IF_VRF(ifp) \ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF) @@ -283,7 +284,6 @@ extern void if_refresh(struct interface *); extern void if_flags_update(struct interface *, uint64_t); extern int if_subnet_add(struct interface *, struct connected *); extern int if_subnet_delete(struct interface *, struct connected *); -extern int ipv6_address_configured(struct interface *ifp); extern void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id); extern void zebra_if_update_link(struct interface *ifp, ifindex_t link_ifindex, ns_id_t ns_id); @@ -308,24 +308,29 @@ extern void cli_show_affinity(struct vty *vty, const struct lyd_node *dnode, */ extern int zebra_if_set_protodown(struct interface *ifp, bool down, enum protodown_reasons new_reason); -extern int if_ip_address_install(struct interface *ifp, struct prefix *prefix, - const char *label, struct prefix *pp); -extern int if_ipv6_address_install(struct interface *ifp, struct prefix *prefix, - const char *label); -extern int if_ip_address_uinstall(struct interface *ifp, struct prefix *prefix); +extern void if_ip_address_install(struct interface *ifp, struct prefix *prefix, + const char *label, struct prefix *pp); +extern void if_ip_address_uninstall(struct interface *ifp, + struct prefix *prefix, struct prefix *pp); +extern void if_ipv6_address_install(struct interface *ifp, + struct prefix *prefix); +extern void if_ipv6_address_uninstall(struct interface *ifp, + struct prefix *prefix); extern int if_shutdown(struct interface *ifp); extern int if_no_shutdown(struct interface *ifp); +extern void if_arp(struct interface *ifp, bool enable); extern int if_multicast_set(struct interface *ifp); extern int if_multicast_unset(struct interface *ifp); extern int if_linkdetect(struct interface *ifp, bool detect); extern void if_addr_wakeup(struct interface *ifp); +void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, + uint32_t type, uint32_t value); +void link_param_cmd_set_float(struct interface *ifp, float *field, + uint32_t type, float value); +void link_param_cmd_unset(struct interface *ifp, uint32_t type); + /* Nexthop group connected functions */ -extern void if_nhg_dependents_add(struct interface *ifp, - struct nhg_hash_entry *nhe); -extern void if_nhg_dependents_del(struct interface *ifp, - struct nhg_hash_entry *nhe); -extern unsigned int if_nhg_dependents_count(const struct interface *ifp); extern bool if_nhg_dependents_is_empty(const struct interface *ifp); extern void vrf_add_update(struct vrf *vrfp); diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 8da1ae37c69f..a35784cd36e4 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -6,6 +6,8 @@ #include +#include + #include "linklist.h" #include "if.h" #include "prefix.h" diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 253e6a8dd617..70f3f57ae02f 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -87,12 +87,12 @@ static const char *inet_2a(uint32_t a, char *b, size_t b_len) static struct prefix *irdp_get_prefix(struct interface *ifp) { - struct listnode *node; struct connected *ifc; - if (ifp->connected) - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) + frr_each (if_connected, ifp->connected, ifc) { + if (ifc->address->family == AF_INET) return ifc->address; + } return NULL; } @@ -198,7 +198,6 @@ static void irdp_if_start(struct interface *ifp, int multicast, { struct zebra_if *zi = ifp->info; struct irdp_interface *irdp = zi->irdp; - struct listnode *node; struct connected *ifc; uint32_t timer, seed; @@ -247,11 +246,12 @@ static void irdp_if_start(struct interface *ifp, int multicast, /* The spec suggests this for randomness */ seed = 0; - if (ifp->connected) - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { + if (ifc->address->family == AF_INET) { seed = ifc->address->u.prefix4.s_addr; break; } + } srandom(seed); timer = (frr_weak_random() % IRDP_DEFAULT_INTERVAL) + 1; @@ -694,7 +694,6 @@ DEFUN (ip_irdp_debug_disable, void irdp_if_init(void) { - hook_register(zebra_if_config_wr, irdp_config_write); hook_register(if_del, irdp_if_delete); install_element(INTERFACE_NODE, &ip_irdp_broadcast_cmd); diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 6548790e9a80..349ae1a19191 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -197,7 +197,6 @@ void irdp_send_thread(struct event *t_advert) struct zebra_if *zi = ifp->info; struct irdp_interface *irdp = zi->irdp; struct prefix *p; - struct listnode *node, *nnode; struct connected *ifc; if (!irdp) @@ -205,16 +204,15 @@ void irdp_send_thread(struct event *t_advert) irdp->flags &= ~IF_SOLICIT; - if (ifp->connected) - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) { - p = ifc->address; + frr_each (if_connected, ifp->connected, ifc) { + p = ifc->address; - if (p->family != AF_INET) - continue; + if (p->family != AF_INET) + continue; - irdp_advertisement(ifp, p); - irdp->irdp_sent++; - } + irdp_advertisement(ifp, p); + irdp->irdp_sent++; + } tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval; timer = frr_weak_random() % (tmp + 1); @@ -237,7 +235,6 @@ void irdp_advert_off(struct interface *ifp) { struct zebra_if *zi = ifp->info; struct irdp_interface *irdp = zi->irdp; - struct listnode *node, *nnode; int i; struct connected *ifc; struct prefix *p; @@ -247,19 +244,21 @@ void irdp_advert_off(struct interface *ifp) EVENT_OFF(irdp->t_advertise); - if (ifp->connected) - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) { - p = ifc->address; + frr_each (if_connected, ifp->connected, ifc) { + p = ifc->address; - /* Output some packets with Lifetime 0 - we should add a wait... - */ + if (p->family != AF_INET) + continue; - for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) { - irdp->irdp_sent++; - irdp_advertisement(ifp, p); - } + /* Output some packets with Lifetime 0 + we should add a wait... + */ + + for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) { + irdp->irdp_sent++; + irdp_advertisement(ifp, p); } + } } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 6f9c5008afc9..d2f1db67ee58 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -4,8 +4,12 @@ */ #include +#include #ifdef HAVE_NETLINK +#include +#include +#include #include "linklist.h" #include "if.h" @@ -35,6 +39,7 @@ #include "zebra/tc_netlink.h" #include "zebra/netconf_netlink.h" #include "zebra/zebra_errors.h" +#include "zebra/ge_netlink.h" #ifndef SO_RCVBUFFORCE #define SO_RCVBUFFORCE (33) @@ -76,43 +81,48 @@ */ #define NL_DEFAULT_BATCH_SEND_THRESHOLD (15 * NL_PKT_BUF_SIZE) -static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, - {RTM_DELROUTE, "RTM_DELROUTE"}, - {RTM_GETROUTE, "RTM_GETROUTE"}, - {RTM_NEWLINK, "RTM_NEWLINK"}, - {RTM_SETLINK, "RTM_SETLINK"}, - {RTM_DELLINK, "RTM_DELLINK"}, - {RTM_GETLINK, "RTM_GETLINK"}, - {RTM_NEWADDR, "RTM_NEWADDR"}, - {RTM_DELADDR, "RTM_DELADDR"}, - {RTM_GETADDR, "RTM_GETADDR"}, - {RTM_NEWNEIGH, "RTM_NEWNEIGH"}, - {RTM_DELNEIGH, "RTM_DELNEIGH"}, - {RTM_GETNEIGH, "RTM_GETNEIGH"}, - {RTM_NEWRULE, "RTM_NEWRULE"}, - {RTM_DELRULE, "RTM_DELRULE"}, - {RTM_GETRULE, "RTM_GETRULE"}, - {RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP"}, - {RTM_DELNEXTHOP, "RTM_DELNEXTHOP"}, - {RTM_GETNEXTHOP, "RTM_GETNEXTHOP"}, - {RTM_NEWNETCONF, "RTM_NEWNETCONF"}, - {RTM_DELNETCONF, "RTM_DELNETCONF"}, - {RTM_NEWTUNNEL, "RTM_NEWTUNNEL"}, - {RTM_DELTUNNEL, "RTM_DELTUNNEL"}, - {RTM_GETTUNNEL, "RTM_GETTUNNEL"}, - {RTM_NEWQDISC, "RTM_NEWQDISC"}, - {RTM_DELQDISC, "RTM_DELQDISC"}, - {RTM_GETQDISC, "RTM_GETQDISC"}, - {RTM_NEWTCLASS, "RTM_NEWTCLASS"}, - {RTM_DELTCLASS, "RTM_DELTCLASS"}, - {RTM_GETTCLASS, "RTM_GETTCLASS"}, - {RTM_NEWTFILTER, "RTM_NEWTFILTER"}, - {RTM_DELTFILTER, "RTM_DELTFILTER"}, - {RTM_GETTFILTER, "RTM_GETTFILTER"}, - {RTM_NEWVLAN, "RTM_NEWVLAN"}, - {RTM_DELVLAN, "RTM_DELVLAN"}, - {RTM_GETVLAN, "RTM_GETVLAN"}, - {0}}; +static const struct message nlmsg_str[] = { + { RTM_NEWROUTE, "RTM_NEWROUTE" }, + { RTM_DELROUTE, "RTM_DELROUTE" }, + { RTM_GETROUTE, "RTM_GETROUTE" }, + { RTM_NEWLINK, "RTM_NEWLINK" }, + { RTM_SETLINK, "RTM_SETLINK" }, + { RTM_DELLINK, "RTM_DELLINK" }, + { RTM_GETLINK, "RTM_GETLINK" }, + { RTM_NEWADDR, "RTM_NEWADDR" }, + { RTM_DELADDR, "RTM_DELADDR" }, + { RTM_GETADDR, "RTM_GETADDR" }, + { RTM_NEWNEIGH, "RTM_NEWNEIGH" }, + { RTM_DELNEIGH, "RTM_DELNEIGH" }, + { RTM_GETNEIGH, "RTM_GETNEIGH" }, + { RTM_NEWRULE, "RTM_NEWRULE" }, + { RTM_DELRULE, "RTM_DELRULE" }, + { RTM_GETRULE, "RTM_GETRULE" }, + { RTM_NEWNEXTHOP, "RTM_NEWNEXTHOP" }, + { RTM_DELNEXTHOP, "RTM_DELNEXTHOP" }, + { RTM_GETNEXTHOP, "RTM_GETNEXTHOP" }, + { RTM_NEWNETCONF, "RTM_NEWNETCONF" }, + { RTM_DELNETCONF, "RTM_DELNETCONF" }, + { RTM_NEWTUNNEL, "RTM_NEWTUNNEL" }, + { RTM_DELTUNNEL, "RTM_DELTUNNEL" }, + { RTM_GETTUNNEL, "RTM_GETTUNNEL" }, + { RTM_NEWQDISC, "RTM_NEWQDISC" }, + { RTM_DELQDISC, "RTM_DELQDISC" }, + { RTM_GETQDISC, "RTM_GETQDISC" }, + { RTM_NEWTCLASS, "RTM_NEWTCLASS" }, + { RTM_DELTCLASS, "RTM_DELTCLASS" }, + { RTM_GETTCLASS, "RTM_GETTCLASS" }, + { RTM_NEWTFILTER, "RTM_NEWTFILTER" }, + { RTM_DELTFILTER, "RTM_DELTFILTER" }, + { RTM_GETTFILTER, "RTM_GETTFILTER" }, + { RTM_NEWVLAN, "RTM_NEWVLAN" }, + { RTM_DELVLAN, "RTM_DELVLAN" }, + { RTM_GETVLAN, "RTM_GETVLAN" }, + { RTM_NEWCHAIN, "RTM_NEWCHAIN" }, + { RTM_DELCHAIN, "RTM_DELCHAIN" }, + { RTM_GETCHAIN, "RTM_GETCHAIN" }, + { 0 } +}; static const struct message rtproto_str[] = { {RTPROT_REDIRECT, "redirect"}, @@ -301,7 +311,7 @@ static const char *group2str(uint32_t group) /* Make socket for Linux netlink interface. */ static int netlink_socket(struct nlsock *nl, unsigned long groups, uint32_t ext_groups[], uint8_t ext_group_size, - ns_id_t ns_id) + ns_id_t ns_id, int nl_family) { int ret; struct sockaddr_nl snl; @@ -309,7 +319,7 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, int namelen; frr_with_privs(&zserv_privs) { - sock = ns_socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, ns_id); + sock = ns_socket(AF_NETLINK, SOCK_RAW, nl_family, ns_id); if (sock < 0) { zlog_err("Can't open %s socket: %s", nl->name, safe_strerror(errno)); @@ -425,6 +435,12 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELVLAN: return netlink_vlan_change(h, ns_id, startup); + /* Messages we may receive, but ignore */ + case RTM_NEWCHAIN: + case RTM_DELCHAIN: + case RTM_GETCHAIN: + return 0; + /* Messages handled in the dplane thread */ case RTM_NEWADDR: case RTM_DELADDR: @@ -603,6 +619,11 @@ static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) safe_strerror(errno)); } +/* + * Please note, the assumption with this function is that the + * flags passed in that are bit masked with type, we are implicitly + * assuming that this is handling the NLA_F_NESTED ilk. + */ void netlink_parse_rtattr_flags(struct rtattr **tb, int max, struct rtattr *rta, int len, unsigned short flags) { @@ -622,8 +643,19 @@ void netlink_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, { memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); while (RTA_OK(rta, len)) { - if (rta->rta_type <= max) - tb[rta->rta_type] = rta; + /* + * The type may be &'ed with NLA_F_NESTED + * which puts data in the upper 8 bits of the + * rta_type. Mask it off and save the actual + * underlying value to be placed into the array. + * This way we don't accidently crash in the future + * when the kernel sends us new data and we try + * to write well beyond the end of the array. + */ + uint16_t type = rta->rta_type & NLA_TYPE_MASK; + + if (type <= max) + tb[type] = rta; rta = RTA_NEXT(rta, len); } } @@ -1213,6 +1245,33 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), return netlink_talk_info(filter, n, &dp_info, startup); } +/* + * Synchronous version of netlink_talk_info. Converts args to suit the + * common version, which is suitable for both sync and async use. + */ +int ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), + struct nlmsghdr *n, struct zebra_ns *zns, bool startup) +{ + struct zebra_dplane_info dp_info; + + if (zns->ge_netlink_cmd.sock < 0) + return -1; + + /* Increment sequence number before capturing snapshot of ns socket + * info. + */ + zns->ge_netlink_cmd.seq = zebra_router_get_next_sequence(); + + /* Capture info in intermediate info struct */ + dp_info.ns_id = zns->ns_id; + + dp_info.is_cmd = true; + dp_info.sock = zns->ge_netlink_cmd.sock; + dp_info.seq = zns->ge_netlink_cmd.seq; + + return netlink_talk_info(filter, n, &dp_info, startup); +} + /* Issue request message to kernel via netlink socket. GET messages * are issued through this interface. */ @@ -1606,6 +1665,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_TC_FILTER_DELETE: case DPLANE_OP_TC_FILTER_UPDATE: return netlink_put_tc_filter_update_msg(bth, ctx); + + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + return netlink_put_sr_tunsrc_set_msg(bth, ctx); } return FRR_NETLINK_ERROR; @@ -1742,8 +1804,8 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink.name, sizeof(zns->netlink.name), "netlink-listen (NS %u)", zns->ns_id); zns->netlink.sock = -1; - if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id) < - 0) { + if (netlink_socket(&zns->netlink, groups, &ext_groups, 1, zns->ns_id, + NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink.name); exit(-1); @@ -1754,7 +1816,8 @@ void kernel_init(struct zebra_ns *zns) snprintf(zns->netlink_cmd.name, sizeof(zns->netlink_cmd.name), "netlink-cmd (NS %u)", zns->ns_id); zns->netlink_cmd.sock = -1; - if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_cmd, 0, 0, 0, zns->ns_id, + NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink_cmd.name); exit(-1); @@ -1767,7 +1830,8 @@ void kernel_init(struct zebra_ns *zns) sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", zns->ns_id); zns->netlink_dplane_out.sock = -1; - if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id) < 0) { + if (netlink_socket(&zns->netlink_dplane_out, 0, 0, 0, zns->ns_id, + NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_out.name); exit(-1); @@ -1781,7 +1845,7 @@ void kernel_init(struct zebra_ns *zns) zns->ns_id); zns->netlink_dplane_in.sock = -1; if (netlink_socket(&zns->netlink_dplane_in, dplane_groups, 0, 0, - zns->ns_id) < 0) { + zns->ns_id, NETLINK_ROUTE) < 0) { zlog_err("Failure to create %s socket", zns->netlink_dplane_in.name); exit(-1); @@ -1789,6 +1853,19 @@ void kernel_init(struct zebra_ns *zns) kernel_netlink_nlsock_insert(&zns->netlink_dplane_in); + /* Generic Netlink socket. */ + snprintf(zns->ge_netlink_cmd.name, sizeof(zns->ge_netlink_cmd.name), + "generic-netlink-cmd (NS %u)", zns->ns_id); + zns->ge_netlink_cmd.sock = -1; + if (netlink_socket(&zns->ge_netlink_cmd, 0, 0, 0, zns->ns_id, + NETLINK_GENERIC) < 0) { + zlog_warn("Failure to create %s socket", + zns->ge_netlink_cmd.name); + } + + if (zns->ge_netlink_cmd.sock >= 0) + kernel_netlink_nlsock_insert(&zns->ge_netlink_cmd); + /* * SOL_NETLINK is not available on all platforms yet * apparently. It's in bits/socket.h which I am not @@ -1827,6 +1904,15 @@ void kernel_init(struct zebra_ns *zns) zlog_notice("Registration for extended dp ACK failed : %d %s", errno, safe_strerror(errno)); + if (zns->ge_netlink_cmd.sock >= 0) { + one = 1; + ret = setsockopt(zns->ge_netlink_cmd.sock, SOL_NETLINK, + NETLINK_EXT_ACK, &one, sizeof(one)); + if (ret < 0) + zlog_err("Registration for extended generic netlink cmd ACK failed : %d %s", + errno, safe_strerror(errno)); + } + /* * Trim off the payload of the original netlink message in the * acknowledgment. This option is available since Linux 4.2, so if @@ -1859,12 +1945,22 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_dplane_in.name, safe_strerror(errno), errno); + if (zns->ge_netlink_cmd.sock >= 0) { + if (fcntl(zns->ge_netlink_cmd.sock, F_SETFL, O_NONBLOCK) < 0) + zlog_err("Can't set %s socket error: %s(%d)", + zns->ge_netlink_cmd.name, safe_strerror(errno), + errno); + } + /* Set receive buffer size if it's set from command line */ if (rcvbufsize) { netlink_recvbuf(&zns->netlink, rcvbufsize); netlink_recvbuf(&zns->netlink_cmd, rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_out, rcvbufsize); netlink_recvbuf(&zns->netlink_dplane_in, rcvbufsize); + + if (zns->ge_netlink_cmd.sock >= 0) + netlink_recvbuf(&zns->ge_netlink_cmd, rcvbufsize); } /* Set filter for inbound sockets, to exclude events we've generated @@ -1883,6 +1979,8 @@ void kernel_init(struct zebra_ns *zns) &zns->t_netlink); rt_netlink_init(); + + ge_netlink_init(zns); } /* Helper to clean up an nlsock */ @@ -1907,11 +2005,16 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) kernel_nlsock_fini(&zns->netlink_dplane_in); + kernel_nlsock_fini(&zns->ge_netlink_cmd); + /* During zebra shutdown, we need to leave the dataplane socket * around until all work is done. */ - if (complete) + if (complete) { kernel_nlsock_fini(&zns->netlink_dplane_out); + + XFREE(MTYPE_NL_BUF, nl_batch_tx_buf); + } } /* diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index e910f6244484..e37bba0cf624 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -98,6 +98,9 @@ extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup); extern int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, bool startup); +extern int +ge_netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup), + struct nlmsghdr *n, struct zebra_ns *zns, bool startup); extern int netlink_request(struct nlsock *nl, void *req); enum netlink_msg_status { diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index d897f4a1df2d..5cfbe7a896dd 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -5,6 +5,8 @@ #include +#include + #ifndef HAVE_NETLINK #include @@ -48,11 +50,7 @@ extern struct zebra_privs_t zserv_privs; * 0). We follow this practice without questioning it, but it is a * bug if frr calls ROUNDUP with 0. */ -#ifdef __APPLE__ -#define ROUNDUP_TYPE int -#else -#define ROUNDUP_TYPE long -#endif +#define ROUNDUP_TYPE long /* * Because of these varying conventions, the only sane approach is for @@ -834,12 +832,12 @@ int ifam_read(struct ifa_msghdr *ifam) struct interface *ifp = NULL; union sockunion addr, mask, brd; bool dest_same = false; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; short ifnlen = 0; bool isalias = false; uint32_t flags = 0; - ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; + ifname[0] = ifname[IFNAMSIZ - 1] = '\0'; /* Allocate and read address information. */ ifam_read_mesg(ifam, &addr, &mask, &brd, ifname, &ifnlen); @@ -851,7 +849,7 @@ int ifam_read(struct ifa_msghdr *ifam) return -1; } - if (ifnlen && strncmp(ifp->name, ifname, INTERFACE_NAMSIZ)) + if (ifnlen && strncmp(ifp->name, ifname, IFNAMSIZ)) isalias = true; /* @@ -995,7 +993,7 @@ void rtm_read(struct rt_msghdr *rtm) int flags; uint32_t zebra_flags; union sockunion dest, mask, gate; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; short ifnlen = 0; struct nexthop nh; struct prefix p; @@ -1470,10 +1468,12 @@ static void routing_socket(struct zebra_ns *zns) void interface_list_second(struct zebra_ns *zns) { + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_ADDRESSES_READ); } void interface_list_tunneldump(struct zebra_ns *zns) { + zebra_dplane_startup_stage(zns, ZEBRA_DPLANE_TUNNELS_READ); } /* Exported interface function. This function simply calls @@ -1626,6 +1626,7 @@ void kernel_update_multi(struct dplane_ctx_list_head *ctx_list) case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: case DPLANE_OP_STARTUP_STAGE: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: zlog_err("Unhandled dplane data for %s", dplane_op2str(dplane_ctx_get_op(ctx))); res = ZEBRA_DPLANE_REQUEST_FAILURE; diff --git a/zebra/label_manager.c b/zebra/label_manager.c index c77470a70109..c97beb6af838 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -28,6 +28,8 @@ #include "zebra/zapi_msg.h" #include "zebra/debug.h" +#include "zebra/label_manager_clippy.c" + #define CONNECTION_DELAY 5 struct label_manager lbl_mgr; @@ -49,10 +51,14 @@ DEFINE_HOOK(lm_get_chunk, DEFINE_HOOK(lm_release_chunk, (struct zserv *client, uint32_t start, uint32_t end), (client, start, end)); +/* show running-config needs an API for dynamic-block */ +DEFINE_HOOK(lm_write_label_block_config, + (struct vty *vty, struct zebra_vrf *zvrf), + (vty, zvrf)); DEFINE_HOOK(lm_cbs_inited, (), ()); -/* define wrappers to be called in zapi_msg.c (as hooks must be called in - * source file where they were defined) +/* define wrappers to be called in zapi_msg.c or zebra_mpls_vty.c (as hooks + * must be called in source file where they were defined) */ void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id) { @@ -69,6 +75,11 @@ void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end) hook_call(lm_release_chunk, client, start, end); } +int lm_write_label_block_config_call(struct vty *vty, struct zebra_vrf *zvrf) +{ + return hook_call(lm_write_label_block_config, vty, zvrf); +} + /* forward declarations of the static functions to be used for some hooks */ static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id); static int label_manager_disconnect(struct zserv *client); @@ -78,6 +89,8 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc, vrf_id_t vrf_id); static int label_manager_release_label_chunk(struct zserv *client, uint32_t start, uint32_t end); +static int label_manager_write_label_block_config(struct vty *vty, + struct zebra_vrf *zvrf); void delete_label_chunk(void *val) { @@ -96,7 +109,7 @@ void delete_label_chunk(void *val) */ int release_daemon_label_chunks(struct zserv *client) { - struct listnode *node; + struct listnode *node, *nnode; struct label_manager_chunk *lmc; int count = 0; int ret; @@ -106,7 +119,7 @@ int release_daemon_label_chunks(struct zserv *client) __func__, zebra_route_string(client->proto), client->instance, client->session_id); - for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + for (ALL_LIST_ELEMENTS(lbl_mgr.lc_list, node, nnode, lmc)) { if (lmc->proto == client->proto && lmc->instance == client->instance && lmc->session_id == client->session_id && lmc->keep == 0) { @@ -136,6 +149,8 @@ void lm_hooks_register(void) hook_register(lm_client_disconnect, label_manager_disconnect); hook_register(lm_get_chunk, label_manager_get_chunk); hook_register(lm_release_chunk, label_manager_release_label_chunk); + hook_register(lm_write_label_block_config, + label_manager_write_label_block_config); } void lm_hooks_unregister(void) { @@ -143,6 +158,127 @@ void lm_hooks_unregister(void) hook_unregister(lm_client_disconnect, label_manager_disconnect); hook_unregister(lm_get_chunk, label_manager_get_chunk); hook_unregister(lm_release_chunk, label_manager_release_label_chunk); + hook_unregister(lm_write_label_block_config, + label_manager_write_label_block_config); +} + +static json_object *lmc_json(struct label_manager_chunk *lmc) +{ + json_object *json = json_object_new_object(); + + json_object_string_add(json, "protocol", zebra_route_string(lmc->proto)); + json_object_int_add(json, "instance", lmc->instance); + json_object_int_add(json, "sessionId", lmc->session_id); + json_object_int_add(json, "start", lmc->start); + json_object_int_add(json, "end", lmc->end); + json_object_boolean_add(json, "dynamic", lmc->is_dynamic); + return json; +} + +DEFPY(show_label_table, show_label_table_cmd, "show debugging label-table [json$uj]", + SHOW_STR + DEBUG_STR + "Display allocated label chunks\n" + JSON_STR) +{ + struct label_manager_chunk *lmc; + struct listnode *node; + json_object *json_array = NULL, *json_global = NULL, *json_dyn_block; + + if (uj) { + json_array = json_object_new_array(); + json_global = json_object_new_object(); + json_dyn_block = json_object_new_object(); + json_object_int_add(json_dyn_block, "lowerBound", + lbl_mgr.dynamic_block_start); + json_object_int_add(json_dyn_block, "upperBound", + lbl_mgr.dynamic_block_end); + json_object_object_add(json_global, "dynamicBlock", + json_dyn_block); + } else + vty_out(vty, "Dynamic block: lower-bound %u, upper-bound %u\n", + lbl_mgr.dynamic_block_start, lbl_mgr.dynamic_block_end); + + for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + if (uj) { + json_object_array_add(json_array, lmc_json(lmc)); + continue; + } + vty_out(vty, "Proto %s: [%u/%u]\n", + zebra_route_string(lmc->proto), lmc->start, lmc->end); + } + if (uj) { + json_object_object_add(json_global, "chunks", json_array); + vty_json(vty, json_global); + } + return CMD_SUCCESS; +} + +DEFPY(mpls_label_dynamic_block, mpls_label_dynamic_block_cmd, + "[no$no] mpls label dynamic-block [(16-1048575)$start (16-1048575)$end]", + NO_STR + MPLS_STR + "Label configuration\n" + "Configure dynamic label block\n" + "Start label\n" + "End label\n") +{ + struct listnode *node; + struct label_manager_chunk *lmc; + + /* unset dynamic range */ + if (no || + (start == MPLS_LABEL_UNRESERVED_MIN && end == MPLS_LABEL_MAX)) { + lbl_mgr.dynamic_block_start = MPLS_LABEL_UNRESERVED_MIN; + lbl_mgr.dynamic_block_end = MPLS_LABEL_MAX; + return CMD_SUCCESS; + } + if (!start || !end) { + vty_out(vty, + "%% label dynamic-block, range missing, aborting\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (start > end) { + vty_out(vty, + "%% label dynamic-block, wrong range (%ld > %ld), aborting\n", + start, end); + return CMD_WARNING_CONFIG_FAILED; + } + + for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { + if (lmc->proto == NO_PROTO) + continue; + if (!lmc->is_dynamic && lmc->start >= (uint32_t)start && + lmc->end <= (uint32_t)end) { + vty_out(vty, + "%% Found a static label chunk [%u-%u] for %s in conflict with the dynamic label block\n", + lmc->start, lmc->end, + zebra_route_string(lmc->proto)); + return CMD_WARNING_CONFIG_FAILED; + } else if (lmc->is_dynamic && (lmc->end > (uint32_t)end || + lmc->start < (uint32_t)start)) { + vty_out(vty, + "%% Found a dynamic label chunk [%u-%u] for %s outside the new dynamic label block, consider restart the service\n", + lmc->start, lmc->end, + zebra_route_string(lmc->proto)); + } + } + lbl_mgr.dynamic_block_start = start; + lbl_mgr.dynamic_block_end = end; + return CMD_SUCCESS; +} + +static int label_manager_write_label_block_config(struct vty *vty, + struct zebra_vrf *zvrf) +{ + if (zvrf_id(zvrf) != VRF_DEFAULT) + return 0; + if (lbl_mgr.dynamic_block_start == MPLS_LABEL_UNRESERVED_MIN && + lbl_mgr.dynamic_block_end == MPLS_LABEL_MAX) + return 0; + vty_out(vty, "mpls label dynamic-block %u %u\n", + lbl_mgr.dynamic_block_start, lbl_mgr.dynamic_block_end); + return 1; } /** @@ -152,6 +288,8 @@ void label_manager_init(void) { lbl_mgr.lc_list = list_new(); lbl_mgr.lc_list->del = delete_label_chunk; + lbl_mgr.dynamic_block_start = MPLS_LABEL_UNRESERVED_MIN; + lbl_mgr.dynamic_block_end = MPLS_LABEL_MAX; hook_register(zserv_client_close, lm_client_disconnect_cb); /* register default hooks for the label manager actions */ @@ -159,12 +297,20 @@ void label_manager_init(void) /* notify any external module that we are done */ hook_call(lm_cbs_inited); + + install_element(VIEW_NODE, &show_label_table_cmd); + install_element(CONFIG_NODE, &mpls_label_dynamic_block_cmd); +} + +void label_manager_terminate(void) +{ + list_delete(&lbl_mgr.lc_list); } /* alloc and fill a label chunk */ struct label_manager_chunk * create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, - uint8_t keep, uint32_t start, uint32_t end) + uint8_t keep, uint32_t start, uint32_t end, bool is_dynamic) { /* alloc chunk, fill it and return it */ struct label_manager_chunk *lmc = @@ -176,6 +322,7 @@ create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, lmc->instance = instance; lmc->session_id = session_id; lmc->keep = keep; + lmc->is_dynamic = is_dynamic; return lmc; } @@ -203,6 +350,15 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, return NULL; } + if ((lbl_mgr.dynamic_block_start != MPLS_LABEL_UNRESERVED_MIN || + lbl_mgr.dynamic_block_end != MPLS_LABEL_MAX) && + base >= lbl_mgr.dynamic_block_start && + end <= lbl_mgr.dynamic_block_end) { + zlog_warn("Invalid LM request arguments: base: %u, size: %u for %s in conflict with the dynamic label block", + base, size, zebra_route_string(proto)); + return NULL; + } + /* Scan the existing chunks to see if the requested range of labels * falls inside any of such chunks */ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { @@ -234,7 +390,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, /* insert chunk between existing chunks */ if (insert_node) { lmc = create_label_chunk(proto, instance, session_id, keep, - base, end); + base, end, false); listnode_add_before(lbl_mgr.lc_list, insert_node, lmc); return lmc; } @@ -257,7 +413,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, } lmc = create_label_chunk(proto, instance, session_id, keep, - base, end); + base, end, false); if (last_node) listnode_add_before(lbl_mgr.lc_list, last_node, lmc); else @@ -268,7 +424,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, /* create a new chunk past all the existing ones and link at * tail */ lmc = create_label_chunk(proto, instance, session_id, keep, - base, end); + base, end, false); listnode_add(lbl_mgr.lc_list, lmc); return lmc; } @@ -293,9 +449,13 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, { struct label_manager_chunk *lmc; struct listnode *node; - uint32_t prev_end = MPLS_LABEL_UNRESERVED_MIN; + uint32_t prev_end = lbl_mgr.dynamic_block_start - 1; + struct label_manager_chunk *lmc_block_last = NULL; - /* handle chunks request with a specific base label */ + /* handle chunks request with a specific base label + * - static label requests: BGP hardset value, Pathd + * - segment routing label requests + */ if (base != MPLS_LABEL_BASE_ANY) return assign_specific_label_chunk(proto, instance, session_id, keep, size, base); @@ -305,37 +465,44 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, /* first check if there's one available */ for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { - if (lmc->proto == NO_PROTO - && lmc->end - lmc->start + 1 == size) { + if (lmc->start <= prev_end) + continue; + if (lmc->proto == NO_PROTO && + lmc->end - lmc->start + 1 == size && + lmc->end <= lbl_mgr.dynamic_block_end) { lmc->proto = proto; lmc->instance = instance; lmc->session_id = session_id; lmc->keep = keep; + lmc->is_dynamic = true; return lmc; } /* check if we hadve a "hole" behind us that we can squeeze into */ - if ((lmc->start > prev_end) && (lmc->start - prev_end > size)) { + if (lmc->start - prev_end > size && + prev_end + 1 + size <= lbl_mgr.dynamic_block_end) { lmc = create_label_chunk(proto, instance, session_id, keep, prev_end + 1, - prev_end + size); + prev_end + size, true); listnode_add_before(lbl_mgr.lc_list, node, lmc); return lmc; } prev_end = lmc->end; + + /* check if we have a chunk that goes over the end block */ + if (lmc->end > lbl_mgr.dynamic_block_end) + continue; + lmc_block_last = lmc; } /* otherwise create a new one */ uint32_t start_free; - if (list_isempty(lbl_mgr.lc_list)) - start_free = MPLS_LABEL_UNRESERVED_MIN; + if (lmc_block_last == NULL) + start_free = lbl_mgr.dynamic_block_start; else - start_free = ((struct label_manager_chunk *)listgetdata( - listtail(lbl_mgr.lc_list))) - ->end - + 1; + start_free = lmc_block_last->end + 1; - if (start_free > MPLS_LABEL_UNRESERVED_MAX - size + 1) { + if (start_free > lbl_mgr.dynamic_block_end - size + 1) { flog_err(EC_ZEBRA_LM_EXHAUSTED_LABELS, "Reached max labels. Start: %u, size: %u", start_free, size); @@ -344,7 +511,7 @@ assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, /* create chunk and link at tail */ lmc = create_label_chunk(proto, instance, session_id, keep, start_free, - start_free + size - 1); + start_free + size - 1, true); listnode_add(lbl_mgr.lc_list, lmc); return lmc; } @@ -399,13 +566,14 @@ int release_label_chunk(uint8_t proto, unsigned short instance, "%s: Daemon mismatch!!", __func__); continue; } - lmc->proto = NO_PROTO; - lmc->instance = 0; - lmc->session_id = 0; - lmc->keep = 0; ret = 0; break; } + if (lmc) { + list_delete_node(lbl_mgr.lc_list, node); + delete_label_chunk(lmc); + } + if (ret != 0) flog_err(EC_ZEBRA_LM_UNRELEASED_CHUNK, "%s: Label chunk not released!!", __func__); @@ -435,7 +603,25 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc, { *lmc = assign_label_chunk(client->proto, client->instance, client->session_id, keep, size, base); - return lm_get_chunk_response(*lmc, client, vrf_id); + /* Respond to a get_chunk request */ + if (!*lmc) { + if (base == MPLS_LABEL_BASE_ANY) + flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, + "Unable to assign Label Chunk size %u to %s instance %u", + size, zebra_route_string(client->proto), + client->instance); + else + flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, + "Unable to assign Label Chunk %u - %u to %s instance %u", + base, base + size - 1, + zebra_route_string(client->proto), + client->instance); + } else if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", + (*lmc)->start, (*lmc)->end, + zebra_route_string(client->proto), client->instance); + + return zsend_assign_label_chunk_response(client, vrf_id, *lmc); } /* Respond to a connect request */ @@ -454,22 +640,6 @@ int lm_client_connect_response(uint8_t proto, uint16_t instance, return zsend_label_manager_connect_response(client, vrf_id, result); } -/* Respond to a get_chunk request */ -int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, - vrf_id_t vrf_id) -{ - if (!lmc) - flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK, - "Unable to assign Label Chunk to %s instance %u", - zebra_route_string(client->proto), client->instance); - else if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", - lmc->start, lmc->end, - zebra_route_string(client->proto), client->instance); - - return zsend_assign_label_chunk_response(client, vrf_id, lmc); -} - void label_manager_close(void) { list_delete(&lbl_mgr.lc_list); diff --git a/zebra/label_manager.h b/zebra/label_manager.h index cfbb4bd16987..03cf6a6813cf 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -42,6 +42,7 @@ struct label_manager_chunk { unsigned short instance; uint32_t session_id; uint8_t keep; + uint8_t is_dynamic; /* Tell if chunk is dynamic or static */ uint32_t start; /* First label of the chunk */ uint32_t end; /* Last label of the chunk */ }; @@ -61,11 +62,14 @@ DECLARE_HOOK(lm_get_chunk, DECLARE_HOOK(lm_release_chunk, (struct zserv *client, uint32_t start, uint32_t end), (client, start, end)); +DECLARE_HOOK(lm_write_label_block_config, + (struct vty *vty, struct zebra_vrf *zvrf), + (vty, zvrf)); DECLARE_HOOK(lm_cbs_inited, (), ()); -/* declare wrappers to be called in zapi_msg.c (as hooks must be called in - * source file where they were defined) +/* declare wrappers to be called in zapi_msg.c or zebra_mpls_vty.c (as hooks + * must be called in source file where they were defined) */ void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id); void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client, @@ -73,18 +77,17 @@ void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client, vrf_id_t vrf_id); void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end); +int lm_write_label_block_config_call(struct vty *vty, struct zebra_vrf *zvrf); /* API for an external LM to return responses for requests */ int lm_client_connect_response(uint8_t proto, uint16_t instance, uint32_t session_id, vrf_id_t vrf_id, uint8_t result); -int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, - vrf_id_t vrf_id); /* convenience function to allocate an lmc to be consumed by the above API */ struct label_manager_chunk * create_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, - uint8_t keep, uint32_t start, uint32_t end); + uint8_t keep, uint32_t start, uint32_t end, bool is_dynamic); void delete_label_chunk(void *val); /* register/unregister callbacks for hooks */ @@ -97,9 +100,13 @@ void lm_hooks_unregister(void); */ struct label_manager { struct list *lc_list; + uint32_t dynamic_block_start; + uint32_t dynamic_block_end; }; void label_manager_init(void); +void label_manager_terminate(void); + struct label_manager_chunk * assign_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, uint8_t keep, uint32_t size, uint32_t base); diff --git a/zebra/main.c b/zebra/main.c index 1e833ce7f182..687da70cabce 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -5,6 +5,10 @@ #include +#ifdef GNU_LINUX +#include +#endif + #include #include "getopt.h" #include "command.h" @@ -21,6 +25,8 @@ #include "affinitymap.h" #include "routemap.h" #include "routing_nb.h" +#include "mgmt_be_client.h" +#include "libagentx.h" #include "zebra/zebra_router.h" #include "zebra/zebra_errors.h" @@ -54,13 +60,11 @@ pid_t pid; /* Pacify zclient.o in libfrr, which expects this variable. */ struct event_loop *master; +struct mgmt_be_client *mgmt_be_client; + /* Route retain mode flag. */ int retain_mode = 0; -int graceful_restart; - -bool v6_rr_semantics = false; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -82,7 +86,6 @@ const struct option longopts[] = { { "socket", required_argument, NULL, 'z' }, { "ecmp", required_argument, NULL, 'e' }, { "retain", no_argument, NULL, 'r' }, - { "graceful_restart", required_argument, NULL, 'K' }, { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK @@ -90,7 +93,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {"routing-table", optional_argument, NULL, 'R'}, + { "routing-table", optional_argument, NULL, 'R' }, { 0 } }; @@ -140,6 +143,10 @@ static void sigint(void) zlog_notice("Terminating on signal"); + nb_oper_cancel_all_walks(); + mgmt_be_client_destroy(mgmt_be_client); + mgmt_be_client = NULL; + atomic_store_explicit(&zrouter.in_shutdown, true, memory_order_relaxed); @@ -194,6 +201,13 @@ static void sigint(void) rib_update_finish(); list_delete(&zrouter.client_list); + list_delete(&zrouter.stale_client_list); + + /* + * Besides other clean-ups zebra's vrf_disable() also enqueues installed + * routes for removal from the kernel, unless ZEBRA_VRF_RETAIN is set. + */ + vrf_iterate(vrf_disable); /* Indicate that all new dplane work has been enqueued. When that * work is complete, the dataplane will enqueue an event @@ -226,8 +240,17 @@ void zebra_finalize(struct event *dummy) /* Final shutdown of ns resources */ ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + zebra_rib_terminate(); zebra_router_terminate(); + zebra_mpls_terminate(); + + zebra_pw_terminate(); + + zebra_srv6_terminate(); + + label_manager_terminate(); + ns_terminate(); frr_fini(); exit(0); @@ -271,19 +294,23 @@ static const struct frr_yang_module_info *const zebra_yang_modules[] = { }; /* clang-format on */ -FRR_DAEMON_INFO( - zebra, ZEBRA, .vty_port = ZEBRA_VTY_PORT, .flags = FRR_NO_ZCLIENT, - +/* clang-format off */ +FRR_DAEMON_INFO(zebra, ZEBRA, + .vty_port = ZEBRA_VTY_PORT, .proghelp = "Daemon which manages kernel routing table management and\nredistribution between different routing protocols.", - .signals = zebra_signals, .n_signals = array_size(zebra_signals), + .flags = FRR_NO_ZCLIENT, + + .signals = zebra_signals, + .n_signals = array_size(zebra_signals), .privs = &zserv_privs, .yang_modules = zebra_yang_modules, .n_yang_modules = array_size(zebra_yang_modules), ); +/* clang-format on */ /* Main startup routine. */ int main(int argc, char **argv) @@ -296,7 +323,6 @@ int main(int argc, char **argv) bool v6_with_v4_nexthop = false; bool notify_on_ack = true; - graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); @@ -312,7 +338,6 @@ int main(int argc, char **argv) " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK @@ -322,8 +347,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ - " -R, --routing-table Set kernel routing table\n" - ); + " -R, --routing-table Set kernel routing table\n"); while (1) { int opt = frr_getopt(argc, argv, NULL); @@ -367,9 +391,6 @@ int main(int argc, char **argv) case 'r': retain_mode = 1; break; - case 'K': - graceful_restart = atoi(optarg); - break; case 's': rcvbufsize = atoi(optarg); if (rcvbufsize < RCVBUFSIZE_MIN) @@ -385,7 +406,7 @@ int main(int argc, char **argv) vrf_configure_backend(VRF_BACKEND_NETNS); break; case OPTION_V6_RR_SEMANTICS: - v6_rr_semantics = true; + zrouter.v6_rr_semantics = true; break; case OPTION_ASIC_OFFLOAD: if (!strcmp(optarg, "notify_on_offload")) @@ -406,9 +427,10 @@ int main(int argc, char **argv) zrouter.master = frr_init(); /* Zebra related initialize. */ + libagentx_init(); zebra_router_init(asic_offload, notify_on_ack, v6_with_v4_nexthop); zserv_init(); - rib_init(); + zebra_rib_init(); zebra_if_init(); zebra_debug_init(); @@ -418,8 +440,12 @@ int main(int argc, char **argv) zebra_ns_init(); router_id_cmd_init(); zebra_vty_init(); - access_list_init(); + mgmt_be_client = mgmt_be_client_create("zebra", NULL, 0, + zrouter.master); + access_list_init_new(true); prefix_list_init(); + + rtadv_init(); rtadv_cmd_init(); /* PTM socket */ #ifdef ZEBRA_PTM_SUPPORT @@ -453,11 +479,25 @@ int main(int argc, char **argv) * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. + * we have to have route_read() called before. + * If FRR is gracefully restarting, we either wait for clients + * (e.g., BGP) to signal GR is complete else we wait for specified + * duration. */ zrouter.startup_time = monotime(NULL); - event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, - &zrouter.sweeper); + zrouter.rib_sweep_time = 0; + zrouter.graceful_restart = zebra_di.graceful_restart; + if (!zrouter.graceful_restart) + event_add_timer(zrouter.master, rib_sweep_route, NULL, 0, NULL); + else { + int gr_cleanup_time; + + gr_cleanup_time = zebra_di.gr_cleanup_time + ? zebra_di.gr_cleanup_time + : ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME; + event_add_timer(zrouter.master, rib_sweep_route, NULL, + gr_cleanup_time, &zrouter.t_rib_sweep); + } /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c index 7352dfb2eec5..002d2c7bf65d 100644 --- a/zebra/netconf_netlink.c +++ b/zebra/netconf_netlink.c @@ -6,11 +6,14 @@ * Donald Sharp */ #include +#include #ifdef HAVE_NETLINK /* Netlink OSes only */ #include +#include +#include #include "linux/netconf.h" #include "lib/lib_errors.h" diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 7aa254b1cb20..11c13303987b 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -16,6 +16,7 @@ #include "log.h" #include "vrf.h" #include "srcdest_table.h" +#include "frrdistance.h" #include "zebra/rib.h" #include "zebra/zebra_router.h" @@ -28,6 +29,7 @@ #include "zebra/zapi_msg.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" +#include "zebra/zebra_neigh.h" #define ZEBRA_PTM_SUPPORT @@ -77,9 +79,8 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) RNODE_FOREACH_RE (rn, newre) { if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)) - zsend_redistribute_route( - ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, - rn, newre); + zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, + client, rn, newre, false); } route_unlock_node(rn); @@ -88,14 +89,26 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) /* Redistribute routes. */ static void zebra_redistribute(struct zserv *client, int type, - unsigned short instance, vrf_id_t vrf_id, + unsigned short instance, struct zebra_vrf *zvrf, int afi) { struct route_entry *newre; struct route_table *table; struct route_node *rn; + bool is_table_direct = false; + vrf_id_t vrf_id = zvrf_id(zvrf); + + if (type == ZEBRA_ROUTE_TABLE_DIRECT) { + if (vrf_id == VRF_DEFAULT) { + table = zebra_router_find_table(zvrf, instance, afi, + SAFI_UNICAST); + type = ZEBRA_ROUTE_ALL; + is_table_direct = true; + } else + return; + } else + table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); - table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id); if (!table) return; @@ -125,10 +138,25 @@ static void zebra_redistribute(struct zserv *client, int type, continue; zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, - client, rn, newre); + client, rn, newre, is_table_direct); } } +/* + * Function to return a valid table id value if table-direct is used + * return 0 otherwise + * This function can be called only if zebra_redistribute_check returns TRUE + */ +static bool zebra_redistribute_is_table_direct(const struct route_entry *re) +{ + struct zebra_vrf *zvrf; + + zvrf = zebra_vrf_lookup_by_id(re->vrf_id); + if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) + return true; + return false; +} + /* * Function to check if prefix is candidate for * redistribute. @@ -146,8 +174,19 @@ static bool zebra_redistribute_check(const struct route_node *rn, afi = family2afi(rn->p.family); zvrf = zebra_vrf_lookup_by_id(re->vrf_id); - if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) + if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) { + if (re->table && + redist_check_instance(&client->mi_redist + [afi][ZEBRA_ROUTE_TABLE_DIRECT], + re->table)) { + /* table-direct redistribution only for route entries which + * are on the default vrf, and that have table id different + * from the default table. + */ + return true; + } return false; + } /* If default route and redistributed */ if (is_default_prefix(&rn->p) && @@ -185,6 +224,7 @@ void redistribute_update(const struct route_node *rn, { struct listnode *node, *nnode; struct zserv *client; + bool is_table_direct; if (IS_ZEBRA_DEBUG_RIB) zlog_debug( @@ -210,11 +250,16 @@ void redistribute_update(const struct route_node *rn, re->vrf_id, re->table, re->type, re->distance, re->metric); } + is_table_direct = zebra_redistribute_is_table_direct(re); zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, - client, rn, re); - } else if (zebra_redistribute_check(rn, prev_re, client)) + client, rn, re, + is_table_direct); + } else if (zebra_redistribute_check(rn, prev_re, client)) { + is_table_direct = zebra_redistribute_is_table_direct(prev_re); zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, rn, prev_re); + client, rn, prev_re, + is_table_direct); + } } } @@ -233,6 +278,7 @@ void redistribute_delete(const struct route_node *rn, struct listnode *node, *nnode; struct zserv *client; vrf_id_t vrfid; + bool is_table_direct; if (old_re) vrfid = old_re->vrf_id; @@ -285,9 +331,20 @@ void redistribute_delete(const struct route_node *rn, continue; /* Send a delete for the 'old' re to any subscribed client. */ - if (zebra_redistribute_check(rn, old_re, client)) + if (zebra_redistribute_check(rn, old_re, client)) { + /* + * SA is complaining that old_re could be false + * SA is wrong because old_re is checked for NULL + * in zebra_redistribute_check and false is + * returned in that case. Let's just make SA + * happy. + */ + assert(old_re); + is_table_direct = zebra_redistribute_is_table_direct(old_re); zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, - client, rn, old_re); + client, rn, old_re, + is_table_direct); + } } } @@ -326,8 +383,7 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS) instance)) { redist_add_instance(&client->mi_redist[afi][type], instance); - zebra_redistribute(client, type, instance, - zvrf_id(zvrf), afi); + zebra_redistribute(client, type, instance, zvrf, afi); } } else { if (!vrf_bitmap_check(&client->redist[afi][type], @@ -339,7 +395,7 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS) zvrf_id(zvrf)); vrf_bitmap_set(&client->redist[afi][type], zvrf_id(zvrf)); - zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi); + zebra_redistribute(client, type, 0, zvrf, afi); } } @@ -472,6 +528,8 @@ void zebra_interface_down_update(struct interface *ifp) zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); } + + zebra_neigh_del_all(ifp); } /* Interface information update. */ @@ -547,10 +605,6 @@ void zebra_interface_address_add_update(struct interface *ifp, client, ifp, ifc); } } - /* interface associated NHGs may have been deleted, - * re-sync zebra -> dplane NHGs - */ - zebra_interface_nhg_reinstall(ifp); } /* Interface address deletion. */ @@ -592,9 +646,8 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", - ifp->name, ifp->vrf->vrf_id, new_vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s VRF Id %u -> %u", + ifp->name, ifp->vrf->vrf_id, new_vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -606,7 +659,6 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp); client->ifdel_cnt++; zsend_interface_delete(client, ifp); - zsend_interface_vrf_update(client, ifp, new_vrf_id); } } @@ -619,9 +671,8 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", - ifp->name, old_vrf_id, ifp->vrf->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s VRF Id %u -> %u", + ifp->name, old_vrf_id, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -663,9 +714,10 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) continue; - if (same->type == re->type && same->instance == re->instance - && same->table == re->table - && same->type != ZEBRA_ROUTE_CONNECT) + if (same->type == re->type && same->instance == re->instance && + same->table == re->table && + (same->type != ZEBRA_ROUTE_CONNECT && + same->type != ZEBRA_ROUTE_LOCAL)) break; } @@ -685,6 +737,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, copy_nexthops(&ng->nexthop, re->nhe->nhg.nexthop, NULL); rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng, false); + nexthop_group_delete(&ng); return 0; } diff --git a/zebra/rib.h b/zebra/rib.h index e70b5c142363..84ea766c4733 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -85,25 +85,12 @@ struct route_entry { */ struct nhg_hash_entry *nhe; - /* Nexthop group from FIB (optional), reflecting what is actually - * installed in the FIB if that differs. The 'backup' group is used - * when backup nexthops are present in the route's nhg. - */ - struct nexthop_group fib_ng; - struct nexthop_group fib_backup_ng; - /* Nexthop group hash entry IDs. The "installed" id is the id * used in linux/netlink, if available. */ uint32_t nhe_id; uint32_t nhe_installed_id; - /* Tag */ - route_tag_t tag; - - /* Uptime. */ - time_t uptime; - /* Type of this route. */ int type; @@ -160,7 +147,20 @@ struct route_entry { /* Distance. */ uint8_t distance; + /* Tag */ + route_tag_t tag; + + /* Uptime. */ + time_t uptime; + struct re_opaque *opaque; + + /* Nexthop group from FIB (optional), reflecting what is actually + * installed in the FIB if that differs. The 'backup' group is used + * when backup nexthops are present in the route's nhg. + */ + struct nexthop_group fib_ng; + struct nexthop_group fib_backup_ng; }; #define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type) @@ -169,7 +169,7 @@ struct route_entry { /* Define route types that are equivalent to "connected". */ #define RIB_CONNECTED_ROUTE(R) \ - ((R)->type == ZEBRA_ROUTE_CONNECT || (R)->type == ZEBRA_ROUTE_NHRP) + ((R)->type == ZEBRA_ROUTE_CONNECT || (R)->type == ZEBRA_ROUTE_LOCAL || (R)->type == ZEBRA_ROUTE_NHRP) /* meta-queue structure: * sub-queue 0: nexthop group objects @@ -345,6 +345,8 @@ extern void _route_entry_dump(const char *func, union prefixconstptr pp, union prefixconstptr src_pp, const struct route_entry *re); +void zebra_rib_route_entry_free(struct route_entry *re); + struct route_entry * zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, uint8_t instance, uint32_t flags, uint32_t nhe_id, uint32_t table_id, @@ -414,7 +416,8 @@ extern void rib_update_table(struct route_table *table, extern void rib_sweep_route(struct event *t); extern void rib_sweep_table(struct route_table *table); extern void rib_close_table(struct route_table *table); -extern void rib_init(void); +extern void zebra_rib_init(void); +extern void zebra_rib_terminate(void); extern unsigned long rib_score_proto(uint8_t proto, unsigned short instance); extern unsigned long rib_score_proto_table(uint8_t proto, unsigned short instance, @@ -429,6 +432,7 @@ extern int rib_queue_nhg_ctx_add(struct nhg_ctx *ctx); /* Enqueue incoming nhg from proto daemon for processing */ extern int rib_queue_nhe_add(struct nhg_hash_entry *nhe); +extern int rib_queue_nhe_del(struct nhg_hash_entry *nhe); /* Enqueue evpn route for processing */ int zebra_rib_queue_evpn_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, @@ -618,17 +622,15 @@ static inline struct nexthop_group *rib_get_fib_backup_nhg( } extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern void zebra_vty_init(void); extern pid_t pid; -extern bool v6_rr_semantics; - extern uint32_t rt_table_main_id; /* Name of hook calls */ diff --git a/zebra/router-id.c b/zebra/router-id.c index ef87d924fe54..2f251a79e584 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -109,7 +109,7 @@ int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) assert(!"Reached end of function we should never hit"); } -static int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) +int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf) { struct prefix after, before; struct listnode *node; @@ -241,256 +241,6 @@ void router_id_del_address(struct connected *ifc) zsend_router_id_update(client, afi, &after, zvrf_id(zvrf)); } -void router_id_write(struct vty *vty, struct zebra_vrf *zvrf) -{ - char space[2]; - - memset(space, 0, sizeof(space)); - - if (zvrf_id(zvrf) != VRF_DEFAULT) - snprintf(space, sizeof(space), "%s", " "); - - if (zvrf->rid_user_assigned.u.prefix4.s_addr != INADDR_ANY) { - vty_out(vty, "%sip router-id %pI4\n", space, - &zvrf->rid_user_assigned.u.prefix4); - } - if (!router_id_v6_is_any(&zvrf->rid6_user_assigned)) { - vty_out(vty, "%sipv6 router-id %pI6\n", space, - &zvrf->rid_user_assigned.u.prefix6); - } -} - -DEFUN (ip_router_id, - ip_router_id_cmd, - "ip router-id A.B.C.D vrf NAME", - IP_STR - "Manually set the router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id; - struct zebra_vrf *zvrf; - - argv_find(argv, argc, "A.B.C.D", &idx); - - if (!inet_pton(AF_INET, argv[idx]->arg, &rid.u.prefix4)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV4_MAX_BITLEN; - rid.family = AF_INET; - - argv_find(argv, argc, "NAME", &idx); - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (ip_router_id, - router_id_cmd, - "router-id A.B.C.D vrf NAME", - "Manually set the router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR); - -DEFUN (ipv6_router_id, - ipv6_router_id_cmd, - "ipv6 router-id X:X::X:X vrf NAME", - IPV6_STR - "Manually set the router-id\n" - "IPv6 address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id; - struct zebra_vrf *zvrf; - - argv_find(argv, argc, "X:X::X:X", &idx); - - if (!inet_pton(AF_INET6, argv[idx]->arg, &rid.u.prefix6)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV6_MAX_BITLEN; - rid.family = AF_INET6; - - argv_find(argv, argc, "NAME", &idx); - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - - -DEFUN (ip_router_id_in_vrf, - ip_router_id_in_vrf_cmd, - "ip router-id A.B.C.D", - IP_STR - "Manually set the router-id\n" - "IP address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - int idx = 0; - struct prefix rid; - - argv_find(argv, argc, "A.B.C.D", &idx); - - if (!inet_pton(AF_INET, argv[idx]->arg, &rid.u.prefix4)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV4_MAX_BITLEN; - rid.family = AF_INET; - - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (ip_router_id_in_vrf, - router_id_in_vrf_cmd, - "router-id A.B.C.D", - "Manually set the router-id\n" - "IP address to use for router-id\n"); - -DEFUN (ipv6_router_id_in_vrf, - ipv6_router_id_in_vrf_cmd, - "ipv6 router-id X:X::X:X", - IP6_STR - "Manually set the IPv6 router-id\n" - "IPV6 address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - int idx = 0; - struct prefix rid; - - argv_find(argv, argc, "X:X::X:X", &idx); - - if (!inet_pton(AF_INET6, argv[idx]->arg, &rid.u.prefix6)) - return CMD_WARNING_CONFIG_FAILED; - - rid.prefixlen = IPV6_MAX_BITLEN; - rid.family = AF_INET6; - - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - -DEFUN (no_ip_router_id, - no_ip_router_id_cmd, - "no ip router-id [A.B.C.D vrf NAME]", - NO_STR - IP_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id = VRF_DEFAULT; - struct zebra_vrf *zvrf; - - rid.u.prefix4.s_addr = 0; - rid.prefixlen = 0; - rid.family = AF_INET; - - if (argv_find(argv, argc, "NAME", &idx)) - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (no_ip_router_id, - no_router_id_cmd, - "no router-id [A.B.C.D vrf NAME]", - NO_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n" - VRF_CMD_HELP_STR); - -DEFUN (no_ipv6_router_id, - no_ipv6_router_id_cmd, - "no ipv6 router-id [X:X::X:X vrf NAME]", - NO_STR - IPV6_STR - "Remove the manually configured IPv6 router-id\n" - "IPv6 address to use for router-id\n" - VRF_CMD_HELP_STR) -{ - int idx = 0; - struct prefix rid; - vrf_id_t vrf_id = VRF_DEFAULT; - struct zebra_vrf *zvrf; - - memset(&rid, 0, sizeof(rid)); - rid.family = AF_INET; - - if (argv_find(argv, argc, "NAME", &idx)) - VRF_GET_ID(vrf_id, argv[idx]->arg, false); - - zvrf = zebra_vrf_lookup_by_id(vrf_id); - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - -DEFUN (no_ip_router_id_in_vrf, - no_ip_router_id_in_vrf_cmd, - "no ip router-id [A.B.C.D]", - NO_STR - IP_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - struct prefix rid; - - rid.u.prefix4.s_addr = 0; - rid.prefixlen = 0; - rid.family = AF_INET; - - router_id_set(AFI_IP, &rid, zvrf); - - return CMD_SUCCESS; -} - -ALIAS (no_ip_router_id_in_vrf, - no_router_id_in_vrf_cmd, - "no router-id [A.B.C.D]", - NO_STR - "Remove the manually configured router-id\n" - "IP address to use for router-id\n"); - -DEFUN (no_ipv6_router_id_in_vrf, - no_ipv6_router_id_in_vrf_cmd, - "no ipv6 router-id [X:X::X:X]", - NO_STR - IP6_STR - "Remove the manually configured IPv6 router-id\n" - "IPv6 address to use for router-id\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - struct prefix rid; - - memset(&rid, 0, sizeof(rid)); - rid.family = AF_INET; - - router_id_set(AFI_IP6, &rid, zvrf); - - return CMD_SUCCESS; -} - DEFUN (show_ip_router_id, show_ip_router_id_cmd, "show [ip|ipv6] router-id [vrf NAME]", @@ -557,24 +307,6 @@ static int router_id_v6_cmp(void *a, void *b) void router_id_cmd_init(void) { - install_element(CONFIG_NODE, &ip_router_id_cmd); - install_element(CONFIG_NODE, &router_id_cmd); - install_element(CONFIG_NODE, &ipv6_router_id_cmd); - install_element(CONFIG_NODE, &no_ip_router_id_cmd); - install_element(CONFIG_NODE, &no_router_id_cmd); - install_element(CONFIG_NODE, &ip_router_id_in_vrf_cmd); - install_element(VRF_NODE, &ip_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &router_id_in_vrf_cmd); - install_element(VRF_NODE, &router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &ipv6_router_id_in_vrf_cmd); - install_element(VRF_NODE, &ipv6_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &no_ipv6_router_id_cmd); - install_element(CONFIG_NODE, &no_ip_router_id_in_vrf_cmd); - install_element(VRF_NODE, &no_ip_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &no_router_id_in_vrf_cmd); - install_element(VRF_NODE, &no_router_id_in_vrf_cmd); - install_element(CONFIG_NODE, &no_ipv6_router_id_in_vrf_cmd); - install_element(VRF_NODE, &no_ipv6_router_id_in_vrf_cmd); install_element(VIEW_NODE, &show_ip_router_id_cmd); } diff --git a/zebra/router-id.h b/zebra/router-id.h index 45860d8b7b80..09ad4ec65eda 100644 --- a/zebra/router-id.h +++ b/zebra/router-id.h @@ -25,8 +25,8 @@ extern void router_id_add_address(struct connected *c); extern void router_id_del_address(struct connected *c); extern void router_id_init(struct zebra_vrf *zvrf); extern void router_id_cmd_init(void); -extern void router_id_write(struct vty *vty, struct zebra_vrf *zvrf); extern int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf); +extern int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf); #ifdef __cplusplus } diff --git a/zebra/rt.h b/zebra/rt.h index af170a22aa16..e5dc26150a8f 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -25,7 +25,8 @@ extern "C" { #define RKERNEL_ROUTE(type) ((type) == ZEBRA_ROUTE_KERNEL) #define RSYSTEM_ROUTE(type) \ - ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT) + ((RKERNEL_ROUTE(type)) || (type) == ZEBRA_ROUTE_CONNECT || \ + (type) == ZEBRA_ROUTE_LOCAL) #ifndef HAVE_NETLINK /* diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index bfe1910a5805..c22145be693b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -278,6 +278,7 @@ int zebra2proto(int proto) proto = RTPROT_ZEBRA; break; case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_LOCAL: case ZEBRA_ROUTE_KERNEL: proto = RTPROT_KERNEL; break; @@ -366,7 +367,8 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop) proto = ZEBRA_ROUTE_NHG; break; } - /* Intentional fall thru */ + proto = ZEBRA_ROUTE_KERNEL; + break; default: /* * When a user adds a new protocol this will show up @@ -504,7 +506,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, void *gate, afi_t afi, vrf_id_t vrf_id) { struct interface *ifp = NULL; - struct nexthop nh = {0}; + struct nexthop nh = {.weight = 1}; mpls_label_t labels[MPLS_MAX_LABELS] = {0}; int num_labels = 0; enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC; @@ -1025,6 +1027,8 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, re, ng, startup, ctx); if (ng) nexthop_group_delete(&ng); + if (ctx) + zebra_rib_route_entry_free(re); } else { /* * I really don't see how this is possible @@ -1036,7 +1040,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_err( "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel", __func__, &p); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } } else { if (ctx) { @@ -1546,7 +1550,7 @@ static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen, srh->first_segment = segs->num_segs - 1; for (i = 0; i < segs->num_segs; i++) { - memcpy(&srh->segments[i], &segs->seg[i], + memcpy(&srh->segments[segs->num_segs - i - 1], &segs->seg[i], sizeof(struct in6_addr)); } @@ -1679,6 +1683,16 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, sizeof(struct in_addr))) return false; break; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + if (!nl_attr_put32(nlmsg, req_size, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX6)) + return false; + if (!nl_attr_put(nlmsg, req_size, + SEG6_LOCAL_NH6, &ctx->nh6, + sizeof(struct in_addr))) + return false; + break; case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: if (!nl_attr_put32(nlmsg, req_size, SEG6_LOCAL_ACTION, @@ -1710,7 +1724,6 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: - case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: case ZEBRA_SEG6_LOCAL_ACTION_END_B6: case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: case ZEBRA_SEG6_LOCAL_ACTION_END_BM: @@ -1878,6 +1891,36 @@ static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, return true; } +/* + * The function returns true if the attribute could be added + * to the message, otherwise false is returned. + */ +static int netlink_route_nexthop_encap(bool fpm, struct nlmsghdr *n, + size_t nlen, const struct nexthop *nh) +{ + struct rtattr *nest; + + if (!fpm) + return true; + + switch (nh->nh_encap_type) { + case NET_VXLAN: + if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) + return false; + + nest = nl_attr_nest(n, nlen, RTA_ENCAP); + if (!nest) + return false; + + if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni)) + return false; + nl_attr_nest_end(n, nest); + break; + } + + return true; +} + /* This function takes a nexthop as argument and * appends to the given netlink msg. If the nexthop * defines a preferred source, the src parameter @@ -1896,10 +1939,13 @@ static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, * The function returns true if the nexthop could be added * to the message, otherwise false is returned. */ -static bool _netlink_route_build_multipath( - const struct prefix *p, const char *routedesc, int bytelen, - const struct nexthop *nexthop, struct nlmsghdr *nlmsg, size_t req_size, - struct rtmsg *rtmsg, const union g_addr **src, route_tag_t tag) +static bool _netlink_route_build_multipath(const struct prefix *p, + const char *routedesc, int bytelen, + const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, + size_t req_size, struct rtmsg *rtmsg, + const union g_addr **src, + route_tag_t tag, bool fpm) { char label_buf[256]; struct vrf *vrf; @@ -2007,6 +2053,13 @@ static bool _netlink_route_build_multipath( if (!_netlink_set_tag(nlmsg, req_size, tag)) return false; + /* + * Add encapsulation information when installing via + * FPM. + */ + if (!netlink_route_nexthop_encap(fpm, nlmsg, req_size, nexthop)) + return false; + nl_attr_rtnh_end(nlmsg, rtnh); return true; } @@ -2041,7 +2094,7 @@ _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc, bytelen = (family == AF_INET ? 4 : 16); return _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop, nlmsg, req_size, - rtmsg, src, 0); + rtmsg, src, 0, false); } static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) @@ -2136,34 +2189,6 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family, return false; } -/* - * The function returns true if the attribute could be added - * to the message, otherwise false is returned. - */ -static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, - struct nexthop *nh) -{ - struct rtattr *nest; - - switch (nh->nh_encap_type) { - case NET_VXLAN: - if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) - return false; - - nest = nl_attr_nest(n, nlen, RTA_ENCAP); - if (!nest) - return false; - - if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, - nh->nh_encap.vni)) - return false; - nl_attr_nest_end(n, nest); - break; - } - - return true; -} - /* * Routing table change via netlink interface, using a dataplane context object * @@ -2208,7 +2233,8 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; if (((cmd == RTM_NEWROUTE) && - ((p->family == AF_INET) || v6_rr_semantics)) || + ((p->family == AF_INET) || kernel_nexthops_supported() || + zrouter.v6_rr_semantics)) || force_rr) req->n.nlmsg_flags |= NLM_F_REPLACE; @@ -2355,6 +2381,14 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx break; setsrc = nexthop_set_src(nexthop, p->family, &src); + if (setsrc && IS_ZEBRA_DEBUG_KERNEL) { + if (p->family == AF_INET) + zlog_debug("%s: %pFX set src %pI4", + __func__, p, &src.ipv4); + else if (p->family == AF_INET6) + zlog_debug("%s: %pFX set src %pI6", + __func__, p, &src.ipv6); + } } if (setsrc) { @@ -2397,6 +2431,16 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx setsrc = nexthop_set_src(nexthop, p->family, &src); + if (setsrc && IS_ZEBRA_DEBUG_KERNEL) { + if (p->family == AF_INET) + zlog_debug("%s: %pFX set src %pI4", + __func__, p, + &src.ipv4); + else if (p->family == AF_INET6) + zlog_debug("%s: %pFX set src %pI6", + __func__, p, + &src.ipv6); + } continue; } @@ -2412,18 +2456,18 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx p, routedesc, bytelen, nexthop, &req->n, &req->r, datalen, cmd)) return 0; - nexthop_num++; - break; - } - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) { - if (!netlink_route_nexthop_encap( - &req->n, datalen, nexthop)) + /* + * Add encapsulation information when + * installing via FPM. + */ + if (!netlink_route_nexthop_encap(fpm, &req->n, + datalen, + nexthop)) return 0; + + nexthop_num++; + break; } } @@ -2456,6 +2500,16 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx setsrc = nexthop_set_src(nexthop, p->family, &src); + if (setsrc && IS_ZEBRA_DEBUG_KERNEL) { + if (p->family == AF_INET) + zlog_debug("%s: %pFX set src %pI4", + __func__, p, + &src.ipv4); + else if (p->family == AF_INET6) + zlog_debug("%s: %pFX set src %pI6", + __func__, p, + &src.ipv6); + } continue; } @@ -2465,10 +2519,14 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx : "multipath"; nexthop_num++; - if (!_netlink_route_build_multipath( - p, routedesc, bytelen, nexthop, - &req->n, datalen, &req->r, &src1, - tag)) + if (!_netlink_route_build_multipath(p, routedesc, + bytelen, + nexthop, + &req->n, + datalen, + &req->r, + &src1, tag, + fpm)) return 0; if (!setsrc && src1) { @@ -2484,23 +2542,6 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx nl_attr_nest_end(&req->n, nest); - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) { - for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), - nexthop)) { - if (CHECK_FLAG(nexthop->flags, - NEXTHOP_FLAG_RECURSIVE)) - continue; - if (!netlink_route_nexthop_encap( - &req->n, datalen, nexthop)) - return 0; - } - } - - if (setsrc) { if (p->family == AF_INET) { if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, @@ -2627,7 +2668,7 @@ static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, if (IS_ZEBRA_DEBUG_KERNEL) { if (i == 0) - snprintf(buf, sizeof(buf1), "group %u", + snprintf(buf, sizeof(buf), "group %u", grp[i].id); else { snprintf(buf1, sizeof(buf1), "/%u", @@ -2931,6 +2972,18 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, sizeof(struct in_addr))) return 0; break; + case SEG6_LOCAL_ACTION_END_DX6: + if (!nl_attr_put32(&req->n, + buflen, + SEG6_LOCAL_ACTION, + SEG6_LOCAL_ACTION_END_DX6)) + return 0; + if (!nl_attr_put(&req->n, buflen, + SEG6_LOCAL_NH6, + &ctx->nh6, + sizeof(struct in_addr))) + return 0; + break; case SEG6_LOCAL_ACTION_END_DT6: if (!nl_attr_put32( &req->n, buflen, @@ -3092,8 +3145,8 @@ netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) { cmd = RTM_NEWROUTE; } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { - - if (p->family == AF_INET || v6_rr_semantics) { + if (p->family == AF_INET || kernel_nexthops_supported() || + zrouter.v6_rr_semantics) { /* Single 'replace' operation */ /* @@ -3157,7 +3210,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, struct interface **ifp, ns_id_t ns_id) { - struct nexthop nh = {}; + struct nexthop nh = {.weight = 1}; void *gate = NULL; enum nexthop_types_t type = 0; int if_index = 0; @@ -3304,7 +3357,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) vrf_id_t vrf_id = VRF_DEFAULT; struct interface *ifp = NULL; struct nhmsg *nhm = NULL; - struct nexthop nh = {}; + struct nexthop nh = {.weight = 1}; struct nh_grp grp[MULTIPATH_NUM] = {}; /* Count of nexthops in group array */ uint8_t grp_count = 0; @@ -4242,11 +4295,11 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) * - struct ethaddr mac; (for NEW) */ if (h->nlmsg_type == RTM_NEWNEIGH) - cmd = ZEBRA_NHRP_NEIGH_ADDED; + cmd = ZEBRA_NEIGH_ADDED; else if (h->nlmsg_type == RTM_GETNEIGH) - cmd = ZEBRA_NHRP_NEIGH_GET; + cmd = ZEBRA_NEIGH_GET; else if (h->nlmsg_type == RTM_DELNEIGH) - cmd = ZEBRA_NHRP_NEIGH_REMOVED; + cmd = ZEBRA_NEIGH_REMOVED; else { zlog_debug("%s(): unknown nlmsg type %u", __func__, h->nlmsg_type); @@ -4256,20 +4309,18 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) /* copy LLADDR information */ l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]); } - if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) { - union sockunion link_layer_ipv4; - if (l2_len) { - sockunion_family(&link_layer_ipv4) = AF_INET; - memcpy((void *)sockunion_get_addr(&link_layer_ipv4), - RTA_DATA(tb[NDA_LLADDR]), l2_len); - } else - sockunion_family(&link_layer_ipv4) = AF_UNSPEC; - zsend_nhrp_neighbor_notify( - cmd, ifp, &ip, - netlink_nbr_entry_state_to_zclient(ndm->ndm_state), - &link_layer_ipv4); - } + union sockunion link_layer_ipv4; + + if (l2_len) { + sockunion_family(&link_layer_ipv4) = AF_INET; + memcpy((void *)sockunion_get_addr(&link_layer_ipv4), + RTA_DATA(tb[NDA_LLADDR]), l2_len); + } else + sockunion_family(&link_layer_ipv4) = AF_UNSPEC; + zsend_neighbor_notify(cmd, ifp, &ip, + netlink_nbr_entry_state_to_zclient(ndm->ndm_state), + &link_layer_ipv4, l2_len); if (h->nlmsg_type == RTM_GETNEIGH) return 0; @@ -4722,77 +4773,24 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { ssize_t ret = 0; + enum dplane_op_e op; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_NEIGH_IP_INSTALL: + op = dplane_ctx_get_op(ctx); + if (op == DPLANE_OP_NEIGH_INSTALL || op == DPLANE_OP_NEIGH_UPDATE || + op == DPLANE_OP_NEIGH_DISCOVER || op == DPLANE_OP_NEIGH_IP_INSTALL) ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen); - break; - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_IP_DELETE: + else if (op == DPLANE_OP_NEIGH_DELETE || op == DPLANE_OP_NEIGH_IP_DELETE) ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); - break; - case DPLANE_OP_VTEP_ADD: + else if (op == DPLANE_OP_VTEP_ADD) ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen); - break; - case DPLANE_OP_VTEP_DELETE: + else if (op == DPLANE_OP_VTEP_DELETE) ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); - break; - case DPLANE_OP_NEIGH_TABLE_UPDATE: + else if (op == DPLANE_OP_NEIGH_TABLE_UPDATE) ret = netlink_neigh_table_update_ctx(ctx, buf, buflen); - break; - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_NONE: - case DPLANE_OP_STARTUP_STAGE: + else ret = -1; - } return ret; } diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index f9888b12d4e8..0bfcd518cade 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -6,6 +6,8 @@ #include +#include + #ifndef HAVE_NETLINK #ifdef __OpenBSD__ diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9af41cbc393a..8f6713517d35 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -6,6 +6,7 @@ */ #include +#include #include "memory.h" #include "sockopt.h" @@ -33,6 +34,7 @@ extern struct zebra_privs_t zserv_privs; static uint32_t interfaces_configured_for_ra_from_bgp; +#define RTADV_ADATA_SIZE 1024 #if defined(HAVE_RTADV) @@ -58,7 +60,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface"); /* adv list node */ struct adv_if { - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; struct adv_if_list_item list_item; }; @@ -182,13 +184,14 @@ static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf, static void rtadv_send_packet(int sock, struct interface *ifp, enum ipv6_nd_suppress_ra_status stop) { - struct msghdr msg; - struct iovec iov; + struct msghdr msg = { 0 }; + struct iovec iov = { 0 }; struct cmsghdr *cmsgptr; struct in6_pktinfo *pkt; - struct sockaddr_in6 addr; - static void *adata = NULL; - unsigned char buf[RTADV_MSG_SIZE]; + struct sockaddr_in6 addr = { 0 }; + unsigned char buf[RTADV_MSG_SIZE] = { 0 }; + char adata[RTADV_ADATA_SIZE] = { 0 }; + struct nd_router_advert *rtadv; int ret; int len = 0; @@ -199,22 +202,6 @@ static void rtadv_send_packet(int sock, struct interface *ifp, struct listnode *node; uint16_t pkt_RouterLifetime; - /* - * Allocate control message bufffer. This is dynamic because - * CMSG_SPACE is not guaranteed not to call a function. Note that - * the size will be different on different architectures due to - * differing alignment rules. - */ - if (adata == NULL) { - /* XXX Free on shutdown. */ - adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo))); - - if (adata == NULL) { - zlog_debug("%s: can't malloc control data", __func__); - exit(-1); - } - } - /* Logging of packet. */ if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name, @@ -1147,7 +1134,8 @@ static void rtadv_prefix_set_defaults(struct rtadv_prefix *rp) rp->AdvValidLifetime = RTADV_VALID_LIFETIME; } -static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp) +static struct rtadv_prefix *rtadv_prefix_set(struct zebra_if *zif, + struct rtadv_prefix *rp) { struct rtadv_prefix *rprefix; @@ -1180,13 +1168,16 @@ static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp) rtadv_prefix_set_defaults(rprefix); } } + + return rprefix; } -static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) +static void rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp, + struct rtadv_prefix *rprefix) { - struct rtadv_prefix *rprefix; + if (!rprefix) + rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp); - rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp); if (rprefix != NULL) { /* @@ -1200,20 +1191,35 @@ static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) { rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO; rtadv_prefix_set_defaults(rprefix); - return 1; + return; } } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) { if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) { rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL; - return 1; + return; } } rtadv_prefixes_del(zif->rtadv.prefixes, rprefix); rtadv_prefix_free(rprefix); - return 1; - } else - return 0; + } +} + +struct rtadv_prefix *rtadv_add_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rp) +{ + rp->AdvPrefixCreate = PREFIX_SRC_MANUAL; + return rtadv_prefix_set(zif, rp); +} + +void rtadv_delete_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rprefix) +{ + struct rtadv_prefix rp; + + rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; + + rtadv_prefix_reset(zif, &rp, rprefix); } /* Add IPv6 prefixes learned from the kernel to the RA prefix list */ @@ -1235,7 +1241,7 @@ void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p) rp.prefix = *((struct prefix_ipv6 *)p); apply_mask_ipv6(&rp.prefix); rp.AdvPrefixCreate = PREFIX_SRC_AUTO; - rtadv_prefix_reset(zif, &rp); + rtadv_prefix_reset(zif, &rp, NULL); } static void rtadv_start_interface_events(struct zebra_vrf *zvrf, @@ -1261,8 +1267,8 @@ static void rtadv_start_interface_events(struct zebra_vrf *zvrf, rtadv_event(zvrf, RTADV_START, 0); } -static void ipv6_nd_suppress_ra_set(struct interface *ifp, - enum ipv6_nd_suppress_ra_status status) +void ipv6_nd_suppress_ra_set(struct interface *ifp, + enum ipv6_nd_suppress_ra_status status) { struct zebra_if *zif; struct zebra_vrf *zvrf; @@ -1310,6 +1316,36 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp, } } +void ipv6_nd_interval_set(struct interface *ifp, uint32_t interval) +{ + struct zebra_if *zif = ifp->info; + struct zebra_vrf *zvrf = rtadv_interface_get_zvrf(ifp); + struct adv_if *adv_if; + + if (zif->rtadv.MaxRtrAdvInterval % 1000) { + adv_if = adv_msec_if_del(zvrf, ifp->name); + if (adv_if != NULL) + adv_if_free(adv_if); + } + + if (interval % 1000) + (void)adv_msec_if_add(zvrf, ifp->name); + + zif->rtadv.MaxRtrAdvInterval = interval; + zif->rtadv.MinRtrAdvInterval = 0.33 * interval; + + if (interval != RTADV_MAX_RTR_ADV_INTERVAL) { + SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); + zif->rtadv.AdvIntervalTimer = 0; + } else { + if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + zif->rtadv.MaxRtrAdvInterval = 10000; + + UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); + zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; + } +} + /* * Handle client (BGP) message to enable or disable IPv6 RA on an interface. * Note that while the client could request RA on an interface on which the @@ -1427,7 +1463,7 @@ void rtadv_stop_ra_all(void) frr_each_safe (rtadv_prefixes, zif->rtadv.prefixes, rprefix) - rtadv_prefix_reset(zif, rprefix); + rtadv_prefix_reset(zif, rprefix, rprefix); rtadv_stop_ra(ifp); } @@ -1512,777 +1548,6 @@ DEFPY(show_ipv6_nd_ra_if, show_ipv6_nd_ra_if_cmd, return CMD_SUCCESS; } -DEFUN (ipv6_nd_ra_fast_retrans, - ipv6_nd_ra_fast_retrans_cmd, - "ipv6 nd ra-fast-retrans", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Fast retransmit of RA packets\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.UseFastRexmit = true; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_ra_fast_retrans, - no_ipv6_nd_ra_fast_retrans_cmd, - "no ipv6 nd ra-fast-retrans", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Fast retransmit of RA packets\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.UseFastRexmit = false; - - return CMD_SUCCESS; -} - -DEFPY (ipv6_nd_ra_hop_limit, - ipv6_nd_ra_hop_limit_cmd, - "ipv6 nd ra-hop-limit (0-255)$hopcount", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Hop Limit\n" - "Advertisement Hop Limit in hops (default:64)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvCurHopLimit = hopcount; - - return CMD_SUCCESS; -} - -DEFPY (no_ipv6_nd_ra_hop_limit, - no_ipv6_nd_ra_hop_limit_cmd, - "no ipv6 nd ra-hop-limit [(0-255)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Hop Limit\n" - "Advertisement Hop Limit in hops\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT; - - return CMD_SUCCESS; -} - -DEFPY (ipv6_nd_ra_retrans_interval, - ipv6_nd_ra_retrans_interval_cmd, - "ipv6 nd ra-retrans-interval (0-4294967295)$interval", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Retransmit Interval\n" - "Advertisement Retransmit Interval in msec\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on loopback interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvRetransTimer = interval; - - return CMD_SUCCESS; -} - -DEFPY (no_ipv6_nd_ra_retrans_interval, - no_ipv6_nd_ra_retrans_interval_cmd, - "no ipv6 nd ra-retrans-interval [(0-4294967295)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Retransmit Interval\n" - "Advertisement Retransmit Interval in msec\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot remove IPv6 Router Advertisements on loopback interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvRetransTimer = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_suppress_ra, - ipv6_nd_suppress_ra_cmd, - "ipv6 nd suppress-ra", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Suppress Router Advertisement\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) - ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS); - - UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_suppress_ra, - no_ipv6_nd_suppress_ra_cmd, - "no ipv6 nd suppress-ra", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Suppress Router Advertisement\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - if (if_is_loopback(ifp)) { - vty_out(vty, - "Cannot configure IPv6 Router Advertisements on this interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - ipv6_nd_suppress_ra_set(ifp, RA_ENABLE); - SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_ra_interval_msec, - ipv6_nd_ra_interval_msec_cmd, - "ipv6 nd ra-interval msec (70-1800000)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router Advertisement interval\n" - "Router Advertisement interval in milliseconds\n" - "Router Advertisement interval in milliseconds\n") -{ - int idx_number = 4; - VTY_DECLVAR_CONTEXT(interface, ifp); - unsigned interval; - struct zebra_if *zif = ifp->info; - struct zebra_vrf *zvrf; - struct adv_if *adv_if; - - zvrf = rtadv_interface_get_zvrf(ifp); - - interval = strtoul(argv[idx_number]->arg, NULL, 10); - if ((zif->rtadv.AdvDefaultLifetime != -1 - && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) { - vty_out(vty, - "This ra-interval would conflict with configured ra-lifetime!\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (zif->rtadv.MaxRtrAdvInterval % 1000) { - adv_if = adv_msec_if_del(zvrf, ifp->name); - if (adv_if != NULL) - adv_if_free(adv_if); - } - - if (interval % 1000) - (void)adv_msec_if_add(zvrf, ifp->name); - - SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); - zif->rtadv.MaxRtrAdvInterval = interval; - zif->rtadv.MinRtrAdvInterval = 0.33 * interval; - zif->rtadv.AdvIntervalTimer = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_ra_interval, - ipv6_nd_ra_interval_cmd, - "ipv6 nd ra-interval (1-1800)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router Advertisement interval\n" - "Router Advertisement interval in seconds\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - unsigned interval; - struct zebra_if *zif = ifp->info; - struct zebra_vrf *zvrf; - struct adv_if *adv_if; - - zvrf = rtadv_interface_get_zvrf(ifp); - - interval = strtoul(argv[idx_number]->arg, NULL, 10); - if ((zif->rtadv.AdvDefaultLifetime != -1 - && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) { - vty_out(vty, - "This ra-interval would conflict with configured ra-lifetime!\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (zif->rtadv.MaxRtrAdvInterval % 1000) { - adv_if = adv_msec_if_del(zvrf, ifp->name); - if (adv_if != NULL) - adv_if_free(adv_if); - } - - /* convert to milliseconds */ - interval = interval * 1000; - - SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); - zif->rtadv.MaxRtrAdvInterval = interval; - zif->rtadv.MinRtrAdvInterval = 0.33 * interval; - zif->rtadv.AdvIntervalTimer = 0; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_ra_interval, - no_ipv6_nd_ra_interval_cmd, - "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router Advertisement interval\n" - "Router Advertisement interval in seconds\n" - "Specify millisecond router advertisement interval\n" - "Router Advertisement interval in milliseconds\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct zebra_vrf *zvrf = NULL; - struct adv_if *adv_if; - - zvrf = rtadv_interface_get_zvrf(ifp); - - if (zif->rtadv.MaxRtrAdvInterval % 1000) { - adv_if = adv_msec_if_del(zvrf, ifp->name); - if (adv_if != NULL) - adv_if_free(adv_if); - } - - UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED); - - if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) - zif->rtadv.MaxRtrAdvInterval = 10000; - else - zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; - - zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; - zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_ra_lifetime, - ipv6_nd_ra_lifetime_cmd, - "ipv6 nd ra-lifetime (0-9000)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router lifetime\n" - "Router lifetime in seconds (0 stands for a non-default gw)\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - int lifetime; - - lifetime = strtoul(argv[idx_number]->arg, NULL, 10); - - /* The value to be placed in the Router Lifetime field - * of Router Advertisements sent from the interface, - * in seconds. MUST be either zero or between - * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */ - if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) { - vty_out(vty, - "This ra-lifetime would conflict with configured ra-interval\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - zif->rtadv.AdvDefaultLifetime = lifetime; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_ra_lifetime, - no_ipv6_nd_ra_lifetime_cmd, - "no ipv6 nd ra-lifetime [(0-9000)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Router lifetime\n" - "Router lifetime in seconds (0 stands for a non-default gw)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvDefaultLifetime = -1; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_reachable_time, - ipv6_nd_reachable_time_cmd, - "ipv6 nd reachable-time (1-3600000)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Reachable time\n" - "Reachable time in milliseconds\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_reachable_time, - no_ipv6_nd_reachable_time_cmd, - "no ipv6 nd reachable-time [(1-3600000)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Reachable time\n" - "Reachable time in milliseconds\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvReachableTime = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_homeagent_preference, - ipv6_nd_homeagent_preference_cmd, - "ipv6 nd home-agent-preference (0-65535)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent preference\n" - "preference value (default is 0, least preferred)\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.HomeAgentPreference = - strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_homeagent_preference, - no_ipv6_nd_homeagent_preference_cmd, - "no ipv6 nd home-agent-preference [(0-65535)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent preference\n" - "preference value (default is 0, least preferred)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.HomeAgentPreference = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_homeagent_lifetime, - ipv6_nd_homeagent_lifetime_cmd, - "ipv6 nd home-agent-lifetime (0-65520)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent lifetime\n" - "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_homeagent_lifetime, - no_ipv6_nd_homeagent_lifetime_cmd, - "no ipv6 nd home-agent-lifetime [(0-65520)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent lifetime\n" - "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.HomeAgentLifetime = -1; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_managed_config_flag, - ipv6_nd_managed_config_flag_cmd, - "ipv6 nd managed-config-flag", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Managed address configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvManagedFlag = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_managed_config_flag, - no_ipv6_nd_managed_config_flag_cmd, - "no ipv6 nd managed-config-flag", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Managed address configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvManagedFlag = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_homeagent_config_flag, - ipv6_nd_homeagent_config_flag_cmd, - "ipv6 nd home-agent-config-flag", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvHomeAgentFlag = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_homeagent_config_flag, - no_ipv6_nd_homeagent_config_flag_cmd, - "no ipv6 nd home-agent-config-flag", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Home Agent configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvHomeAgentFlag = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_adv_interval_config_option, - ipv6_nd_adv_interval_config_option_cmd, - "ipv6 nd adv-interval-option", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Interval Option\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvIntervalOption = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_adv_interval_config_option, - no_ipv6_nd_adv_interval_config_option_cmd, - "no ipv6 nd adv-interval-option", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertisement Interval Option\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvIntervalOption = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_other_config_flag, - ipv6_nd_other_config_flag_cmd, - "ipv6 nd other-config-flag", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Other statefull configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvOtherConfigFlag = 1; - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_other_config_flag, - no_ipv6_nd_other_config_flag_cmd, - "no ipv6 nd other-config-flag", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Other statefull configuration flag\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.AdvOtherConfigFlag = 0; - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_prefix, - ipv6_nd_prefix_cmd, - "ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] []", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Prefix information\n" - "IPv6 prefix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n" - "Preferred lifetime in seconds\n" - "Infinite preferred lifetime\n" - "Set Router Address flag\n" - "Do not use prefix for onlink determination\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for onlink determination\n") -{ - /* prelude */ - char *prefix = argv[3]->arg; - int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN - || strmatch(argv[4]->text, "infinite")); - int routeropts = lifetimes ? argc > 6 : argc > 4; - - int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0; - - char *lifetime = NULL, *preflifetime = NULL; - int routeraddr = 0, offlink = 0, noautoconf = 0; - if (lifetimes) { - lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg - : argv[4]->text; - preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg - : argv[5]->text; - } - if (routeropts) { - routeraddr = - strmatch(argv[idx_routeropts]->text, "router-address"); - if (!routeraddr) { - offlink = (argc > idx_routeropts + 1 - || strmatch(argv[idx_routeropts]->text, - "off-link")); - noautoconf = (argc > idx_routeropts + 1 - || strmatch(argv[idx_routeropts]->text, - "no-autoconfig")); - } - } - - /* business */ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zebra_if = ifp->info; - int ret; - struct rtadv_prefix rp; - - ret = str2prefix_ipv6(prefix, &rp.prefix); - if (!ret) { - vty_out(vty, "Malformed IPv6 prefix\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */ - rp.AdvOnLinkFlag = !offlink; - rp.AdvAutonomousFlag = !noautoconf; - rp.AdvRouterAddressFlag = routeraddr; - rp.AdvValidLifetime = RTADV_VALID_LIFETIME; - rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; - rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; - - if (lifetimes) { - rp.AdvValidLifetime = strmatch(lifetime, "infinite") - ? UINT32_MAX - : strtoll(lifetime, NULL, 10); - rp.AdvPreferredLifetime = - strmatch(preflifetime, "infinite") - ? UINT32_MAX - : strtoll(preflifetime, NULL, 10); - if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) { - vty_out(vty, "Invalid preferred lifetime\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - - rtadv_prefix_set(zebra_if, &rp); - - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_prefix, - no_ipv6_nd_prefix_cmd, - "no ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] []", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Prefix information\n" - "IPv6 prefix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n" - "Preferred lifetime in seconds\n" - "Infinite preferred lifetime\n" - "Set Router Address flag\n" - "Do not use prefix for onlink determination\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for autoconfiguration\n" - "Do not use prefix for onlink determination\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zebra_if = ifp->info; - int ret; - struct rtadv_prefix rp; - char *prefix = argv[4]->arg; - - ret = str2prefix_ipv6(prefix, &rp.prefix); - if (!ret) { - vty_out(vty, "Malformed IPv6 prefix\n"); - return CMD_WARNING_CONFIG_FAILED; - } - apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */ - rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; - - ret = rtadv_prefix_reset(zebra_if, &rp); - if (!ret) { - vty_out(vty, "Non-existant IPv6 prefix\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_router_preference, - ipv6_nd_router_preference_cmd, - "ipv6 nd router-preference ", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Default router preference\n" - "High default router preference\n" - "Medium default router preference (default)\n" - "Low default router preference\n") -{ - int idx_high_medium_low = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - int i = 0; - - while (0 != rtadv_pref_strs[i]) { - if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i], - 1) - == 0) { - zif->rtadv.DefaultPreference = i; - return CMD_SUCCESS; - } - i++; - } - - return CMD_ERR_NO_MATCH; -} - -DEFUN (no_ipv6_nd_router_preference, - no_ipv6_nd_router_preference_cmd, - "no ipv6 nd router-preference []", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Default router preference\n" - "High default router preference\n" - "Medium default router preference (default)\n" - "Low default router preference\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - - zif->rtadv.DefaultPreference = - RTADV_PREF_MEDIUM; /* Default per RFC4191. */ - - return CMD_SUCCESS; -} - -DEFUN (ipv6_nd_mtu, - ipv6_nd_mtu_cmd, - "ipv6 nd mtu (1-65535)", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertised MTU\n" - "MTU in bytes\n") -{ - int idx_number = 3; - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nd_mtu, - no_ipv6_nd_mtu_cmd, - "no ipv6 nd mtu [(1-65535)]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Advertised MTU\n" - "MTU in bytes\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - zif->rtadv.AdvLinkMTU = 0; - return CMD_SUCCESS; -} - static struct rtadv_rdnss *rtadv_rdnss_new(void) { return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss)); @@ -2293,55 +1558,22 @@ static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss) XFREE(MTYPE_RTADV_RDNSS, rdnss); } -static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list, - struct rtadv_rdnss *rdnss) +struct rtadv_rdnss *rtadv_rdnss_set(struct zebra_if *zif, + struct rtadv_rdnss *rdnss) { - struct listnode *node; struct rtadv_rdnss *p; - for (ALL_LIST_ELEMENTS_RO(list, node, p)) - if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr)) - return p; - return NULL; -} - -static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list, - struct rtadv_rdnss *rdnss) -{ - struct rtadv_rdnss *p; - - p = rtadv_rdnss_lookup(list, rdnss); - if (p) - return p; - p = rtadv_rdnss_new(); memcpy(p, rdnss, sizeof(struct rtadv_rdnss)); - listnode_add(list, p); + listnode_add(zif->rtadv.AdvRDNSSList, p); return p; } -static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss) +void rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *p) { - struct rtadv_rdnss *p; - - p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss); - p->lifetime = rdnss->lifetime; - p->lifetime_set = rdnss->lifetime_set; -} - -static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss) -{ - struct rtadv_rdnss *p; - - p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss); - if (p) { - listnode_delete(zif->rtadv.AdvRDNSSList, p); - rtadv_rdnss_free(p); - return 1; - } - - return 0; + listnode_delete(zif->rtadv.AdvRDNSSList, p); + rtadv_rdnss_free(p); } static struct rtadv_dnssl *rtadv_dnssl_new(void) @@ -2354,54 +1586,22 @@ static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl) XFREE(MTYPE_RTADV_DNSSL, dnssl); } -static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list, - struct rtadv_dnssl *dnssl) +struct rtadv_dnssl *rtadv_dnssl_set(struct zebra_if *zif, + struct rtadv_dnssl *dnssl) { - struct listnode *node; struct rtadv_dnssl *p; - for (ALL_LIST_ELEMENTS_RO(list, node, p)) - if (!strcasecmp(p->name, dnssl->name)) - return p; - return NULL; -} - -static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list, - struct rtadv_dnssl *dnssl) -{ - struct rtadv_dnssl *p; - - p = rtadv_dnssl_lookup(list, dnssl); - if (p) - return p; - p = rtadv_dnssl_new(); memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); - listnode_add(list, p); + listnode_add(zif->rtadv.AdvDNSSLList, p); return p; } -static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl) -{ - struct rtadv_dnssl *p; - - p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl); - memcpy(p, dnssl, sizeof(struct rtadv_dnssl)); -} - -static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) +void rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *p) { - struct rtadv_dnssl *p; - - p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl); - if (p) { - listnode_delete(zif->rtadv.AdvDNSSLList, p); - rtadv_dnssl_free(p); - return 1; - } - - return 0; + listnode_delete(zif->rtadv.AdvDNSSLList, p); + rtadv_dnssl_free(p); } /* @@ -2412,7 +1612,7 @@ static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl) * Returns the number of octets written to out or -1 if in does not constitute * a valid domain name. */ -static int rtadv_dnssl_encode(uint8_t *out, const char *in) +int rtadv_dnssl_encode(uint8_t *out, const char *in) { const char *label_start, *label_end; size_t outp; @@ -2443,148 +1643,6 @@ static int rtadv_dnssl_encode(uint8_t *out, const char *in) return outp; } -DEFUN(ipv6_nd_rdnss, - ipv6_nd_rdnss_cmd, - "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Recursive DNS server information\n" - "IPv6 address\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_rdnss rdnss = {}; - - if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) { - vty_out(vty, "Malformed IPv6 address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (argc > 4) { - char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg - : argv[4]->text; - rdnss.lifetime = strmatch(lifetime, "infinite") - ? UINT32_MAX - : strtoll(lifetime, NULL, 10); - rdnss.lifetime_set = 1; - } - - rtadv_rdnss_set(zif, &rdnss); - - return CMD_SUCCESS; -} - -DEFUN(no_ipv6_nd_rdnss, - no_ipv6_nd_rdnss_cmd, - "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "Recursive DNS server information\n" - "IPv6 address\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_rdnss rdnss = {}; - - if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) { - vty_out(vty, "Malformed IPv6 address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (rtadv_rdnss_reset(zif, &rdnss) != 1) { - vty_out(vty, "Non-existant RDNSS address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - -DEFUN(ipv6_nd_dnssl, - ipv6_nd_dnssl_cmd, - "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "DNS search list information\n" - "Domain name suffix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_dnssl dnssl = {}; - size_t len; - int ret; - - len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name)); - if (len == 0 || len >= sizeof(dnssl.name)) { - vty_out(vty, "Malformed DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (dnssl.name[len - 1] == '.') { - /* - * Allow, but don't require, a trailing dot signifying the root - * zone. Canonicalize by cutting it off if present. - */ - dnssl.name[len - 1] = '\0'; - len--; - } - if (argc > 4) { - char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg - : argv[4]->text; - dnssl.lifetime = strmatch(lifetime, "infinite") - ? UINT32_MAX - : strtoll(lifetime, NULL, 10); - dnssl.lifetime_set = 1; - } - - ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); - if (ret < 0) { - vty_out(vty, "Malformed DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - dnssl.encoded_len = ret; - rtadv_dnssl_set(zif, &dnssl); - - return CMD_SUCCESS; -} - -DEFUN(no_ipv6_nd_dnssl, - no_ipv6_nd_dnssl_cmd, - "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]", - NO_STR - "Interface IPv6 config commands\n" - "Neighbor discovery\n" - "DNS search list information\n" - "Domain name suffix\n" - "Valid lifetime in seconds\n" - "Infinite valid lifetime\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif = ifp->info; - struct rtadv_dnssl dnssl = {}; - size_t len; - - len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name)); - if (len == 0 || len >= sizeof(dnssl.name)) { - vty_out(vty, "Malformed DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (dnssl.name[len - 1] == '.') { - dnssl.name[len - 1] = '\0'; - len--; - } - if (rtadv_dnssl_reset(zif, &dnssl) != 1) { - vty_out(vty, "Non-existant DNS search domain\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - - /* Dump interface ND information to vty. */ static int nd_dump_vty(struct vty *vty, struct interface *ifp) { @@ -2655,136 +1713,6 @@ static int nd_dump_vty(struct vty *vty, struct interface *ifp) return 0; } - -/* Write configuration about router advertisement. */ -static int rtadv_config_write(struct vty *vty, struct interface *ifp) -{ - struct zebra_if *zif; - struct listnode *node; - struct rtadv_prefix *rprefix; - struct rtadv_rdnss *rdnss; - struct rtadv_dnssl *dnssl; - int interval; - - zif = ifp->info; - - if (!if_is_loopback(ifp)) { - if (zif->rtadv.AdvSendAdvertisements - && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED)) - vty_out(vty, " no ipv6 nd suppress-ra\n"); - } - - interval = zif->rtadv.MaxRtrAdvInterval; - if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) { - if (interval % 1000) - vty_out(vty, " ipv6 nd ra-interval msec %d\n", - interval); - else if (interval != RTADV_MAX_RTR_ADV_INTERVAL) - vty_out(vty, " ipv6 nd ra-interval %d\n", - interval / 1000); - } - - if (zif->rtadv.AdvIntervalOption) - vty_out(vty, " ipv6 nd adv-interval-option\n"); - - if (!zif->rtadv.UseFastRexmit) - vty_out(vty, " no ipv6 nd ra-fast-retrans\n"); - - if (zif->rtadv.AdvRetransTimer != 0) - vty_out(vty, " ipv6 nd ra-retrans-interval %u\n", - zif->rtadv.AdvRetransTimer); - - if (zif->rtadv.AdvCurHopLimit != RTADV_DEFAULT_HOPLIMIT) - vty_out(vty, " ipv6 nd ra-hop-limit %d\n", - zif->rtadv.AdvCurHopLimit); - - if (zif->rtadv.AdvDefaultLifetime != -1) - vty_out(vty, " ipv6 nd ra-lifetime %d\n", - zif->rtadv.AdvDefaultLifetime); - - if (zif->rtadv.HomeAgentPreference) - vty_out(vty, " ipv6 nd home-agent-preference %u\n", - zif->rtadv.HomeAgentPreference); - - if (zif->rtadv.HomeAgentLifetime != -1) - vty_out(vty, " ipv6 nd home-agent-lifetime %u\n", - zif->rtadv.HomeAgentLifetime); - - if (zif->rtadv.AdvHomeAgentFlag) - vty_out(vty, " ipv6 nd home-agent-config-flag\n"); - - if (zif->rtadv.AdvReachableTime) - vty_out(vty, " ipv6 nd reachable-time %d\n", - zif->rtadv.AdvReachableTime); - - if (zif->rtadv.AdvManagedFlag) - vty_out(vty, " ipv6 nd managed-config-flag\n"); - - if (zif->rtadv.AdvOtherConfigFlag) - vty_out(vty, " ipv6 nd other-config-flag\n"); - - if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM) - vty_out(vty, " ipv6 nd router-preference %s\n", - rtadv_pref_strs[zif->rtadv.DefaultPreference]); - - if (zif->rtadv.AdvLinkMTU) - vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU); - - frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) { - if ((rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL) - || (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH)) { - vty_out(vty, " ipv6 nd prefix %pFX", &rprefix->prefix); - if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) - || (rprefix->AdvPreferredLifetime - != RTADV_PREFERRED_LIFETIME)) { - if (rprefix->AdvValidLifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", - rprefix->AdvValidLifetime); - if (rprefix->AdvPreferredLifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", - rprefix->AdvPreferredLifetime); - } - if (!rprefix->AdvOnLinkFlag) - vty_out(vty, " off-link"); - if (!rprefix->AdvAutonomousFlag) - vty_out(vty, " no-autoconfig"); - if (rprefix->AdvRouterAddressFlag) - vty_out(vty, " router-address"); - vty_out(vty, "\n"); - } - } - - for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { - char buf[INET6_ADDRSTRLEN]; - - vty_out(vty, " ipv6 nd rdnss %s", - inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf))); - if (rdnss->lifetime_set) { - if (rdnss->lifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", rdnss->lifetime); - } - vty_out(vty, "\n"); - } - for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) { - vty_out(vty, " ipv6 nd dnssl %s", dnssl->name); - if (dnssl->lifetime_set) { - if (dnssl->lifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", dnssl->lifetime); - } - vty_out(vty, "\n"); - } - return 0; -} - - static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val) { struct rtadv *rtadv; @@ -2930,49 +1858,8 @@ void rtadv_cmd_init(void) interfaces_configured_for_ra_from_bgp = 0; hook_register(zebra_if_extra_info, nd_dump_vty); - hook_register(zebra_if_config_wr, rtadv_config_write); install_element(VIEW_NODE, &show_ipv6_nd_ra_if_cmd); - - install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_retrans_interval_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_hop_limit_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd); - install_element(INTERFACE_NODE, - &ipv6_nd_adv_interval_config_option_cmd); - install_element(INTERFACE_NODE, - &no_ipv6_nd_adv_interval_config_option_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd); - install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); - install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd); } static int if_join_all_router(int sock, struct interface *ifp) @@ -3069,3 +1956,13 @@ uint32_t rtadv_get_interfaces_configured_from_bgp(void) { return interfaces_configured_for_ra_from_bgp; } + +void rtadv_init(void) +{ + if (CMSG_SPACE(sizeof(struct in6_pktinfo)) > RTADV_ADATA_SIZE) { + zlog_debug("%s: RTADV_ADATA_SIZE chosen will not work on this platform, please use a larger size", + __func__); + + exit(-1); + } +} diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 1ec376a10626..0983ea578fe1 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -385,6 +385,30 @@ extern void rtadv_if_fini(struct zebra_if *zif); extern void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p); extern void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p); +/* returns created prefix */ +struct rtadv_prefix *rtadv_add_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rp); +/* rprefix must be the one returned by rtadv_add_prefix_manual */ +void rtadv_delete_prefix_manual(struct zebra_if *zif, + struct rtadv_prefix *rprefix); + +/* returns created address */ +struct rtadv_rdnss *rtadv_rdnss_set(struct zebra_if *zif, + struct rtadv_rdnss *rdnss); +/* p must be the one returned by rtadv_rdnss_set */ +void rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *p); + +/* returns created domain */ +struct rtadv_dnssl *rtadv_dnssl_set(struct zebra_if *zif, + struct rtadv_dnssl *dnssl); +/* p must be the one returned by rtadv_dnssl_set */ +void rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *p); +int rtadv_dnssl_encode(uint8_t *out, const char *in); + +void ipv6_nd_suppress_ra_set(struct interface *ifp, + enum ipv6_nd_suppress_ra_status status); +void ipv6_nd_interval_set(struct interface *ifp, uint32_t interval); + #else /* !HAVE_RTADV */ struct rtadv { /* empty structs aren't valid ISO C */ @@ -435,6 +459,7 @@ extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); extern uint32_t rtadv_get_interfaces_configured_from_bgp(void); extern bool rtadv_compiled_in(void); +extern void rtadv_init(void); #ifdef __cplusplus } diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index ef1e21b4f7d0..8e2d13fafff0 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -6,6 +6,8 @@ #include +#include + #if !defined(GNU_LINUX) #include "memory.h" diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index f00aef52c07a..05282793d72d 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -9,6 +9,9 @@ #ifdef HAVE_NETLINK +#include +#include + #include "if.h" #include "prefix.h" #include "vrf.h" diff --git a/zebra/subdir.am b/zebra/subdir.am index 1060e3878532..f7674473661c 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -19,6 +19,12 @@ if LINUX module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la endif +#if FPM_LISTENER +sbin_PROGRAMS += zebra/fpm_listener +zebra_fpm_listener_SOURCES = zebra/fpm_listener.c +zebra_fpm_listener_LDADD = lib/libfrr.la +#endf + # Dataplane sample plugin if DEV_BUILD module_LTLIBRARIES += zebra/dplane_sample_plugin.la @@ -28,7 +34,7 @@ man8 += $(MANBUILD)/frr-zebra.8 ## endif ZEBRA endif -zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) $(UST_LIBS) +zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) $(LIBYANG_LIBS) $(UST_LIBS) if HAVE_PROTOBUF3 zebra_zebra_LDADD += mlag/libmlag_pb.la $(PROTOBUF_C_LIBS) zebra/zebra_mlag.$(OBJEXT): mlag/mlag.pb-c.h @@ -52,6 +58,7 @@ zebra_zebra_SOURCES = \ zebra/redistribute.c \ zebra/router-id.c \ zebra/rt_netlink.c \ + zebra/ge_netlink.c \ zebra/rt_socket.c \ zebra/rtadv.c \ zebra/rtread_netlink.c \ @@ -115,15 +122,17 @@ zebra_zebra_SOURCES = \ clippy_scan += \ zebra/debug.c \ + zebra/dplane_fpm_nl.c \ zebra/interface.c \ zebra/rtadv.c \ - zebra/zebra_evpn_mh.c \ zebra/zebra_mlag_vty.c \ zebra/zebra_routemap.c \ zebra/zebra_vty.c \ zebra/zebra_srv6_vty.c \ zebra/zebra_vrf.c \ zebra/dpdk/zebra_dplane_dpdk_vty.c \ + zebra/label_manager.c \ + zebra/zebra_cli.c \ # end noinst_HEADERS += \ @@ -143,6 +152,7 @@ noinst_HEADERS += \ zebra/router-id.h \ zebra/rt.h \ zebra/rt_netlink.h \ + zebra/ge_netlink.h \ zebra/rtadv.h \ zebra/rule_netlink.h \ zebra/table_manager.h \ diff --git a/zebra/table_manager.c b/zebra/table_manager.c index 512508b79f96..8417a22114f4 100644 --- a/zebra/table_manager.c +++ b/zebra/table_manager.c @@ -24,21 +24,6 @@ #include "zebra/table_manager.h" #include "zebra/zebra_errors.h" -/* routing table identifiers - * - */ -#if !defined(GNU_LINUX) -/* BSD systems - */ -#else -/* Linux Systems - */ -#define RT_TABLE_ID_LOCAL 255 -#define RT_TABLE_ID_MAIN 254 -#define RT_TABLE_ID_DEFAULT 253 -#define RT_TABLE_ID_COMPAT 252 -#define RT_TABLE_ID_UNSPEC 0 -#endif /* !def(GNU_LINUX) */ #define RT_TABLE_ID_UNRESERVED_MIN 1 #define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff @@ -279,52 +264,11 @@ void table_manager_disable(struct zebra_vrf *zvrf) zvrf->tbl_mgr = NULL; } -int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf, - const char *start_table_str, const char *end_table_str) +void table_manager_range(bool add, struct zebra_vrf *zvrf, uint32_t start, + uint32_t end) { - uint32_t start; - uint32_t end; - - if (add) { - if (!start_table_str || !end_table_str) { - vty_out(vty, "%% Labels not specified\n"); - return CMD_WARNING_CONFIG_FAILED; - } - start = atoi(start_table_str); - end = atoi(end_table_str); - if (end < start) { - vty_out(vty, "%% End table is less than Start table\n"); - return CMD_WARNING_CONFIG_FAILED; - } - -#if !defined(GNU_LINUX) -/* BSD systems - */ -#else - /* Linux Systems - */ - if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL) - || (end >= RT_TABLE_ID_COMPAT - && end <= RT_TABLE_ID_LOCAL)) { - vty_out(vty, "%% Values forbidden in range [%u;%u]\n", - RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); - return CMD_WARNING_CONFIG_FAILED; - } - if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) { - vty_out(vty, - "%% Range overlaps range [%u;%u] forbidden\n", - RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); - return CMD_WARNING_CONFIG_FAILED; - } -#endif - if (zvrf->tbl_mgr - && ((zvrf->tbl_mgr->start && zvrf->tbl_mgr->start != start) - || (zvrf->tbl_mgr->end && zvrf->tbl_mgr->end != end))) { - vty_out(vty, - "%% New range will be taken into account at restart\n"); - } + if (add) table_range_add(zvrf, start, end); - } else + else table_range_add(zvrf, 0, 0); - return CMD_SUCCESS; } diff --git a/zebra/table_manager.h b/zebra/table_manager.h index f8e99a357dba..21691994cba6 100644 --- a/zebra/table_manager.h +++ b/zebra/table_manager.h @@ -18,6 +18,22 @@ extern "C" { #endif +/* routing table identifiers + * + */ +#if !defined(GNU_LINUX) +/* BSD systems + */ +#else +/* Linux Systems + */ +#define RT_TABLE_ID_LOCAL 255 +#define RT_TABLE_ID_MAIN 254 +#define RT_TABLE_ID_DEFAULT 253 +#define RT_TABLE_ID_COMPAT 252 +#define RT_TABLE_ID_UNSPEC 0 +#endif /* !def(GNU_LINUX) */ + /* * Table chunk struct * Client daemon which the chunk belongs to can be identified by either @@ -56,8 +72,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start, uint32_t end, struct zebra_vrf *zvrf); int release_daemon_table_chunks(struct zserv *client); void table_manager_disable(struct zebra_vrf *zvrf); -int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf, - const char *min, const char *max); +void table_manager_range(bool add, struct zebra_vrf *zvrf, uint32_t start, + uint32_t end); #ifdef __cplusplus } diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c index d0f4ed6d1862..19667e66acc0 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -9,6 +9,7 @@ #ifdef HAVE_NETLINK +#include #include #include #include @@ -160,7 +161,7 @@ static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -236,7 +237,7 @@ static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; @@ -486,7 +487,7 @@ static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, struct nlmsghdr n; struct tcmsg t; char buf[0]; - } *req = (void *)data; + } *req = data; if (datalen < sizeof(*req)) return 0; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 8a480cfa1ca1..aecbba2ebc5f 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -24,6 +24,7 @@ #include "lib/vrf.h" #include "lib/libfrr.h" #include "lib/lib_errors.h" +#include "lib/frrdistance.h" #include "zebra/zebra_router.h" #include "zebra/rib.h" @@ -63,7 +64,7 @@ static void zserv_encode_interface(struct stream *s, struct interface *ifp) /* Interface information. */ struct zebra_if *zif = ifp->info; - stream_put(s, ifp->name, INTERFACE_NAMSIZ); + stream_put(s, ifp->name, IFNAMSIZ); stream_putl(s, ifp->ifindex); stream_putc(s, ifp->status); stream_putq(s, ifp->flags); @@ -414,7 +415,7 @@ int zsend_interface_addresses(struct zserv *client, struct interface *ifp) struct nbr_connected *nc; /* Send interface addresses. */ - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each (if_connected, ifp->connected, c) { if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) continue; @@ -435,27 +436,6 @@ int zsend_interface_addresses(struct zserv *client, struct interface *ifp) return 0; } -/* Notify client about interface moving from one VRF to another. - * Whether client is interested in old and new VRF is checked by caller. - */ -int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, - vrf_id_t vrf_id) -{ - struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - - zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf->vrf_id); - - /* Fill in the name of the interface and its new VRF (id) */ - stream_put(s, ifp->name, INTERFACE_NAMSIZ); - stream_putl(s, vrf_id); - - /* Write packet size. */ - stream_putw_at(s, 0, stream_get_endp(s)); - - client->if_vrfchg_cnt++; - return zserv_send_message(client, s); -} - /* Add new nbr connected IPv6 address */ void nbr_connected_add_ipv6(struct interface *ifp, struct in6_addr *address) { @@ -531,7 +511,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) int zsend_redistribute_route(int cmd, struct zserv *client, const struct route_node *rn, - const struct route_entry *re) + const struct route_entry *re, bool is_table_direct) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -547,7 +527,11 @@ int zsend_redistribute_route(int cmd, struct zserv *client, api.vrf_id = re->vrf_id; api.type = re->type; api.safi = SAFI_UNICAST; - api.instance = re->instance; + if (is_table_direct) { + api.instance = re->table; + api.type = ZEBRA_ROUTE_TABLE_DIRECT; + } else + api.instance = re->instance; api.flags = re->flags; afi = family2afi(p->family); @@ -614,7 +598,10 @@ int zsend_redistribute_route(int cmd, struct zserv *client, /* Attributes. */ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = re->distance; + if (is_table_direct) + api.distance = ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT; + else + api.distance = re->distance; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = re->metric; if (re->tag) { @@ -848,12 +835,14 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, ZEBRA_RULE_NOTIFY_OWNER, + dplane_ctx_rule_get_vrfid(ctx)); + stream_put(s, ¬e, sizeof(note)); stream_putl(s, dplane_ctx_rule_get_seq(ctx)); stream_putl(s, dplane_ctx_rule_get_priority(ctx)); stream_putl(s, dplane_ctx_rule_get_unique(ctx)); - stream_put(s, dplane_ctx_rule_get_ifname(ctx), INTERFACE_NAMSIZ); + stream_put(s, dplane_ctx_rule_get_ifname(ctx), IFNAMSIZ); stream_putw_at(s, 0, stream_get_endp(s)); @@ -979,9 +968,9 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, zserv_send_message(client, s); } -void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, - struct ipaddr *ipaddr, int ndm_state, - union sockunion *link_layer_ipv4) +void zsend_neighbor_notify(int cmd, struct interface *ifp, + struct ipaddr *ipaddr, int ndm_state, + union sockunion *link_layer_ipv4, int ip_len) { struct stream *s; struct listnode *node, *nnode; @@ -998,18 +987,60 @@ void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, family2addrsize(sockunion_family(&ip))); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if (!vrf_bitmap_check(&client->nhrp_neighinfo[afi], + if (!vrf_bitmap_check(&client->neighinfo[afi], ifp->vrf->vrf_id)) continue; s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_neigh_ip_encode(s, cmd, &ip, link_layer_ipv4, ifp, - ndm_state); + ndm_state, ip_len); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } } +void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note) + +{ + struct stream *s; + uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: notifying %s ctx %s sid %pI6 note %s (proto=%u, instance=%u, sessionId=%u)", + __func__, zserv_command_string(cmd), + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, + zapi_srv6_sid_notify2str(note), client->proto, + client->instance, client->session_id); + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + /* Notification type (e.g. ZAPI_SRV6_SID_ALLOCATED, ZAPI_SRV6_SID_FAIL_ALLOC, ...) */ + stream_put(s, ¬e, sizeof(note)); + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + /* SRv6 SID value (i.e. IPv6 address) */ + stream_put(s, sid_value, sizeof(struct in6_addr)); + /* SRv6 SID function */ + stream_putl(s, func); + /* SRv6 wide SID function */ + stream_putl(s, wide_func); + /* SRv6 locator name optional */ + if (locator_name) { + stream_putw(s, strlen(locator_name)); + stream_put(s, locator_name, strlen(locator_name)); + } else + stream_putw(s, 0); + + stream_putw_at(s, 0, stream_get_endp(s)); + + zserv_send_message(client, s); +} + /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, @@ -1047,7 +1078,7 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw) struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, ZEBRA_PW_STATUS_UPDATE, pw->vrf_id); - stream_write(s, pw->ifname, INTERFACE_NAMSIZ); + stream_write(s, pw->ifname, IFNAMSIZ); stream_putl(s, pw->ifindex); stream_putl(s, pw->status); @@ -1147,9 +1178,25 @@ static int zsend_table_manager_connect_response(struct zserv *client, int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct srv6_locator locator = {}; + struct srv6_sid_format *format = loc->sid_format; + + /* + * Copy the locator and fill locator block/node/func/arg length from the format + * before sending the locator to the zclient + */ + srv6_locator_copy(&locator, loc); + if (format) { + locator.block_bits_length = format->block_len; + locator.node_bits_length = format->node_len; + locator.function_bits_length = format->function_len; + locator.argument_bits_length = format->argument_len; + if (format->type == SRV6_SID_FORMAT_TYPE_USID) + SET_FLAG(locator.flags, SRV6_LOCATOR_USID); + } zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT); - zapi_srv6_locator_encode(s, loc); + zapi_srv6_locator_encode(s, &locator); stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); @@ -1698,10 +1745,14 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, struct nexthop_group **png, struct nhg_backup_info **pbnhg) { + struct zapi_nexthop *znh; struct nexthop_group *ng = NULL; struct nhg_backup_info *bnhg = NULL; uint16_t i; struct nexthop *last_nh = NULL; + bool same_weight = true; + uint64_t max_weight = 0; + uint64_t tmp; assert(!(png && pbnhg)); @@ -1716,6 +1767,40 @@ static bool zapi_read_nexthops(struct zserv *client, struct prefix *p, bnhg = zebra_nhg_backup_alloc(); } + for (i = 0; i < nexthop_num; i++) { + znh = &nhops[i]; + + if (max_weight < znh->weight) { + if (i != 0 || znh->weight != 1) + same_weight = false; + + max_weight = znh->weight; + } + } + + /* + * Let's convert the weights to a scaled value + * between 1 and zrouter.nexthop_weight_scale_value + * This is a simple application of a ratio: + * scaled_weight/zrouter.nexthop_weight_scale_value = + * weight/max_weight + * This translates to: + * scaled_weight = weight * zrouter.nexthop_weight_scale_value + * ------------------------------------------- + * max_weight + * + * This same formula is applied to both the nexthops + * and the backup nexthops + */ + if (!same_weight) { + for (i = 0; i < nexthop_num; i++) { + znh = &nhops[i]; + + tmp = znh->weight * zrouter.nexthop_weight_scale_value; + znh->weight = MAX(1, (tmp / max_weight)); + } + } + /* * TBD should _all_ of the nexthop add operations use * api_nh->vrf_id instead of re->vrf_id ? I only changed @@ -1931,20 +2016,21 @@ static void zread_nhg_del(ZAPI_HANDLER_ARGS) return; } - /* - * Delete the received nhg id - */ - nhe = zebra_nhg_proto_del(api_nhg.id, api_nhg.proto); + /* Create a temporary nhe */ + nhe = zebra_nhg_alloc(); + nhe->id = api_nhg.id; + nhe->type = api_nhg.proto; + nhe->zapi_instance = client->instance; + nhe->zapi_session = client->session_id; - if (nhe) { - zebra_nhg_decrement_ref(nhe); - zsend_nhg_notify(api_nhg.proto, client->instance, - client->session_id, api_nhg.id, - ZAPI_NHG_REMOVED); - } else - zsend_nhg_notify(api_nhg.proto, client->instance, - client->session_id, api_nhg.id, - ZAPI_NHG_REMOVE_FAIL); + /* Sanity check - Empty nexthop and group */ + nhe->nhg.nexthop = NULL; + + /* Enqueue to workqueue for processing */ + rib_queue_nhe_del(nhe); + + /* Stats */ + client->nhg_del_cnt++; } static void zread_nhg_add(ZAPI_HANDLER_ARGS) @@ -1953,7 +2039,7 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) struct zapi_nhg api_nhg = {}; struct nexthop_group *nhg = NULL; struct nhg_backup_info *bnhg = NULL; - struct nhg_hash_entry *nhe; + struct nhg_hash_entry *nhe, *nhe_tmp; s = msg; if (zapi_nhg_decode(s, hdr->command, &api_nhg) < 0) { @@ -2011,6 +2097,12 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&nhg); zebra_nhg_backup_free(&bnhg); + /* Stats */ + nhe_tmp = zebra_nhg_lookup_id(api_nhg.id); + if (nhe_tmp) + client->nhg_upd8_cnt++; + else + client->nhg_add_cnt++; } static void zread_route_add(ZAPI_HANDLER_ARGS) @@ -2056,7 +2148,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, &api.prefix, zebra_route_string(client->proto)); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2081,7 +2173,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2100,8 +2192,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) @@ -2113,8 +2204,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, api.safi); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2143,8 +2233,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ if (ret == -1) { client->error_cnt++; - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } /* At this point, these allocations are not needed: 're' has been @@ -2172,9 +2261,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } } -void zapi_re_opaque_free(struct re_opaque *opaque) +void zapi_re_opaque_free(struct route_entry *re) { - XFREE(MTYPE_RE_OPAQUE, opaque); + XFREE(MTYPE_RE_OPAQUE, re->opaque); + re->opaque = NULL; } static void zread_route_del(ZAPI_HANDLER_ARGS) @@ -2322,6 +2412,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); stream_putc(s, zrouter.v6_with_v4_nexthop); + stream_putc(s, zrouter.graceful_restart); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } @@ -2348,23 +2439,19 @@ static void zread_hello(ZAPI_HANDLER_ARGS) /* type of protocol (lib/zebra.h) */ uint8_t proto; unsigned short instance; - uint8_t notify; uint8_t synchronous; uint32_t session_id; STREAM_GETC(msg, proto); STREAM_GETW(msg, instance); STREAM_GETL(msg, session_id); - STREAM_GETC(msg, notify); STREAM_GETC(msg, synchronous); - if (notify) - client->notify_owner = true; if (synchronous) client->synchronous = true; /* accept only dynamic routing protocols */ - if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_CONNECT)) { + if ((proto < ZEBRA_ROUTE_MAX) && (proto > ZEBRA_ROUTE_LOCAL)) { zlog_notice( "client %d says hello and bids fair to announce only %s routes vrf=%u", client->sock, zebra_route_string(proto), @@ -2400,7 +2487,7 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) zvrf_id(zvrf)); vrf_bitmap_unset(&client->redist_default[afi], zvrf_id(zvrf)); vrf_bitmap_unset(&client->ridinfo[afi], zvrf_id(zvrf)); - vrf_bitmap_unset(&client->nhrp_neighinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->neighinfo[afi], zvrf_id(zvrf)); } } @@ -2960,6 +3047,96 @@ static void zread_srv6_manager_release_locator_chunk(struct zserv *client, return; } +/** + * Handle SRv6 SID request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct in6_addr *sid_value_ptr = NULL; + char locator[SRV6_LOCNAME_SIZE] = { 0 }; + uint16_t len; + struct zebra_srv6_sid *sid = NULL; + uint8_t flags; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GETC(s, flags); + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) { + STREAM_GET(&sid_value, s, sizeof(struct in6_addr)); + sid_value_ptr = &sid_value; + } + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + STREAM_GETW(s, len); + STREAM_GET(locator, s, len); + } + + /* Call hook to get a SID using wrapper */ + srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator); + +stream_failure: + return; +} + +/** + * Handle SRv6 SID release request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_release_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + + /* Call hook to release a SID using wrapper */ + srv6_manager_release_sid_call(client, &ctx); + +stream_failure: + return; +} + +/** + * Handle SRv6 locator get request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_locator(struct zserv *client, + struct stream *msg) +{ + struct stream *s = msg; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = { 0 }; + struct srv6_locator *locator = NULL; + + /* Get data */ + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + /* Call hook to get the locator info using wrapper */ + srv6_manager_get_locator_call(&locator, client, locator_name); + +stream_failure: + return; +} + static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { @@ -2971,6 +3148,15 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zread_srv6_manager_release_locator_chunk(client, msg, zvrf_id(zvrf)); break; + case ZEBRA_SRV6_MANAGER_GET_SRV6_SID: + zread_srv6_manager_get_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID: + zread_srv6_manager_release_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR: + zread_srv6_manager_get_locator(client, msg); + break; default: zlog_err("%s: unknown SRv6 Manager command", __func__); break; @@ -2980,7 +3166,7 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) static void zread_pseudowire(ZAPI_HANDLER_ARGS) { struct stream *s; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int type; int af; @@ -2996,8 +3182,8 @@ static void zread_pseudowire(ZAPI_HANDLER_ARGS) s = msg; /* Get data. */ - STREAM_GET(ifname, s, INTERFACE_NAMSIZ); - ifname[INTERFACE_NAMSIZ - 1] = '\0'; + STREAM_GET(ifname, s, IFNAMSIZ); + ifname[IFNAMSIZ - 1] = '\0'; STREAM_GETL(s, ifindex); STREAM_GETL(s, type); STREAM_GETL(s, af); @@ -3093,6 +3279,28 @@ static void zread_interface_set_master(ZAPI_HANDLER_ARGS) } +static void zread_interface_set_arp(ZAPI_HANDLER_ARGS) +{ + struct stream *s = msg; + struct interface *ifp; + bool arp_enable; + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + int ifindex; + + STREAM_GETL(s, ifindex); + STREAM_GETC(s, arp_enable); + ifp = if_lookup_by_index(ifindex, vrf_id); + + if (!ifp) + return; + + if_arp(ifp, arp_enable); + +stream_failure: + return; +} + + static void zread_vrf_label(ZAPI_HANDLER_ARGS) { struct interface *ifp; @@ -3532,7 +3740,7 @@ static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS) afi); goto stream_failure; } - vrf_bitmap_set(&client->nhrp_neighinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_set(&client->neighinfo[afi], zvrf_id(zvrf)); stream_failure: return; } @@ -3548,7 +3756,7 @@ static inline void zebra_neigh_unregister(ZAPI_HANDLER_ARGS) afi); goto stream_failure; } - vrf_bitmap_unset(&client->nhrp_neighinfo[afi], zvrf_id(zvrf)); + vrf_bitmap_unset(&client->neighinfo[afi], zvrf_id(zvrf)); stream_failure: return; } @@ -3874,6 +4082,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_REMOTE_MACIP_DEL] = zebra_vxlan_remote_macip_del, [ZEBRA_DUPLICATE_ADDR_DETECTION] = zebra_vxlan_dup_addr_detection, [ZEBRA_INTERFACE_SET_MASTER] = zread_interface_set_master, + [ZEBRA_INTERFACE_SET_ARP] = zread_interface_set_arp, [ZEBRA_PW_ADD] = zread_pseudowire, [ZEBRA_PW_DELETE] = zread_pseudowire, [ZEBRA_PW_SET] = zread_pseudowire, @@ -3896,6 +4105,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NHG_ADD] = zread_nhg_add, @@ -3905,8 +4117,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh, [ZEBRA_NEIGH_IP_ADD] = zebra_neigh_ip_add, [ZEBRA_NEIGH_IP_DEL] = zebra_neigh_ip_del, - [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register, - [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister, + [ZEBRA_NEIGH_REGISTER] = zebra_neigh_register, + [ZEBRA_NEIGH_UNREGISTER] = zebra_neigh_unregister, [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp, [ZEBRA_GRE_GET] = zebra_gre_get, [ZEBRA_GRE_SOURCE_SET] = zebra_gre_source_set, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index ce8e154465ff..a59ccc838b97 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -53,12 +53,11 @@ extern int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp); extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct route_node *rn, - const struct route_entry *re); + const struct route_entry *re, + bool is_table_direct); extern int zsend_router_id_update(struct zserv *zclient, afi_t afi, struct prefix *p, vrf_id_t vrf_id); -extern int zsend_interface_vrf_update(struct zserv *zclient, - struct interface *ifp, vrf_id_t vrf_id); extern int zsend_interface_link_params(struct zserv *zclient, struct interface *ifp); extern int zsend_pw_update(struct zserv *client, struct zebra_pw *pw); @@ -92,9 +91,14 @@ extern int zsend_label_manager_connect_response(struct zserv *client, extern int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint, char *name, int status); -extern void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, - struct ipaddr *ipaddr, int ndm_state, - union sockunion *link_layer_ipv4); +extern void zsend_neighbor_notify(int cmd, struct interface *ifp, + struct ipaddr *ipaddr, int ndm_state, + union sockunion *link_layer_ipv4, int ip_len); +extern void zsend_srv6_sid_notify(struct zserv *client, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); @@ -102,7 +106,7 @@ extern int zsend_client_close_notify(struct zserv *client, int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, uint32_t id, enum zapi_nhg_notify_owner note); -extern void zapi_re_opaque_free(struct re_opaque *opaque); +extern void zapi_re_opaque_free(struct route_entry *re); extern int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc); @@ -111,6 +115,9 @@ extern int zsend_zebra_srv6_locator_delete(struct zserv *client, extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_response(struct zserv *client, + struct srv6_locator *locator); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_affinitymap.c b/zebra/zebra_affinitymap.c index ae0f9a8a354d..79bc78a7dcbb 100644 --- a/zebra/zebra_affinitymap.c +++ b/zebra/zebra_affinitymap.c @@ -26,102 +26,26 @@ #include "zebra/redistribute.h" #include "zebra/zebra_affinitymap.h" -static bool zebra_affinity_map_check_use(const char *affmap_name) -{ - char xpath[XPATH_MAXLEN]; - struct interface *ifp; - struct vrf *vrf; - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - FOR_ALL_INTERFACES (vrf, ifp) { - snprintf(xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']", - ifp->name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", - ifp->name, affmap_name); - if (yang_dnode_exists(running_config->dnode, xpath)) - return true; - } - } - return false; -} - -static bool zebra_affinity_map_check_update(const char *affmap_name, - uint16_t new_pos) -{ - char xpath[XPATH_MAXLEN]; - struct interface *ifp; - struct vrf *vrf; - - /* check whether the affinity-map new bit position is upper than 31 - * but is used on an interface on which affinity-mode is standard. - * Return false if the change is not possible. - */ - if (new_pos < 32) - return true; - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - FOR_ALL_INTERFACES (vrf, ifp) { - snprintf(xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']", - ifp->name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", - ifp->name, affmap_name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - if (yang_dnode_get_enum( - running_config->dnode, - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinity-mode", - ifp->name) == AFFINITY_MODE_STANDARD) - return false; - } - } - return true; -} - static void zebra_affinity_map_update(const char *affmap_name, uint16_t old_pos, uint16_t new_pos) { struct if_link_params *iflp; - enum affinity_mode aff_mode; - char xpath[XPATH_MAXLEN]; struct interface *ifp; struct vrf *vrf; RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { FOR_ALL_INTERFACES (vrf, ifp) { - snprintf(xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']", - ifp->name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - snprintf( - xpath, sizeof(xpath), - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinities[affinity='%s']", - ifp->name, affmap_name); - if (!yang_dnode_exists(running_config->dnode, xpath)) - continue; - aff_mode = yang_dnode_get_enum( - running_config->dnode, - "/frr-interface:lib/interface[name='%s']/frr-zebra:zebra/link-params/affinity-mode", - ifp->name); iflp = if_link_params_get(ifp); - if (aff_mode == AFFINITY_MODE_EXTENDED || - aff_mode == AFFINITY_MODE_BOTH) { + if (!iflp) + continue; + if (IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && + admin_group_get(&iflp->ext_admin_grp, old_pos)) { admin_group_unset(&iflp->ext_admin_grp, old_pos); admin_group_set(&iflp->ext_admin_grp, new_pos); } - if (aff_mode == AFFINITY_MODE_STANDARD || - aff_mode == AFFINITY_MODE_BOTH) { + if (IS_PARAM_SET(iflp, LP_ADM_GRP) && + (iflp->admin_grp & (1 << old_pos))) { iflp->admin_grp &= ~(1 << old_pos); if (new_pos < 32) iflp->admin_grp |= 1 << new_pos; @@ -138,7 +62,5 @@ void zebra_affinity_map_init(void) { affinity_map_init(); - affinity_map_set_check_use_hook(zebra_affinity_map_check_use); - affinity_map_set_check_update_hook(zebra_affinity_map_check_update); affinity_map_set_update_hook(zebra_affinity_map_update); } diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c new file mode 100644 index 000000000000..3e03d7477575 --- /dev/null +++ b/zebra/zebra_cli.c @@ -0,0 +1,2984 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "command.h" +#include "defaults.h" +#include "northbound_cli.h" +#include "vrf.h" + +#include "zebra_cli.h" +#include "zebra/zebra_cli_clippy.c" + +#define EVPN_MH_VTY_STR "Multihoming\n" + +FRR_CFG_DEFAULT_BOOL(ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT, + { .val_bool = true, .match_profile = "traditional", }, + { .val_bool = false }, +); + +#if HAVE_BFDD == 0 +DEFPY_YANG (zebra_ptm_enable, + zebra_ptm_enable_cmd, + "[no] ptm-enable", + NO_STR + "Enable neighbor check with specified topology\n") +{ + nb_cli_enqueue_change(vty, "/frr-zebra:zebra/ptm-enable", NB_OP_MODIFY, + no ? "false" : "true"); + return nb_cli_apply_changes(vty, NULL); +} + +static void zebra_ptm_enable_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool enable = yang_dnode_get_bool(dnode, NULL); + + if (enable) + vty_out(vty, "ptm-enable\n"); + else if (show_defaults) + vty_out(vty, "no ptm-enable\n"); +} +#endif + +DEFPY_YANG (zebra_route_map_timer, + zebra_route_map_timer_cmd, + "[no] zebra route-map delay-timer ![(0-600)$delay]", + NO_STR + ZEBRA_STR + "Set route-map parameters\n" + "Time to wait before route-map updates are processed\n" + "0 means route-map changes are run immediately instead of delaying\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "/frr-zebra:zebra/route-map-delay", + NB_OP_MODIFY, delay_str); + else + nb_cli_enqueue_change(vty, "/frr-zebra:zebra/route-map-delay", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void zebra_route_map_delay_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + uint32_t delay = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, "zebra route-map delay-timer %u\n", delay); +} + +DEFPY_YANG (multicast_new, + multicast_new_cmd, + "[no] multicast ", + NO_STR + "Control multicast flag on interface\n" + "Set multicast flag on interface\n" + "Unset multicast flag on interface\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/multicast", + NB_OP_CREATE, on ? "true" : "false"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/multicast", + NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_multicast_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool multicast = yang_dnode_get_bool(dnode, NULL); + + if (multicast) + vty_out(vty, " multicast enable\n"); + else + vty_out(vty, " multicast disable\n"); +} + +/* Deprecated multicast commands */ + +DEFPY_YANG_HIDDEN (multicast, + multicast_cmd, + "[no] multicast", + NO_STR + "Set multicast flag to interface\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/multicast", + NB_OP_CREATE, no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG (mpls, + mpls_cmd, + "[no] mpls ", + NO_STR + MPLS_STR + "Set mpls to be on for the interface\n" + "Set mpls to be off for the interface\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls", + NB_OP_CREATE, on ? "true" : "false"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/mpls", + NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_mpls_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool mpls = yang_dnode_get_bool(dnode, NULL); + + if (mpls) + vty_out(vty, " mpls enable\n"); + else + vty_out(vty, " mpls disable\n"); +} + +DEFPY_YANG (linkdetect, + linkdetect_cmd, + "[no] link-detect", + NO_STR + "Enable link detection on interface\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/link-detect", + NB_OP_CREATE, no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_detect_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool link_detect = yang_dnode_get_bool(dnode, NULL); + + if (!link_detect) + vty_out(vty, " no link-detect\n"); + else if (show_defaults) + vty_out(vty, " link-detect\n"); +} + +DEFPY_YANG (shutdown_if, + shutdown_if_cmd, + "[no] shutdown", + NO_STR + "Shutdown the selected interface\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/enabled", NB_OP_CREATE, + no ? "true" : "false"); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_enabled_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + bool enabled = yang_dnode_get_bool(dnode, NULL); + + if (!enabled) + vty_out(vty, " shutdown\n"); + else if (show_defaults) + vty_out(vty, " no shutdown\n"); +} + +DEFPY_YANG (bandwidth_if, + bandwidth_if_cmd, + "[no] bandwidth ![(1-1000000)]$bw", + NO_STR + "Set bandwidth informational parameter\n" + "Bandwidth in megabits\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/bandwidth", + NB_OP_CREATE, bw_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/bandwidth", + NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_bandwidth_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + uint32_t bandwidth = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " bandwidth %u\n", bandwidth); +} + +DEFUN_YANG_NOSH (link_params, + link_params_cmd, + "link-params", + LINK_PARAMS_STR) +{ + int ret; + + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/link-params", + NB_OP_CREATE, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) { + char *xpath; + + xpath = asprintfrr(MTYPE_TMP, "%s/frr-zebra:zebra/link-params", + VTY_CURR_XPATH); + VTY_PUSH_XPATH(LINK_PARAMS_NODE, xpath); + XFREE(MTYPE_TMP, xpath); + } + + return ret; +} + +DEFUN_YANG_NOSH (exit_link_params, + exit_link_params_cmd, + "exit-link-params", + "Exit from Link Params configuration mode\n") +{ + cmd_exit(vty); + return CMD_SUCCESS; +} + +static void lib_interface_zebra_link_params_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " link-params\n"); +} + +static void +lib_interface_zebra_link_params_cli_write_end(struct vty *vty, + const struct lyd_node *dnode) +{ + vty_out(vty, " exit-link-params\n"); +} + +DEFUN_YANG (no_link_params, + no_link_params_cmd, + "no link-params", + NO_STR + LINK_PARAMS_STR) +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/link-params", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +/* [no] enable is deprecated, link-params is enabled when entering the node. */ + +DEFUN_YANG_HIDDEN (link_params_enable, + link_params_enable_cmd, + "enable", + "Activate link parameters on this interface\n") +{ + vty_out(vty, "This command is deprecated. Link parameters are activated when \"link-params\" node is entered.\n"); + + return CMD_SUCCESS; +} + +DEFUN_YANG_NOSH (no_link_params_enable, + no_link_params_enable_cmd, + "no enable", + NO_STR + "Disable link parameters on this interface\n") +{ + int ret; + + vty_out(vty, "This command is deprecated. To disable link parameters use \"no link-params\" in the interface node.\n"); + + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + + ret = nb_cli_apply_changes(vty, NULL); + if (ret == CMD_SUCCESS) + cmd_exit(vty); + + return ret; +} + +DEFPY_YANG (link_params_metric, + link_params_metric_cmd, + "[no] metric ![(0-4294967295)]$metric", + NO_STR + "Link metric for MPLS-TE purpose\n" + "Metric value in decimal\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY, metric_str); + else + nb_cli_enqueue_change(vty, "./metric", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_metric_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t metric = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " metric %u\n", metric); +} + +DEFPY_YANG (link_params_maxbw, + link_params_maxbw_cmd, + "max-bw BANDWIDTH", + "Maximum bandwidth that can be used\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./max-bandwidth", NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_max_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float max_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, NULL); + + vty_out(vty, " max-bw %g\n", max_bandwidth); +} + +DEFPY_YANG (link_params_max_rsv_bw, + link_params_max_rsv_bw_cmd, + "max-rsv-bw BANDWIDTH", + "Maximum bandwidth that may be reserved\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./max-reservable-bandwidth", NB_OP_MODIFY, + value); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_max_reservable_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float max_reservable_bandwidth = + yang_dnode_get_bandwidth_ieee_float32(dnode, NULL); + + vty_out(vty, " max-rsv-bw %g\n", max_reservable_bandwidth); +} + +DEFPY_YANG (link_params_unrsv_bw, + link_params_unrsv_bw_cmd, + "unrsv-bw (0-7)$priority BANDWIDTH", + "Unreserved bandwidth at each priority level\n" + "Priority\n" + "Bytes/second (IEEE floating point format)\n") +{ + char xpath[XPATH_MAXLEN]; + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(xpath, sizeof(xpath), + "./unreserved-bandwidths/unreserved-bandwidth[priority='%s']/unreserved-bandwidth", + priority_str); + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, value); + + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint8_t priority = yang_dnode_get_uint8(dnode, "priority"); + float unreserved_bandwidth = + yang_dnode_get_bandwidth_ieee_float32(dnode, + "unreserved-bandwidth"); + + vty_out(vty, " unrsv-bw %u %g\n", priority, unreserved_bandwidth); +} + +DEFPY_YANG (link_params_admin_grp, + link_params_admin_grp_cmd, + "[no] admin-grp ![BITPATTERN]", + NO_STR + "Administrative group membership\n" + "32-bit Hexadecimal value (e.g. 0xa1)\n") +{ + uint32_t value; + char value_str[YANG_VALUE_MAXLEN]; + + if (!no) { + assert(bitpattern); + + if (bitpattern[0] != '0' || bitpattern[1] != 'x' || + strlen(bitpattern) > 10) { + vty_out(vty, "Invalid bitpattern value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sscanf(bitpattern, "%x", &value) != 1) { + vty_out(vty, "Invalid bitpattern value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value_str, sizeof(value_str), "%u", value); + + nb_cli_enqueue_change(vty, "./legacy-admin-group", NB_OP_MODIFY, + value_str); + } else { + nb_cli_enqueue_change(vty, "./legacy-admin-group", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_legacy_admin_group_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " admin-grp %#x\n", yang_dnode_get_uint32(dnode, NULL)); +} + +/* RFC5392 & RFC5316: INTER-AS */ +DEFPY_YANG (link_params_inter_as, + link_params_inter_as_cmd, + "[no] neighbor ![A.B.C.D$ip as (1-4294967295)$as]", + NO_STR + "Configure remote ASBR information (Neighbor IP address and AS number)\n" + "Remote IP address in dot decimal A.B.C.D\n" + "Remote AS number\n" + "AS number in the range <1-4294967295>\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./neighbor/remote-as", NB_OP_MODIFY, + as_str); + nb_cli_enqueue_change(vty, "./neighbor/ipv4-remote-id", + NB_OP_MODIFY, ip_str); + } else { + nb_cli_enqueue_change(vty, "./neighbor", NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_neighbor_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t remote_as = yang_dnode_get_uint32(dnode, "remote-as"); + const char *ipv4_remote_id = yang_dnode_get_string(dnode, + "ipv4-remote-id"); + + vty_out(vty, " neighbor %s as %u\n", ipv4_remote_id, remote_as); +} + +/* RFC7471 & RFC8570 */ +DEFPY_YANG (link_params_delay, + link_params_delay_cmd, + "[no] delay ![(0-16777215)$delay [min (0-16777215)$min max (0-16777215)$max]]", + NO_STR + "Unidirectional Average Link Delay\n" + "Average delay in micro-second as decimal (0...16777215)\n" + "Minimum delay\n" + "Minimum delay in micro-second as decimal (0...16777215)\n" + "Maximum delay\n" + "Maximum delay in micro-second as decimal (0...16777215)\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, "./delay", NB_OP_MODIFY, delay_str); + if (min_str && max_str) { + nb_cli_enqueue_change(vty, "./min-max-delay", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./min-max-delay/delay-min", + NB_OP_MODIFY, min_str); + nb_cli_enqueue_change(vty, "./min-max-delay/delay-max", + NB_OP_MODIFY, max_str); + } else { + nb_cli_enqueue_change(vty, "./min-max-delay", + NB_OP_DESTROY, NULL); + } + } else { + nb_cli_enqueue_change(vty, "./delay", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./min-max-delay", NB_OP_DESTROY, + NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_delay_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t delay = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " delay %u", delay); + + if (yang_dnode_exists(dnode, "../min-max-delay")) { + uint32_t delay_min = + yang_dnode_get_uint32(dnode, + "../min-max-delay/delay-min"); + uint32_t delay_max = + yang_dnode_get_uint32(dnode, + "../min-max-delay/delay-max"); + + vty_out(vty, " min %u max %u", delay_min, delay_max); + } + + vty_out(vty, "\n"); +} + +DEFPY_YANG (link_params_delay_var, + link_params_delay_var_cmd, + "[no] delay-variation ![(0-16777215)$delay_var]", + NO_STR + "Unidirectional Link Delay Variation\n" + "delay variation in micro-second as decimal (0...16777215)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./delay-variation", NB_OP_MODIFY, + delay_var_str); + else + nb_cli_enqueue_change(vty, "./delay-variation", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_delay_variation_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t delay_variation = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " delay-variation %u\n", delay_variation); +} + +DEFPY_YANG( + link_params_pkt_loss, link_params_pkt_loss_cmd, + "[no] packet-loss ![PERCENTAGE]", + NO_STR + "Unidirectional Link Packet Loss\n" + "percentage of total traffic by 0.000003% step and less than 50.331642%\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./packet-loss", NB_OP_MODIFY, + percentage); + else + nb_cli_enqueue_change(vty, "./packet-loss", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_packet_loss_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + double packet_loss = yang_dnode_get_dec64(dnode, NULL); + + vty_out(vty, " packet-loss %lf\n", packet_loss); +} + +DEFPY_YANG (link_params_res_bw, + link_params_res_bw_cmd, + "[no] res-bw ![BANDWIDTH]", + NO_STR + "Unidirectional Residual Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (!no) { + assert(bandwidth); + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./residual-bandwidth", NB_OP_MODIFY, + value); + } else { + nb_cli_enqueue_change(vty, "./residual-bandwidth", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_residual_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float residual_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, + NULL); + + vty_out(vty, " res-bw %g\n", residual_bandwidth); +} + +DEFPY_YANG (link_params_ava_bw, + link_params_ava_bw_cmd, + "[no] ava-bw ![BANDWIDTH]", + NO_STR + "Unidirectional Available Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (!no) { + assert(bandwidth); + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./available-bandwidth", + NB_OP_MODIFY, value); + } else { + nb_cli_enqueue_change(vty, "./available-bandwidth", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_available_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float available_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, + NULL); + + vty_out(vty, " ava-bw %g\n", available_bandwidth); +} + +DEFPY_YANG (link_params_use_bw, + link_params_use_bw_cmd, + "[no] use-bw ![BANDWIDTH]", + NO_STR + "Unidirectional Utilised Bandwidth\n" + "Bytes/second (IEEE floating point format)\n") +{ + char value[YANG_VALUE_MAXLEN]; + float bw; + + if (!no) { + assert(bandwidth); + + if (sscanf(bandwidth, "%g", &bw) != 1) { + vty_out(vty, "Invalid bandwidth value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(value, sizeof(value), "%a", bw); + + nb_cli_enqueue_change(vty, "./utilized-bandwidth", NB_OP_MODIFY, + value); + } else { + nb_cli_enqueue_change(vty, "./utilized-bandwidth", + NB_OP_DESTROY, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_utilized_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + float utilized_bandwidth = yang_dnode_get_bandwidth_ieee_float32(dnode, + NULL); + + vty_out(vty, " use-bw %g\n", utilized_bandwidth); +} + +DEFPY_YANG (link_params_affinity, + link_params_affinity_cmd, + "[no] affinity NAME...", + NO_STR + "Interface affinities\n" + "Affinity names\n") +{ + char xpath[XPATH_MAXLEN]; + int i; + + for (i = no ? 2 : 1; i < argc; i++) { + snprintf(xpath, XPATH_MAXLEN, "./affinities/affinity[.='%s']", + argv[i]->arg); + nb_cli_enqueue_change(vty, xpath, + no ? NB_OP_DESTROY : NB_OP_CREATE, NULL); + } + + return nb_cli_apply_changes(vty, NULL); +} + +static int ag_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct vty *vty = arg; + + vty_out(vty, " %s", yang_dnode_get_string(dnode, NULL)); + return YANG_ITER_CONTINUE; +} + +static void lib_interface_zebra_link_params_affinities_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + vty_out(vty, " affinity"); + yang_dnode_iterate(ag_iter_cb, vty, dnode, "affinity"); + vty_out(vty, "\n"); +} + +DEFPY_YANG (link_params_affinity_mode, + link_params_affinity_mode_cmd, + "[no] affinity-mode ![$mode]", + NO_STR + "Interface affinity mode\n" + "Standard Admin-Group only RFC3630,5305,5329\n" + "Extended Admin-Group only RFC7308 (default)\n" + "Standard and extended Admin-Group format\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./affinity-mode", NB_OP_MODIFY, + mode); + else + nb_cli_enqueue_change(vty, "./affinity-mode", NB_OP_DESTROY, + NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_link_params_affinity_mode_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + enum affinity_mode affinity_mode = yang_dnode_get_enum(dnode, NULL); + + if (affinity_mode == AFFINITY_MODE_STANDARD) + vty_out(vty, " affinity-mode standard\n"); + else if (affinity_mode == AFFINITY_MODE_BOTH) + vty_out(vty, " affinity-mode both\n"); + else if (affinity_mode == AFFINITY_MODE_EXTENDED && show_defaults) + vty_out(vty, " affinity-mode extended\n"); +} + +#ifdef HAVE_NETLINK +DEFPY_YANG (ip_address, + ip_address_cmd, + "[no] ip address A.B.C.D/M [label LINE$label]", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +#else +DEFPY_YANG (ip_address, + ip_address_cmd, + "[no] ip address A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "IP address (e.g. 10.0.0.1/8)\n") +#endif +{ + char ip[INET_ADDRSTRLEN + 3]; + char *mask; + + if (no) { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); +#ifdef HAVE_NETLINK + if (label) + nb_cli_enqueue_change(vty, "./label", NB_OP_MODIFY, + label); + else + nb_cli_enqueue_change(vty, "./label", NB_OP_DESTROY, + NULL); +#endif + } + + strlcpy(ip, address_str, sizeof(ip)); + + mask = strchr(ip, '/'); + assert(mask); + *mask = 0; + mask++; + + return nb_cli_apply_changes(vty, + "./frr-zebra:zebra/ipv4-addrs[ip='%s'][prefix-length='%s']", + ip, mask); +} + +static void lib_interface_zebra_ipv4_addrs_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *ip = yang_dnode_get_string(dnode, "ip"); + uint8_t prefix_length = yang_dnode_get_uint8(dnode, "prefix-length"); + + vty_out(vty, " ip address %s/%u", ip, prefix_length); + + if (yang_dnode_exists(dnode, "label")) { + const char *label = yang_dnode_get_string(dnode, "label"); + + vty_out(vty, " label %s", label); + } + + vty_out(vty, "\n"); +} + +#ifdef HAVE_NETLINK +DEFPY_YANG (ip_address_peer, + ip_address_peer_cmd, + "[no] ip address A.B.C.D peer A.B.C.D/M [label LINE$label]", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" + "Specify P-t-P address\n" + "Peer IP address (e.g. 10.0.0.1/8)\n" + "Label of this address\n" + "Label\n") +#else +DEFPY_YANG (ip_address_peer, + ip_address_peer_cmd, + "[no] ip address A.B.C.D peer A.B.C.D/M", + NO_STR + "Interface Internet Protocol config commands\n" + "Set the IP address of an interface\n" + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" + "Specify P-t-P address\n" + "Peer IP address (e.g. 10.0.0.1/8)\n") +#endif +{ + char peer_ip[INET_ADDRSTRLEN + 3]; + char *peer_mask; + + if (no) { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); +#ifdef HAVE_NETLINK + if (label) + nb_cli_enqueue_change(vty, "./label", NB_OP_MODIFY, + label); + else + nb_cli_enqueue_change(vty, "./label", NB_OP_DESTROY, + NULL); +#endif + } + + strlcpy(peer_ip, peer_str, sizeof(peer_ip)); + + peer_mask = strchr(peer_ip, '/'); + assert(peer_mask); + *peer_mask = 0; + peer_mask++; + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv4-p2p-addrs[ip='%s'][peer-ip='%s'][peer-prefix-length='%s']", + address_str, peer_ip, peer_mask); +} + +static void lib_interface_zebra_ipv4_p2p_addrs_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *ip = yang_dnode_get_string(dnode, "ip"); + const char *peer_ip = yang_dnode_get_string(dnode, "peer-ip"); + uint8_t peer_prefix_length = yang_dnode_get_uint8(dnode, + "peer-prefix-length"); + + vty_out(vty, " ip address %s peer %s/%u", ip, peer_ip, + peer_prefix_length); + + if (yang_dnode_exists(dnode, "label")) { + const char *label = yang_dnode_get_string(dnode, "label"); + + vty_out(vty, " label %s", label); + } + + vty_out(vty, "\n"); +} + +DEFPY_YANG (ipv6_address, + ipv6_address_cmd, + "[no] ipv6 address X:X::X:X/M", + NO_STR + "Interface IPv6 config commands\n" + "Set the IP address of an interface\n" + "IPv6 address (e.g. 3ffe:506::1/48)\n") +{ + char ip[INET6_ADDRSTRLEN + 4]; + char *mask; + + if (no) + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + + strlcpy(ip, address_str, sizeof(ip)); + + mask = strchr(ip, '/'); + assert(mask); + *mask = 0; + mask++; + + return nb_cli_apply_changes(vty, + "./frr-zebra:zebra/ipv6-addrs[ip='%s'][prefix-length='%s']", + ip, mask); +} + +static void lib_interface_zebra_ipv6_addrs_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *ip = yang_dnode_get_string(dnode, "ip"); + uint8_t prefix_length = yang_dnode_get_uint8(dnode, "prefix-length"); + + vty_out(vty, " ipv6 address %s/%u\n", ip, prefix_length); +} + +/* CLI for setting an ES in bypass mode */ +DEFPY_YANG_HIDDEN (zebra_evpn_es_bypass, + zebra_evpn_es_bypass_cmd, + "[no] evpn mh bypass", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Set bypass mode\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/bypass", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/bypass", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_bypass_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool bypass = yang_dnode_get_bool(dnode, NULL); + + if (bypass) + vty_out(vty, " evpn mh bypass\n"); + else if (show_defaults) + vty_out(vty, " no evpn mh bypass\n"); +} + +/* CLI for configuring DF preference part for an ES */ +DEFPY_YANG (zebra_evpn_es_pref, + zebra_evpn_es_pref_cmd, + "[no$no] evpn mh es-df-pref ![(1-65535)$df_pref]", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Preference value used for DF election\n" + "Preference\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/df-preference", + NB_OP_MODIFY, df_pref_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/df-preference", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_df_preference_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t df_pref = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " evpn mh es-df-pref %u\n", df_pref); +} + +/* CLI for setting up sysmac part of ESI on an access port */ +DEFPY_YANG (zebra_evpn_es_sys_mac, + zebra_evpn_es_sys_mac_cmd, + "[no$no] evpn mh es-sys-mac ![X:X:X:X:X:X$mac]", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Ethernet segment system MAC\n" + MAC_STR) +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/system-mac", + NB_OP_MODIFY, mac_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/system-mac", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_type_3_system_mac_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + char buf[ETHER_ADDR_STRLEN]; + struct ethaddr mac; + + yang_dnode_get_mac(&mac, dnode, NULL); + + vty_out(vty, " evpn mh es-sys-mac %s\n", + prefix_mac2str(&mac, buf, sizeof(buf))); +} + +/* CLI for setting up local-ID part of ESI on an access port */ +DEFPY_YANG (zebra_evpn_es_id, + zebra_evpn_es_id_cmd, + "[no$no] evpn mh es-id ![(1-16777215)$es_lid | NAME$esi_str]", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Ethernet segment identifier\n" + "local discriminator\n" + "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n") +{ + if (no) { + /* We don't know which one is configured, so detroy both types. */ + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-0/esi", + NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + NB_OP_DESTROY, NULL); + } else { + if (esi_str) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-0/esi", + NB_OP_MODIFY, esi_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + NB_OP_MODIFY, es_lid_str); + } + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_type_0_esi_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *esi_str = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, " evpn mh es-id %s\n", esi_str); +} + +static void lib_interface_zebra_evpn_mh_type_3_local_discriminator_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t es_lid = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " evpn mh es-id %u\n", es_lid); +} + +/* CLI for tagging an interface as an uplink */ +DEFPY_YANG (zebra_evpn_mh_uplink, + zebra_evpn_mh_uplink_cmd, + "[no] evpn mh uplink", + NO_STR + "EVPN\n" + EVPN_MH_VTY_STR + "Uplink to the VxLAN core\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/uplink", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/evpn-mh/uplink", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_evpn_mh_uplink_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool uplink = yang_dnode_get_bool(dnode, NULL); + + if (uplink) + vty_out(vty, " evpn mh uplink\n"); + else if (show_defaults) + vty_out(vty, " no evpn mh uplink\n"); +} + +#if defined(HAVE_RTADV) +DEFPY_YANG (ipv6_nd_ra_fast_retrans, + ipv6_nd_ra_fast_retrans_cmd, + "[no] ipv6 nd ra-fast-retrans", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Fast retransmit of RA packets\n") +{ + if (no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool fast_retransmit = yang_dnode_get_bool(dnode, NULL); + + if (!fast_retransmit) + vty_out(vty, " no ipv6 nd ra-fast-retrans\n"); + else if (show_defaults) + vty_out(vty, " ipv6 nd ra-fast-retrans\n"); +} + +DEFPY_YANG (ipv6_nd_ra_hop_limit, + ipv6_nd_ra_hop_limit_cmd, + "[no] ipv6 nd ra-hop-limit ![(0-255)$hopcount]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertisement Hop Limit\n" + "Advertisement Hop Limit in hops (default:64)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + NB_OP_MODIFY, hopcount_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint8_t hop_limit = yang_dnode_get_uint8(dnode, NULL); + + vty_out(vty, " ipv6 nd ra-hop-limit %u\n", hop_limit); +} + +DEFPY_YANG (ipv6_nd_ra_retrans_interval, + ipv6_nd_ra_retrans_interval_cmd, + "[no] ipv6 nd ra-retrans-interval ![(0-4294967295)$interval]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertisement Retransmit Interval\n" + "Advertisement Retransmit Interval in msec\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + NB_OP_MODIFY, interval_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_retrans_timer_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t retrans_timer = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " ipv6 nd ra-retrans-interval %u\n", retrans_timer); +} + +DEFPY_YANG (ipv6_nd_suppress_ra, + ipv6_nd_suppress_ra_cmd, + "[no] ipv6 nd suppress-ra", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Suppress Router Advertisement\n") +{ + if (no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_send_advertisements_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool send_advertisements = yang_dnode_get_bool(dnode, NULL); + + if (send_advertisements) + vty_out(vty, " no ipv6 nd suppress-ra\n"); + else if (show_defaults) + vty_out(vty, " ipv6 nd suppress-ra\n"); +} + +DEFPY_YANG (ipv6_nd_ra_interval, + ipv6_nd_ra_interval_cmd, + "[no] ipv6 nd ra-interval ![<(1-1800)$sec|msec (70-1800000)$msec>]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router Advertisement interval\n" + "Router Advertisement interval in seconds\n" + "Router Advertisement interval in milliseconds\n" + "Router Advertisement interval in milliseconds\n") +{ + char value[YANG_VALUE_MAXLEN]; + + if (!no) { + if (sec) + snprintf(value, sizeof(value), "%lu", sec * 1000); + else + snprintf(value, sizeof(value), "%lu", msec); + + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + NB_OP_MODIFY, value); + } else { + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t max_rtr_adv_interval = yang_dnode_get_uint32(dnode, NULL); + + if (max_rtr_adv_interval % 1000) + vty_out(vty, " ipv6 nd ra-interval msec %u\n", + max_rtr_adv_interval); + else + vty_out(vty, " ipv6 nd ra-interval %u\n", + max_rtr_adv_interval / 1000); +} + +DEFPY_YANG (ipv6_nd_ra_lifetime, + ipv6_nd_ra_lifetime_cmd, + "[no] ipv6 nd ra-lifetime ![(0-9000)$lifetime]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Router lifetime\n" + "Router lifetime in seconds (0 stands for a non-default gw)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + NB_OP_MODIFY, lifetime_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_default_lifetime_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t default_lifetime = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " ipv6 nd ra-lifetime %u\n", default_lifetime); +} + +DEFPY_YANG (ipv6_nd_reachable_time, + ipv6_nd_reachable_time_cmd, + "[no] ipv6 nd reachable-time ![(1-3600000)$msec]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Reachable time\n" + "Reachable time in milliseconds\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + NB_OP_MODIFY, msec_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_reachable_time_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t reachable_time = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " ipv6 nd reachable-time %u\n", reachable_time); +} + +DEFPY_YANG (ipv6_nd_homeagent_preference, + ipv6_nd_homeagent_preference_cmd, + "[no] ipv6 nd home-agent-preference ![(0-65535)$pref]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent preference\n" + "preference value (default is 0, least preferred)\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + NB_OP_MODIFY, pref_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t home_agent_preference = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " ipv6 nd home-agent-preference %u\n", + home_agent_preference); +} + +DEFPY_YANG (ipv6_nd_homeagent_lifetime, + ipv6_nd_homeagent_lifetime_cmd, + "[no] ipv6 nd home-agent-lifetime ![(1-65520)$lifetime]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent lifetime\n" + "Home Agent lifetime in seconds\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + NB_OP_MODIFY, lifetime_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t home_agent_lifetime = yang_dnode_get_uint16(dnode, NULL); + + vty_out(vty, " ipv6 nd home-agent-lifetime %u\n", home_agent_lifetime); +} + +DEFPY_YANG (ipv6_nd_managed_config_flag, + ipv6_nd_managed_config_flag_cmd, + "[no] ipv6 nd managed-config-flag", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Managed address configuration flag\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_ipv6_router_advertisements_managed_flag_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool managed_flag = yang_dnode_get_bool(dnode, NULL); + + if (managed_flag) + vty_out(vty, " ipv6 nd managed-config-flag\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd managed-config-flag\n"); +} + +DEFPY_YANG (ipv6_nd_homeagent_config_flag, + ipv6_nd_homeagent_config_flag_cmd, + "[no] ipv6 nd home-agent-config-flag", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Home Agent configuration flag\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool home_agent_flag = yang_dnode_get_bool(dnode, NULL); + + if (home_agent_flag) + vty_out(vty, " ipv6 nd home-agent-config-flag\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd home-agent-config-flag\n"); +} + +DEFPY_YANG (ipv6_nd_adv_interval_config_option, + ipv6_nd_adv_interval_config_option_cmd, + "[no] ipv6 nd adv-interval-option", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertisement Interval Option\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool advertisement_interval_option = yang_dnode_get_bool(dnode, NULL); + + if (advertisement_interval_option) + vty_out(vty, " ipv6 nd adv-interval-option\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd adv-interval-option\n"); +} + +DEFPY_YANG (ipv6_nd_other_config_flag, + ipv6_nd_other_config_flag_cmd, + "[no] ipv6 nd other-config-flag", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Other statefull configuration flag\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_other_config_flag_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool other_config_flag = yang_dnode_get_bool(dnode, NULL); + + if (other_config_flag) + vty_out(vty, " ipv6 nd other-config-flag\n"); + else if (show_defaults) + vty_out(vty, " no ipv6 nd other-config-flag\n"); +} + +DEFPY_YANG (ipv6_nd_prefix, + ipv6_nd_prefix_cmd, + "[no] ipv6 nd prefix X:X::X:X/M$prefix [<(0-4294967295)|infinite>$valid <(0-4294967295)|infinite>$preferred] [{router-address$routeraddr|off-link$offlink|no-autoconfig$noautoconf}]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Prefix information\n" + "IPv6 prefix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n" + "Preferred lifetime in seconds\n" + "Infinite preferred lifetime\n" + "Set Router Address flag\n" + "Do not use prefix for onlink determination\n" + "Do not use prefix for autoconfiguration\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + if (valid) { + if (strmatch(valid, "infinite")) + valid = "4294967295"; + nb_cli_enqueue_change(vty, "./valid-lifetime", + NB_OP_MODIFY, valid); + } else { + nb_cli_enqueue_change(vty, "./valid-lifetime", + NB_OP_DESTROY, NULL); + } + if (preferred) { + if (strmatch(preferred, "infinite")) + preferred = "4294967295"; + nb_cli_enqueue_change(vty, "./preferred-lifetime", + NB_OP_MODIFY, preferred); + } else { + nb_cli_enqueue_change(vty, "./preferred-lifetime", + NB_OP_DESTROY, NULL); + } + if (routeraddr) + nb_cli_enqueue_change(vty, "./router-address-flag", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./router-address-flag", + NB_OP_DESTROY, NULL); + if (offlink) + nb_cli_enqueue_change(vty, "./on-link-flag", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, "./on-link-flag", + NB_OP_DESTROY, NULL); + if (noautoconf) + nb_cli_enqueue_change(vty, "./autonomous-flag", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, "./autonomous-flag", + NB_OP_DESTROY, NULL); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix[prefix-spec='%s']", + prefix_str); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *prefix = yang_dnode_get_string(dnode, "prefix-spec"); + struct lyd_node *valid = yang_dnode_get(dnode, "valid-lifetime"); + struct lyd_node *preferred = yang_dnode_get(dnode, "preferred-lifetime"); + bool router_address_flag = yang_dnode_get_bool(dnode, + "router-address-flag"); + bool on_link_flag = yang_dnode_get_bool(dnode, "on-link-flag"); + bool autonomous_flag = yang_dnode_get_bool(dnode, "autonomous-flag"); + + vty_out(vty, " ipv6 nd prefix %s", prefix); + + if (!yang_dnode_is_default(valid, NULL) || + !yang_dnode_is_default(preferred, NULL) || show_defaults) { + uint32_t valid_lifetime = yang_dnode_get_uint32(valid, NULL); + uint32_t preferred_lifetime = yang_dnode_get_uint32(preferred, + NULL); + + if (valid_lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", valid_lifetime); + if (preferred_lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", preferred_lifetime); + } + + if (!on_link_flag) + vty_out(vty, " off-link"); + + if (!autonomous_flag) + vty_out(vty, " no-autoconfig"); + + if (router_address_flag) + vty_out(vty, " router-address"); + + vty_out(vty, "\n"); +} + +DEFPY_YANG (ipv6_nd_router_preference, + ipv6_nd_router_preference_cmd, + "[no] ipv6 nd router-preference ![$pref]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Default router preference\n" + "High default router preference\n" + "Medium default router preference (default)\n" + "Low default router preference\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + NB_OP_MODIFY, pref); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_default_router_preference_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *default_router_preference = yang_dnode_get_string(dnode, + NULL); + + vty_out(vty, " ipv6 nd router-preference %s\n", + default_router_preference); +} + +DEFPY_YANG (ipv6_nd_mtu, + ipv6_nd_mtu_cmd, + "[no] ipv6 nd mtu ![(1-65535)]", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Advertised MTU\n" + "MTU in bytes\n") +{ + if (!no) + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + NB_OP_MODIFY, mtu_str); + else + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_ipv6_router_advertisements_link_mtu_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint16_t link_mtu = yang_dnode_get_uint32(dnode, NULL); + + vty_out(vty, " ipv6 nd mtu %u\n", link_mtu); +} + +DEFPY_YANG (ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "[no] ipv6 nd rdnss X:X::X:X$addr [<(0-4294967295)|infinite>]$lifetime", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "Recursive DNS server information\n" + "IPv6 address\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + if (lifetime) { + if (strmatch(lifetime, "infinite")) + lifetime = "4294967295"; + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_MODIFY, + lifetime); + } else { + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_DESTROY, + NULL); + } + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address[address='%s']", + addr_str); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *address = yang_dnode_get_string(dnode, "address"); + + vty_out(vty, " ipv6 nd rdnss %s", address); + + if (yang_dnode_exists(dnode, "lifetime")) { + uint32_t lifetime = yang_dnode_get_uint32(dnode, "lifetime"); + + if (lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", lifetime); + } + + vty_out(vty, "\n"); +} + +DEFPY_YANG (ipv6_nd_dnssl, + ipv6_nd_dnssl_cmd, + "[no] ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]$lifetime", + NO_STR + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "DNS search list information\n" + "Domain name suffix\n" + "Valid lifetime in seconds\n" + "Infinite valid lifetime\n") +{ + char domain[254]; + size_t len; + + len = strlcpy(domain, suffix, sizeof(domain)); + if (len == 0 || len >= sizeof(domain)) { + vty_out(vty, "Malformed DNS search domain\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (domain[len - 1] == '.') { + /* + * Allow, but don't require, a trailing dot signifying the root + * zone. Canonicalize by cutting it off if present. + */ + domain[len - 1] = '\0'; + len--; + } + + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + if (lifetime) { + if (strmatch(lifetime, "infinite")) + lifetime = "4294967295"; + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_MODIFY, + lifetime); + } else { + nb_cli_enqueue_change(vty, "./lifetime", NB_OP_DESTROY, + NULL); + } + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain[domain='%s']", + domain); +} + +static void +lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + const char *domain = yang_dnode_get_string(dnode, "domain"); + + vty_out(vty, " ipv6 nd dnssl %s", domain); + + if (yang_dnode_exists(dnode, "lifetime")) { + uint32_t lifetime = yang_dnode_get_uint32(dnode, "lifetime"); + + if (lifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", lifetime); + } + + vty_out(vty, "\n"); +} +#endif /* HAVE_RTADV */ + +#if HAVE_BFDD == 0 +DEFPY_YANG (zebra_ptm_enable_if, + zebra_ptm_enable_if_cmd, + "[no] ptm-enable", + NO_STR + "Enable neighbor check with specified topology\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ptm-enable", + NB_OP_MODIFY, "false"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ptm-enable", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_interface_zebra_ptm_enable_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool enable = yang_dnode_get_bool(dnode, NULL); + + if (!enable) + vty_out(vty, " no ptm-enable\n"); + else if (show_defaults) + vty_out(vty, " ptm-enable\n"); +} +#endif /* HAVE_BFDD == 0 */ + +/* + * VRF commands + */ + +static void zebra_vrf_indent_cli_write(struct vty *vty, + const struct lyd_node *dnode) +{ + const struct lyd_node *vrf = yang_dnode_get_parent(dnode, "vrf"); + + if (vrf && strcmp(yang_dnode_get_string(vrf, "name"), VRF_DEFAULT_NAME)) + vty_out(vty, " "); +} + +DEFPY_YANG (ip_router_id, + ip_router_id_cmd, + "[no] ip router-id A.B.C.D$id vrf NAME", + NO_STR + IP_STR + "Manually set the router-id\n" + "IP address to use for router-id\n" + VRF_CMD_HELP_STR) +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_MODIFY, + id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_DESTROY, + NULL); + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", vrf); +} + +ALIAS_YANG (ip_router_id, + router_id_cmd, + "[no] router-id A.B.C.D$id vrf NAME", + NO_STR + "Manually set the router-id\n" + "IP address to use for router-id\n" + VRF_CMD_HELP_STR); + +DEFPY_YANG (ipv6_router_id, + ipv6_router_id_cmd, + "[no] ipv6 router-id X:X::X:X$id vrf NAME", + NO_STR + IPV6_STR + "Manually set the router-id\n" + "IPv6 address to use for router-id\n" + VRF_CMD_HELP_STR) +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_MODIFY, id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", vrf); +} + +DEFPY_YANG (ip_router_id_in_vrf, + ip_router_id_in_vrf_cmd, + "[no] ip router-id ![A.B.C.D$id]", + NO_STR + IP_STR + "Manually set the router-id\n" + "IP address to use for router-id\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_MODIFY, + id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/router-id", NB_OP_DESTROY, + NULL); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +ALIAS_YANG (ip_router_id_in_vrf, + router_id_in_vrf_cmd, + "[no] router-id ![A.B.C.D$id]", + NO_STR + "Manually set the router-id\n" + "IP address to use for router-id\n"); + +DEFPY_YANG (ipv6_router_id_in_vrf, + ipv6_router_id_in_vrf_cmd, + "[no] ipv6 router-id ![X:X::X:X$id]", + NO_STR + IP6_STR + "Manually set the IPv6 router-id\n" + "IPV6 address to use for router-id\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_MODIFY, id_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-router-id", + NB_OP_DESTROY, NULL); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_router_id_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *id = yang_dnode_get_string(dnode, NULL); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "ip router-id %s\n", id); +} + +static void lib_vrf_zebra_ipv6_router_id_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *id = yang_dnode_get_string(dnode, NULL); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "ipv6 router-id %s\n", id); +} + +DEFPY_YANG (ip_protocol, + ip_protocol_cmd, + "[no] ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP_STR + "Filter routing info exchanged between zebra and protocol\n" + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route-map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), proto); +} + +DEFPY_YANG (ipv6_protocol, + ipv6_protocol_cmd, + "[no] ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP6_STR + "Filter IPv6 routing info exchanged between zebra and protocol\n" + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route-map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-protocol[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), proto); +} + +static void lib_vrf_zebra_filter_protocol_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *afi_safi = yang_dnode_get_string(dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(dnode, "protocol"); + const char *rmap = yang_dnode_get_string(dnode, "route-map"); + afi_t afi; + safi_t safi; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (safi != SAFI_UNICAST) + return; + + zebra_vrf_indent_cli_write(vty, dnode); + + if (afi == AFI_IP) + vty_out(vty, "ip protocol %s route-map %s\n", proto, rmap); + else + vty_out(vty, "ipv6 protocol %s route-map %s\n", proto, rmap); +} + +DEFPY_YANG (ip_protocol_nht_rmap, + ip_protocol_nht_rmap_cmd, + "[no] ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP_STR + "Filter Next Hop tracking route resolution\n" + FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP, SAFI_UNICAST), proto); +} + +DEFPY_YANG (ipv6_protocol_nht_rmap, + ipv6_protocol_nht_rmap_cmd, + "[no] ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA + " $proto ![route-map ROUTE-MAP$rmap]", + NO_STR + IP6_STR + "Filter Next Hop tracking route resolution\n" + FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA + "Specify route map\n" + "Route map name\n") +{ + if (!no) { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./route-map", NB_OP_MODIFY, rmap); + } else { + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes( + vty, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + VRF_DEFAULT_NAME, + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), + proto); + + return nb_cli_apply_changes( + vty, + "./frr-zebra:zebra/filter-nht[afi-safi='%s'][protocol='%s']", + yang_afi_safi_value2identity(AFI_IP6, SAFI_UNICAST), proto); +} + +static void lib_vrf_zebra_filter_nht_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *afi_safi = yang_dnode_get_string(dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(dnode, "protocol"); + const char *rmap = yang_dnode_get_string(dnode, "route-map"); + afi_t afi; + safi_t safi; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (safi != SAFI_UNICAST) + return; + + zebra_vrf_indent_cli_write(vty, dnode); + + if (afi == AFI_IP) + vty_out(vty, "ip nht %s route-map %s\n", proto, rmap); + else + vty_out(vty, "ipv6 nht %s route-map %s\n", proto, rmap); +} + +DEFPY_YANG (ip_nht_default_route, + ip_nht_default_route_cmd, + "[no] ip nht resolve-via-default", + NO_STR + IP_STR + "Filter Next Hop tracking route resolution\n" + "Resolve via default route\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/resolve-via-default", + NB_OP_MODIFY, no ? "false" : "true"); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_resolve_via_default_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool resolve_via_default = yang_dnode_get_bool(dnode, NULL); + + if (resolve_via_default != SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT || + show_defaults) { + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "%sip nht resolve-via-default\n", + resolve_via_default ? "" : "no "); + } +} + +DEFPY_YANG (ipv6_nht_default_route, + ipv6_nht_default_route_cmd, + "[no] ipv6 nht resolve-via-default", + NO_STR + IP6_STR + "Filter Next Hop tracking route resolution\n" + "Resolve via default route\n") +{ + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/ipv6-resolve-via-default", + NB_OP_MODIFY, no ? "false" : "true"); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_ipv6_resolve_via_default_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + bool resolve_via_default = yang_dnode_get_bool(dnode, NULL); + + if (resolve_via_default != SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT || + show_defaults) { + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "%sipv6 nht resolve-via-default\n", + resolve_via_default ? "" : "no "); + } +} + +DEFPY_YANG (vrf_netns, + vrf_netns_cmd, + "[no] netns ![NAME$netns_name]", + NO_STR + "Attach VRF to a Namespace\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + vty_out(vty, "%% This command doesn't do anything.\n"); + vty_out(vty, + "%% VRF is linked to a netns automatically based on its name.\n"); + return CMD_WARNING; +} + +DEFPY_YANG (ip_table_range, ip_table_range_cmd, + "[no] ip table range ![(1-4294967295)$start (1-4294967295)$end]", + NO_STR IP_STR + "table configuration\n" + "Configure table range\n" + "Start Routing Table\n" + "End Routing Table\n") +{ + if (!no) { + const struct lyd_node *start_node; + const struct lyd_node *end_node; + + if (vty->node == CONFIG_NODE) { + start_node = + yang_dnode_getf(vty->candidate_config->dnode, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/netns/table-range/start", + VRF_DEFAULT_NAME); + end_node = + yang_dnode_getf(vty->candidate_config->dnode, + "/frr-vrf:lib/vrf[name='%s']/frr-zebra:zebra/netns/table-range/end", + VRF_DEFAULT_NAME); + } else { + start_node = + yang_dnode_getf(vty->candidate_config->dnode, + "%s/frr-zebra:zebra/netns/table-range/start", + VTY_CURR_XPATH); + end_node = + yang_dnode_getf(vty->candidate_config->dnode, + "%s/frr-zebra:zebra/netns/table-range/end", + VTY_CURR_XPATH); + } + + if (start_node && end_node) { + if (yang_dnode_get_uint32(start_node, NULL) != + (uint32_t)start || + yang_dnode_get_uint32(end_node, NULL) != + (uint32_t)end) { + vty_out(vty, + "%% New range will be taken into account at restart.\n"); + vty_out(vty, + "%% Don't forget to save your configuration.\n"); + } + } + + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/netns/table-range", + NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/netns/table-range/start", + NB_OP_MODIFY, start_str); + nb_cli_enqueue_change(vty, + "./frr-zebra:zebra/netns/table-range/end", + NB_OP_MODIFY, end_str); + } else { + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/netns/table-range", + NB_OP_DESTROY, NULL); + } + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_netns_table_range_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + uint32_t start = yang_dnode_get_uint32(dnode, "start"); + uint32_t end = yang_dnode_get_uint32(dnode, "end"); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "ip table range %u %u\n", start, end); +} + +DEFPY_YANG (vni_mapping, + vni_mapping_cmd, + "[no] vni ![" CMD_VNI_RANGE "[prefix-routes-only$filter]]", + NO_STR + "VNI corresponding to tenant VRF\n" + "VNI-ID\n" + "prefix-routes-only\n") +{ + if (!no) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_MODIFY, + vni_str); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_DESTROY, + NULL); + + if (filter) + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", + NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", + NB_OP_DESTROY, NULL); + + if (vty->node == CONFIG_NODE) + return nb_cli_apply_changes(vty, "/frr-vrf:lib/vrf[name='%s']", + VRF_DEFAULT_NAME); + + return nb_cli_apply_changes(vty, NULL); +} + +static void lib_vrf_zebra_l3vni_id_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + vni_t vni = yang_dnode_get_uint32(dnode, NULL); + bool prefix_only = yang_dnode_get_bool(dnode, "../prefix-only"); + + zebra_vrf_indent_cli_write(vty, dnode); + + vty_out(vty, "vni %u", vni); + + if (prefix_only) + vty_out(vty, " prefix-routes-only"); + + vty_out(vty, "\n"); +} + +DEFPY_YANG( + match_ip_address_prefix_len, match_ip_address_prefix_len_cmd, + "match ip address prefix-len (0-32)$length", + MATCH_STR + IP_STR + "Match prefix length of IP address\n" + "Match prefix length of IP address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd, + "no match ip address prefix-len [(0-32)]", + NO_STR + MATCH_STR + IP_STR + "Match prefix length of IP address\n" + "Match prefix length of IP address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd, + "match ipv6 address prefix-len (0-128)$length", + MATCH_STR + IPV6_STR + "Match prefix length of IPv6 address\n" + "Match prefix length of IPv6 address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd, + "no match ipv6 address prefix-len [(0-128)]", + NO_STR + MATCH_STR + IPV6_STR + "Match prefix length of IPv6 address\n" + "Match prefix length of IPv6 address\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd, + "match ip next-hop prefix-len (0-32)$length", + MATCH_STR + IP_STR + "Match prefixlen of nexthop IP address\n" + "Match prefixlen of given nexthop\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd, + "no match ip next-hop prefix-len [(0-32)]", + NO_STR + MATCH_STR + IP_STR + "Match prefixlen of nexthop IP address\n" + "Match prefix length of nexthop\n" + "Prefix length\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_source_protocol, match_source_protocol_cmd, + "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto", + MATCH_STR + "Match protocol via which the route was learnt\n" + FRR_REDIST_HELP_STR_ZEBRA) +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-protocol']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:source-protocol", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_source_protocol, no_match_source_protocol_cmd, + "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]", + NO_STR + MATCH_STR + "Match protocol via which the route was learnt\n" + FRR_REDIST_HELP_STR_ZEBRA) +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-protocol']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + match_source_instance, match_source_instance_cmd, + "match source-instance (0-255)$instance", + MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-instance']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:source-instance", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_match_source_instance, no_match_source_instance_cmd, + "no match source-instance [(0-255)]", + NO_STR MATCH_STR + "Match the protocol's instance number\n" + "The instance number\n") +{ + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-instance']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +/* set functions */ + +DEFPY_YANG( + set_src, set_src_cmd, + "set src ", + SET_STR + "src address for route\n" + "IPv4 src address\n" + "IPv6 src address\n") +{ + const char *xpath = + "./set-action[action='frr-zebra-route-map:src-address']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (addrv4_str) { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv4_str); + } else { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv6_str); + } + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_set_src, no_set_src_cmd, + "no set src []", + NO_STR + SET_STR + "Source address for route\n" + "IPv4 address\n" + "IPv6 address\n") +{ + const char *xpath = + "./set-action[action='frr-zebra-route-map:src-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +const char *features[] = { +#if HAVE_BFDD == 0 + "ptm-bfd", +#endif +#if defined(HAVE_RTADV) + "ipv6-router-advertisements", +#endif + NULL +}; + +/* clang-format off */ +const struct frr_yang_module_info frr_zebra_cli_info = { + .name = "frr-zebra", + .ignore_cfg_cbs = true, + .features = features, + .nodes = { +#if HAVE_BFDD == 0 + { + .xpath = "/frr-zebra:zebra/ptm-enable", + .cbs.cli_show = zebra_ptm_enable_cli_write, + }, +#endif + { + .xpath = "/frr-zebra:zebra/route-map-delay", + .cbs.cli_show = zebra_route_map_delay_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs", + .cbs.cli_show = lib_interface_zebra_ipv4_addrs_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs", + .cbs.cli_show = lib_interface_zebra_ipv4_p2p_addrs_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-addrs", + .cbs.cli_show = lib_interface_zebra_ipv6_addrs_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/multicast", + .cbs.cli_show = lib_interface_zebra_multicast_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect", + .cbs.cli_show = lib_interface_zebra_link_detect_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/enabled", + .cbs.cli_show = lib_interface_zebra_enabled_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth", + .cbs.cli_show = lib_interface_zebra_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/mpls", + .cbs.cli_show = lib_interface_zebra_mpls_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params", + .cbs.cli_show = lib_interface_zebra_link_params_cli_write, + .cbs.cli_show_end = lib_interface_zebra_link_params_cli_write_end, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/metric", + .cbs.cli_show = lib_interface_zebra_link_params_metric_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_max_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-reservable-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_max_reservable_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/residual-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_residual_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/available-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_available_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/utilized-bandwidth", + .cbs.cli_show = lib_interface_zebra_link_params_utilized_bandwidth_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group", + .cbs.cli_show = lib_interface_zebra_link_params_legacy_admin_group_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities", + .cbs.cli_show = lib_interface_zebra_link_params_affinities_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode", + .cbs.cli_show = lib_interface_zebra_link_params_affinity_mode_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor", + .cbs.cli_show = lib_interface_zebra_link_params_neighbor_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay", + .cbs.cli_show = lib_interface_zebra_link_params_delay_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay-variation", + .cbs.cli_show = lib_interface_zebra_link_params_delay_variation_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/packet-loss", + .cbs.cli_show = lib_interface_zebra_link_params_packet_loss_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi", + .cbs.cli_show = lib_interface_zebra_evpn_mh_type_0_esi_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac", + .cbs.cli_show = lib_interface_zebra_evpn_mh_type_3_system_mac_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + .cbs.cli_show = lib_interface_zebra_evpn_mh_type_3_local_discriminator_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/df-preference", + .cbs.cli_show = lib_interface_zebra_evpn_mh_df_preference_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/bypass", + .cbs.cli_show = lib_interface_zebra_evpn_mh_bypass_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/uplink", + .cbs.cli_show = lib_interface_zebra_evpn_mh_uplink_cli_write, + }, +#if defined(HAVE_RTADV) + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_send_advertisements_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_managed_flag_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_other_config_flag_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_link_mtu_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_reachable_time_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_retrans_timer_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_default_lifetime_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_default_router_preference_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_cli_write, + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address", + .cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_cli_write, + }, +#endif /* defined(HAVE_RTADV) */ +#if HAVE_BFDD == 0 + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ptm-enable", + .cbs.cli_show = lib_interface_zebra_ptm_enable_cli_write, + }, +#endif + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/router-id", + .cbs.cli_show = lib_vrf_zebra_router_id_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-router-id", + .cbs.cli_show = lib_vrf_zebra_ipv6_router_id_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol", + .cbs.cli_show = lib_vrf_zebra_filter_protocol_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht", + .cbs.cli_show = lib_vrf_zebra_filter_nht_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/resolve-via-default", + .cbs.cli_show = lib_vrf_zebra_resolve_via_default_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-resolve-via-default", + .cbs.cli_show = lib_vrf_zebra_ipv6_resolve_via_default_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range", + .cbs.cli_show = lib_vrf_zebra_netns_table_range_cli_write, + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id", + .cbs.cli_show = lib_vrf_zebra_l3vni_id_cli_write, + }, + { + .xpath = NULL, + }, + } +}; + +struct cmd_node link_params_node = { + .name = "link-params", + .node = LINK_PARAMS_NODE, + .parent_node = INTERFACE_NODE, + .prompt = "%s(config-link-params)# ", +}; + +void zebra_cli_init(void) +{ + install_node(&link_params_node); + + install_element(INTERFACE_NODE, &multicast_new_cmd); + install_element(INTERFACE_NODE, &multicast_cmd); + install_element(INTERFACE_NODE, &mpls_cmd); + install_element(INTERFACE_NODE, &linkdetect_cmd); + install_element(INTERFACE_NODE, &shutdown_if_cmd); + install_element(INTERFACE_NODE, &bandwidth_if_cmd); + install_element(INTERFACE_NODE, &ip_address_cmd); + install_element(INTERFACE_NODE, &ip_address_peer_cmd); + install_element(INTERFACE_NODE, &ipv6_address_cmd); + install_element(INTERFACE_NODE, &link_params_cmd); + install_element(INTERFACE_NODE, &no_link_params_cmd); + install_default(LINK_PARAMS_NODE); + install_element(LINK_PARAMS_NODE, &link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); + install_element(LINK_PARAMS_NODE, &link_params_metric_cmd); + install_element(LINK_PARAMS_NODE, &link_params_maxbw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_max_rsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_unrsv_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_admin_grp_cmd); + install_element(LINK_PARAMS_NODE, &link_params_inter_as_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_cmd); + install_element(LINK_PARAMS_NODE, &link_params_delay_var_cmd); + install_element(LINK_PARAMS_NODE, &link_params_pkt_loss_cmd); + install_element(LINK_PARAMS_NODE, &link_params_ava_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_res_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_use_bw_cmd); + install_element(LINK_PARAMS_NODE, &link_params_affinity_cmd); + install_element(LINK_PARAMS_NODE, &link_params_affinity_mode_cmd); + install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); + + install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd); + install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd); + +#if defined(HAVE_RTADV) + install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd); + install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd); +#endif +#if HAVE_BFDD == 0 + install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd); +#endif + + install_element(CONFIG_NODE, &ip_router_id_cmd); + install_element(CONFIG_NODE, &router_id_cmd); + install_element(CONFIG_NODE, &ipv6_router_id_cmd); + install_element(CONFIG_NODE, &ip_router_id_in_vrf_cmd); + install_element(CONFIG_NODE, &router_id_in_vrf_cmd); + install_element(CONFIG_NODE, &ipv6_router_id_in_vrf_cmd); + install_element(VRF_NODE, &ip_router_id_in_vrf_cmd); + install_element(VRF_NODE, &router_id_in_vrf_cmd); + install_element(VRF_NODE, &ipv6_router_id_in_vrf_cmd); + + install_element(CONFIG_NODE, &ip_protocol_cmd); + install_element(VRF_NODE, &ip_protocol_cmd); + install_element(CONFIG_NODE, &ipv6_protocol_cmd); + install_element(VRF_NODE, &ipv6_protocol_cmd); + install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd); + install_element(VRF_NODE, &ip_protocol_nht_rmap_cmd); + install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd); + install_element(VRF_NODE, &ipv6_protocol_nht_rmap_cmd); + install_element(CONFIG_NODE, &zebra_route_map_timer_cmd); + + install_element(CONFIG_NODE, &ip_nht_default_route_cmd); + install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); + install_element(VRF_NODE, &ip_nht_default_route_cmd); + install_element(VRF_NODE, &ipv6_nht_default_route_cmd); + + install_element(CONFIG_NODE, &vni_mapping_cmd); + install_element(VRF_NODE, &vni_mapping_cmd); + + if (vrf_is_backend_netns()) + install_element(VRF_NODE, &vrf_netns_cmd); + + install_element(CONFIG_NODE, &ip_table_range_cmd); + install_element(VRF_NODE, &ip_table_range_cmd); +#if HAVE_BFDD == 0 + install_element(CONFIG_NODE, &zebra_ptm_enable_cmd); +#endif + install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd); + install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd); + install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd); + install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd); + install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd); + install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd); + install_element(RMAP_NODE, &match_source_protocol_cmd); + install_element(RMAP_NODE, &no_match_source_protocol_cmd); + install_element(RMAP_NODE, &match_source_instance_cmd); + install_element(RMAP_NODE, &no_match_source_instance_cmd); + + install_element(RMAP_NODE, &set_src_cmd); + install_element(RMAP_NODE, &no_set_src_cmd); +} diff --git a/zebra/zebra_cli.h b/zebra/zebra_cli.h new file mode 100644 index 000000000000..01931a47ab6b --- /dev/null +++ b/zebra/zebra_cli.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef _ZEBRA_CLI_H +#define _ZEBRA_CLI_H 1 + +extern const struct frr_yang_module_info frr_zebra_cli_info; + +void zebra_cli_init(void); + +#endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 03d7bb88a218..1cee1ebb9331 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -39,6 +39,13 @@ DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes"); # define AOK 0 #endif +/* + * Dataplane API version. This must be updated when any incompatible changes + * are made. The minor version (at least) should be updated when new APIs + * are introduced. + */ +static uint32_t zdplane_version = MAKE_FRRVERSION(2, 0, 0); + /* Control for collection of extra interface info with route updates; a plugin * can enable the extra info via a dplane api. */ @@ -230,6 +237,7 @@ struct dplane_intf_info { #define DPLANE_INTF_BROADCAST (1 << 2) #define DPLANE_INTF_HAS_DEST DPLANE_INTF_CONNECTED #define DPLANE_INTF_HAS_LABEL (1 << 4) +#define DPLANE_INTF_NOPREFIXROUTE (1 << 5) /* Interface address/prefix */ struct prefix prefix; @@ -355,6 +363,13 @@ struct dplane_tc_filter_info { uint32_t classid; }; +/* + * SRv6 encapsulation params context for the dataplane + */ +struct dplane_srv6_encap_ctx { + struct in6_addr srcaddr; +}; + /* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the @@ -391,7 +406,7 @@ struct zebra_dplane_ctx { vrf_id_t zd_vrf_id; uint32_t zd_table_id; - char zd_ifname[INTERFACE_NAMSIZ]; + char zd_ifname[IFNAMSIZ]; ifindex_t zd_ifindex; /* Support info for different kinds of updates */ @@ -417,6 +432,7 @@ struct zebra_dplane_ctx { struct dplane_gre_ctx gre; struct dplane_netconf_info netconf; enum zebra_dplane_startup_notifications spot; + struct dplane_srv6_encap_ctx srv6_encap; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -598,6 +614,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_tcs_in; _Atomic uint32_t dg_tcs_errors; + _Atomic uint32_t dg_srv6_encap_srcaddr_set_in; + _Atomic uint32_t dg_srv6_encap_srcaddr_set_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -652,6 +671,12 @@ neigh_update_internal(enum dplane_op_e op, const struct interface *ifp, * Public APIs */ +/* Access the dplane API version */ +uint32_t zebra_dplane_get_version(void) +{ + return zdplane_version; +} + /* Obtain thread_master for dataplane thread */ struct event_loop *dplane_get_thread_master(void) { @@ -860,6 +885,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_GRE_SET: case DPLANE_OP_INTF_NETCONFIG: case DPLANE_OP_STARTUP_STAGE: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: break; } } @@ -943,6 +969,11 @@ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q) return ctx; } +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q) +{ + return dplane_ctx_list_count(q); +} + /* * Accessors for information from the context object */ @@ -1185,6 +1216,11 @@ const char *dplane_op2str(enum dplane_op_e op) break; case DPLANE_OP_STARTUP_STAGE: ret = "STARTUP_STAGE"; + break; + + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + ret = "SRV6_ENCAP_SRCADDR_SET"; + break; } return ret; @@ -2541,6 +2577,13 @@ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx) return (ctx->u.intf.flags & DPLANE_INTF_CONNECTED); } +bool dplane_ctx_intf_is_noprefixroute(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return (ctx->u.intf.flags & DPLANE_INTF_NOPREFIXROUTE); +} + bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2569,6 +2612,13 @@ void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx) ctx->u.intf.flags |= DPLANE_INTF_SECONDARY; } +void dplane_ctx_intf_set_noprefixroute(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags |= DPLANE_INTF_NOPREFIXROUTE; +} + void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -2584,6 +2634,16 @@ const struct prefix *dplane_ctx_get_intf_addr( return &(ctx->u.intf.prefix); } + +/* Accessors for SRv6 encapsulation source address information */ +const struct in6_addr * +dplane_ctx_get_srv6_encap_srcaddr(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.srv6_encap.srcaddr); +} + void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx, const struct prefix *p) { @@ -3031,6 +3091,13 @@ void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, ctx->u.rule.new.dp_flow_ptr = dp_flow_ptr; } +vrf_id_t dplane_ctx_rule_get_vrfid(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.rule.new.prule.vrf_id; +} + /*********************************************************************** * PBR RULE ACCESSORS - end **********************************************************************/ @@ -4040,6 +4107,7 @@ static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, ctx->zd_vrf_id = iptable->vrf_id; memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable)); + ctx->u.iptable.interface_name_list = NULL; if (iptable->nb_interface > 0) { ctx->u.iptable.interface_name_list = list_new(); ctx->u.iptable.interface_name_list->del = @@ -4246,6 +4314,10 @@ dplane_route_update_internal(struct route_node *rn, NEXTHOP_FLAG_RECURSIVE)) continue; + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE)) + continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) SET_FLAG(nexthop->flags, @@ -5849,6 +5921,59 @@ dplane_gre_set(struct interface *ifp, struct interface *ifp_link, return result; } +/* + * Common helper api for SRv6 encapsulation source address set + */ +enum zebra_dplane_result +dplane_srv6_encap_srcaddr_set(const struct in6_addr *addr, ns_id_t ns_id) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx = NULL; + enum dplane_op_e op = DPLANE_OP_SRV6_ENCAP_SRCADDR_SET; + int ret; + struct zebra_ns *zns; + + if (!addr) + return result; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: addr %pI6", dplane_op2str(op), + addr); + } + + zns = zebra_ns_lookup(ns_id); + if (!zns) + return result; + + ctx = dplane_ctx_alloc(); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zns, false); + + /* Init the SRv6 encap source address specific data area */ + memcpy(&ctx->u.srv6_encap.srcaddr, addr, + sizeof(ctx->u.srv6_encap.srcaddr)); + + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_srv6_encap_srcaddr_set_in, 1, + memory_order_relaxed); + + /* Enqueue context for processing */ + ret = dplane_update_enqueue(ctx); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info + .dg_srv6_encap_srcaddr_set_errors, + 1, memory_order_relaxed); + dplane_ctx_free(&ctx); + } + return result; +} + /* * Handler for 'show dplane' */ @@ -5878,6 +6003,14 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n", incoming); vty_out(vty, "Route update errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_nexthops_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_nexthop_errors, + memory_order_relaxed); + vty_out(vty, "Nexthop updates: %" PRIu64 "\n", incoming); + vty_out(vty, "Nexthop update errors: %" PRIu64 "\n", errs); + vty_out(vty, "Other errors : %"PRIu64"\n", other_errs); vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit); vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued); @@ -6248,7 +6381,7 @@ dplane_provider_dequeue_out_ctx(struct zebra_dplane_provider *prov) */ bool dplane_provider_is_threaded(const struct zebra_dplane_provider *prov) { - return (prov->dp_flags & DPLANE_PROV_FLAG_THREADED); + return CHECK_FLAG(prov->dp_flags, DPLANE_PROV_FLAG_THREADED); } #ifdef HAVE_NETLINK @@ -6574,6 +6707,12 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_TC_FILTER_UPDATE: case DPLANE_OP_STARTUP_STAGE: break; + + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + zlog_debug("Dplane SRv6 encap source address set op %s, addr %pI6", + dplane_op2str(dplane_ctx_get_op(ctx)), + &ctx->u.srv6_encap.srcaddr); + break; } } @@ -6744,6 +6883,13 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_NETCONFIG: break; + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info + .dg_srv6_encap_srcaddr_set_errors, + 1, memory_order_relaxed); + break; + case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) @@ -6852,6 +6998,31 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) return 0; } +static int kernel_dplane_shutdown_func(struct zebra_dplane_provider *prov, + bool early) +{ + struct zebra_dplane_ctx *ctx; + + if (early) + return 1; + + ctx = dplane_provider_dequeue_in_ctx(prov); + while (ctx) { + dplane_ctx_free(&ctx); + + ctx = dplane_provider_dequeue_in_ctx(prov); + } + + ctx = dplane_provider_dequeue_out_ctx(prov); + while (ctx) { + dplane_ctx_free(&ctx); + + ctx = dplane_provider_dequeue_out_ctx(prov); + } + + return 1; +} + #ifdef DPLANE_TEST_PROVIDER /* @@ -6924,12 +7095,10 @@ static void dplane_provider_init(void) { int ret; - ret = dplane_provider_register("Kernel", - DPLANE_PRIO_KERNEL, + ret = dplane_provider_register("Kernel", DPLANE_PRIO_KERNEL, DPLANE_PROV_FLAGS_DEFAULT, NULL, kernel_dplane_process_func, - NULL, - NULL, NULL); + kernel_dplane_shutdown_func, NULL, NULL); if (ret != AOK) zlog_err("Unable to register kernel dplane provider: %d", @@ -7289,6 +7458,11 @@ static void dplane_thread_loop(struct event *event) zlog_debug("dplane dequeues %d completed work from provider %s", counter, dplane_provider_get_name(prov)); + if (event_should_yield(event)) { + reschedule = true; + break; + } + /* Locate next provider */ prov = dplane_prov_list_next(&zdplane_info.dg_providers, prov); } @@ -7330,6 +7504,7 @@ static void dplane_thread_loop(struct event *event) void zebra_dplane_shutdown(void) { struct zebra_dplane_provider *dp; + struct zebra_dplane_ctx *ctx; if (IS_ZEBRA_DEBUG_DPLANE) zlog_debug("Zebra dataplane shutdown called"); @@ -7357,8 +7532,25 @@ void zebra_dplane_shutdown(void) } /* TODO -- Clean-up provider objects */ + dp = dplane_prov_list_first(&zdplane_info.dg_providers); + while (dp) { + dplane_prov_list_del(&zdplane_info.dg_providers, dp); + XFREE(MTYPE_DP_PROV, dp); + + dp = dplane_prov_list_first(&zdplane_info.dg_providers); + } /* TODO -- Clean queue(s), free memory */ + DPLANE_LOCK(); + { + ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list); + while (ctx) { + dplane_ctx_free(&ctx); + + ctx = dplane_ctx_list_pop(&zdplane_info.dg_update_list); + } + } + DPLANE_UNLOCK(); } /* diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 4d4a17bbaeba..0e9a8bfb99f5 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -18,11 +18,19 @@ #include "zebra/zserv.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_nhg.h" +#include "zebra/ge_netlink.h" #ifdef __cplusplus extern "C" { #endif +/* Retrieve the dataplane API version number; see libfrr.h to decode major, + * minor, sub version values. + * Plugins should pay attention to the major version number, at least, to + * be able to detect API changes that may not be backward-compatible. + */ +uint32_t zebra_dplane_get_version(void); + /* Key netlink info from zebra ns */ struct zebra_dplane_info { ns_id_t ns_id; @@ -198,6 +206,9 @@ enum dplane_op_e { /* Startup Control */ DPLANE_OP_STARTUP_STAGE, + + /* Source address for SRv6 encapsulation */ + DPLANE_OP_SRV6_ENCAP_SRCADDR_SET, }; /* @@ -312,6 +323,8 @@ struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q); /* Init a list of contexts */ void dplane_ctx_q_init(struct dplane_ctx_list_head *q); +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q); + /* * Accessors for information from the context object */ @@ -658,10 +671,14 @@ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx); +bool dplane_ctx_intf_is_noprefixroute(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_intf_set_noprefixroute(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx); void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx); const struct prefix *dplane_ctx_get_intf_addr( const struct zebra_dplane_ctx *ctx); +const struct in6_addr * +dplane_ctx_get_srv6_encap_srcaddr(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx, const struct prefix *p); bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx); @@ -740,6 +757,8 @@ intptr_t dplane_ctx_rule_get_old_dp_flow_ptr(const struct zebra_dplane_ctx *ctx); void dplane_ctx_rule_set_dp_flow_ptr(struct zebra_dplane_ctx *ctx, intptr_t dp_flow_ptr); +vrf_id_t dplane_ctx_rule_get_vrfid(const struct zebra_dplane_ctx *ctx); + /* Accessors for policy based routing iptable information */ struct zebra_pbr_iptable; void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, @@ -988,6 +1007,13 @@ enum zebra_dplane_result dplane_gre_set(struct interface *ifp, struct interface *ifp_link, unsigned int mtu, const struct zebra_l2info_gre *gre_info); +/* + * Enqueue an SRv6 encap source address set + */ +enum zebra_dplane_result +dplane_srv6_encap_srcaddr_set(const struct in6_addr *addr, ns_id_t ns_id); + + /* Forward ref of zebra_pbr_rule */ struct zebra_pbr_rule; diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 09b369e23eaf..dcfa37d268cb 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -787,6 +787,18 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Wait for Zebra to reattempt update.", }, + { + .code = EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + .title = "SRv6 manager unable to assign SID", + .description = "Zebra's SRv6 manager was unable to assign a SID to client.", + .suggestion = "Ensure that Zebra has a sufficient SID range available.", + }, + { + .code = EC_ZEBRA_SM_DAEMON_MISMATCH, + .title = "Daemon mismatch when releasing SRV6 SIDs", + .description = "Zebra noticed a mismatch between a SRv6 SID and a protocol daemon number or instance when releasing unused SRv6 SIDs.", + .suggestion = "Ignore this error.", + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 3ac654bda5c3..84632e1ad5c1 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -124,6 +124,8 @@ enum zebra_log_refs { EC_ZEBRA_GRE_SET_UPDATE, EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, EC_ZEBRA_INTF_UPDATE_FAILURE, + EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + EC_ZEBRA_SM_DAEMON_MISMATCH, }; void zebra_error_init(void); diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index ce5e63992850..ebb5a422985e 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -109,21 +109,14 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) } else { json_object_int_add(json, "vni", zevpn->vni); json_object_string_add(json, "type", "L2"); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `vrf` from JSON output") -#endif - json_object_string_add(json, "vrf", - vrf_id_to_name(zevpn->vrf_id)); - json_object_string_add(json, "tenantVrf", - vrf_id_to_name(zevpn->vrf_id)); + json_object_string_add(json, "tenantVrf", vrf_id_to_name(zevpn->vrf_id)); } if (!zevpn->vxlan_if) { // unexpected if (json == NULL) vty_out(vty, " VxLAN interface: unknown\n"); else - json_object_string_add(json, "vxlanInterface", - "unknown"); + json_object_string_add(json, "vxlanInterface", "unknown"); return; } num_macs = num_valid_macs(zevpn); @@ -135,35 +128,21 @@ CPP_NOTICE("Drop `vrf` from JSON output") (zevpn->svi_if ? zevpn->svi_if->name : "")); vty_out(vty, " SVI ifIndex: %u\n", (zevpn->svi_if ? zevpn->svi_if->ifindex : 0)); - vty_out(vty, " Local VTEP IP: %pI4\n", - &zevpn->local_vtep_ip); - vty_out(vty, " Mcast group: %pI4\n", - &zevpn->mcast_grp); + vty_out(vty, " Local VTEP IP: %pI4\n", &zevpn->local_vtep_ip); + vty_out(vty, " Mcast group: %pI4\n", &zevpn->mcast_grp); } else { - json_object_string_add(json, "vxlanInterface", - zevpn->vxlan_if->name); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `ifindex` from JSON output") -#endif - json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex); - json_object_int_add(json, "vxlanIfindex", - zevpn->vxlan_if->ifindex); + json_object_string_add(json, "vxlanInterface", zevpn->vxlan_if->name); + json_object_int_add(json, "vxlanIfindex", zevpn->vxlan_if->ifindex); if (zevpn->svi_if) { - json_object_string_add(json, "sviInterface", - zevpn->svi_if->name); - json_object_int_add(json, "sviIfindex", - zevpn->svi_if->ifindex); + json_object_string_add(json, "sviInterface", zevpn->svi_if->name); + json_object_int_add(json, "sviIfindex", zevpn->svi_if->ifindex); } - json_object_string_addf(json, "vtepIp", "%pI4", - &zevpn->local_vtep_ip); - json_object_string_addf(json, "mcastGroup", "%pI4", - &zevpn->mcast_grp); + json_object_string_addf(json, "vtepIp", "%pI4", &zevpn->local_vtep_ip); + json_object_string_addf(json, "mcastGroup", "%pI4", &zevpn->mcast_grp); json_object_string_add(json, "advertiseGatewayMacip", - zevpn->advertise_gw_macip ? "Yes" - : "No"); + zevpn->advertise_gw_macip ? "Yes" : "No"); json_object_string_add(json, "advertiseSviMacip", - zevpn->advertise_svi_macip ? "Yes" - : "No"); + zevpn->advertise_svi_macip ? "Yes" : "No"); json_object_int_add(json, "numMacs", num_macs); json_object_int_add(json, "numArpNd", num_neigh); } @@ -179,28 +158,21 @@ CPP_NOTICE("Drop `ifindex` from JSON output") json_vtep_list = json_object_new_array(); for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { const char *flood_str = lookup_msg( - zvtep_flood_str, zvtep->flood_control, - VXLAN_FLOOD_STR_DEFAULT); + zvtep_flood_str, zvtep->flood_control, VXLAN_FLOOD_STR_DEFAULT); if (json == NULL) { - vty_out(vty, " %pI4 flood: %s\n", - &zvtep->vtep_ip, - flood_str); + vty_out(vty, " %pI4 flood: %s\n", &zvtep->vtep_ip, flood_str); } else { json_vtep = json_object_new_object(); - json_object_string_addf(json_vtep, "ip", "%pI4", - &zvtep->vtep_ip); - json_object_string_add(json_vtep, "flood", - flood_str); - json_object_array_add(json_vtep_list, - json_vtep); + json_object_string_addf(json_vtep, "ip", "%pI4", &zvtep->vtep_ip); + json_object_string_add(json_vtep, "flood", flood_str); + json_object_array_add(json_vtep_list, json_vtep); } num_vteps++; } if (json) { json_object_int_add(json, "numRemoteVteps", num_vteps); - json_object_object_add(json, "remoteVteps", - json_vtep_list); + json_object_object_add(json, "remoteVteps", json_vtep_list); } } if (json == NULL) { @@ -261,8 +233,7 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) json_object_int_add(json_evpn, "vni", zevpn->vni); json_object_string_add(json_evpn, "type", "L2"); json_object_string_add(json_evpn, "vxlanIf", - zevpn->vxlan_if ? zevpn->vxlan_if->name - : "unknown"); + zevpn->vxlan_if ? zevpn->vxlan_if->name : "unknown"); json_object_int_add(json_evpn, "numMacs", num_macs); json_object_int_add(json_evpn, "numArpNd", num_neigh); json_object_int_add(json_evpn, "numRemoteVteps", num_vteps); @@ -272,13 +243,10 @@ void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) json_vtep_list = json_object_new_array(); for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { json_ip_str = json_object_new_string( - inet_ntop(AF_INET, &zvtep->vtep_ip, buf, - sizeof(buf))); - json_object_array_add(json_vtep_list, - json_ip_str); + inet_ntop(AF_INET, &zvtep->vtep_ip, buf, sizeof(buf))); + json_object_array_add(json_vtep_list, json_ip_str); } - json_object_object_add(json_evpn, "remoteVteps", - json_vtep_list); + json_object_object_add(json_evpn, "remoteVteps", json_vtep_list); } json_object_object_add(json, vni_str, json_evpn); } @@ -310,13 +278,12 @@ void zebra_evpn_print_hash_detail(struct hash_bucket *bucket, void *data) int zebra_evpn_del_macip_for_intf(struct interface *ifp, struct zebra_evpn *zevpn) { - struct listnode *cnode = NULL, *cnnode = NULL; struct connected *c = NULL; struct ethaddr macaddr; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each_safe (if_connected, ifp->connected, c) { struct ipaddr ip; memset(&ip, 0, sizeof(struct ipaddr)); @@ -344,13 +311,12 @@ int zebra_evpn_del_macip_for_intf(struct interface *ifp, int zebra_evpn_add_macip_for_intf(struct interface *ifp, struct zebra_evpn *zevpn) { - struct listnode *cnode = NULL, *cnnode = NULL; struct connected *c = NULL; struct ethaddr macaddr; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each_safe (if_connected, ifp->connected, c) { struct ipaddr ip; if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) @@ -385,7 +351,7 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, vrf_id); stream_put(s, p, sizeof(struct prefix)); @@ -409,13 +375,12 @@ static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, int zebra_evpn_advertise_subnet(struct zebra_evpn *zevpn, struct interface *ifp, int advertise) { - struct listnode *cnode = NULL, *cnnode = NULL; struct connected *c = NULL; struct ethaddr macaddr; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); - for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + frr_each (if_connected, ifp->connected, c) { struct prefix p; memcpy(&p, c->address, sizeof(struct prefix)); @@ -493,8 +458,7 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, struct zebra_evpn *zevpn, /* Remove neighbor from BGP. */ zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac, - n->flags, ZEBRA_NEIGH_ACTIVE, - false /*force*/); + n->flags, ZEBRA_NEIGH_ACTIVE, false /*force*/); /* Delete this neighbor entry. */ zebra_evpn_neigh_del(zevpn, n); @@ -524,8 +488,7 @@ void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket, */ if (zevpn->advertise_gw_macip) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", - zevpn->vni); + zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", zevpn->vni); return; } @@ -697,8 +660,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns, if (zif->brslave_info.br_if != br_if) continue; - vni_id = - zebra_vxlan_if_access_vlan_vni_find(zif, br_if); + vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; break; @@ -735,9 +697,7 @@ struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp, in_param.zif = zif; p_zevpn = &zevpn; - ns_walk_func(zebra_evpn_map_vlan_ns, - (void *)&in_param, - (void **)p_zevpn); + ns_walk_func(zebra_evpn_map_vlan_ns, (void *)&in_param, (void **)p_zevpn); return zevpn; } @@ -857,9 +817,7 @@ struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp, return zevpn; } -static int zvni_map_to_macvlan_ns(struct ns *ns, - void *_in_param, - void **_p_ifp) +static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp) { struct zebra_ns *zns = ns->info; struct zebra_from_svi_param *in_param = @@ -921,9 +879,7 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if, p_ifp = &tmp_if; /* Identify corresponding VLAN interface. */ - ns_walk_func(zvni_map_to_macvlan_ns, - (void *)&in_param, - (void **)p_ifp); + ns_walk_func(zvni_map_to_macvlan_ns, (void *)&in_param, (void **)p_ifp); return tmp_if; } @@ -1128,8 +1084,7 @@ struct zebra_evpn *zebra_evpn_add(vni_t vni) /* Create hash table for MAC */ zevpn->mac_table = zebra_mac_db_create(buffer); - snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", - vni); + snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", vni); /* Create hash table for neighbors */ zevpn->neigh_table = zebra_neigh_db_create(buffer); @@ -1185,7 +1140,7 @@ int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn) svi_index = zevpn->svi_if ? zevpn->svi_if->ifindex : 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id()); stream_putl(s, zevpn->vni); @@ -1208,8 +1163,8 @@ int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn) client->vniadd_cnt++; rc = zserv_send_message(client, s); - if (!(zevpn->flags & ZEVPN_READY_FOR_BGP)) { - zevpn->flags |= ZEVPN_READY_FOR_BGP; + if (!CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) { + SET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP); /* once the EVPN is sent the ES-EVIs can also be replayed * to BGP */ @@ -1231,13 +1186,13 @@ int zebra_evpn_send_del_to_client(struct zebra_evpn *zevpn) if (!client) return 0; - if (zevpn->flags & ZEVPN_READY_FOR_BGP) { - zevpn->flags &= ~ZEVPN_READY_FOR_BGP; + if (CHECK_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP)) { + UNSET_FLAG(zevpn->flags, ZEVPN_READY_FOR_BGP); /* the ES-EVIs must be removed from BGP before the EVPN is */ zebra_evpn_update_all_es(zevpn); } - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id()); @@ -1353,8 +1308,7 @@ int zebra_evpn_vtep_install(struct zebra_evpn *zevpn, struct zebra_vtep *zvtep) if (is_vxlan_flooding_head_end() && (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) { if (ZEBRA_DPLANE_REQUEST_FAILURE == - dplane_vtep_add(zevpn->vxlan_if, - &zvtep->vtep_ip, zevpn->vni)) + dplane_vtep_add(zevpn->vxlan_if, &zvtep->vtep_ip, zevpn->vni)) return -1; } @@ -1445,9 +1399,7 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, zevpn->vni, macaddr, ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", sticky ? " sticky" : "", remote_gw ? " remote_gw" : ""); return; @@ -1462,16 +1414,13 @@ static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { mac = zebra_evpn_proc_sync_mac_update(zevpn, macaddr, - ipa_len, ipaddr, - flags, seq, esi); + ipa_len, ipaddr, flags, seq, esi); } if (!mac) return; n = zebra_evpn_neigh_lookup(zevpn, ipaddr); - if (n - && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, - true)) + if (n && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, true)) return; zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, @@ -1517,22 +1466,19 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, * SYNC - if ES is local * REMOTE - if ES is not local */ - if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) { + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH)) { struct zebra_evpn_es *es; es = zebra_evpn_es_find(esi); - if (es && (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)) { + if (es && CHECK_FLAG(es->flags, ZEBRA_EVPNES_READY_FOR_BGP)) { zebra_evpn_process_sync_macip_add(zevpn, macaddr, - ipa_len, ipaddr, - flags, seq, esi); + ipa_len, ipaddr, flags, seq, esi); } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES) { char esi_str[ESI_STR_LEN]; esi_to_str(esi, esi_str, sizeof(esi_str)); - zlog_debug( - "Ignore sync-macip add; ES %s is not ready", - esi_str); + zlog_debug("Ignore sync-macip add; ES %s is not ready", esi_str); } } @@ -1546,8 +1492,7 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, if (vtep_ip.s_addr) { zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); if (!zvtep) { - zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, - VXLAN_FLOOD_DISABLED); + zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, VXLAN_FLOOD_DISABLED); if (!zvtep) { flog_err( EC_ZEBRA_VTEP_ADD_FAILED, @@ -1624,9 +1569,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, vnip = zebra_vxlan_if_vni_find(zif, vni); if (!vnip) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "VNI %u not in interface upon remote MACIP DEL", - vni); + zlog_debug("VNI %u not in interface upon remote MACIP DEL", vni); return; } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 6d5cd66143d3..bfc060db61ab 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -103,9 +103,7 @@ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)", - zmac->zevpn->vni, - &zmac->macaddr, - ifp->name, ifp->ifindex); + zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex); zif = ifp->info; list_delete_node(zif->mac_list, &zmac->ifp_listnode); @@ -122,7 +120,7 @@ void zebra_evpn_mac_ifp_del(struct interface *ifp) if (zif->mac_list) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("MAC list deleted for ifp %s (%u)", - zif->ifp->name, zif->ifp->ifindex); + zif->ifp->name, zif->ifp->ifindex); for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) { zebra_evpn_mac_ifp_unlink(zmac); @@ -161,9 +159,7 @@ static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)", - zmac->zevpn->vni, - &zmac->macaddr, - ifp->name, ifp->ifindex); + zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex); zmac->ifp = ifp; listnode_init(&zmac->ifp_listnode, zmac); @@ -205,7 +201,7 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac, return -1; sticky = !!CHECK_FLAG(mac->flags, - (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); + (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); /* If nexthop group for the FDB entry is inactive (not programmed in * the dataplane) the MAC entry cannot be installed @@ -249,7 +245,7 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn, enum zebra_dplane_result res; /* If the MAC was not installed there is no need to uninstall it */ - if (!force && mac->es && !(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) + if (!force && mac->es && !CHECK_FLAG(mac->es->flags, ZEBRA_EVPNES_NHG_ACTIVE)) return -1; if (!zevpn->vxlan_if) { @@ -282,8 +278,7 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn, ifp = zevpn->vxlan_if; vtep_ip = mac->fwd_info.r_vtep_ip; - res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, - vtep_ip); + res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -341,8 +336,7 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac, *vid = mac->fwd_info.local.vid; zns = zebra_ns_lookup(mac->fwd_info.local.ns_id); - *p_ifp = if_lookup_by_index_per_ns(zns, - mac->fwd_info.local.ifindex); + *p_ifp = if_lookup_by_index_per_ns(zns, mac->fwd_info.local.ifindex); } } @@ -355,26 +349,19 @@ static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf, return buf; } - snprintfrr( - buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s", + snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s", CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " - : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW " - : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) - ? "PEER Active " - : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "PEER Active " : "", CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) - ? "LOC Inactive " - : ""); + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "LOC Inactive " : ""); return buf; } @@ -407,8 +394,7 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) zlog_debug( "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count, listcount(mac->neigh_list)); } @@ -418,8 +404,7 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) ZEBRA_NEIGH_SET_INACTIVE(nbr); else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) - zebra_evpn_rem_neigh_install( - zevpn, nbr, false /*was_static*/); + zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); } UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); @@ -438,13 +423,11 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { /* Inform to BGP */ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr, - mac->flags, mac->loc_seq, - mac->es)) + mac->flags, mac->loc_seq, mac->es)) return; /* Process all neighbors associated with this MAC. */ - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, - 0 /*es_change*/); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, 0 /*es_change*/); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -479,8 +462,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zlog_debug( "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count, zvrf->dad_freeze_time); } /* For duplicate MAC do not update @@ -516,8 +498,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zlog_debug( "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), mac->dad_count); } @@ -545,10 +526,10 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (mac->dad_count >= zvrf->dad_max_moves) { flog_warn(EC_ZEBRA_DUP_MAC_DETECTED, - "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", - mac->zevpn->vni, &mac->macaddr, - is_local ? "local update, last" : - "remote update, from", &vtep_ip); + "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", + mac->zevpn->vni, &mac->macaddr, + is_local ? "local update, last" : "remote update, from", + &vtep_ip); SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); @@ -583,15 +564,13 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, zlog_debug( "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), zvrf->dad_freeze_time); } event_add_timer(zrouter.master, - zebra_evpn_dad_mac_auto_recovery_exp, - mac, zvrf->dad_freeze_time, - &mac->dad_mac_auto_recovery_timer); + zebra_evpn_dad_mac_auto_recovery_exp, mac, + zvrf->dad_freeze_time, &mac->dad_mac_auto_recovery_timer); } /* In case of local update, do not inform to client (BGPd), @@ -638,22 +617,18 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) zebra_evpn_mac_get_access_info(mac, &ifp, &vid); json_object_string_add(json_mac, "type", "local"); if (ifp) { - json_object_string_add(json_mac, "intf", - ifp->name); - json_object_int_add(json_mac, "ifindex", - ifp->ifindex); + json_object_string_add(json_mac, "intf", ifp->name); + json_object_int_add(json_mac, "ifindex", ifp->ifindex); } if (vid) json_object_int_add(json_mac, "vlan", vid); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { json_object_string_add(json_mac, "type", "remote"); if (mac->es) - json_object_string_add(json_mac, "remoteEs", - mac->es->esi_str); + json_object_string_add(json_mac, "remoteEs", mac->es->esi_str); else json_object_string_addf( - json_mac, "remoteVtep", "%pI4", - &mac->fwd_info.r_vtep_ip); + json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) json_object_string_add(json_mac, "type", "auto"); @@ -664,12 +639,10 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) json_object_boolean_true_add(json_mac, "sviMac"); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) - json_object_boolean_true_add(json_mac, - "defaultGateway"); + json_object_boolean_true_add(json_mac, "defaultGateway"); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)) - json_object_boolean_true_add(json_mac, - "remoteGatewayMac"); + json_object_boolean_true_add(json_mac, "remoteGatewayMac"); json_object_string_add(json_mac, "uptime", up_str); json_object_int_add(json_mac, "localSequence", mac->loc_seq); @@ -690,46 +663,31 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) json_object_boolean_true_add(json_mac, "peerActive"); if (mac->hold_timer) - json_object_string_add( - json_mac, "peerActiveHold", - event_timer_to_hhmmss(thread_buf, - sizeof(thread_buf), - mac->hold_timer)); + json_object_string_add(json_mac, "peerActiveHold", + event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer)); if (mac->es) - json_object_string_add(json_mac, "esi", - mac->es->esi_str); + json_object_string_add(json_mac, "esi", mac->es->esi_str); /* print all the associated neigh */ if (!listcount(mac->neigh_list)) json_object_string_add(json_mac, "neighbors", "none"); else { json_object *json_active_nbrs = json_object_new_array(); - json_object *json_inactive_nbrs = - json_object_new_array(); + json_object *json_inactive_nbrs = json_object_new_array(); json_object *json_nbrs = json_object_new_object(); for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { if (IS_ZEBRA_NEIGH_ACTIVE(n)) - json_object_array_add( - json_active_nbrs, - json_object_new_string( - ipaddr2str( - &n->ip, buf2, - sizeof(buf2)))); + json_object_array_add(json_active_nbrs, + json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2)))); else json_object_array_add( json_inactive_nbrs, - json_object_new_string( - ipaddr2str( - &n->ip, buf2, - sizeof(buf2)))); + json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2)))); } - json_object_object_add(json_nbrs, "active", - json_active_nbrs); - json_object_object_add(json_nbrs, "inactive", - json_inactive_nbrs); - json_object_object_add(json_mac, "neighbors", - json_nbrs); + json_object_object_add(json_nbrs, "active", json_active_nbrs); + json_object_object_add(json_nbrs, "inactive", json_inactive_nbrs); + json_object_object_add(json_mac, "neighbors", json_nbrs); } json_object_object_add(json, buf1, json_mac); @@ -746,18 +704,15 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) vty_out(vty, " ESI: %s\n", mac->es->esi_str); if (ifp) - vty_out(vty, " Intf: %s(%u)", ifp->name, - ifp->ifindex); + vty_out(vty, " Intf: %s(%u)", ifp->name, ifp->ifindex); else vty_out(vty, " Intf: -"); vty_out(vty, " VLAN: %u", vid); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { if (mac->es) - vty_out(vty, " Remote ES: %s", - mac->es->esi_str); + vty_out(vty, " Remote ES: %s", mac->es->esi_str); else - vty_out(vty, " Remote VTEP: %pI4", - &mac->fwd_info.r_vtep_ip); + vty_out(vty, " Remote VTEP: %pI4", &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { vty_out(vty, " Auto Mac "); } @@ -784,24 +739,18 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) vty_out(vty, " peer-active"); if (mac->hold_timer) vty_out(vty, " (ht: %s)", - event_timer_to_hhmmss(thread_buf, - sizeof(thread_buf), - mac->hold_timer)); + event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer)); vty_out(vty, "\n"); - vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, - mac->rem_seq); + vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, mac->rem_seq); vty_out(vty, " Uptime: %s\n", up_str); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { vty_out(vty, " Duplicate, detected at %s", - time_to_string(mac->dad_dup_detect_time, - timebuf)); + time_to_string(mac->dad_dup_detect_time, timebuf)); } else if (mac->dad_count) { - monotime_since(&mac->detect_start_time, - &detect_start_time); + monotime_since(&mac->detect_start_time, &detect_start_time); if (detect_start_time.tv_sec <= zvrf->dad_time) { - time_to_string(mac->detect_start_time.tv_sec, - timebuf); + time_to_string(mac->detect_start_time.tv_sec, timebuf); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", timebuf, mac->dad_count); @@ -816,9 +765,7 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { vty_out(vty, " %s %s\n", ipaddr2str(&n->ip, buf2, sizeof(buf2)), - (IS_ZEBRA_NEIGH_ACTIVE(n) - ? "Active" - : "Inactive")); + (IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active" : "Inactive")); } } @@ -831,9 +778,9 @@ static char *zebra_evpn_print_mac_flags(struct zebra_mac *mac, char *flags_buf, { snprintf(flags_buf, flags_buf_sz, "%s%s%s%s", mac->sync_neigh_cnt ? "N" : "", - (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "", - (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "", - (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : ""); + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : ""); return flags_buf; } @@ -870,14 +817,12 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) zebra_evpn_mac_get_access_info(mac, &ifp, &vid); if (json_mac_hdr == NULL) { vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local", - zebra_evpn_print_mac_flags(mac, flags_buf, - sizeof(flags_buf)), + zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)), ifp ? ifp->name : "-"); } else { json_object_string_add(json_mac, "type", "local"); if (ifp) - json_object_string_add(json_mac, "intf", - ifp->name); + json_object_string_add(json_mac, "intf", ifp->name); } if (vid) { if (json_mac_hdr == NULL) @@ -891,18 +836,13 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq); vty_out(vty, "\n"); } else { - json_object_int_add(json_mac, "localSequence", - mac->loc_seq); - json_object_int_add(json_mac, "remoteSequence", - mac->rem_seq); - json_object_int_add(json_mac, "detectionCount", - mac->dad_count); + json_object_int_add(json_mac, "localSequence", mac->loc_seq); + json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); + json_object_int_add(json_mac, "detectionCount", mac->dad_count); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - json_object_boolean_true_add(json_mac, - "isDuplicate"); + json_object_boolean_true_add(json_mac, "isDuplicate"); else - json_object_boolean_false_add(json_mac, - "isDuplicate"); + json_object_boolean_false_add(json_mac, "isDuplicate"); json_object_object_add(json_mac_hdr, buf1, json_mac); } @@ -910,19 +850,16 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) - && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, - &wctx->r_vtep_ip)) + if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) + && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) return; if (json_mac_hdr == NULL) { - if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) + if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) && (wctx->count == 0)) { vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni); vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n", - "MAC", "Type", "Flags", - "Intf/Remote ES/VTEP", "VLAN", - "Seq #'s"); + "MAC", "Type", "Flags", "Intf/Remote ES/VTEP", "VLAN", "Seq #'s"); } if (mac->es == NULL) inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip, @@ -930,32 +867,24 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1, "remote", - zebra_evpn_print_mac_flags(mac, flags_buf, - sizeof(flags_buf)), + zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)), mac->es ? mac->es->esi_str : addr_buf, "", mac->loc_seq, mac->rem_seq); } else { json_object_string_add(json_mac, "type", "remote"); if (mac->es) - json_object_string_add(json_mac, "remoteEs", - mac->es->esi_str); + json_object_string_add(json_mac, "remoteEs", mac->es->esi_str); else json_object_string_addf( - json_mac, "remoteVtep", "%pI4", - &mac->fwd_info.r_vtep_ip); + json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip); json_object_object_add(json_mac_hdr, buf1, json_mac); - json_object_int_add(json_mac, "localSequence", - mac->loc_seq); - json_object_int_add(json_mac, "remoteSequence", - mac->rem_seq); - json_object_int_add(json_mac, "detectionCount", - mac->dad_count); + json_object_int_add(json_mac, "localSequence", mac->loc_seq); + json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); + json_object_int_add(json_mac, "detectionCount", mac->dad_count); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - json_object_boolean_true_add(json_mac, - "isDuplicate"); + json_object_boolean_true_add(json_mac, "isDuplicate"); else - json_object_boolean_false_add(json_mac, - "isDuplicate"); + json_object_boolean_false_add(json_mac, "isDuplicate"); } wctx->count++; @@ -1004,7 +933,7 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, cmd, zebra_vrf_get_evpn_id()); stream_putl(s, vni); @@ -1040,9 +969,9 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, zlog_debug( "Send MACIP %s f %s state %u MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", - zclient_evpn_dump_macip_flags(flags, flag_buf, - sizeof(flag_buf)), - state, macaddr, ip, seq, vni, es ? es->esi_str : "-", + zclient_evpn_dump_macip_flags(flags, flag_buf, sizeof(flag_buf)), + state, macaddr, ip, seq, vni, + es ? es->esi_str : "-", zebra_route_string(client->proto)); } @@ -1076,8 +1005,7 @@ static bool mac_cmp(const void *p1, const void *p2) if (pmac1 == NULL || pmac2 == NULL) return false; - return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) - == 0); + return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) == 0); } /* @@ -1117,10 +1045,8 @@ struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %pEA flags %s", __func__, - &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } return mac; } @@ -1135,10 +1061,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug("%s: MAC %pEA flags %s", __func__, - &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* force de-ref any ES entry linked to the MAC */ @@ -1165,9 +1089,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list " - "count %u, mark MAC as AUTO", - &mac->macaddr, mac->flags, zevpn->vni, - listcount(mac->neigh_list)); + "count %u, mark MAC as AUTO", &mac->macaddr, mac->flags, + zevpn->vni, listcount(mac->neigh_list)); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); return 0; @@ -1204,25 +1127,25 @@ struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn, static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx, struct zebra_mac *mac) { - if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) + if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return true; - else if ((wctx->flags & DEL_REMOTE_MAC) - && (mac->flags & ZEBRA_MAC_REMOTE)) + else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) return true; - else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) - && (mac->flags & ZEBRA_MAC_REMOTE) + else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC_FROM_VTEP) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) return true; - else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO) + else if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) + && CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) && !listcount(mac->neigh_list)) { if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; zlog_debug( - "%s: Del MAC %pEA flags %s", __func__, - &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + "%s: Del MAC %pEA flags %s", __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } wctx->uninstall = 0; @@ -1241,21 +1164,17 @@ static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct zebra_mac *mac = bucket->data; if (zebra_evpn_check_mac_del_from_db(wctx, mac)) { - if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { + if (wctx->upd_client && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni, - &mac->macaddr, - mac->flags, false); + &mac->macaddr, mac->flags, false); } if (wctx->uninstall) { if (zebra_evpn_mac_is_static(mac)) - zebra_evpn_sync_mac_dp_install( - mac, false /* set_inactive */, - true /* force_clear_static */, - __func__); + zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, + true /* force_clear_static */, __func__); if (mac->flags & ZEBRA_MAC_REMOTE) - zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, - false /*force*/); + zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false /*force*/); } zebra_evpn_mac_del(wctx->zevpn, mac); @@ -1330,8 +1249,7 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr, SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags, - seq, ZEBRA_NEIGH_ACTIVE, es, - ZEBRA_MACIP_ADD); + seq, ZEBRA_NEIGH_ACTIVE, es, ZEBRA_MACIP_ADD); } /* @@ -1357,9 +1275,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, state = ZEBRA_NEIGH_INACTIVE; } - return zebra_evpn_macip_send_msg_to_client( - vni, macaddr, NULL, 0 /* flags */, 0 /* seq */, state, NULL, - ZEBRA_MACIP_DEL); + return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, + 0 /* flags */, 0 /* seq */, state, NULL, ZEBRA_MACIP_DEL); } /* @@ -1412,8 +1329,7 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port", caller, zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_inactive ? "inactive " : ""); } return -1; @@ -1429,8 +1345,7 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br", caller, zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_inactive ? "inactive " : ""); } return -1; @@ -1455,19 +1370,16 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, set_static ? "install" : "uninstall", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_inactive ? "inactive " : ""); } if (set_static) /* XXX - old_static needs to be computed more * accurately */ - zebra_evpn_rem_mac_install(zevpn, mac, - true /* old_static */); + zebra_evpn_rem_mac_install(zevpn, mac, true /* old_static */); else - zebra_evpn_rem_mac_uninstall(zevpn, mac, - false /* force */); + zebra_evpn_rem_mac_uninstall(zevpn, mac, false /* force */); return 0; } @@ -1478,14 +1390,13 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), set_static ? "static " : "", set_inactive ? "inactive " : ""); } dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky, - set_static, set_inactive); + set_static, set_inactive); return 0; } @@ -1495,12 +1406,11 @@ void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac, { if (new_bgp_ready) zebra_evpn_mac_send_add_to_client(mac->zevpn->vni, - &mac->macaddr, mac->flags, - mac->loc_seq, mac->es); + &mac->macaddr, mac->flags, + mac->loc_seq, mac->es); else if (old_bgp_ready) zebra_evpn_mac_send_del_to_client(mac->zevpn->vni, - &mac->macaddr, mac->flags, - true /* force */); + &mac->macaddr, mac->flags, true /* force */); } /* MAC hold timer is used to age out peer-active flag. @@ -1537,8 +1447,7 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t) "sync-mac vni %u mac %pEA es %s %shold expired", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* re-program the local mac in the dataplane if the mac is no @@ -1546,13 +1455,11 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t) */ if (old_static != new_static) zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); /* inform bgp if needed */ if (old_bgp_ready != new_bgp_ready) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); } static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) @@ -1567,8 +1474,7 @@ static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) "sync-mac vni %u mac %pEA es %s %shold started", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } event_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac, zmh_info->mac_hold_time, &mac->hold_timer); @@ -1586,8 +1492,7 @@ void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac) "sync-mac vni %u mac %pEA es %s %shold stopped", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } EVENT_OFF(mac->hold_timer); @@ -1605,8 +1510,7 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) "sync-mac del vni %u mac %pEA es %s seq %d f %s", mac->zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } old_static = zebra_evpn_mac_is_static(mac); @@ -1618,8 +1522,7 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) if (old_static != new_static) /* program the local mac in the kernel */ zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); } static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, @@ -1647,8 +1550,7 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, zlog_debug( "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x", sync ? "sync" : "rem", zevpn->vni, - n_type, &mac->macaddr, tmp_seq, - mac->flags); + n_type, &mac->macaddr, tmp_seq, mac->flags); return true; } @@ -1660,10 +1562,9 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s", - sync ? "sync" : "rem", zevpn->vni, - n_type, &mac->macaddr, tmp_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + (sync ? "sync" : "rem"), + zevpn->vni, n_type, &mac->macaddr, tmp_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } return true; @@ -1672,10 +1573,8 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { zlog_debug( "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s", - sync ? "sync" : "rem", zevpn->vni, n_type, - &mac->macaddr, tmp_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + (sync ? "sync" : "rem"), zevpn->vni, n_type, &mac->macaddr, tmp_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } return false; @@ -1749,9 +1648,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, "Ignore sync-macip vni %u mac %pEA%s%s%s%s", zevpn->vni, macaddr, ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, - sizeof(ipbuf)) - : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", sticky ? " sticky" : "", remote_gw ? " remote_gw" : ""); return NULL; @@ -1766,16 +1663,16 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, new_flags = 0; SET_FLAG(new_flags, ZEBRA_MAC_LOCAL); /* retain old local activity flag */ - if (old_flags & ZEBRA_MAC_LOCAL) - new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE); + if (CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL)) + SET_FLAG (new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL_INACTIVE)); else - new_flags |= ZEBRA_MAC_LOCAL_INACTIVE; + SET_FLAG(new_flags, ZEBRA_MAC_LOCAL_INACTIVE); if (ipa_len) { /* if mac-ip route do NOT update the peer flags * i.e. retain only flags as is */ - new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS); + SET_FLAG(new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_ALL_PEER_FLAGS)); } else { /* if mac-only route update peer flags */ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) { @@ -1785,10 +1682,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * holdtimer on it. the peer-active flag is * cleared on holdtimer expiry. */ - if (CHECK_FLAG(old_flags, - ZEBRA_MAC_ES_PEER_ACTIVE)) { - SET_FLAG(new_flags, - ZEBRA_MAC_ES_PEER_ACTIVE); + if (CHECK_FLAG(old_flags, ZEBRA_MAC_ES_PEER_ACTIVE)) { + SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE); zebra_evpn_mac_start_hold_timer(mac); } } else { @@ -1811,10 +1706,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, zlog_debug( "sync-mac vni %u mac %pEA old_f %snew_f %s", zevpn->vni, macaddr, - zebra_evpn_zebra_mac_flag_dump( - &omac, omac_buf, sizeof(omac_buf)), - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(&omac, omac_buf, sizeof(omac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* update es */ @@ -1854,24 +1747,24 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s", - created ? "created" : "updated", zevpn->vni, macaddr, - mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), - inform_bgp ? "inform_bgp" : "", - inform_dataplane ? " inform_dp" : ""); + created ? "created" : "updated", + zevpn->vni, macaddr, + mac->es ? mac->es->esi_str : "-", + mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), + inform_bgp ? "inform_bgp" : "", + inform_dataplane ? " inform_dp" : ""); } if (inform_bgp) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); /* neighs using the mac may need to be re-sent to * bgp with updated info */ if (seq_change || es_change || !old_local) zebra_evpn_process_neigh_on_local_mac_change( - zevpn, mac, seq_change, es_change); + zevpn, mac, seq_change, es_change); if (inform_dataplane && !ipa_len) { /* program the local mac in the kernel. when the ES @@ -1879,9 +1772,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * the activity as we are yet to establish activity * locally */ - zebra_evpn_sync_mac_dp_install( - mac, mac_inactive /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, mac_inactive /* set_inactive */, + false /* force_clear_static */, __func__); } return mac; @@ -1891,8 +1783,7 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * is detected */ static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac, - struct interface *ifp, - vlanid_t vid) + struct interface *ifp, vlanid_t vid) { struct zebra_if *zif = ifp->info; bool es_change; @@ -1934,8 +1825,8 @@ static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket, if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni, - &zmac->macaddr, zmac->flags, - zmac->loc_seq, zmac->es); + &zmac->macaddr, zmac->flags, + zmac->loc_seq, zmac->es); } /* Iterator to Notify Local MACs of a EVPN */ @@ -1949,8 +1840,7 @@ void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn) memset(&wctx, 0, sizeof(wctx)); wctx.zevpn = zevpn; - hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, - &wctx); + hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, &wctx); } void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) @@ -1992,8 +1882,7 @@ void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt) } /* Print Duplicate MAC in detail */ -void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, - void *ctxt) +void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) { struct zebra_mac *mac; @@ -2043,11 +1932,13 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * If so, that needs to be updated first. Note that client could * install MAC and MACIP separately or just install the latter. */ - if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) - || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) - || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) - || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq) + if (!mac + || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) + || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) + || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) + || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) + || memcmp(old_esi, esi, sizeof(esi_t)) + || seq != mac->rem_seq) update_mac = 1; if (update_mac) { @@ -2063,8 +1954,7 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * the sequence number and ignore this update * if appropriate. */ - if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, - false)) + if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, false)) return -1; old_es_present = !!mac->es; @@ -2091,8 +1981,7 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * MAC is already marked duplicate set dad, then * is_dup_detect will be set to not install the entry. */ - if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - && mac->dad_count) + if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && mac->dad_count) || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) do_dad = true; @@ -2108,14 +1997,12 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } zebra_evpn_mac_clear_sync_info(mac); - zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, - mac->flags, - false /* force */); + zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags, + false /* force */); } /* Set "auto" and "remote" forwarding info. */ @@ -2135,8 +2022,7 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad, - &is_dup_detect, false); + zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad, &is_dup_detect, false); if (!is_dup_detect) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -2180,8 +2066,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug( "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s", - sticky ? "sticky " : "", macaddr, - ifp->name, ifp->ifindex, vid, zevpn->vni, + sticky ? "sticky " : "", + macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? " local-inactive" : ""); mac = zebra_evpn_mac_add(zevpn, macaddr); @@ -2196,11 +2082,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zlog_debug( "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", - sticky ? "sticky " : "", macaddr, - ifp->name, ifp->ifindex, vid, zevpn->vni, + sticky ? "sticky " : "", + macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive ? "local-inactive " : "", - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { @@ -2209,42 +2094,34 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, bool old_static; zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid); - old_bgp_ready = - zebra_evpn_mac_is_ready_for_bgp(mac->flags); - old_local_inactive = - !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE); + old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + old_local_inactive = !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE); old_static = zebra_evpn_mac_is_static(mac); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) mac_sticky = true; - es_change = zebra_evpn_local_mac_update_fwd_info( - mac, ifp, vid); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); /* * Update any changes and if changes are relevant to * BGP, note it. */ - if (mac_sticky == sticky && old_ifp == ifp - && old_vid == vid - && old_local_inactive == local_inactive - && dp_static == old_static && !es_change) { + if (mac_sticky == sticky && old_ifp == ifp && old_vid == vid + && old_local_inactive == local_inactive + && dp_static == old_static && !es_change) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, " "entry exists and has not changed ", sticky ? "sticky " : "", - macaddr, ifp->name, - ifp->ifindex, vid, zevpn->vni, - local_inactive - ? " local_inactive" - : ""); + macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, + local_inactive ? " local_inactive" : ""); return 0; } if (mac_sticky != sticky) { if (sticky) SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); else - UNSET_FLAG(mac->flags, - ZEBRA_MAC_STICKY); + UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); inform_client = true; } @@ -2262,11 +2139,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* force drop the peer/sync info as it is * simply no longer relevant */ - if (CHECK_FLAG(mac->flags, - ZEBRA_MAC_ALL_PEER_FLAGS)) { + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS)) { zebra_evpn_mac_clear_sync_info(mac); - new_static = - zebra_evpn_mac_is_static(mac); + new_static = zebra_evpn_mac_is_static(mac); /* if we clear peer-flags we * also need to notify the dataplane * to drop the static flag @@ -2289,16 +2164,13 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, flog_warn( EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u", - macaddr, - &mac->fwd_info.r_vtep_ip, - zevpn->vni); + macaddr, &mac->fwd_info.r_vtep_ip, zevpn->vni); return 0; } /* If an actual move, compute MAC's seq number */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - mac->loc_seq = - MAX(mac->rem_seq + 1, mac->loc_seq); + mac->loc_seq = MAX(mac->rem_seq + 1, mac->loc_seq); vtep_ip = mac->fwd_info.r_vtep_ip; /* Trigger DAD for remote MAC */ do_dad = true; @@ -2307,8 +2179,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); - es_change = zebra_evpn_local_mac_update_fwd_info( - mac, ifp, vid); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); if (sticky) SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); else @@ -2321,8 +2192,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, upd_neigh = true; zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, vtep_ip, do_dad, &is_dup_detect, - true); + zvrf, mac, vtep_ip, do_dad, &is_dup_detect, true); if (is_dup_detect) { inform_client = false; upd_neigh = false; @@ -2357,8 +2227,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, "local mac vni %u mac %pEA es %s seq %d f %s%s", zevpn->vni, macaddr, mac->es ? mac->es->esi_str : "", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, - sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), local_inactive ? "local-inactive" : ""); } @@ -2374,18 +2243,15 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* Inform dataplane if required. */ if (inform_dataplane) zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); /* Inform BGP if required. */ if (inform_client) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); /* Process all neighbors associated with this MAC, if required. */ if (upd_neigh) - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, - es_change); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, es_change); return 0; } @@ -2415,23 +2281,20 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, "re-add sync-mac vni %u mac %pEA es %s seq %d f %s", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump( - mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); } /* inform-bgp about change in local-activity if any */ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) { SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); - new_bgp_ready = - zebra_evpn_mac_is_ready_for_bgp(mac->flags); + new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); zebra_evpn_mac_send_add_del_to_client( - mac, old_bgp_ready, new_bgp_ready); + mac, old_bgp_ready, new_bgp_ready); } /* re-install the inactive entry in the kernel */ zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */, - false /* force_clear_static */, - __func__); + false /* force_clear_static */, __func__); return 0; } @@ -2519,8 +2382,7 @@ void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn) old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI); - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - false); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, false); zebra_evpn_deref_ip2mac(mac->zevpn, mac); } } @@ -2548,13 +2410,11 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("SVI %s mac add", zif->ifp->name); - old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) - ? true - : false; + old_bgp_ready = + (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) ? true : false; zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false); new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, - new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); } diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index a5092c629ac7..75e7e20176a9 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -52,10 +52,9 @@ static void zebra_evpn_es_get_one_base_evpn(void); static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es, struct zebra_evpn *zevpn, bool add); static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp); -static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi); +static void zebra_evpn_local_es_update(struct zebra_if *zif); static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es, const char *caller); -static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set); static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es, bool resync_dplane); static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es); @@ -564,8 +563,9 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if) struct zebra_evpn_access_bd *acc_bd; struct interface *vlan_if; - if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("access vlan %d bridge %s add", vid, br_if->name); + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s access vlan %d bridge %s add", __func__, vid, + br_if->name); acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd)); @@ -583,8 +583,8 @@ zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if) vlan_if = zvni_map_to_svi(vid, br_if); if (vlan_if) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("vlan %d bridge %s SVI %s set", vid, - br_if->name, vlan_if->name); + zlog_debug("%s vlan %d bridge %s SVI %s set", __func__, + vid, br_if->name, vlan_if->name); acc_bd->vlan_zif = vlan_if->info; } return acc_bd; @@ -732,6 +732,29 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd, } } +/* Lookup API for VxLAN_IF's Bridge, VLAN in EVPN cache */ +int zebra_evpn_vl_vxl_bridge_lookup(uint16_t vid, struct zebra_if *vxlan_zif) +{ + struct interface *br_if; + struct zebra_evpn_access_bd *acc_bd; + + if (!vid) + return -1; + + br_if = vxlan_zif->brslave_info.br_if; + + if (!br_if) + return -1; + + acc_bd = zebra_evpn_acc_vl_find(vid, br_if); + + if (!acc_bd) + return 0; + + return 1; +} + + /* handle VLAN->VxLAN_IF association */ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id, struct zebra_if *vxlan_zif) @@ -769,8 +792,9 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id, if (acc_bd->zevpn == old_zevpn) return; - if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("access vlan %d vni %u ref", acc_bd->vid, vni_id); + if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s bridge %s access vlan %d vni %u ref", __func__, + br_if->name, acc_bd->vid, vni_id); if (old_zevpn) zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn); @@ -1139,7 +1163,7 @@ void zebra_evpn_if_init(struct zebra_if *zif) /* if an es_id and sysmac are already present against the interface * activate it */ - zebra_evpn_local_es_update(zif, &zif->es_info.esi); + zebra_evpn_local_es_update(zif); } /* handle deletion of an access port by removing it from all associated @@ -1936,7 +1960,7 @@ static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es) if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id()); stream_put(s, &es->esi, sizeof(esi_t)); @@ -1972,7 +1996,7 @@ static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es) if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); stream_reset(s); zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id()); @@ -2250,8 +2274,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, /* attach es to interface */ zif->es_info.es = es; - es->df_pref = zif->es_info.df_pref ? zif->es_info.df_pref - : EVPN_MH_DF_PREF_DEFAULT; + es->df_pref = zif->es_info.df_pref; /* attach interface to es */ es->zif = zif; @@ -2402,73 +2425,63 @@ static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp) } } +void zebra_build_type3_esi(uint32_t lid, struct ethaddr *mac, esi_t *esi) +{ + int offset = 0; + int field_bytes = 0; + + /* build 10-byte type-3-ESI - + * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes) + */ + field_bytes = 1; + esi->val[offset] = ESI_TYPE_MAC; + offset += field_bytes; + + field_bytes = ETH_ALEN; + memcpy(&esi->val[offset], (uint8_t *)mac, field_bytes); + offset += field_bytes; + + esi->val[offset++] = (uint8_t)(lid >> 16); + esi->val[offset++] = (uint8_t)(lid >> 8); + esi->val[offset++] = (uint8_t)lid; +} + /* A new local es is created when a local-es-id and sysmac is configured * against an interface. */ -static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi) +static void zebra_evpn_local_es_update(struct zebra_if *zif) { struct zebra_evpn_es *old_es = zif->es_info.es; struct zebra_evpn_es *es; + esi_t _esi, *esi; + + if (!zebra_evpn_is_if_es_capable(zif)) + return; + + if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) { + esi = &zif->es_info.esi; + } else if (zif->es_info.lid && !is_zero_mac(&zif->es_info.sysmac)) { + zebra_build_type3_esi(zif->es_info.lid, &zif->es_info.sysmac, + &_esi); + esi = &_esi; + } else { + esi = zero_esi; + } if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi))) /* dup - nothing to be done */ - return 0; + return; /* release the old_es against the zif */ if (old_es) zebra_evpn_local_es_del(&old_es); es = zebra_evpn_es_find(esi); - if (es) { - /* if it exists against another interface flag an error */ - if (es->zif && es->zif != zif) - return -1; - } else { - /* create new es */ + if (!es) es = zebra_evpn_es_new(esi); - } - memcpy(&zif->es_info.esi, esi, sizeof(*esi)); if (es) zebra_evpn_es_local_info_set(es, zif); - - return 0; -} - -static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid, - struct ethaddr *sysmac) -{ - struct zebra_evpn_es *old_es = zif->es_info.es; - esi_t esi; - int offset = 0; - int field_bytes = 0; - - /* Complete config of the ES-ID bootstraps the ES */ - if (!lid || is_zero_mac(sysmac)) { - /* clear old esi */ - memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi)); - /* if in ES is attached to zif delete it */ - if (old_es) - zebra_evpn_local_es_del(&old_es); - return 0; - } - - /* build 10-byte type-3-ESI - - * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes) - */ - field_bytes = 1; - esi.val[offset] = ESI_TYPE_MAC; - offset += field_bytes; - - field_bytes = ETH_ALEN; - memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes); - offset += field_bytes; - - esi.val[offset++] = (uint8_t)(lid >> 16); - esi.val[offset++] = (uint8_t)(lid >> 8); - esi.val[offset++] = (uint8_t)lid; - - return zebra_evpn_local_es_update(zif, &esi); } int zebra_evpn_remote_es_del(const esi_t *esi, struct in_addr vtep_ip) @@ -2651,7 +2664,7 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es, if (!client) return 0; - s = stream_new(ZEBRA_MAX_PACKET_SIZ); + s = stream_new(ZEBRA_SMALL_PACKET_SIZE); zclient_create_header(s, add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL, @@ -2673,44 +2686,33 @@ static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es, } /* sysmac part of a local ESI has changed */ -static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif, - struct ethaddr *sysmac) +void zebra_evpn_es_sys_mac_update(struct zebra_if *zif, struct ethaddr *sysmac) { - int rv; - - rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac); - if (!rv) + if (sysmac) memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr)); + else + memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr)); - return rv; + zebra_evpn_local_es_update(zif); } /* local-ID part of ESI has changed */ -static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid) +void zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid) { - int rv; - - rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac); - if (!rv) - zif->es_info.lid = lid; + zif->es_info.lid = lid; - return rv; + zebra_evpn_local_es_update(zif); } /* type-0 esi has changed */ -static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi) +void zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi) { - int rv; - - rv = zebra_evpn_local_es_update(zif, esi); - - /* clear the old es_lid, es_sysmac - type-0 is being set so old - * type-3 params need to be flushed - */ - memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr)); - zif->es_info.lid = 0; + if (esi) + memcpy(&zif->es_info.esi, esi, sizeof(*esi)); + else + memset(&zif->es_info.esi, 0, sizeof(*esi)); - return rv; + zebra_evpn_local_es_update(zif); } void zebra_evpn_es_cleanup(void) @@ -2726,10 +2728,9 @@ void zebra_evpn_es_cleanup(void) } } -static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) +void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) { struct zebra_evpn_es *es; - uint16_t tmp_pref; if (zif->es_info.df_pref == df_pref) return; @@ -2740,13 +2741,10 @@ static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref) if (!es) return; - tmp_pref = zif->es_info.df_pref ? zif->es_info.df_pref - : EVPN_MH_DF_PREF_DEFAULT; - - if (es->df_pref == tmp_pref) + if (es->df_pref == zif->es_info.df_pref) return; - es->df_pref = tmp_pref; + es->df_pref = zif->es_info.df_pref; /* run df election */ zebra_evpn_es_run_df_election(es, __func__); /* notify bgp */ @@ -2833,7 +2831,7 @@ void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es, zebra_evpn_es_br_port_dplane_update(es, __func__); } -static void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass) +void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass) { bool old_bypass = !!(zif->es_info.flags & ZIF_CFG_ES_FLAG_BYPASS); @@ -3028,7 +3026,7 @@ void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up) } static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es, - uint8_t vtep_str_size) + size_t vtep_str_size) { struct zebra_evpn_es_vtep *zvtep; struct listnode *node; @@ -3326,208 +3324,9 @@ void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi) vty_json(vty, json); } -int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp) -{ - struct zebra_if *zif = ifp->info; - char buf[ETHER_ADDR_STRLEN]; - bool type_3_esi = false; - char esi_buf[ESI_STR_LEN]; - - if (zif->es_info.lid) { - vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid); - type_3_esi = true; - } - - if (!is_zero_mac(&zif->es_info.sysmac)) { - vty_out(vty, " evpn mh es-sys-mac %s\n", - prefix_mac2str(&zif->es_info.sysmac, - buf, sizeof(buf))); - type_3_esi = true; - } - - if (!type_3_esi - && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) - vty_out(vty, " evpn mh es-id %s\n", - esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf))); - - if (zif->es_info.df_pref) - vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref); - - if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) - vty_out(vty, " evpn mh uplink\n"); - - return 0; -} - -#include "zebra/zebra_evpn_mh_clippy.c" -/* CLI for setting an ES in bypass mode */ -DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd, - "[no] evpn mh bypass", - NO_STR "EVPN\n" EVPN_MH_VTY_STR "set bypass mode\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - - zif = ifp->info; - - if (no) { - zebra_evpn_es_bypass_cfg_update(zif, false); - } else { - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% DF bypass cannot be associated with this interface type\n"); - return CMD_WARNING; - } - zebra_evpn_es_bypass_cfg_update(zif, true); - } - return CMD_SUCCESS; -} - -/* CLI for configuring DF preference part for an ES */ -DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd, - "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]", - NO_STR "EVPN\n" EVPN_MH_VTY_STR - "preference value used for DF election\n" - "pref\n") +void zebra_evpn_mh_if_init(struct zebra_if *zif) { - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - - zif = ifp->info; - - if (no) { - zebra_evpn_es_df_pref_update(zif, 0); - } else { - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% DF preference cannot be associated with this interface type\n"); - return CMD_WARNING; - } - zebra_evpn_es_df_pref_update(zif, df_pref); - } - return CMD_SUCCESS; -} - -/* CLI for setting up sysmac part of ESI on an access port */ -DEFPY(zebra_evpn_es_sys_mac, - zebra_evpn_es_sys_mac_cmd, - "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]", - NO_STR - "EVPN\n" - EVPN_MH_VTY_STR - "Ethernet segment system MAC\n" - MAC_STR -) -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - int ret = 0; - - zif = ifp->info; - - if (no) { - static struct ethaddr zero_mac; - - ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac); - if (ret == -1) { - vty_out(vty, "%% Failed to clear ES sysmac\n"); - return CMD_WARNING; - } - } else { - - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% ESI cannot be associated with this interface type\n"); - return CMD_WARNING; - } - - if (!mac || is_zero_mac(&mac->eth_addr)) { - vty_out(vty, "%% ES sysmac value is invalid\n"); - return CMD_WARNING; - } - - ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr); - if (ret == -1) { - vty_out(vty, - "%% ESI already exists on a different interface\n"); - return CMD_WARNING; - } - } - return CMD_SUCCESS; -} - -/* CLI for setting up local-ID part of ESI on an access port */ -DEFPY(zebra_evpn_es_id, - zebra_evpn_es_id_cmd, - "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]", - NO_STR - "EVPN\n" - EVPN_MH_VTY_STR - "Ethernet segment identifier\n" - "local discriminator\n" - "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n" -) -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - int ret = 0; - esi_t esi; - - zif = ifp->info; - - if (no) { - if (zif->es_info.lid) - ret = zebra_evpn_es_lid_update(zif, 0); - else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) - ret = zebra_evpn_es_type0_esi_update(zif, zero_esi); - - if (ret == -1) { - vty_out(vty, - "%% Failed to clear ES local id or ESI name\n"); - return CMD_WARNING; - } - } else { - if (!zebra_evpn_is_if_es_capable(zif)) { - vty_out(vty, - "%% ESI cannot be associated with this interface type\n"); - return CMD_WARNING; - } - - if (esi_str) { - if (!str_to_esi(esi_str, &esi)) { - vty_out(vty, "%% Malformed ESI name\n"); - return CMD_WARNING; - } - ret = zebra_evpn_es_type0_esi_update(zif, &esi); - } else { - if (!es_lid) { - vty_out(vty, - "%% Specify ES local id or ESI name\n"); - return CMD_WARNING; - } - ret = zebra_evpn_es_lid_update(zif, es_lid); - } - - if (ret == -1) { - vty_out(vty, - "%% ESI already exists on a different interface\n"); - return CMD_WARNING; - } - } - return CMD_SUCCESS; -} - -/* CLI for tagging an interface as an uplink */ -DEFPY(zebra_evpn_mh_uplink, zebra_evpn_mh_uplink_cmd, "[no] evpn mh uplink", - NO_STR "EVPN\n" EVPN_MH_VTY_STR "uplink to the VxLAN core\n") -{ - VTY_DECLVAR_CONTEXT(interface, ifp); - struct zebra_if *zif; - - zif = ifp->info; - zebra_evpn_mh_uplink_cfg_update(zif, no ? false : true); - - return CMD_SUCCESS; + zif->es_info.df_pref = EVPN_MH_DF_PREF_DEFAULT; } void zebra_evpn_mh_json(json_object *json) @@ -3864,7 +3663,7 @@ static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif, } } -static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set) +void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set) { bool old_protodown = zebra_evpn_mh_is_all_uplinks_down(); bool new_protodown; @@ -4087,15 +3886,6 @@ int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off) return 0; } -void zebra_evpn_interface_init(void) -{ - install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd); - install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd); -} - void zebra_evpn_mh_init(void) { zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info)); diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 59a41d060699..f68e2eae6005 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -17,8 +17,7 @@ #include "zebra_vxlan.h" #include "zebra_vxlan_private.h" #include "zebra_nhg.h" - -#define EVPN_MH_VTY_STR "Multihoming\n" +#include "zebra_nb.h" /* Ethernet Segment entry - * - Local and remote ESs are maintained in a global RB tree, @@ -155,7 +154,7 @@ struct zebra_evpn_es_vtep { /* Parameters for DF election */ uint8_t df_alg; - uint32_t df_pref; + uint16_t df_pref; /* XXX - maintain a backpointer to struct zebra_vtep */ }; @@ -336,8 +335,6 @@ extern bool zebra_evpn_es_mac_ref_entry(struct zebra_mac *mac, struct zebra_evpn_es *es); extern bool zebra_evpn_es_mac_ref(struct zebra_mac *mac, const esi_t *esi); extern struct zebra_evpn_es *zebra_evpn_es_find(const esi_t *esi); -extern void zebra_evpn_interface_init(void); -extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp); extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj); extern void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj); extern void zebra_evpn_if_es_print(struct vty *vty, json_object *json, @@ -381,5 +378,18 @@ extern void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es, extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS); extern struct zebra_evpn_es_evi * zebra_evpn_es_evi_find(struct zebra_evpn_es *es, struct zebra_evpn *zevpn); +extern int zebra_evpn_vl_vxl_bridge_lookup(uint16_t vid, + struct zebra_if *vxlan_zif); +void zebra_build_type3_esi(uint32_t lid, struct ethaddr *mac, esi_t *esi); + +void zebra_evpn_es_sys_mac_update(struct zebra_if *zif, struct ethaddr *sysmac); +void zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid); +void zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi); + +void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref); +void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass); +void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set); + +void zebra_evpn_mh_if_init(struct zebra_if *zif); #endif /* _ZEBRA_EVPN_MH_H */ diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index a00d8c969af0..81705d4e8512 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -6,6 +6,10 @@ #include +#ifdef GNU_LINUX +#include +#endif + #include "hash.h" #include "interface.h" #include "jhash.h" diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 699f3ed11064..92dc591d40e1 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -8,6 +8,10 @@ #include +#ifdef GNU_LINUX +#include +#endif + #include "log.h" #include "libfrr.h" #include "stream.h" diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index 94308a961b07..ce5eb6fe1573 100644 --- a/zebra/zebra_fpm_dt.c +++ b/zebra/zebra_fpm_dt.c @@ -22,6 +22,10 @@ */ #include + +#ifdef GNU_LINUX +#include +#endif #include "log.h" #include "vrf.h" diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 127976223221..95207ce75cb2 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -11,6 +11,9 @@ #ifdef HAVE_NETLINK +#include +#include + #include "log.h" #include "rib.h" #include "vty.h" @@ -589,19 +592,19 @@ int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, RTM_DELNEIGH : RTM_NEWNEIGH; req->hdr.nlmsg_flags = NLM_F_REQUEST; if (req->hdr.nlmsg_type == RTM_NEWNEIGH) - req->hdr.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + SET_FLAG(req->hdr.nlmsg_flags, (NLM_F_CREATE | NLM_F_REPLACE)); /* Construct ndmsg */ req->ndm.ndm_family = AF_BRIDGE; req->ndm.ndm_ifindex = mac->vxlan_if; req->ndm.ndm_state = NUD_REACHABLE; - req->ndm.ndm_flags |= NTF_SELF | NTF_MASTER; + SET_FLAG(req->ndm.ndm_flags, (NTF_SELF | NTF_MASTER)); if (CHECK_FLAG(mac->zebra_flags, (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW))) - req->ndm.ndm_state |= NUD_NOARP; + SET_FLAG(req->ndm.ndm_state, NUD_NOARP); else - req->ndm.ndm_flags |= NTF_EXT_LEARNED; + SET_FLAG(req->ndm.ndm_flags, NTF_EXT_LEARNED); /* Add attributes */ nl_attr_put(&req->hdr, in_buf_len, NDA_LLADDR, &mac->macaddr, 6); diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index 39fd8641de23..07391b7ac719 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -103,6 +103,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) info->stale_client_ptr = client; TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + info->client_ptr = client; return info; } @@ -290,6 +291,7 @@ struct zebra_gr_afi_clean { afi_t afi; uint8_t proto; uint8_t instance; + time_t restart_time; struct event *t_gac; }; @@ -298,6 +300,16 @@ struct zebra_gr_afi_clean { * Functions to deal with capabilities */ +void zebra_gr_client_final_shutdown(struct zserv *client) +{ + struct client_gr_info *info; + + while (!TAILQ_EMPTY(&client->gr_info_queue)) { + info = TAILQ_FIRST(&client->gr_info_queue); + zebra_gr_client_info_delete(client, info); + } +} + /* * Function to decode and call appropriate functions * to handle client capabilities. @@ -327,7 +339,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) return; /* GR only for dynamic clients */ - if (client->proto <= ZEBRA_ROUTE_CONNECT) { + if (client->proto <= ZEBRA_ROUTE_LOCAL) { LOG_GR("%s: GR capabilities for client %s not supported", __func__, zebra_route_string(client->proto)); return; @@ -410,7 +422,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Schedule for after anything already in the meta Q */ rib_add_gr_run(api.afi, api.vrf_id, client->proto, - client->instance); + client->instance, client->restart_time); zebra_gr_process_client_stale_routes(client, info); break; case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -445,7 +457,11 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) struct zserv *client; struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - client = (struct zserv *)info->stale_client_ptr; + info->t_stale_removal = NULL; + if (zrouter.graceful_restart) + client = (struct zserv *)info->client_ptr; + else + client = (struct zserv *)info->stale_client_ptr; cnt = zebra_gr_delete_stale_routes(info); @@ -476,16 +492,24 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) * * Returns true when a node is deleted else false */ -static bool zebra_gr_process_route_entry(struct zserv *client, - struct route_node *rn, - struct route_entry *re) +static bool zebra_gr_process_route_entry(struct route_node *rn, + struct route_entry *re, + time_t compare_time, uint8_t proto) { + struct nexthop *nexthop; + char buf[PREFIX2STR_BUFFER]; + /* If the route is not refreshed after restart, delete the entry */ - if (re->uptime < client->restart_time) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: Client %s stale route %pFX is deleted", - __func__, zebra_route_string(client->proto), - &rn->p); + if (re->uptime < compare_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(proto), buf); + } + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + rib_delnode(rn, re); return true; @@ -522,8 +546,9 @@ static void zebra_gr_delete_stale_route_table_afi(struct event *event) if (re->type == gac->proto && re->instance == gac->instance && - zebra_gr_process_route_entry( - gac->info->stale_client_ptr, rn, re)) + zebra_gr_process_route_entry(rn, re, + gac->restart_time, + gac->proto)) n++; /* If the max route count is reached @@ -557,28 +582,42 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, uint8_t proto; uint16_t instance; struct zserv *s_client; + struct zserv *client; + time_t restart_time; - s_client = info->stale_client_ptr; - if (s_client == NULL) { - LOG_GR("%s: Stale client %s(%u) not present", __func__, - zvrf->vrf->name, zvrf->vrf->vrf_id); + if ((info == NULL) || (zvrf == NULL)) return -1; - } - proto = s_client->proto; - instance = s_client->instance; + if (zrouter.graceful_restart) { + client = info->client_ptr; + if (client == NULL) { + LOG_GR("%s: client not present", __func__); + return -1; + } + proto = client->proto; + instance = client->instance; + restart_time = zrouter.startup_time; + } else { + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + proto = s_client->proto; + instance = s_client->instance; + restart_time = s_client->restart_time; + } LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__, zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id); /* Process routes for all AFI */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - /* * Schedule for immediately after anything in the * meta-Q */ - rib_add_gr_run(afi, info->vrf_id, proto, instance); + rib_add_gr_run(afi, info->vrf_id, proto, instance, restart_time); } return 0; } @@ -631,12 +670,13 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, /* * Route update completed for all AFI, SAFI - * Cancel the stale timer, routes are already being processed + * Also perform the cleanup if FRR itself is gracefully restarting. */ - if (info->t_stale_removal) { + info->route_sync_done_time = monotime(NULL); + if (info->t_stale_removal || zrouter.graceful_restart) { struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)", + LOG_GR("%s: Client %s route update complete for all AFI/SAFI in vrf %s(%d)", __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf), info->vrf_id); EVENT_OFF(info->t_stale_removal); @@ -644,7 +684,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, } void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance) + uint8_t instance, time_t restart_time) { struct zserv *client = zserv_find_client(proto, instance); struct client_gr_info *info = NULL; @@ -666,6 +706,7 @@ void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, gac->afi = afi; gac->proto = proto; gac->instance = instance; + gac->restart_time = restart_time; event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi, gac, 0, &gac->t_gac); diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 4f7a1cd4cead..240f674b0f55 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -111,13 +111,13 @@ static void zebra_l2_bond_lacp_bypass_eval(struct zebra_if *bond_zif) { struct listnode *node; struct zebra_if *bond_mbr; - bool old_bypass = !!(bond_zif->flags & ZIF_FLAG_LACP_BYPASS); + bool old_bypass = !!CHECK_FLAG(bond_zif->flags, ZIF_FLAG_LACP_BYPASS); bool new_bypass = false; if (bond_zif->bond_info.mbr_zifs) { for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, bond_mbr)) { - if (bond_mbr->flags & ZIF_FLAG_LACP_BYPASS) { + if (CHECK_FLAG(bond_mbr->flags, ZIF_FLAG_LACP_BYPASS)) { new_bypass = true; break; } @@ -132,9 +132,9 @@ static void zebra_l2_bond_lacp_bypass_eval(struct zebra_if *bond_zif) bond_zif->ifp->name, new_bypass ? "on" : "off"); if (new_bypass) - bond_zif->flags |= ZIF_FLAG_LACP_BYPASS; + SET_FLAG(bond_zif->flags, ZIF_FLAG_LACP_BYPASS); else - bond_zif->flags &= ~ZIF_FLAG_LACP_BYPASS; + UNSET_FLAG(bond_zif->flags, ZIF_FLAG_LACP_BYPASS); if (bond_zif->es_info.es) zebra_evpn_es_bypass_update(bond_zif->es_info.es, bond_zif->ifp, @@ -174,8 +174,7 @@ void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id) } } else { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bond mbr %s link to bond skipped", - zif->ifp->name); + zlog_debug("bond mbr %s link to bond skipped", zif->ifp->name); } } @@ -186,8 +185,7 @@ void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif) if (!bond_slave->bond_if) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bond mbr %s unlink from bond skipped", - zif->ifp->name); + zlog_debug("bond mbr %s unlink from bond skipped", zif->ifp->name); return; } @@ -218,8 +216,7 @@ void zebra_l2if_update_bond(struct interface *ifp, bool add) if (add) { if (!bond->mbr_zifs) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) - zlog_debug("bond %s mbr list create", - ifp->name); + zlog_debug("bond %s mbr list create", ifp->name); bond->mbr_zifs = list_new(); } } else { @@ -347,7 +344,7 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp, ctx.old_vtep_ip = zif->l2info.vxl.vtep_ip; if (!IPV4_ADDR_SAME(&ctx.old_vtep_ip, &vxlan_info->vtep_ip)) { - chgflags |= ZEBRA_VXLIF_LOCAL_IP_CHANGE; + SET_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE); zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip; } @@ -355,7 +352,7 @@ void zebra_l2_vxlanif_add_update(struct interface *ifp, ctx.old_vni = vxlan_info->vni_info.vni; if (!IPV4_ADDR_SAME(&zif->l2info.vxl.vni_info.vni.mcast_grp, &vxlan_info->vni_info.vni.mcast_grp)) { - chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE; + SET_FLAG(chgflags, ZEBRA_VXLIF_MCAST_GRP_CHANGE); zif->l2info.vxl.vni_info.vni.mcast_grp = vxlan_info->vni_info.vni.mcast_grp; } @@ -387,7 +384,7 @@ void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, return; old_access_vlan = zif->l2info.vxl.vni_info.vni.access_vlan; - ; + if (old_access_vlan == access_vlan) return; @@ -441,11 +438,11 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, if (zif->zif_type == ZEBRA_IF_VXLAN && chgflags != ZEBRA_BRIDGE_NO_ACTION) { - if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_BRIDGE_MASTER_MAC_CHANGE)) { ctx.chgflags = ZEBRA_VXLIF_MASTER_MAC_CHANGE; zebra_vxlan_if_update(ifp, &ctx); } - if (chgflags & ZEBRA_BRIDGE_MASTER_UP) { + if (CHECK_FLAG(chgflags, ZEBRA_BRIDGE_MASTER_UP)) { ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE; zebra_vxlan_if_update(ifp, &ctx); } @@ -494,16 +491,16 @@ void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, zif = ifp->info; assert(zif); - old_bypass = !!(zif->flags & ZIF_FLAG_LACP_BYPASS); + old_bypass = !!CHECK_FLAG(zif->flags, ZIF_FLAG_LACP_BYPASS); if (old_bypass != new_bypass) { if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) zlog_debug("bond-mbr %s lacp bypass changed to %s", zif->ifp->name, new_bypass ? "on" : "off"); if (new_bypass) - zif->flags |= ZIF_FLAG_LACP_BYPASS; + SET_FLAG(zif->flags, ZIF_FLAG_LACP_BYPASS); else - zif->flags &= ~ZIF_FLAG_LACP_BYPASS; + UNSET_FLAG(zif->flags, ZIF_FLAG_LACP_BYPASS); bond_mbr = &zif->bondslave_info; if (bond_mbr->bond_if) { diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 7715eab0a8d6..8fd373cb19d1 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -627,6 +627,8 @@ void zebra_mlag_init(void) void zebra_mlag_terminate(void) { + stream_fifo_free(zrouter.mlag_info.mlag_fifo); + zrouter.mlag_info.mlag_fifo = NULL; } @@ -983,8 +985,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, /* No Batching */ stream_putw(s, MLAG_MSG_NO_BATCH); /* Actual Data */ - zebra_fill_protobuf_msg(s, msg->peerlink, - INTERFACE_NAMSIZ); + zebra_fill_protobuf_msg(s, msg->peerlink, IFNAMSIZ); stream_putl(s, msg->my_role); stream_putl(s, msg->peer_state); zebra_mlag_status_update__free_unpacked(msg, NULL); @@ -1032,9 +1033,9 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) zebra_fill_protobuf_msg(s, msg->intf_name, - INTERFACE_NAMSIZ); + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); zebra_mlag_mroute_add__free_unpacked(msg, NULL); } break; case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL: { @@ -1059,9 +1060,9 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) zebra_fill_protobuf_msg(s, msg->intf_name, - INTERFACE_NAMSIZ); + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); zebra_mlag_mroute_del__free_unpacked(msg, NULL); } break; case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: { @@ -1083,8 +1084,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, /* Actual Data */ for (i = 0; i < Bulk_msg->n_mroute_add; i++) { - if (STREAM_SIZE(s) - < VRF_NAMSIZ + 22 + INTERFACE_NAMSIZ) { + if (STREAM_SIZE(s) < VRF_NAMSIZ + 22 + IFNAMSIZ) { zlog_warn( "We have received more messages than we can parse at this point in time: %zu", Bulk_msg->n_mroute_add); @@ -1103,11 +1103,11 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putc(s, msg->am_i_dual_active); stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) - zebra_fill_protobuf_msg( - s, msg->intf_name, - INTERFACE_NAMSIZ); + zebra_fill_protobuf_msg(s, + msg->intf_name, + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); } stream_putw_at(s, length_spot, i + 1); @@ -1134,8 +1134,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, /* Actual Data */ for (i = 0; i < Bulk_msg->n_mroute_del; i++) { - if (STREAM_SIZE(s) - < VRF_NAMSIZ + 16 + INTERFACE_NAMSIZ) { + if (STREAM_SIZE(s) < VRF_NAMSIZ + 16 + IFNAMSIZ) { zlog_warn( "We have received more messages than we can parse at this time"); break; @@ -1150,11 +1149,11 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data, stream_putl(s, msg->owner_id); stream_putl(s, msg->vrf_id); if (msg->owner_id == MLAG_OWNER_INTERFACE) - zebra_fill_protobuf_msg( - s, msg->intf_name, - INTERFACE_NAMSIZ); + zebra_fill_protobuf_msg(s, + msg->intf_name, + IFNAMSIZ); else - stream_put(s, NULL, INTERFACE_NAMSIZ); + stream_put(s, NULL, IFNAMSIZ); } stream_putw_at(s, length_spot, i + 1); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index eac4fcc8e060..d1c9cd54affc 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -329,7 +329,7 @@ static void fec_evaluate(struct zebra_vrf *zvrf) /* Skip configured FECs and those without a label index. */ - if (fec->flags & FEC_FLAG_CONFIGURED + if (CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED) || fec->label_index == MPLS_INVALID_LABEL_INDEX) continue; @@ -616,8 +616,9 @@ static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe, for (match_nh = match->nhe->nhg.nexthop; match_nh; match_nh = match_nh->next) { - if (match->type == ZEBRA_ROUTE_CONNECT - || nexthop->ifindex == match_nh->ifindex) { + if ((match->type == ZEBRA_ROUTE_CONNECT || + match->type == ZEBRA_ROUTE_LOCAL) || + nexthop->ifindex == match_nh->ifindex) { nexthop->ifindex = match_nh->ifindex; return 1; } @@ -659,9 +660,10 @@ static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe, /* Locate a valid connected route. */ RNODE_FOREACH_RE (rn, match) { - if ((match->type == ZEBRA_ROUTE_CONNECT) - && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED) - && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) + if (((match->type == ZEBRA_ROUTE_CONNECT || + match->type == ZEBRA_ROUTE_LOCAL)) && + !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED) && + CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) break; } @@ -1182,6 +1184,7 @@ static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size) break; case NEXTHOP_TYPE_IFINDEX: snprintf(buf, size, "Ifindex: %u", nexthop->ifindex); + break; case NEXTHOP_TYPE_BLACKHOLE: break; } @@ -1769,9 +1772,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) label = dplane_ctx_get_in_label(ctx); - switch (op) { - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: + if (op == DPLANE_OP_LSP_INSTALL || op == DPLANE_OP_LSP_UPDATE) { /* Look for zebra LSP object */ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); lsp_table = zvrf->lsp_table; @@ -1782,7 +1783,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) if (IS_ZEBRA_DEBUG_DPLANE) zlog_debug("LSP ctx %p: in-label %u not found", ctx, dplane_ctx_get_in_label(ctx)); - break; + return; } /* TODO -- Confirm that this result is still 'current' */ @@ -1793,7 +1794,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE, "LSP Install Failure: in-label %u", lsp->ile.in_label); - break; + return; } /* Update zebra object */ @@ -1814,74 +1815,16 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx) ? ZEBRA_SR_POLICY_LABEL_CREATED : ZEBRA_SR_POLICY_LABEL_UPDATED; zebra_sr_policy_label_update(label, update_mode); - break; - - case DPLANE_OP_LSP_DELETE: + } else if (op == DPLANE_OP_LSP_DELETE) { if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) { flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE, "LSP Deletion Failure: in-label %u", dplane_ctx_get_in_label(ctx)); - break; + return; } zebra_sr_policy_label_update(label, ZEBRA_SR_POLICY_LABEL_REMOVED); - break; - - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: - break; - - } /* Switch */ + } } /* @@ -2348,7 +2291,7 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p, new_client = true; } else { /* Check if the FEC has been statically defined in the config */ - is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED; + is_configured_fec = CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED); /* Client may register same FEC with different label index. */ new_client = (listnode_lookup(fec->client_list, client) == NULL); @@ -2439,8 +2382,8 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, /* If not a configured entry, delete the FEC if no other clients. Before * deleting, see if any LSP needs to be uninstalled. */ - if (!(fec->flags & FEC_FLAG_CONFIGURED) - && list_isempty(fec->client_list)) { + if (!CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED) && + list_isempty(fec->client_list)) { mpls_label_t old_label = fec->label; fec->label = MPLS_INVALID_LABEL; /* reset */ fec_change_update_lsp(zvrf, fec, old_label); @@ -2477,7 +2420,7 @@ static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client) if (fec_client == client) { listnode_delete(fec->client_list, fec_client); - if (!(fec->flags & FEC_FLAG_CONFIGURED) + if (!CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED) && list_isempty(fec->client_list)) fec_del(fec); break; @@ -2533,7 +2476,7 @@ static int zebra_mpls_cleanup_zclient_labels(struct zserv *client) * hash.. */ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, - mpls_label_t label) + struct prefix *p, mpls_label_t label) { struct route_node *rn; struct zebra_fec *fec; @@ -2548,8 +2491,11 @@ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, if (!rn->info) continue; fec = rn->info; - if (fec->label == label) + if (fec->label == label) { + if (p && prefix_same(p, &rn->p)) + return NULL; return fec; + } } } @@ -2559,9 +2505,10 @@ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, /* * Inform if specified label is currently bound to a FEC or not. */ -int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label) +int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t label) { - return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0); + return (zebra_mpls_fec_for_label(zvrf, p, label) ? 1 : 0); } /* @@ -2595,7 +2542,7 @@ int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p, if (IS_ZEBRA_DEBUG_MPLS) zlog_debug("Add fec %pFX label %u", p, in_label); } else { - fec->flags |= FEC_FLAG_CONFIGURED; + SET_FLAG(fec->flags, FEC_FLAG_CONFIGURED); if (fec->label == in_label) /* Duplicate config */ return 0; @@ -2644,7 +2591,7 @@ int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p) } old_label = fec->label; - fec->flags &= ~FEC_FLAG_CONFIGURED; + UNSET_FLAG(fec->flags, FEC_FLAG_CONFIGURED); fec->label = MPLS_INVALID_LABEL; /* If no client exists, just delete the FEC. */ @@ -2687,12 +2634,20 @@ int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf) char lstr[BUFSIZ]; fec = rn->info; - if (!(fec->flags & FEC_FLAG_CONFIGURED)) + if (!CHECK_FLAG(fec->flags, FEC_FLAG_CONFIGURED)) continue; write = 1; - vty_out(vty, "mpls label bind %pFX %s\n", &rn->p, - label2str(fec->label, 0, lstr, BUFSIZ)); + + if (fec->label == MPLS_LABEL_IPV4_EXPLICIT_NULL || + fec->label == MPLS_LABEL_IPV6_EXPLICIT_NULL) + strlcpy(lstr, "explicit-null", sizeof(lstr)); + else if (fec->label == MPLS_LABEL_IMPLICIT_NULL) + strlcpy(lstr, "implicit-null", sizeof(lstr)); + else + snprintf(lstr, sizeof(lstr), "%d", fec->label); + + vty_out(vty, "mpls label bind %pFX %s\n", &rn->p, lstr); } } @@ -4093,10 +4048,12 @@ void zebra_mpls_turned_on(void) if (!mpls_enabled) { mpls_processq_init(); mpls_enabled = true; - } - hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); - hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels); + hook_register(zserv_client_close, + zebra_mpls_cleanup_fecs_for_client); + hook_register(zserv_client_close, + zebra_mpls_cleanup_zclient_labels); + } } /* @@ -4115,3 +4072,9 @@ void zebra_mpls_init(void) zebra_mpls_turned_on(); } + +void zebra_mpls_terminate(void) +{ + hook_unregister(zserv_client_close, zebra_mpls_cleanup_fecs_for_client); + hook_unregister(zserv_client_close, zebra_mpls_cleanup_zclient_labels); +} diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index 7feace56b55d..dd6f9601468a 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -203,12 +203,13 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p, * hash.. */ struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf, - mpls_label_t label); + struct prefix *p, mpls_label_t label); /* * Inform if specified label is currently bound to a FEC or not. */ -int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label); +int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, struct prefix *p, + mpls_label_t label); /* * Add static FEC to label binding. If there are clients registered for this @@ -400,9 +401,10 @@ void zebra_mpls_init_tables(struct zebra_vrf *zvrf); void zebra_mpls_turned_on(void); /* - * Global MPLS initialization. + * Global MPLS initialization/termination. */ void zebra_mpls_init(void); +void zebra_mpls_terminate(void); /* * MPLS VTY. diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index 4bc676f3926e..f0f2c4b7a333 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -4,9 +4,13 @@ */ #include +#include #ifdef HAVE_NETLINK +#include +#include + #include "zebra/debug.h" #include "zebra/rt.h" #include "zebra/rt_netlink.h" diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index 5015f2ed1adf..85a53dd4c5a3 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -4,6 +4,8 @@ */ #include +#include +#include #ifdef OPEN_BSD @@ -62,8 +64,8 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, sa_label_in.smpls_family = AF_MPLS; sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_flags |= RTF_MPLS | RTF_MPATH; - hdr.rtm_addrs |= RTA_DST; + SET_FLAG(hdr.rtm_flags, (RTF_MPLS | RTF_MPATH)); + SET_FLAG(hdr.rtm_addrs, RTA_DST); hdr.rtm_msglen += sizeof(sa_label_in); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_in; @@ -75,8 +77,8 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, nexthop.sin_family = AF_INET; nexthop.sin_addr = nhlfe->nexthop->gate.ipv4; /* adjust header */ - hdr.rtm_flags |= RTF_GATEWAY; - hdr.rtm_addrs |= RTA_GATEWAY; + SET_FLAG(hdr.rtm_flags, RTF_GATEWAY); + SET_FLAG(hdr.rtm_addrs, RTA_GATEWAY); hdr.rtm_msglen += sizeof(nexthop); /* adjust iovec */ iov[iovcnt].iov_base = &nexthop; @@ -91,8 +93,8 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label, htonl(nhlfe->nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_addrs |= RTA_SRC; - hdr.rtm_flags |= RTF_MPLS; + SET_FLAG(hdr.rtm_addrs, RTA_SRC); + SET_FLAG(hdr.rtm_flags, RTF_MPLS); hdr.rtm_msglen += sizeof(sa_label_out); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_out; @@ -157,8 +159,8 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, sa_label_in.smpls_family = AF_MPLS; sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_flags |= RTF_MPLS | RTF_MPATH; - hdr.rtm_addrs |= RTA_DST; + SET_FLAG(hdr.rtm_flags, (RTF_MPLS | RTF_MPATH)); + SET_FLAG(hdr.rtm_addrs, RTA_DST); hdr.rtm_msglen += sizeof(sa_label_in); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_in; @@ -182,8 +184,8 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, } /* adjust header */ - hdr.rtm_flags |= RTF_GATEWAY; - hdr.rtm_addrs |= RTA_GATEWAY; + SET_FLAG(hdr.rtm_flags, RTF_GATEWAY); + SET_FLAG(hdr.rtm_addrs, RTA_GATEWAY); hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6)); /* adjust iovec */ iov[iovcnt].iov_base = &nexthop; @@ -198,8 +200,8 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label, htonl(nhlfe->nexthop->nh_label->label[0] << MPLS_LABEL_OFFSET); /* adjust header */ - hdr.rtm_addrs |= RTA_SRC; - hdr.rtm_flags |= RTF_MPLS; + SET_FLAG(hdr.rtm_addrs, RTA_SRC); + SET_FLAG(hdr.rtm_flags, RTF_MPLS); hdr.rtm_msglen += sizeof(sa_label_out); /* adjust iovec */ iov[iovcnt].iov_base = &sa_label_out; @@ -229,71 +231,18 @@ static int kernel_lsp_cmd(struct zebra_dplane_ctx *ctx) const struct nexthop *nexthop = NULL; unsigned int nexthop_num = 0; int action; + enum dplane_op_e op; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_LSP_DELETE: + op = dplane_ctx_get_op(ctx); + + if (op == DPLANE_OP_LSP_DELETE) action = RTM_DELETE; - break; - case DPLANE_OP_LSP_INSTALL: + else if (op == DPLANE_OP_LSP_INSTALL) action = RTM_ADD; - break; - case DPLANE_OP_LSP_UPDATE: + else if (op == DPLANE_OP_LSP_UPDATE) action = RTM_CHANGE; - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: + else return -1; - } head = dplane_ctx_get_nhlfe_list(ctx); frr_each(nhlfe_list_const, head, nhlfe) { @@ -375,8 +324,8 @@ static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_FAILURE; } - if (dplane_ctx_get_pw_flags(ctx) & F_PSEUDOWIRE_CWORD) - imr.imr_flags |= IMR_FLAG_CONTROLWORD; + if (CHECK_FLAG(dplane_ctx_get_pw_flags(ctx), F_PSEUDOWIRE_CWORD)) + SET_FLAG(imr.imr_flags, IMR_FLAG_CONTROLWORD); /* pseudowire nexthop */ memset(&ss, 0, sizeof(ss)); @@ -443,69 +392,14 @@ static enum zebra_dplane_result kmpw_uninstall(struct zebra_dplane_ctx *ctx) enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx) { enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + enum dplane_op_e op; - switch (dplane_ctx_get_op(ctx)) { - case DPLANE_OP_PW_INSTALL: + op = dplane_ctx_get_op(ctx); + + if (op == DPLANE_OP_PW_INSTALL) result = kmpw_install(ctx); - break; - case DPLANE_OP_PW_UNINSTALL: + else if (op == DPLANE_OP_PW_UNINSTALL) result = kmpw_uninstall(ctx); - break; - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: - break; - } return result; } diff --git a/zebra/zebra_mpls_vty.c b/zebra/zebra_mpls_vty.c index e64e7009b4d2..b31bf449a9a4 100644 --- a/zebra/zebra_mpls_vty.c +++ b/zebra/zebra_mpls_vty.c @@ -22,6 +22,7 @@ #include "zebra/zebra_rnh.h" #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" +#include "zebra/label_manager.h" static int zebra_mpls_transit_lsp(struct vty *vty, int add_cmd, const char *inlabel_str, const char *gate_str, @@ -209,7 +210,7 @@ static int zebra_mpls_bind(struct vty *vty, int add_cmd, const char *prefix, vty_out(vty, "%% Invalid label\n"); return CMD_WARNING_CONFIG_FAILED; } - if (zebra_mpls_label_already_bound(zvrf, label)) { + if (zebra_mpls_label_already_bound(zvrf, &p, label)) { vty_out(vty, "%% Label already bound to a FEC\n"); return CMD_WARNING_CONFIG_FAILED; @@ -246,7 +247,7 @@ DEFUN (mpls_label_bind, DEFUN (no_mpls_label_bind, no_mpls_label_bind_cmd, - "no mpls label bind [<(16-1048575)|implicit-null>]", + "no mpls label bind [<(16-1048575)|implicit-null|explicit-null>]", NO_STR MPLS_STR "Label configuration\n" @@ -254,7 +255,8 @@ DEFUN (no_mpls_label_bind, "IPv4 prefix\n" "IPv6 prefix\n" "MPLS Label to bind\n" - "Use Implicit-Null Label\n") + "Use Implicit-Null Label\n" + "Use Explicit-Null Label\n") { return zebra_mpls_bind(vty, 0, argv[4]->arg, NULL); } @@ -270,6 +272,8 @@ static int zebra_mpls_config(struct vty *vty) write += zebra_mpls_write_lsp_config(vty, zvrf); write += zebra_mpls_write_fec_config(vty, zvrf); write += zebra_mpls_write_label_block_config(vty, zvrf); + write += lm_write_label_block_config_call(vty, zvrf); + return write; } diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index a93dbbb008cc..eee9323082ff 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -10,9 +10,20 @@ #include "libfrr.h" #include "zebra_nb.h" +const char *features[] = { +#if HAVE_BFDD == 0 + "ptm-bfd", +#endif +#if defined(HAVE_RTADV) + "ipv6-router-advertisements", +#endif + NULL +}; + /* clang-format off */ const struct frr_yang_module_info frr_zebra_info = { .name = "frr-zebra", + .features = features, .nodes = { { .xpath = "/frr-zebra:zebra/mcast-rpf-lookup", @@ -79,6 +90,20 @@ const struct frr_yang_module_info frr_zebra_info = { .modify = zebra_dplane_queue_limit_modify, } }, +#if HAVE_BFDD == 0 + { + .xpath = "/frr-zebra:zebra/ptm-enable", + .cbs = { + .modify = zebra_ptm_enable_modify, + } + }, +#endif + { + .xpath = "/frr-zebra:zebra/route-map-delay", + .cbs = { + .modify = zebra_route_map_delay_modify, + } + }, { .xpath = "/frr-zebra:zebra/debugs/debug-events", .cbs = { @@ -290,24 +315,38 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs", + .cbs = { + .create = lib_interface_zebra_ipv4_addrs_create, + .destroy = lib_interface_zebra_ipv4_addrs_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs/label", + .cbs = { + .modify = lib_interface_zebra_ipv4_addrs_label_modify, + .destroy = lib_interface_zebra_ipv4_addrs_label_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs", .cbs = { - .create = lib_interface_zebra_ip_addrs_create, - .destroy = lib_interface_zebra_ip_addrs_destroy, + .create = lib_interface_zebra_ipv4_p2p_addrs_create, + .destroy = lib_interface_zebra_ipv4_p2p_addrs_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/label", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs/label", .cbs = { - .modify = lib_interface_zebra_ip_addrs_label_modify, - .destroy = lib_interface_zebra_ip_addrs_label_destroy, + .modify = lib_interface_zebra_ipv4_p2p_addrs_label_modify, + .destroy = lib_interface_zebra_ipv4_p2p_addrs_label_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/ip4-peer", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-addrs", .cbs = { - .modify = lib_interface_zebra_ip_addrs_ip4_peer_modify, - .destroy = lib_interface_zebra_ip_addrs_ip4_peer_destroy, + .create = lib_interface_zebra_ipv6_addrs_create, + .destroy = lib_interface_zebra_ipv6_addrs_destroy, } }, { @@ -321,14 +360,13 @@ const struct frr_yang_module_info frr_zebra_info = { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-detect", .cbs = { .modify = lib_interface_zebra_link_detect_modify, - .destroy = lib_interface_zebra_link_detect_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/shutdown", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/enabled", .cbs = { - .modify = lib_interface_zebra_shutdown_modify, - .destroy = lib_interface_zebra_shutdown_destroy, + .modify = lib_interface_zebra_enabled_modify, + .destroy = lib_interface_zebra_enabled_destroy, } }, { @@ -346,10 +384,66 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { - .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/bandwidth", + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params", .cbs = { - .modify = lib_interface_zebra_bandwidth_modify, - .destroy = lib_interface_zebra_bandwidth_destroy, + .create = lib_interface_zebra_link_params_create, + .destroy = lib_interface_zebra_link_params_destroy, + .apply_finish = lib_interface_zebra_link_params_apply_finish, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/metric", + .cbs = { + .modify = lib_interface_zebra_link_params_metric_modify, + .destroy = lib_interface_zebra_link_params_metric_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_max_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_max_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/max-reservable-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_max_reservable_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_max_reservable_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth", + .cbs = { + .create = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_create, + .destroy = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth/unreserved-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/residual-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_residual_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_residual_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/available-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_available_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_available_bandwidth_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/utilized-bandwidth", + .cbs = { + .modify = lib_interface_zebra_link_params_utilized_bandwidth_modify, + .destroy = lib_interface_zebra_link_params_utilized_bandwidth_destroy, } }, { @@ -357,13 +451,13 @@ const struct frr_yang_module_info frr_zebra_info = { .cbs = { .modify = lib_interface_zebra_legacy_admin_group_modify, .destroy = lib_interface_zebra_legacy_admin_group_destroy, - .cli_show = cli_show_legacy_admin_group, }, }, { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities", .cbs = { - .cli_show = cli_show_affinity, + .create = lib_interface_zebra_affinities_create, + .destroy = lib_interface_zebra_affinities_destroy, }, }, { @@ -377,9 +471,289 @@ const struct frr_yang_module_info frr_zebra_info = { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode", .cbs = { .modify = lib_interface_zebra_affinity_mode_modify, - .cli_show = cli_show_affinity_mode, }, }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor", + .cbs = { + .create = lib_interface_zebra_link_params_neighbor_create, + .destroy = lib_interface_zebra_link_params_neighbor_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/remote-as", + .cbs = { + .modify = lib_interface_zebra_link_params_neighbor_remote_as_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/ipv4-remote-id", + .cbs = { + .modify = lib_interface_zebra_link_params_neighbor_ipv4_remote_id_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay", + .cbs = { + .modify = lib_interface_zebra_link_params_delay_modify, + .destroy = lib_interface_zebra_link_params_delay_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay", + .cbs = { + .create = lib_interface_zebra_link_params_min_max_delay_create, + .destroy = lib_interface_zebra_link_params_min_max_delay_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-min", + .cbs = { + .modify = lib_interface_zebra_link_params_min_max_delay_delay_min_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-max", + .cbs = { + .modify = lib_interface_zebra_link_params_min_max_delay_delay_max_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/delay-variation", + .cbs = { + .modify = lib_interface_zebra_link_params_delay_variation_modify, + .destroy = lib_interface_zebra_link_params_delay_variation_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/link-params/packet-loss", + .cbs = { + .modify = lib_interface_zebra_link_params_packet_loss_modify, + .destroy = lib_interface_zebra_link_params_packet_loss_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0", + .cbs = { + .create = lib_interface_zebra_evpn_mh_type_0_create, + .destroy = lib_interface_zebra_evpn_mh_type_0_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_type_0_esi_modify, + .destroy = lib_interface_zebra_evpn_mh_type_0_esi_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3", + .cbs = { + .create = lib_interface_zebra_evpn_mh_type_3_create, + .destroy = lib_interface_zebra_evpn_mh_type_3_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_type_3_system_mac_modify, + .destroy = lib_interface_zebra_evpn_mh_type_3_system_mac_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/local-discriminator", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_type_3_local_discriminator_modify, + .destroy = lib_interface_zebra_evpn_mh_type_3_local_discriminator_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/df-preference", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_df_preference_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/bypass", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_bypass_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/uplink", + .cbs = { + .modify = lib_interface_zebra_evpn_mh_uplink_modify, + } + }, +#if defined(HAVE_RTADV) + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/send-advertisements", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_send_advertisements_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/managed-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_managed_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/other-config-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_other_config_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/link-mtu", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_link_mtu_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/reachable-time", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_reachable_time_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/retrans-timer", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_retrans_timer_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_default_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_default_lifetime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-router-preference", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_default_router_preference_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix", + .cbs = { + .create = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_create, + .destroy = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain", + .cbs = { + .create = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_create, + .destroy = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain/lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/valid-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_valid_lifetime_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/on-link-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_on_link_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/preferred-lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_preferred_lifetime_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/autonomous-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_autonomous_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/router-address-flag", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_router_address_flag_modify, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address", + .cbs = { + .create = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_create, + .destroy = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_destroy, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address/lifetime", + .cbs = { + .modify = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_modify, + .destroy = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy, + } + }, +#endif /* defined(HAVE_RTADV) */ +#if HAVE_BFDD == 0 + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ptm-enable", + .cbs = { + .modify = lib_interface_zebra_ptm_enable_modify, + } + }, +#endif { .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/up-count", .cbs = { @@ -428,12 +802,94 @@ const struct frr_yang_module_info frr_zebra_info = { .get_elem = lib_interface_zebra_state_mcast_group_get_elem, } }, + { + .xpath = "/frr-interface:lib/interface/frr-zebra:zebra/state/bond", + .cbs = { + .get_elem = lib_interface_zebra_state_bond_get_elem, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/router-id", + .cbs = { + .modify = lib_vrf_zebra_router_id_modify, + .destroy = lib_vrf_zebra_router_id_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-router-id", + .cbs = { + .modify = lib_vrf_zebra_ipv6_router_id_modify, + .destroy = lib_vrf_zebra_ipv6_router_id_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol", + .cbs = { + .create = lib_vrf_zebra_filter_protocol_create, + .destroy = lib_vrf_zebra_filter_protocol_destroy, + .apply_finish = lib_vrf_zebra_filter_protocol_apply_finish, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol/route-map", + .cbs = { + .modify = lib_vrf_zebra_filter_protocol_route_map_modify, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht", + .cbs = { + .create = lib_vrf_zebra_filter_nht_create, + .destroy = lib_vrf_zebra_filter_nht_destroy, + .apply_finish = lib_vrf_zebra_filter_nht_apply_finish, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht/route-map", + .cbs = { + .modify = lib_vrf_zebra_filter_nht_route_map_modify, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/resolve-via-default", + .cbs = { + .modify = lib_vrf_zebra_resolve_via_default_modify, + .destroy = lib_vrf_zebra_resolve_via_default_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-resolve-via-default", + .cbs = { + .modify = lib_vrf_zebra_ipv6_resolve_via_default_modify, + .destroy = lib_vrf_zebra_ipv6_resolve_via_default_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range", + .cbs = { + .create = lib_vrf_zebra_netns_table_range_create, + .destroy = lib_vrf_zebra_netns_table_range_destroy, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/start", + .cbs = { + .modify = lib_vrf_zebra_netns_table_range_start_modify, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/end", + .cbs = { + .modify = lib_vrf_zebra_netns_table_range_end_modify, + } + }, { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib", .cbs = { .get_next = lib_vrf_zebra_ribs_rib_get_next, .get_keys = lib_vrf_zebra_ribs_rib_get_keys, .lookup_entry = lib_vrf_zebra_ribs_rib_lookup_entry, + .lookup_next = lib_vrf_zebra_ribs_rib_lookup_next, } }, { @@ -454,6 +910,7 @@ const struct frr_yang_module_info frr_zebra_info = { .get_next = lib_vrf_zebra_ribs_rib_route_get_next, .get_keys = lib_vrf_zebra_ribs_rib_route_get_keys, .lookup_entry = lib_vrf_zebra_ribs_rib_route_lookup_entry, + .lookup_next = lib_vrf_zebra_ribs_rib_route_lookup_next, } }, { diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index 80d2aaa6fee5..b40ed6822909 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -44,6 +44,10 @@ int zebra_import_kernel_table_route_map_destroy( int zebra_allow_external_route_update_create(struct nb_cb_create_args *args); int zebra_allow_external_route_update_destroy(struct nb_cb_destroy_args *args); int zebra_dplane_queue_limit_modify(struct nb_cb_modify_args *args); +#if HAVE_BFDD == 0 +int zebra_ptm_enable_modify(struct nb_cb_modify_args *args); +#endif +int zebra_route_map_delay_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_events_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_events_destroy(struct nb_cb_destroy_args *args); int zebra_debugs_debug_zapi_send_modify(struct nb_cb_modify_args *args); @@ -80,31 +84,191 @@ int zebra_debugs_debug_dplane_detail_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_dplane_detail_destroy(struct nb_cb_destroy_args *args); int zebra_debugs_debug_mlag_modify(struct nb_cb_modify_args *args); int zebra_debugs_debug_mlag_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args); -int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_ip_addrs_label_modify(struct nb_cb_modify_args *args); -int lib_interface_zebra_ip_addrs_label_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_ip_addrs_ip4_peer_modify( +int lib_interface_zebra_ipv4_addrs_create(struct nb_cb_create_args *args); +int lib_interface_zebra_ipv4_addrs_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv4_addrs_label_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv4_addrs_label_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv4_p2p_addrs_create(struct nb_cb_create_args *args); +int lib_interface_zebra_ipv4_p2p_addrs_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv4_p2p_addrs_label_modify( struct nb_cb_modify_args *args); -int lib_interface_zebra_ip_addrs_ip4_peer_destroy( +int lib_interface_zebra_ipv4_p2p_addrs_label_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_addrs_create(struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_addrs_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_multicast_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_multicast_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_link_detect_modify(struct nb_cb_modify_args *args); -int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args); -int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_enabled_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_enabled_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_mpls_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_mpls_destroy(struct nb_cb_destroy_args *args); -int lib_interface_zebra_legacy_admin_group_modify( +int lib_interface_zebra_link_params_create(struct nb_cb_create_args *args); +int lib_interface_zebra_link_params_destroy(struct nb_cb_destroy_args *args); +void lib_interface_zebra_link_params_apply_finish( + struct nb_cb_apply_finish_args *args); +int lib_interface_zebra_link_params_metric_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_metric_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_max_bandwidth_modify( struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_max_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_max_reservable_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_max_reservable_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_create( + struct nb_cb_create_args *args); +void lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_modify( + struct nb_cb_modify_args *args); +void lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_cli_write( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +int lib_interface_zebra_link_params_residual_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_residual_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_available_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_available_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_utilized_bandwidth_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_utilized_bandwidth_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_legacy_admin_group_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_legacy_admin_group_destroy( struct nb_cb_destroy_args *args); +int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args); +int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args); int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_neighbor_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_link_params_neighbor_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_neighbor_remote_as_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_neighbor_ipv4_remote_id_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_min_max_delay_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_link_params_min_max_delay_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_min_max_delay_delay_min_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_min_max_delay_delay_max_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_variation_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_delay_variation_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_link_params_packet_loss_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_link_params_packet_loss_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args); +int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_type_0_esi_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args); +int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_system_mac_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_evpn_mh_df_preference_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_bypass_modify(struct nb_cb_modify_args *args); +int lib_interface_zebra_evpn_mh_uplink_modify(struct nb_cb_modify_args *args); +#if defined(HAVE_RTADV) +int lib_interface_zebra_ipv6_router_advertisements_send_advertisements_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_managed_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_other_config_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_link_mtu_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_reachable_time_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_retrans_timer_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_default_router_preference_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_valid_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_on_link_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_preferred_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_autonomous_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_router_address_flag_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_create( + struct nb_cb_create_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_modify( + struct nb_cb_modify_args *args); +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy( + struct nb_cb_destroy_args *args); +#endif /* defined(HAVE_RTADV) */ +#if HAVE_BFDD == 0 +int lib_interface_zebra_ptm_enable_modify(struct nb_cb_modify_args *args); +#endif struct yang_data * lib_interface_zebra_state_up_count_get_elem(struct nb_cb_get_elem_args *args); struct yang_data * @@ -121,10 +285,36 @@ struct yang_data *lib_interface_zebra_state_remote_vtep_get_elem( struct nb_cb_get_elem_args *args); struct yang_data *lib_interface_zebra_state_mcast_group_get_elem( struct nb_cb_get_elem_args *args); +struct yang_data *lib_interface_zebra_state_bond_get_elem(struct nb_cb_get_elem_args *args); +int lib_vrf_zebra_router_id_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_router_id_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_ipv6_router_id_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_ipv6_router_id_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_filter_protocol_create(struct nb_cb_create_args *args); +int lib_vrf_zebra_filter_protocol_destroy(struct nb_cb_destroy_args *args); +void lib_vrf_zebra_filter_protocol_apply_finish( + struct nb_cb_apply_finish_args *args); +int lib_vrf_zebra_filter_protocol_route_map_modify( + struct nb_cb_modify_args *args); +int lib_vrf_zebra_filter_nht_create(struct nb_cb_create_args *args); +int lib_vrf_zebra_filter_nht_destroy(struct nb_cb_destroy_args *args); +void lib_vrf_zebra_filter_nht_apply_finish(struct nb_cb_apply_finish_args *args); +int lib_vrf_zebra_filter_nht_route_map_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_resolve_via_default_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_resolve_via_default_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_ipv6_resolve_via_default_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_ipv6_resolve_via_default_destroy( + struct nb_cb_destroy_args *args); +int lib_vrf_zebra_netns_table_range_create(struct nb_cb_create_args *args); +int lib_vrf_zebra_netns_table_range_destroy(struct nb_cb_destroy_args *args); +int lib_vrf_zebra_netns_table_range_start_modify(struct nb_cb_modify_args *args); +int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args); const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args); const void * lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args); +const void * +lib_vrf_zebra_ribs_rib_lookup_next(struct nb_cb_lookup_entry_args *args); struct yang_data * lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem(struct nb_cb_get_elem_args *args); struct yang_data * @@ -134,6 +324,8 @@ lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args); const void * lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args); +const void * +lib_vrf_zebra_ribs_rib_route_lookup_next(struct nb_cb_lookup_entry_args *args); struct yang_data * lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args); struct yang_data *lib_vrf_zebra_ribs_rib_route_protocol_get_elem( diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index 5ea03112bc5f..ae6232a1bbfb 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -23,6 +23,12 @@ #include "zebra/debug.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_evpn_mh.h" +#include "zebra/zebra_ptm.h" +#include "zebra/router-id.h" +#include "zebra/zebra_routemap.h" +#include "zebra/zebra_rnh.h" +#include "zebra/table_manager.h" /* * XPath: /frr-zebra:zebra/mcast-rpf-lookup @@ -264,6 +270,43 @@ int zebra_dplane_queue_limit_modify(struct nb_cb_modify_args *args) return NB_OK; } +#if HAVE_BFDD == 0 +/* + * XPath: /frr-zebra:zebra/ptm-enable + */ +int zebra_ptm_enable_modify(struct nb_cb_modify_args *args) +{ + bool ptm; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ptm = yang_dnode_get_bool(args->dnode, NULL); + + if (ptm) + zebra_global_ptm_enable(); + else + zebra_global_ptm_disable(); + + return NB_OK; +} +#endif + +/* + * XPath: /frr-zebra:zebra/route-map-delay + */ +int zebra_route_map_delay_modify(struct nb_cb_modify_args *args) +{ + uint32_t delay = yang_dnode_get_uint32(args->dnode, NULL); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + zebra_route_map_set_delay_timer(delay); + + return NB_OK; +} + /* * XPath: /frr-zebra:zebra/debugs/debug-events */ @@ -823,28 +866,26 @@ int zebra_debugs_debug_mlag_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs */ -int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args) +int lib_interface_zebra_ipv4_addrs_create(struct nb_cb_create_args *args) { struct interface *ifp; - struct prefix prefix; + struct prefix p; + const char *label = NULL; - // addr_family = yang_dnode_get_enum(dnode, "./address-family"); - yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix"); - apply_mask(&prefix); + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); + + if (yang_dnode_exists(args->dnode, "label")) + label = yang_dnode_get_string(args->dnode, "label"); switch (args->event) { case NB_EV_VALIDATE: - if (prefix.family == AF_INET - && ipv4_martian(&prefix.u.prefix4)) { - snprintfrr(args->errmsg, args->errmsg_len, - "invalid address %pFX", &prefix); - return NB_ERR_VALIDATION; - } else if (prefix.family == AF_INET6 - && ipv6_martian(&prefix.u.prefix6)) { + if (ipv4_martian(&p.u.prefix4)) { snprintfrr(args->errmsg, args->errmsg_len, - "invalid address %pFX", &prefix); + "invalid address %pFX", &p); return NB_ERR_VALIDATION; } break; @@ -853,65 +894,105 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args) break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - if (prefix.family == AF_INET) - if_ip_address_install(ifp, &prefix, NULL, NULL); - else if (prefix.family == AF_INET6) - if_ipv6_address_install(ifp, &prefix, NULL); + if_ip_address_install(ifp, &p, label, NULL); + /* set something for checking on label modify */ + nb_running_set_entry(args->dnode, (void *)0x1); break; } return NB_OK; } -int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) +int lib_interface_zebra_ipv4_addrs_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; - struct prefix prefix; - struct connected *ifc; + struct prefix p; - yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix"); - apply_mask(&prefix); + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); switch (args->event) { case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, false); - if (!ifp) - return NB_OK; - - if (prefix.family == AF_INET) { - /* Check current interface address. */ - ifc = connected_check_ptp(ifp, &prefix, NULL); - if (!ifc) { - snprintf(args->errmsg, args->errmsg_len, - "interface %s Can't find address\n", - ifp->name); - return NB_ERR_VALIDATION; - } - } else if (prefix.family == AF_INET6) { - /* Check current interface address. */ - ifc = connected_check(ifp, &prefix); - if (!ifc) { - snprintf(args->errmsg, args->errmsg_len, - "interface can't find address %s", - ifp->name); - return NB_ERR_VALIDATION; - } - } else - return NB_ERR_VALIDATION; + if_ip_address_uninstall(ifp, &p, NULL); + break; + } + + return NB_OK; +} - /* This is not configured address. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-addrs/label + */ +int lib_interface_zebra_ipv4_addrs_label_modify(struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + if (nb_running_get_entry_non_rec(lyd_parent(args->dnode), NULL, + false)) { snprintf(args->errmsg, args->errmsg_len, - "interface %s not configured", ifp->name); + "Changing label is not allowed"); return NB_ERR_VALIDATION; } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_zebra_ipv4_addrs_label_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + snprintf(args->errmsg, args->errmsg_len, + "Removing label is not allowed"); + return NB_ERR_VALIDATION; + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs + */ +int lib_interface_zebra_ipv4_p2p_addrs_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct prefix p, pp; + const char *label = NULL; + + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = 32; + + pp.family = AF_INET; + yang_dnode_get_ipv4(&pp.u.prefix4, args->dnode, "peer-ip"); + pp.prefixlen = yang_dnode_get_uint8(args->dnode, "peer-prefix-length"); + + if (yang_dnode_exists(args->dnode, "label")) + label = yang_dnode_get_string(args->dnode, "label"); - /* This is not real address or interface is not active. */ - if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) - || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - listnode_delete(ifp->connected, ifc); - connected_free(&ifc); + switch (args->event) { + case NB_EV_VALIDATE: + if (ipv4_martian(&p.u.prefix4)) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid address %pFX", &p); return NB_ERR_VALIDATION; } break; @@ -920,7 +1001,39 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); - if_ip_address_uinstall(ifp, &prefix); + if_ip_address_install(ifp, &p, label, &pp); + + /* set something for checking on label modify */ + nb_running_set_entry(args->dnode, (void *)0x1); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_ipv4_p2p_addrs_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct prefix p, pp; + + p.family = AF_INET; + yang_dnode_get_ipv4(&p.u.prefix4, args->dnode, "ip"); + p.prefixlen = 32; + + pp.family = AF_INET; + yang_dnode_get_ipv4(&pp.u.prefix4, args->dnode, "peer-ip"); + pp.prefixlen = yang_dnode_get_uint8(args->dnode, "peer-prefix-length"); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + nb_running_unset_entry(args->dnode); + + ifp = nb_running_get_entry(args->dnode, NULL, false); + if_ip_address_uninstall(ifp, &p, &pp); break; } @@ -928,30 +1041,39 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/label + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv4-p2p-addrs/label */ -int lib_interface_zebra_ip_addrs_label_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_ipv4_p2p_addrs_label_modify(struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: + if (nb_running_get_entry_non_rec(lyd_parent(args->dnode), NULL, + false)) { + snprintf(args->errmsg, args->errmsg_len, + "Changing label is not allowed"); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ break; } return NB_OK; } -int lib_interface_zebra_ip_addrs_label_destroy(struct nb_cb_destroy_args *args) +int lib_interface_zebra_ipv4_p2p_addrs_label_destroy( + struct nb_cb_destroy_args *args) { switch (args->event) { case NB_EV_VALIDATE: + snprintf(args->errmsg, args->errmsg_len, + "Removing label is not allowed"); + return NB_ERR_VALIDATION; case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ break; } @@ -959,31 +1081,54 @@ int lib_interface_zebra_ip_addrs_label_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ip-addrs/ip4-peer + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-addrs */ -int lib_interface_zebra_ip_addrs_ip4_peer_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_ipv6_addrs_create(struct nb_cb_create_args *args) { + struct interface *ifp; + struct prefix p; + + p.family = AF_INET6; + yang_dnode_get_ipv6(&p.u.prefix6, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); + switch (args->event) { case NB_EV_VALIDATE: + if (ipv6_martian(&p.u.prefix6)) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid address %pFX", &p); + return NB_ERR_VALIDATION; + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: - /* TODO: implement me. */ + ifp = nb_running_get_entry(args->dnode, NULL, true); + if_ipv6_address_install(ifp, &p); break; } return NB_OK; } -int lib_interface_zebra_ip_addrs_ip4_peer_destroy( - struct nb_cb_destroy_args *args) +int lib_interface_zebra_ipv6_addrs_destroy(struct nb_cb_destroy_args *args) { + struct interface *ifp; + struct prefix p; + + p.family = AF_INET6; + yang_dnode_get_ipv6(&p.u.prefix6, args->dnode, "ip"); + p.prefixlen = yang_dnode_get_uint8(args->dnode, "prefix-length"); + switch (args->event) { case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: - /* TODO: implement me. */ + ifp = nb_running_get_entry(args->dnode, NULL, false); + if_ipv6_address_uninstall(ifp, &p); break; } @@ -999,10 +1144,14 @@ int lib_interface_zebra_multicast_modify(struct nb_cb_modify_args *args) return NB_OK; struct interface *ifp; + bool multicast = yang_dnode_get_bool(args->dnode, NULL); ifp = nb_running_get_entry(args->dnode, NULL, true); - if_multicast_set(ifp); + if (multicast) + if_multicast_set(ifp); + else + if_multicast_unset(ifp); return NB_OK; } @@ -1013,10 +1162,12 @@ int lib_interface_zebra_multicast_destroy(struct nb_cb_destroy_args *args) return NB_OK; struct interface *ifp; + struct zebra_if *zif; ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; - if_multicast_unset(ifp); + zif->multicast = IF_ZEBRA_DATA_UNSPEC; return NB_OK; } @@ -1033,23 +1184,7 @@ int lib_interface_zebra_link_detect_modify(struct nb_cb_modify_args *args) bool link_detect; ifp = nb_running_get_entry(args->dnode, NULL, true); - link_detect = yang_dnode_get_bool(args->dnode, "./link-detect"); - - if_linkdetect(ifp, link_detect); - - return NB_OK; -} - -int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args) -{ - if (args->event != NB_EV_APPLY) - return NB_OK; - - struct interface *ifp; - bool link_detect; - - ifp = nb_running_get_entry(args->dnode, NULL, true); - link_detect = yang_dnode_get_bool(args->dnode, "./link-detect"); + link_detect = yang_dnode_get_bool(args->dnode, NULL); if_linkdetect(ifp, link_detect); @@ -1057,32 +1192,39 @@ int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-zebra:zebra/shutdown + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/enabled */ -int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_enabled_modify(struct nb_cb_modify_args *args) { if (args->event != NB_EV_APPLY) return NB_OK; struct interface *ifp; + bool enabled; ifp = nb_running_get_entry(args->dnode, NULL, true); + enabled = yang_dnode_get_bool(args->dnode, NULL); - if_shutdown(ifp); + if (enabled) + if_no_shutdown(ifp); + else + if_shutdown(ifp); return NB_OK; } -int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args) +int lib_interface_zebra_enabled_destroy(struct nb_cb_destroy_args *args) { if (args->event != NB_EV_APPLY) return NB_OK; struct interface *ifp; + struct zebra_if *zif; ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; - if_no_shutdown(ifp); + zif->shutdown = IF_ZEBRA_DATA_UNSPEC; return NB_OK; } @@ -1143,7 +1285,7 @@ int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args) uint32_t bandwidth; ifp = nb_running_get_entry(args->dnode, NULL, true); - bandwidth = yang_dnode_get_uint32(args->dnode, "./bandwidth"); + bandwidth = yang_dnode_get_uint32(args->dnode, NULL); ifp->bandwidth = bandwidth; @@ -1173,391 +1315,2525 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params */ -int lib_interface_zebra_legacy_admin_group_modify( - struct nb_cb_modify_args *args) +int lib_interface_zebra_link_params_create(struct nb_cb_create_args *args) { struct interface *ifp; - struct if_link_params *iflp; - uint32_t admin_group_value; + + if (args->event != NB_EV_APPLY) + return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); - admin_group_value = yang_dnode_get_uint32(args->dnode, "."); + if_link_params_enable(ifp); - if (!ifp) - return NB_ERR_RESOURCE; + /* + * The interface is updated in the apply_finish callback after all + * parameters are set in the corresponding callbacks. + */ - iflp = if_link_params_get(ifp); + return NB_OK; +} - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); +int lib_interface_zebra_link_params_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; - iflp->admin_grp = admin_group_value; - SET_PARAM(iflp, LP_ADM_GRP); + if (args->event != NB_EV_APPLY) + return NB_OK; - admin_group_clear(&iflp->ext_admin_grp); - UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + ifp = nb_running_get_entry(args->dnode, NULL, true); + if_link_params_free(ifp); + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - break; - } return NB_OK; } -int lib_interface_zebra_legacy_admin_group_destroy( - struct nb_cb_destroy_args *args) +void lib_interface_zebra_link_params_apply_finish( + struct nb_cb_apply_finish_args *args) { struct interface *ifp; - struct if_link_params *iflp; ifp = nb_running_get_entry(args->dnode, NULL, true); + if (if_is_operative(ifp)) + zebra_interface_parameters_update(ifp); +} - if (!ifp) - return NB_ERR_RESOURCE; +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/metric + */ +int lib_interface_zebra_link_params_metric_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t metric; - iflp = if_link_params_get(ifp); + if (args->event != NB_EV_APPLY) + return NB_OK; - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + metric = yang_dnode_get_uint32(args->dnode, NULL); - iflp->admin_grp = 0; - UNSET_PARAM(iflp, LP_ADM_GRP); + link_param_cmd_set_uint32(ifp, &iflp->te_metric, LP_TE_METRIC, metric); - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - break; - } return NB_OK; } -/* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity - */ -int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) +int lib_interface_zebra_link_params_metric_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; - const char *affname; - struct if_link_params *iflp; - struct affinity_map *affmap; - enum affinity_mode affinity_mode; + if (args->event != NB_EV_APPLY) + return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); - affname = yang_dnode_get_string(args->dnode, "."); - affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); - if (!ifp) - return NB_ERR_RESOURCE; + link_param_cmd_unset(ifp, LP_TE_METRIC); - affmap = affinity_map_get(affname); - iflp = if_link_params_get(ifp); + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/max-bandwidth + */ +int lib_interface_zebra_link_params_max_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + float max_bw, res_bw, ava_bw, use_bw; + + max_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); switch (args->event) { case NB_EV_VALIDATE: - if (!affmap) { - snprintf(args->errmsg, args->errmsg_len, - "affinity-map %s not found.", affname); - return NB_ERR_VALIDATION; + if (yang_dnode_exists(args->dnode, "../residual-bandwidth")) { + res_bw = yang_dnode_get_bandwidth_ieee_float32( + args->dnode, "../residual-bandwidth"); + if (max_bw < res_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than residual-bandwidth %f", + max_bw, res_bw); + return NB_ERR_VALIDATION; + } } - if (affinity_mode == AFFINITY_MODE_STANDARD && - affmap->bit_position > 31) { - snprintf( - args->errmsg, args->errmsg_len, - "affinity %s bit-position %d is not compatible with affinity-mode standard (bit-position > 31).", - affname, affmap->bit_position); - return NB_ERR_VALIDATION; + if (yang_dnode_exists(args->dnode, "../available-bandwidth")) { + ava_bw = yang_dnode_get_bandwidth_ieee_float32( + args->dnode, "../available-bandwidth"); + if (max_bw < ava_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than available-bandwidth %f", + max_bw, ava_bw); + return NB_ERR_VALIDATION; + } + } + if (yang_dnode_exists(args->dnode, "../utilized-bandwidth")) { + use_bw = yang_dnode_get_bandwidth_ieee_float32( + args->dnode, "../utilized-bandwidth"); + if (max_bw < use_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than utilized-bandwidth %f", + max_bw, use_bw); + return NB_ERR_VALIDATION; + } } break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->max_bw, LP_MAX_BW, max_bw); + break; + } - if (affmap->bit_position < 32 && - (affinity_mode == AFFINITY_MODE_STANDARD || - affinity_mode == AFFINITY_MODE_BOTH)) { - iflp->admin_grp |= 1 << affmap->bit_position; - SET_PARAM(iflp, LP_ADM_GRP); - } - if (affinity_mode == AFFINITY_MODE_EXTENDED || - affinity_mode == AFFINITY_MODE_BOTH) { - admin_group_set(&iflp->ext_admin_grp, - affmap->bit_position); - SET_PARAM(iflp, LP_EXTEND_ADM_GRP); - } + return NB_OK; +} - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); - break; +int lib_interface_zebra_link_params_max_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + snprintfrr(args->errmsg, args->errmsg_len, + "Removing max-bandwidth is not allowed"); + return NB_ERR_VALIDATION; } + return NB_OK; } -int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args) +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/max-reservable-bandwidth + */ +int lib_interface_zebra_link_params_max_reservable_bandwidth_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; - const char *affname; struct if_link_params *iflp; - struct affinity_map *affmap; - enum affinity_mode affinity_mode; + float max_rsv_bw; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + max_rsv_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); ifp = nb_running_get_entry(args->dnode, NULL, true); - affname = yang_dnode_get_string(args->dnode, "."); - affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, + max_rsv_bw); + + return NB_OK; +} + +int lib_interface_zebra_link_params_max_reservable_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + snprintfrr(args->errmsg, args->errmsg_len, + "Removing max-reservable-bandwidth is not allowed"); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth + */ +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint8_t priority; + float unrsv_bw; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + priority = yang_dnode_get_uint8(args->dnode, "priority"); + unrsv_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "unreserved-bandwidth"); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, + unrsv_bw); + + return NB_OK; +} + +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + if (args->event == NB_EV_VALIDATE) { + snprintfrr(args->errmsg, args->errmsg_len, + "Removing unreserved-bandwidth is not allowed"); + return NB_ERR_VALIDATION; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/unreserved-bandwidths/unreserved-bandwidth/unreserved-bandwidth + */ +int lib_interface_zebra_link_params_unreserved_bandwidths_unreserved_bandwidth_unreserved_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint8_t priority; + float unrsv_bw; + + if (args->event != NB_EV_APPLY) + return NB_OK; - if (!ifp) - return NB_ERR_RESOURCE; + priority = yang_dnode_get_uint8(args->dnode, "../priority"); + unrsv_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); - affmap = affinity_map_get(affname); + ifp = nb_running_get_entry(args->dnode, NULL, true); iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW, + unrsv_bw); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/residual-bandwidth + */ +int lib_interface_zebra_link_params_residual_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + float max_bw, res_bw; + + res_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); switch (args->event) { case NB_EV_VALIDATE: - if (!affmap) { - snprintf(args->errmsg, args->errmsg_len, - "affinity-map %s not found.", affname); - return NB_ERR_VALIDATION; + if (yang_dnode_exists(args->dnode, "../max-bandwidth")) { + max_bw = + yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "../max-bandwidth"); + if (max_bw < res_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than residual-bandwidth %f", + max_bw, res_bw); + return NB_ERR_VALIDATION; + } } break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - return NB_OK; - if (affmap->bit_position < 32 && - (affinity_mode == AFFINITY_MODE_STANDARD || - affinity_mode == AFFINITY_MODE_BOTH)) { - iflp->admin_grp &= ~(1 << affmap->bit_position); - if (iflp->admin_grp == 0) - UNSET_PARAM(iflp, LP_ADM_GRP); - } - if (affinity_mode == AFFINITY_MODE_EXTENDED || - affinity_mode == AFFINITY_MODE_BOTH) { - admin_group_unset(&iflp->ext_admin_grp, - affmap->bit_position); - if (admin_group_zero(&iflp->ext_admin_grp)) - UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); - } - - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->res_bw, LP_RES_BW, res_bw); break; } + return NB_OK; } -/* - * XPath: - * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode - */ -int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_link_params_residual_bandwidth_destroy( + struct nb_cb_destroy_args *args) { struct interface *ifp; - struct if_link_params *iflp; - enum affinity_mode affinity_mode; + if (args->event != NB_EV_APPLY) + return NB_OK; ifp = nb_running_get_entry(args->dnode, NULL, true); - affinity_mode = yang_dnode_get_enum(args->dnode, "."); + link_param_cmd_unset(ifp, LP_RES_BW); - if (!ifp) - return NB_ERR_RESOURCE; + return NB_OK; +} - iflp = if_link_params_get(ifp); +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/available-bandwidth + */ +int lib_interface_zebra_link_params_available_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + float max_bw, ava_bw; + + ava_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); switch (args->event) { case NB_EV_VALIDATE: - if (affinity_mode == AFFINITY_MODE_STANDARD && - admin_group_nb_words(&iflp->ext_admin_grp) > 1) { - snprintf( - args->errmsg, args->errmsg_len, - "affinity-mode standard cannot be set when a bit-position > 31 is set."); - return NB_ERR_VALIDATION; + if (yang_dnode_exists(args->dnode, "../max-bandwidth")) { + max_bw = + yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "../max-bandwidth"); + if (max_bw < ava_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than available-bandwidth %f", + max_bw, ava_bw); + return NB_ERR_VALIDATION; + } } break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - if (!iflp) - iflp = if_link_params_enable(ifp); - if (affinity_mode == AFFINITY_MODE_STANDARD) { - if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && - IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { - iflp->admin_grp = admin_group_get_offset( - &iflp->ext_admin_grp, 0); - SET_PARAM(iflp, LP_ADM_GRP); - } - admin_group_clear(&iflp->ext_admin_grp); - UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); - } - if (affinity_mode == AFFINITY_MODE_EXTENDED) { - if (!IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && - IS_PARAM_SET(iflp, LP_ADM_GRP)) { - admin_group_bulk_set(&iflp->ext_admin_grp, - iflp->admin_grp, 0); - SET_PARAM(iflp, LP_EXTEND_ADM_GRP); - } - iflp->admin_grp = 0; - UNSET_PARAM(iflp, LP_ADM_GRP); - } - if (affinity_mode == AFFINITY_MODE_BOTH) { - if (!IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && - IS_PARAM_SET(iflp, LP_ADM_GRP)) { - admin_group_bulk_set(&iflp->ext_admin_grp, - iflp->admin_grp, 0); - SET_PARAM(iflp, LP_EXTEND_ADM_GRP); - } else if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && - IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { - iflp->admin_grp = admin_group_get_offset( - &iflp->ext_admin_grp, 0); - SET_PARAM(iflp, LP_ADM_GRP); - } - } - - if (if_is_operative(ifp)) - zebra_interface_parameters_update(ifp); + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->ava_bw, LP_AVA_BW, ava_bw); break; } + + return NB_OK; +} + +int lib_interface_zebra_link_params_available_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + link_param_cmd_unset(ifp, LP_AVA_BW); + return NB_OK; } /* - * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/utilized-bandwidth */ -int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) +int lib_interface_zebra_link_params_utilized_bandwidth_modify( + struct nb_cb_modify_args *args) { - struct vrf *vrf; - struct zebra_vrf *zvrf; - vni_t vni = 0; - struct zebra_l3vni *zl3vni = NULL; - char err[ERR_STR_SZ]; - bool pfx_only = false; - const struct lyd_node *pn_dnode; - const char *vrfname; + struct interface *ifp; + struct if_link_params *iflp; + float max_bw, use_bw; + + use_bw = yang_dnode_get_bandwidth_ieee_float32(args->dnode, NULL); switch (args->event) { + case NB_EV_VALIDATE: + if (yang_dnode_exists(args->dnode, "../max-bandwidth")) { + max_bw = + yang_dnode_get_bandwidth_ieee_float32(args->dnode, + "../max-bandwidth"); + if (max_bw < use_bw) { + snprintfrr(args->errmsg, args->errmsg_len, + "max-bandwidth %f is less than utilized-bandwidth %f", + max_bw, use_bw); + return NB_ERR_VALIDATION; + } + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + link_param_cmd_set_float(ifp, &iflp->use_bw, LP_USE_BW, use_bw); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_link_params_utilized_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) return NB_OK; - case NB_EV_VALIDATE: - vni = yang_dnode_get_uint32(args->dnode, NULL); - /* Get vrf info from parent node, reject configuration - * if zebra vrf already mapped to different vni id. - */ - pn_dnode = yang_dnode_get_parent(args->dnode, "vrf"); - vrfname = yang_dnode_get_string(pn_dnode, "./name"); - zvrf = zebra_vrf_lookup_by_name(vrfname); - if (!zvrf) { - snprintf(args->errmsg, args->errmsg_len, - "zebra vrf info not found for vrf:%s.", - vrfname); - return NB_ERR_VALIDATION; - } - if (zvrf->l3vni && zvrf->l3vni != vni) { - snprintf( - args->errmsg, args->errmsg_len, - "vni %u cannot be configured as vni %u is already configured under the vrf", - vni, zvrf->l3vni); - return NB_ERR_VALIDATION; - } - /* Check if this VNI is already present in the system */ - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - snprintf(args->errmsg, args->errmsg_len, - "VNI %u is already configured as L3-VNI", vni); - return NB_ERR_VALIDATION; - } + ifp = nb_running_get_entry(args->dnode, NULL, true); + link_param_cmd_unset(ifp, LP_USE_BW); - break; - case NB_EV_APPLY: + return NB_OK; +} - vrf = nb_running_get_entry(args->dnode, NULL, true); - zvrf = zebra_vrf_lookup_by_name(vrf->name); - vni = yang_dnode_get_uint32(args->dnode, NULL); - /* Note: This covers lib_vrf_zebra_prefix_only_modify() config - * along with l3vni config - */ - pfx_only = yang_dnode_get_bool(args->dnode, "../prefix-only"); +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/legacy-admin-group + */ +int lib_interface_zebra_legacy_admin_group_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t admin_group_value; - if (zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - pfx_only ? 1 : 0, 1) - != 0) { - if (IS_ZEBRA_DEBUG_VXLAN) - snprintf( - args->errmsg, args->errmsg_len, - "vrf vni %u mapping failed with error: %s", - vni, err); - return NB_ERR; - } + admin_group_value = yang_dnode_get_uint32(args->dnode, "."); + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: break; - } + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + iflp->admin_grp = admin_group_value; + SET_PARAM(iflp, LP_ADM_GRP); + break; + } return NB_OK; } -int lib_vrf_zebra_l3vni_id_destroy(struct nb_cb_destroy_args *args) +int lib_interface_zebra_legacy_admin_group_destroy( + struct nb_cb_destroy_args *args) { - struct vrf *vrf; - struct zebra_vrf *zvrf; - vni_t vni = 0; - char err[ERR_STR_SZ]; - uint8_t filter = 0; + struct interface *ifp; + struct if_link_params *iflp; switch (args->event) { + case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - case NB_EV_VALIDATE: - return NB_OK; + break; case NB_EV_APPLY: - vrf = nb_running_get_entry(args->dnode, NULL, true); - zvrf = zebra_vrf_lookup_by_name(vrf->name); - vni = yang_dnode_get_uint32(args->dnode, NULL); - - if (!zl3vni_lookup(vni)) - return NB_OK; + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); - if (zvrf->l3vni != vni) { - snprintf(args->errmsg, args->errmsg_len, - "vrf %s has different vni %u mapped", - vrf->name, zvrf->l3vni); - return NB_ERR; - } + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + break; + } + return NB_OK; +} - if (is_l3vni_for_prefix_routes_only(zvrf->l3vni)) - filter = 1; - - if (zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - filter, 0) - != 0) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "vrf vni %u unmapping failed with error: %s", - vni, err); - return NB_ERR; - } +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities + */ +int lib_interface_zebra_affinities_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_affinities_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + + admin_group_clear(&iflp->ext_admin_grp); + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinities/affinity + */ +int lib_interface_zebra_affinity_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + const char *affname; + struct if_link_params *iflp; + struct affinity_map *affmap; + enum affinity_mode affinity_mode; + + affname = yang_dnode_get_string(args->dnode, "."); + affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + affmap = affinity_map_get(affname); + + if (affmap->bit_position < 32 && + (affinity_mode == AFFINITY_MODE_STANDARD || + affinity_mode == AFFINITY_MODE_BOTH)) { + iflp->admin_grp |= 1 << affmap->bit_position; + SET_PARAM(iflp, LP_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_EXTENDED || + affinity_mode == AFFINITY_MODE_BOTH) { + admin_group_set(&iflp->ext_admin_grp, + affmap->bit_position); + SET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + break; + } + return NB_OK; +} + +int lib_interface_zebra_affinity_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + const char *affname; + struct if_link_params *iflp; + struct affinity_map *affmap; + enum affinity_mode affinity_mode; + + affname = yang_dnode_get_string(args->dnode, "."); + affinity_mode = yang_dnode_get_enum(args->dnode, "../../affinity-mode"); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + affmap = affinity_map_get(affname); + + if (affmap->bit_position < 32 && + (affinity_mode == AFFINITY_MODE_STANDARD || + affinity_mode == AFFINITY_MODE_BOTH)) { + iflp->admin_grp &= ~(1 << affmap->bit_position); + if (iflp->admin_grp == 0) + UNSET_PARAM(iflp, LP_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_EXTENDED || + affinity_mode == AFFINITY_MODE_BOTH) { + admin_group_unset(&iflp->ext_admin_grp, + affmap->bit_position); + if (admin_group_zero(&iflp->ext_admin_grp)) + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + break; + } + return NB_OK; +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-zebra:zebra/link-params/affinity-mode + */ +int lib_interface_zebra_affinity_mode_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + enum affinity_mode affinity_mode; + + affinity_mode = yang_dnode_get_enum(args->dnode, "."); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + if (affinity_mode == AFFINITY_MODE_STANDARD) { + if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && + IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { + iflp->admin_grp = admin_group_get_offset( + &iflp->ext_admin_grp, 0); + SET_PARAM(iflp, LP_ADM_GRP); + } + admin_group_clear(&iflp->ext_admin_grp); + UNSET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_EXTENDED) { + if (!IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && + IS_PARAM_SET(iflp, LP_ADM_GRP)) { + admin_group_bulk_set(&iflp->ext_admin_grp, + iflp->admin_grp, 0); + SET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } + iflp->admin_grp = 0; + UNSET_PARAM(iflp, LP_ADM_GRP); + } + if (affinity_mode == AFFINITY_MODE_BOTH) { + if (!IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP) && + IS_PARAM_SET(iflp, LP_ADM_GRP)) { + admin_group_bulk_set(&iflp->ext_admin_grp, + iflp->admin_grp, 0); + SET_PARAM(iflp, LP_EXTEND_ADM_GRP); + } else if (!IS_PARAM_SET(iflp, LP_ADM_GRP) && + IS_PARAM_SET(iflp, LP_EXTEND_ADM_GRP)) { + iflp->admin_grp = admin_group_get_offset( + &iflp->ext_admin_grp, 0); + SET_PARAM(iflp, LP_ADM_GRP); + } + } + break; + } + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor + */ +int lib_interface_zebra_link_params_neighbor_create(struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + struct in_addr ip; + uint32_t as; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + as = yang_dnode_get_uint32(args->dnode, "remote-as"); + yang_dnode_get_ipv4(&ip, args->dnode, "ipv4-remote-id"); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_as = as; + iflp->rmt_ip = ip; + SET_PARAM(iflp, LP_RMT_AS); + + return NB_OK; +} + +int lib_interface_zebra_link_params_neighbor_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_as = 0; + iflp->rmt_ip.s_addr = 0; + UNSET_PARAM(iflp, LP_RMT_AS); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/remote-as + */ +int lib_interface_zebra_link_params_neighbor_remote_as_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t as; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + as = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_as = as; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/neighbor/ipv4-remote-id + */ +int lib_interface_zebra_link_params_neighbor_ipv4_remote_id_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + struct in_addr ip; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + yang_dnode_get_ipv4(&ip, args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->rmt_ip = ip; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/delay + */ +int lib_interface_zebra_link_params_delay_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + link_param_cmd_set_uint32(ifp, &iflp->av_delay, LP_DELAY, delay); + + return NB_OK; +} + +int lib_interface_zebra_link_params_delay_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->av_delay = 0; + link_param_cmd_unset(ifp, LP_DELAY); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay + */ +int lib_interface_zebra_link_params_min_max_delay_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_min, delay_max; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_min = yang_dnode_get_uint32(args->dnode, "delay-min"); + delay_max = yang_dnode_get_uint32(args->dnode, "delay-max"); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->min_delay = delay_min; + iflp->max_delay = delay_max; + SET_PARAM(iflp, LP_MM_DELAY); + + return NB_OK; +} + +int lib_interface_zebra_link_params_min_max_delay_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->min_delay = 0; + iflp->max_delay = 0; + UNSET_PARAM(iflp, LP_MM_DELAY); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-min + */ +int lib_interface_zebra_link_params_min_max_delay_delay_min_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_min; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_min = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->min_delay = delay_min; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/min-max-delay/delay-max + */ +int lib_interface_zebra_link_params_min_max_delay_delay_max_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_max; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_max = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + iflp->max_delay = delay_max; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/delay-variation + */ +int lib_interface_zebra_link_params_delay_variation_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + uint32_t delay_var; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + delay_var = yang_dnode_get_uint32(args->dnode, NULL); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + link_param_cmd_set_uint32(ifp, &iflp->delay_var, LP_DELAY_VAR, + delay_var); + + return NB_OK; +} + +int lib_interface_zebra_link_params_delay_variation_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + link_param_cmd_unset(ifp, LP_DELAY_VAR); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/link-params/packet-loss + */ +int lib_interface_zebra_link_params_packet_loss_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct if_link_params *iflp; + double packet_loss; + uint32_t value; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + packet_loss = yang_dnode_get_dec64(args->dnode, NULL); + value = (uint32_t)(packet_loss / LOSS_PRECISION); + + ifp = nb_running_get_entry(args->dnode, NULL, true); + iflp = if_link_params_get(ifp); + + link_param_cmd_set_uint32(ifp, &iflp->pkt_loss, LP_PKT_LOSS, value); + + return NB_OK; +} + +int lib_interface_zebra_link_params_packet_loss_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + link_param_cmd_unset(ifp, LP_PKT_LOSS); + + return NB_OK; +} + +static bool evpn_mh_dnode_to_esi(const struct lyd_node *dnode, esi_t *esi) +{ + if (yang_dnode_exists(dnode, "type-0/esi")) { + if (!str_to_esi(yang_dnode_get_string(dnode, "type-0/esi"), esi)) + assert(false); + } else if (yang_dnode_exists(dnode, "type-3/system-mac") && + yang_dnode_exists(dnode, "type-3/local-discriminator")) { + struct ethaddr mac; + uint32_t lid; + + yang_dnode_get_mac(&mac, dnode, "type-3/system-mac"); + lid = yang_dnode_get_uint32(dnode, "type-3/local-discriminator"); + + zebra_build_type3_esi(lid, &mac, esi); + } else { + return false; + } + + return true; +} + +struct esi_cmp_iter_arg { + struct lyd_node *dnode; + esi_t esi; + bool exists; +}; + +static int esi_cmp_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct esi_cmp_iter_arg *iter = arg; + esi_t esi; + + if (dnode == iter->dnode) + return YANG_ITER_CONTINUE; + + if (!evpn_mh_dnode_to_esi(dnode, &esi)) + return YANG_ITER_CONTINUE; + + if (!memcmp(&esi, &iter->esi, ESI_BYTES)) { + iter->exists = true; + return YANG_ITER_STOP; + } + + return YANG_ITER_CONTINUE; +} + +/* evpn-mh should be passed to this function */ +static bool esi_unique(struct lyd_node *dnode) +{ + struct esi_cmp_iter_arg iter; + + iter.dnode = dnode; + evpn_mh_dnode_to_esi(dnode, &iter.esi); + iter.exists = false; + + yang_dnode_iterate(esi_cmp_iter_cb, &iter, dnode, + "/frr-interface:lib/interface/frr-zebra:zebra/evpn-mh"); + + if (iter.exists) + return false; + + return true; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0 + */ +int lib_interface_zebra_evpn_mh_type_0_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_0_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_type0_esi_update(ifp->info, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-0/esi + */ +int lib_interface_zebra_evpn_mh_type_0_esi_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + esi_t esi; + + switch (args->event) { + case NB_EV_VALIDATE: + if (!esi_unique(lyd_parent(lyd_parent(args->dnode)))) { + snprintfrr(args->errmsg, args->errmsg_len, + "ESI already exists on a different interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + if (!str_to_esi(yang_dnode_get_string(args->dnode, NULL), &esi)) + assert(false); + zebra_evpn_es_type0_esi_update(ifp->info, &esi); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_0_esi_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_type0_esi_update(ifp->info, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3 + */ +int lib_interface_zebra_evpn_mh_type_3_create(struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_destroy(struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, NULL); + zebra_evpn_es_lid_update(ifp->info, 0); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/system-mac + */ +int lib_interface_zebra_evpn_mh_type_3_system_mac_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct ethaddr mac; + + yang_dnode_get_mac(&mac, args->dnode, NULL); + + switch (args->event) { + case NB_EV_VALIDATE: + if (is_zero_mac(&mac)) { + snprintfrr(args->errmsg, args->errmsg_len, + "MAC cannot be all-zeroes"); + return NB_ERR_VALIDATION; + } + if (!esi_unique(lyd_parent(lyd_parent(args->dnode)))) { + snprintfrr(args->errmsg, args->errmsg_len, + "ESI already exists on a different interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, &mac); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_system_mac_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_sys_mac_update(ifp->info, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/type-3/local-discriminator + */ +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + uint32_t lid; + + switch (args->event) { + case NB_EV_VALIDATE: + if (!esi_unique(lyd_parent(lyd_parent(args->dnode)))) { + snprintfrr(args->errmsg, args->errmsg_len, + "ESI already exists on a different interface"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + lid = yang_dnode_get_uint32(args->dnode, NULL); + zebra_evpn_es_lid_update(ifp->info, lid); + break; + } + + return NB_OK; +} + +int lib_interface_zebra_evpn_mh_type_3_local_discriminator_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zebra_evpn_es_lid_update(ifp->info, 0); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/df-preference + */ +int lib_interface_zebra_evpn_mh_df_preference_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + uint16_t df_pref; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + df_pref = yang_dnode_get_uint16(args->dnode, NULL); + zebra_evpn_es_df_pref_update(ifp->info, df_pref); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/bypass + */ +int lib_interface_zebra_evpn_mh_bypass_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool bypass; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + bypass = yang_dnode_get_bool(args->dnode, NULL); + zebra_evpn_es_bypass_cfg_update(ifp->info, bypass); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/evpn-mh/uplink + */ +int lib_interface_zebra_evpn_mh_uplink_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool uplink; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + uplink = yang_dnode_get_bool(args->dnode, NULL); + zebra_evpn_mh_uplink_cfg_update(ifp->info, uplink); + + return NB_OK; +} + +#if defined(HAVE_RTADV) +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/send-advertisements + */ +int lib_interface_zebra_ipv6_router_advertisements_send_advertisements_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool send_adv; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + send_adv = yang_dnode_get_bool(args->dnode, NULL); + + if (send_adv) { + ipv6_nd_suppress_ra_set(ifp, RA_ENABLE); + SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); + } else { + if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED)) + ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS); + UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED); + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/max-rtr-adv-interval + */ +int lib_interface_zebra_ipv6_router_advertisements_max_rtr_adv_interval_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + uint32_t interval; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + interval = yang_dnode_get_uint32(args->dnode, NULL); + + ipv6_nd_interval_set(ifp, interval); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/managed-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_managed_flag_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool managed_flag; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + managed_flag = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvManagedFlag = managed_flag; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/other-config-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_other_config_flag_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool other_config_flag; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + other_config_flag = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvOtherConfigFlag = other_config_flag; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_home_agent_flag_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool home_agent_flag; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + home_agent_flag = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvHomeAgentFlag = home_agent_flag; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/link-mtu + */ +int lib_interface_zebra_ipv6_router_advertisements_link_mtu_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint32_t mtu; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + mtu = yang_dnode_get_uint32(args->dnode, NULL); + + zif->rtadv.AdvLinkMTU = mtu; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/reachable-time + */ +int lib_interface_zebra_ipv6_router_advertisements_reachable_time_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint32_t time; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + time = yang_dnode_get_uint32(args->dnode, NULL); + + zif->rtadv.AdvReachableTime = time; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/retrans-timer + */ +int lib_interface_zebra_ipv6_router_advertisements_retrans_timer_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint32_t timer; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + timer = yang_dnode_get_uint32(args->dnode, NULL); + + zif->rtadv.AdvRetransTimer = timer; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/cur-hop-limit + */ +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint8_t limit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + limit = yang_dnode_get_uint8(args->dnode, NULL); + + zif->rtadv.AdvCurHopLimit = limit; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_cur_hop_limit_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint16_t lifetime; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + lifetime = yang_dnode_get_uint16(args->dnode, NULL); + + zif->rtadv.AdvDefaultLifetime = lifetime; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_default_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.AdvDefaultLifetime = -1; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/fast-retransmit + */ +int lib_interface_zebra_ipv6_router_advertisements_fast_retransmit_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool fast_retransmit; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + fast_retransmit = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.UseFastRexmit = fast_retransmit; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/advertisement-interval-option + */ +int lib_interface_zebra_ipv6_router_advertisements_advertisement_interval_option_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + bool option; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + option = yang_dnode_get_bool(args->dnode, NULL); + + zif->rtadv.AdvIntervalOption = option; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-preference + */ +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint16_t preference; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + preference = yang_dnode_get_uint16(args->dnode, NULL); + + zif->rtadv.HomeAgentPreference = preference; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_home_agent_preference_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.HomeAgentPreference = 0; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/home-agent-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + uint16_t lifetime; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + lifetime = yang_dnode_get_uint16(args->dnode, NULL); + + zif->rtadv.HomeAgentLifetime = lifetime; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_home_agent_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + zif->rtadv.HomeAgentLifetime = -1; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/default-router-preference + */ +int lib_interface_zebra_ipv6_router_advertisements_default_router_preference_modify( + struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct zebra_if *zif; + int preference; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + zif = ifp->info; + + preference = yang_dnode_get_enum(args->dnode, NULL); + + zif->rtadv.DefaultPreference = preference; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct rtadv_prefix rp, *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv6p(&rp.prefix, args->dnode, "prefix-spec"); + rp.AdvOnLinkFlag = yang_dnode_get_bool(args->dnode, "on-link-flag"); + rp.AdvAutonomousFlag = yang_dnode_get_bool(args->dnode, + "autonomous-flag"); + rp.AdvRouterAddressFlag = yang_dnode_get_bool(args->dnode, + "router-address-flag"); + rp.AdvValidLifetime = yang_dnode_get_uint32(args->dnode, + "valid-lifetime"); + rp.AdvPreferredLifetime = yang_dnode_get_uint32(args->dnode, + "preferred-lifetime"); + + prefix = rtadv_add_prefix_manual(ifp->info, &rp); + nb_running_set_entry(args->dnode, prefix); + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, true); + + rtadv_delete_prefix_manual(ifp->info, prefix); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/valid-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_valid_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvValidLifetime = yang_dnode_get_uint32(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/on-link-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_on_link_flag_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvOnLinkFlag = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/preferred-lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_preferred_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvPreferredLifetime = yang_dnode_get_uint32(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/autonomous-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_autonomous_flag_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvAutonomousFlag = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/prefix-list/prefix/router-address-flag + */ +int lib_interface_zebra_ipv6_router_advertisements_prefix_list_prefix_router_address_flag_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_prefix *prefix; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + prefix = nb_running_get_entry(args->dnode, NULL, true); + + prefix->AdvRouterAddressFlag = yang_dnode_get_bool(args->dnode, NULL); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address + */ +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct rtadv_rdnss rdnss = {{{{0}}}}, *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv6(&rdnss.addr, args->dnode, "address"); + if (yang_dnode_exists(args->dnode, "lifetime")) { + rdnss.lifetime = yang_dnode_get_uint32(args->dnode, "lifetime"); + rdnss.lifetime_set = 1; + } else { + rdnss.lifetime_set = 0; + } + + p = rtadv_rdnss_set(ifp->info, &rdnss); + nb_running_set_entry(args->dnode, p); + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct rtadv_rdnss *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, true); + + rtadv_rdnss_reset(ifp->info, p); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address/lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_rdnss *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime = yang_dnode_get_uint32(args->dnode, NULL); + p->lifetime_set = 1; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct rtadv_rdnss *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime_set = 0; + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain + */ +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_create( + struct nb_cb_create_args *args) +{ + struct interface *ifp; + struct rtadv_dnssl dnssl = {{0}}, *p; + int ret; + + strlcpy(dnssl.name, yang_dnode_get_string(args->dnode, "domain"), + sizeof(dnssl.name)); + ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name); + dnssl.encoded_len = ret; + + if (args->event == NB_EV_VALIDATE) { + if (ret < 0) { + snprintfrr(args->errmsg, args->errmsg_len, + "Malformed DNS search domain"); + return NB_ERR_VALIDATION; + } + } + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + if (yang_dnode_exists(args->dnode, "lifetime")) { + dnssl.lifetime = yang_dnode_get_uint32(args->dnode, "lifetime"); + dnssl.lifetime_set = 1; + } else { + dnssl.lifetime_set = 0; + } + + p = rtadv_dnssl_set(ifp->info, &dnssl); + nb_running_set_entry(args->dnode, p); + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_destroy( + struct nb_cb_destroy_args *args) +{ + struct interface *ifp; + struct rtadv_dnssl *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_unset_entry(args->dnode); + ifp = nb_running_get_entry(args->dnode, NULL, true); + + rtadv_dnssl_reset(ifp->info, p); + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/dnssl/dnssl-domain/lifetime + */ +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_modify( + struct nb_cb_modify_args *args) +{ + struct rtadv_dnssl *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime = yang_dnode_get_uint32(args->dnode, NULL); + p->lifetime_set = 1; + + return NB_OK; +} + +int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy( + struct nb_cb_destroy_args *args) +{ + struct rtadv_dnssl *p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + p = nb_running_get_entry(args->dnode, NULL, true); + + p->lifetime_set = 0; + + return NB_OK; +} +#endif /* defined(HAVE_RTADV) */ + +#if HAVE_BFDD == 0 +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/ptm-enable + */ +int lib_interface_zebra_ptm_enable_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + bool ptm; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ifp = nb_running_get_entry(args->dnode, NULL, true); + + ptm = yang_dnode_get_bool(args->dnode, NULL); + if (ptm) + zebra_if_ptm_enable(ifp); + else + zebra_if_ptm_disable(ifp); + + return NB_OK; +} +#endif + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/router-id + */ +int lib_vrf_zebra_router_id_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv4p(&p, args->dnode, NULL); + + router_id_set(AFI_IP, &p, vrf->info); + + return NB_OK; +} + +int lib_vrf_zebra_router_id_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + memset(&p, 0, sizeof(p)); + p.family = AF_INET; + + router_id_set(AFI_IP, &p, vrf->info); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-router-id + */ +int lib_vrf_zebra_ipv6_router_id_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + yang_dnode_get_ipv6p(&p, args->dnode, NULL); + + router_id_set(AFI_IP6, &p, vrf->info); + + return NB_OK; +} + +int lib_vrf_zebra_ipv6_router_id_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct prefix p; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + memset(&p, 0, sizeof(p)); + p.family = AF_INET6; + + router_id_set(AFI_IP6, &p, vrf->info); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol + */ +int lib_vrf_zebra_filter_protocol_create(struct nb_cb_create_args *args) +{ + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + int rtype; + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + if (args->event == NB_EV_VALIDATE) + if (rtype < 0) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid protocol name \"%s\"", proto); + return NB_ERR_VALIDATION; + } + + /* the creation finishes in the apply_finish callback */ + + return NB_OK; +} + +int lib_vrf_zebra_filter_protocol_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* deleting an existing entry, it can't be invalid */ + assert(rtype >= 0); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_protocol_rm_del(vrf->info, rmap, rtype, afi, safi); + + return NB_OK; +} + +void lib_vrf_zebra_filter_protocol_apply_finish( + struct nb_cb_apply_finish_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* finishing apply for a validated entry, it can't be invalid */ + assert(rtype >= 0); + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_protocol_rm_add(vrf->info, rmap, rtype, afi, safi); +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-protocol/route-map + */ +int lib_vrf_zebra_filter_protocol_route_map_modify(struct nb_cb_modify_args *args) +{ + /* the update is done in the apply_finish callback */ + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht + */ +int lib_vrf_zebra_filter_nht_create(struct nb_cb_create_args *args) +{ + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + if (args->event == NB_EV_VALIDATE) { + if (rtype < 0) { + snprintfrr(args->errmsg, args->errmsg_len, + "invalid protocol name \"%s\"", proto); + return NB_ERR_VALIDATION; + } + if (safi != SAFI_UNICAST) { + snprintfrr(args->errmsg, args->errmsg_len, + "only SAFI unicast is supported"); + return NB_ERR_VALIDATION; + } + } + + /* the creation finishes in the apply_finish callback */ + + return NB_OK; +} + +int lib_vrf_zebra_filter_nht_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* deleting an existing entry, it can't be invalid */ + assert(rtype >= 0); + assert(safi == SAFI_UNICAST); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_nht_rm_del(vrf->info, rmap, rtype, afi); + + return NB_OK; +} + +void lib_vrf_zebra_filter_nht_apply_finish(struct nb_cb_apply_finish_args *args) +{ + struct vrf *vrf; + const char *afi_safi = yang_dnode_get_string(args->dnode, "afi-safi"); + const char *proto = yang_dnode_get_string(args->dnode, "protocol"); + const char *rmap = yang_dnode_get_string(args->dnode, "route-map"); + afi_t afi; + safi_t safi; + int rtype; + + yang_afi_safi_identity2value(afi_safi, &afi, &safi); + + if (strcasecmp(proto, "any") == 0) + rtype = ZEBRA_ROUTE_MAX; + else + rtype = proto_name2num(proto); + + /* finishing apply for an existing entry, it can't be invalid */ + assert(rtype >= 0); + assert(safi == SAFI_UNICAST); + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + ip_nht_rm_add(vrf->info, rmap, rtype, afi); +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/filter-nht/route-map + */ +int lib_vrf_zebra_filter_nht_route_map_modify(struct nb_cb_modify_args *args) +{ + /* the update is done in the apply_finish callback */ + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/resolve-via-default + */ +int lib_vrf_zebra_resolve_via_default_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = yang_dnode_get_bool(args->dnode, NULL); + + if (zvrf->zebra_rnh_ip_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ip_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +int lib_vrf_zebra_resolve_via_default_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT; + + if (zvrf->zebra_rnh_ip_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ip_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ipv6-resolve-via-default + */ +int lib_vrf_zebra_ipv6_resolve_via_default_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = yang_dnode_get_bool(args->dnode, NULL); + + if (zvrf->zebra_rnh_ipv6_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ipv6_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +int lib_vrf_zebra_ipv6_resolve_via_default_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct zebra_vrf *zvrf; + bool resolve_via_default; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + zvrf = vrf->info; + + resolve_via_default = DFLT_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT; + + if (zvrf->zebra_rnh_ipv6_default_route == resolve_via_default) + return NB_OK; + + zvrf->zebra_rnh_ipv6_default_route = resolve_via_default; + + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range + */ +static int table_range_validate(uint32_t start, uint32_t end, char *errmsg, + size_t errmsg_len) +{ +#if defined(GNU_LINUX) + if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL) || + (end >= RT_TABLE_ID_COMPAT && end <= RT_TABLE_ID_LOCAL)) { + snprintfrr(errmsg, errmsg_len, + "Values forbidden in range [%u;%u]", + RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); + return NB_ERR_VALIDATION; + } + if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) { + snprintfrr(errmsg, errmsg_len, + "Range overlaps range [%u;%u] forbidden", + RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL); + return NB_ERR_VALIDATION; + } +#endif + return NB_OK; +} + +int lib_vrf_zebra_netns_table_range_create(struct nb_cb_create_args *args) +{ + struct vrf *vrf; + uint32_t start, end; + const char *vrf_name; + + start = yang_dnode_get_uint32(args->dnode, "start"); + end = yang_dnode_get_uint32(args->dnode, "end"); + + if (args->event == NB_EV_VALIDATE) { + vrf_name = yang_dnode_get_string(args->dnode, "../../../name"); + if (!vrf_is_backend_netns() && + strcmp(vrf_name, VRF_DEFAULT_NAME)) { + snprintfrr(args->errmsg, args->errmsg_len, + "Configuration is not available in non-default VRFs when using VRF-lite backend."); + return NB_ERR_VALIDATION; + } + return table_range_validate(start, end, args->errmsg, + args->errmsg_len); + } + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(true, vrf->info, start, end); + + return NB_OK; +} + +int lib_vrf_zebra_netns_table_range_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(false, vrf->info, 0, 0); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/start + */ +int lib_vrf_zebra_netns_table_range_start_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + uint32_t start, end; + + start = yang_dnode_get_uint32(args->dnode, NULL); + end = yang_dnode_get_uint32(args->dnode, "../end"); + + if (args->event == NB_EV_VALIDATE) + return table_range_validate(start, end, args->errmsg, + args->errmsg_len); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(true, vrf->info, start, end); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/netns/table-range/end + */ +int lib_vrf_zebra_netns_table_range_end_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + uint32_t start, end; + + start = yang_dnode_get_uint32(args->dnode, "../start"); + end = yang_dnode_get_uint32(args->dnode, NULL); + + if (args->event == NB_EV_VALIDATE) + return table_range_validate(start, end, args->errmsg, + args->errmsg_len); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_get_entry(args->dnode, NULL, true); + + table_manager_range(true, vrf->info, start, end); + + return NB_OK; +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id + */ +int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + vni_t vni = 0; + bool pfx_only = false; + uint32_t count; + + vni = yang_dnode_get_uint32(args->dnode, NULL); + + switch (args->event) { + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_VALIDATE: + count = yang_dnode_count(args->dnode, + "/frr-vrf:lib/vrf/frr-zebra:zebra[l3vni-id='%u']", + vni); + if (count > 1) { + snprintfrr(args->errmsg, args->errmsg_len, + "vni %u is already mapped to another vrf", + vni); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pfx_only = yang_dnode_get_bool(args->dnode, "../prefix-only"); + + zebra_vxlan_process_vrf_vni_cmd(vrf->info, vni, + pfx_only ? 1 : 0, 1); + break; + } + + return NB_OK; +} + +int lib_vrf_zebra_l3vni_id_destroy(struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + vni_t vni = 0; + + switch (args->event) { + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_VALIDATE: + return NB_OK; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + vni = yang_dnode_get_uint32(args->dnode, NULL); + zebra_vxlan_process_vrf_vni_cmd(vrf->info, vni, 0, 0); break; } diff --git a/zebra/zebra_nb_rpcs.c b/zebra/zebra_nb_rpcs.c index 083ab3fde69d..744ba620f22e 100644 --- a/zebra/zebra_nb_rpcs.c +++ b/zebra/zebra_nb_rpcs.c @@ -12,6 +12,8 @@ #include "zebra/zebra_router.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" +#include "zebra/zebra_vxlan_if.h" +#include "zebra/zebra_evpn.h" /* * XPath: /frr-zebra:clear-evpn-dup-addr @@ -20,48 +22,41 @@ int clear_evpn_dup_addr_rpc(struct nb_cb_rpc_args *args) { struct zebra_vrf *zvrf; int ret = NB_OK; - struct yang_data *yang_dup_choice = NULL, *yang_dup_vni = NULL, - *yang_dup_ip = NULL, *yang_dup_mac = NULL; - - yang_dup_choice = yang_data_list_find(args->input, "%s/%s", args->xpath, - "input/clear-dup-choice"); + if (!is_evpn_enabled()) { + snprintf(args->errmsg, args->errmsg_len, + "%% EVPN not enabled\n"); + return NB_ERR_VALIDATION; + } zvrf = zebra_vrf_get_evpn(); - if (yang_dup_choice - && strcmp(yang_dup_choice->value, "all-case") == 0) { + if (yang_dnode_exists(args->input, "all-vnis")) { zebra_vxlan_clear_dup_detect_vni_all(zvrf); } else { - vni_t vni; + vni_t vni = yang_dnode_get_uint32(args->input, "vni-id"); struct ipaddr host_ip = {.ipa_type = IPADDR_NONE}; struct ethaddr mac; - yang_dup_vni = yang_data_list_find( - args->input, "%s/%s", args->xpath, - "input/clear-dup-choice/single-case/vni-id"); - if (yang_dup_vni) { - vni = yang_str2uint32(yang_dup_vni->value); - - yang_dup_mac = yang_data_list_find( - args->input, "%s/%s", args->xpath, - "input/clear-dup-choice/single-case/vni-id/mac-addr"); - yang_dup_ip = yang_data_list_find( - args->input, "%s/%s", args->xpath, - "input/clear-dup-choice/single-case/vni-id/vni-ipaddr"); - - if (yang_dup_mac) { - yang_str2mac(yang_dup_mac->value, &mac); - ret = zebra_vxlan_clear_dup_detect_vni_mac( - zvrf, vni, &mac, args->errmsg, - args->errmsg_len); - } else if (yang_dup_ip) { - yang_str2ip(yang_dup_ip->value, &host_ip); - ret = zebra_vxlan_clear_dup_detect_vni_ip( - zvrf, vni, &host_ip, args->errmsg, - args->errmsg_len); - } else - ret = zebra_vxlan_clear_dup_detect_vni(zvrf, - vni); + if (!zebra_evpn_lookup(vni)) { + snprintf(args->errmsg, args->errmsg_len, + "%% VNI %u does not exist\n", vni); + return NB_ERR_VALIDATION; + } + + if (yang_dnode_exists(args->input, "mac-addr")) { + yang_dnode_get_mac(&mac, args->input, "mac-addr"); + ret = zebra_vxlan_clear_dup_detect_vni_mac(zvrf, vni, + &mac, + args->errmsg, + args->errmsg_len); + } else if (yang_dnode_exists(args->input, "vni-ipaddr")) { + yang_dnode_get_ip(&host_ip, args->input, "vni-ipaddr"); + ret = zebra_vxlan_clear_dup_detect_vni_ip(zvrf, vni, + &host_ip, + args->errmsg, + args->errmsg_len); + } else { + ret = zebra_vxlan_clear_dup_detect_vni(zvrf, vni); } } if (ret < 0) diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index ba537475cbcc..63ac7877d0f9 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -49,8 +49,50 @@ lib_interface_zebra_state_down_count_get_elem(struct nb_cb_get_elem_args *args) struct yang_data * lib_interface_zebra_state_zif_type_get_elem(struct nb_cb_get_elem_args *args) { - /* TODO: implement me. */ - return NULL; + const struct interface *ifp = args->list_entry; + struct zebra_if *zebra_if; + const char *type = NULL; + + zebra_if = ifp->info; + + /* + * NOTE: when adding a new type to the switch, make sure it is defined + * in it's YANG model. + */ + switch (zebra_if->zif_type) { + case ZEBRA_IF_OTHER: + type = "frr-zebra:zif-other"; + break; + case ZEBRA_IF_VXLAN: + type = "frr-zebra:zif-vxlan"; + break; + case ZEBRA_IF_VRF: + type = "frr-zebra:zif-vrf"; + break; + case ZEBRA_IF_BRIDGE: + type = "frr-zebra:zif-bridge"; + break; + case ZEBRA_IF_VLAN: + type = "frr-zebra:zif-vlan"; + break; + case ZEBRA_IF_MACVLAN: + type = "frr-zebra:zif-macvlan"; + break; + case ZEBRA_IF_VETH: + type = "frr-zebra:zif-veth"; + break; + case ZEBRA_IF_BOND: + type = "frr-zebra:zif-bond"; + break; + case ZEBRA_IF_GRE: + type = "frr-zebra:zif-gre"; + break; + } + + if (!type) + return NULL; + + return yang_data_new_string(args->xpath, type); } /* @@ -145,6 +187,28 @@ lib_interface_zebra_state_mcast_group_get_elem(struct nb_cb_get_elem_args *args) return yang_data_new_ipv4(args->xpath, &vni->mcast_grp); } +/* + * XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/bond + */ +struct yang_data * +lib_interface_zebra_state_bond_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct interface *ifp = args->list_entry; + struct zebra_if *zebra_if; + struct interface *bond; + + if (!IS_ZEBRA_IF_BOND_SLAVE(ifp)) + return NULL; + + zebra_if = ifp->info; + bond = zebra_if->bondslave_info.bond_if; + + if (!bond) + return NULL; + + return yang_data_new_string(args->xpath, bond->name); +} + const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) { struct vrf *vrf = (struct vrf *)args->parent_list_entry; @@ -156,6 +220,8 @@ const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) safi_t safi; zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id); + if (!zvrf) + return NULL; if (args->list_entry == NULL) { afi = AFI_IP; @@ -167,7 +233,8 @@ const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args) } else { zrt = RB_NEXT(zebra_router_table_head, zrt); /* vrf_id/ns_id do not match, only walk for the given VRF */ - while (zrt && zrt->ns_id != zvrf->zns->ns_id) + while (zrt && (zrt->tableid != zvrf->table_id || + zrt->ns_id != zvrf->zns->ns_id)) zrt = RB_NEXT(zebra_router_table_head, zrt); } @@ -198,6 +265,8 @@ lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args) uint32_t table_id = 0; zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id); + if (!zvrf) + return NULL; yang_afi_safi_identity2value(args->keys->key[0], &afi, &safi); table_id = yang_str2uint32(args->keys->key[1]); @@ -208,6 +277,28 @@ lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args) return zebra_router_find_zrt(zvrf, table_id, afi, safi); } +const void * +lib_vrf_zebra_ribs_rib_lookup_next(struct nb_cb_lookup_entry_args *args) +{ + struct vrf *vrf = (struct vrf *)args->parent_list_entry; + struct zebra_vrf *zvrf; + afi_t afi; + safi_t safi; + uint32_t table_id = 0; + + zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id); + if (!zvrf) + return NULL; + + yang_afi_safi_identity2value(args->keys->key[0], &afi, &safi); + table_id = yang_str2uint32(args->keys->key[1]); + /* table_id 0 assume vrf's table_id. */ + if (!table_id) + table_id = zvrf->table_id; + + return zebra_router_find_next_zrt(zvrf, table_id, afi, safi); +} + /* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/afi-safi-name */ @@ -285,6 +376,25 @@ lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args) return rn; } +const void * +lib_vrf_zebra_ribs_rib_route_lookup_next(struct nb_cb_lookup_entry_args *args) +{ + const struct zebra_router_table *zrt = args->parent_list_entry; + struct prefix p; + struct route_node *rn; + + yang_str2prefix(args->keys->key[0], &p); + + rn = route_table_get_next(zrt->table, &p); + + if (!rn) + return NULL; + + route_unlock_node(rn); + + return rn; +} + /* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/prefix */ @@ -502,7 +612,7 @@ struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_uptime_get_elem( { struct route_entry *re = (struct route_entry *)args->list_entry; - return yang_data_new_date_and_time(args->xpath, re->uptime); + return yang_data_new_date_and_time(args->xpath, re->uptime, true); } /* diff --git a/zebra/zebra_neigh.c b/zebra/zebra_neigh.c index 0c3fb97afdf7..a222e7f6e8bc 100644 --- a/zebra/zebra_neigh.c +++ b/zebra/zebra_neigh.c @@ -83,7 +83,7 @@ zebra_neigh_new(ifindex_t ifindex, struct ipaddr *ip, struct ethaddr *mac) n->ifindex = ifindex; if (mac) { memcpy(&n->mac, mac, sizeof(*mac)); - n->flags |= ZEBRA_NEIGH_ENT_ACTIVE; + SET_FLAG(n->flags, ZEBRA_NEIGH_ENT_ACTIVE); } /* Add to rb_tree */ @@ -118,10 +118,8 @@ static void zebra_neigh_free(struct zebra_neigh_ent *n) /* if rules are still using the neigh mark it as inactive and * update the dataplane */ - if (n->flags & ZEBRA_NEIGH_ENT_ACTIVE) { - n->flags &= ~ZEBRA_NEIGH_ENT_ACTIVE; - memset(&n->mac, 0, sizeof(n->mac)); - } + UNSET_FLAG(n->flags, ZEBRA_NEIGH_ENT_ACTIVE); + memset(&n->mac, 0, sizeof(n->mac)); zebra_neigh_pbr_rules_update(n); return; } @@ -152,6 +150,19 @@ void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip) zebra_neigh_free(n); } +/* kernel neigh delete all for a given interface */ +void zebra_neigh_del_all(struct interface *ifp) +{ + struct zebra_neigh_ent *n, *nn; + + if (IS_ZEBRA_DEBUG_NEIGH) + zlog_debug("zebra neigh delete all for interface %s/%d", + ifp->name, ifp->ifindex); + + RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, nn) + zebra_neigh_del(ifp, &n->ip); +} + /* kernel neigh add */ void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac) @@ -168,7 +179,7 @@ void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip, return; memcpy(&n->mac, mac, sizeof(*mac)); - n->flags |= ZEBRA_NEIGH_ENT_ACTIVE; + SET_FLAG(n->flags, ZEBRA_NEIGH_ENT_ACTIVE); /* update rules linked to the neigh */ zebra_neigh_pbr_rules_update(n); @@ -188,7 +199,7 @@ void zebra_neigh_deref(struct zebra_pbr_rule *rule) rule->action.neigh = NULL; /* remove rule from the list and free if it is inactive */ list_delete_node(n->pbr_rule_list, &rule->action.neigh_listnode); - if (!(n->flags & ZEBRA_NEIGH_ENT_ACTIVE)) + if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ENT_ACTIVE)) zebra_neigh_free(n); } diff --git a/zebra/zebra_neigh.h b/zebra/zebra_neigh.h index b957b5efe580..adc5f94f76e1 100644 --- a/zebra/zebra_neigh.h +++ b/zebra/zebra_neigh.h @@ -43,6 +43,7 @@ struct zebra_neigh_info { extern void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip, struct ethaddr *mac); extern void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip); +extern void zebra_neigh_del_all(struct interface *ifp); extern void zebra_neigh_show(struct vty *vty); extern void zebra_neigh_init(void); extern void zebra_neigh_terminate(void); diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c index 0531ab959100..4cee3b89f198 100644 --- a/zebra/zebra_netns_id.c +++ b/zebra/zebra_netns_id.c @@ -5,6 +5,12 @@ */ #include +#include +#include + +#ifdef GNU_LINUX +#include +#endif #include "ns.h" #include "vrf.h" @@ -36,7 +42,7 @@ #define NETLINK_SOCKET_BUFFER_SIZE 512 #define NETLINK_ALIGNTO 4 #define NETLINK_ALIGN(len) \ - (((len) + NETLINK_ALIGNTO - 1) & ~(NETLINK_ALIGNTO - 1)) + CHECK_FLAG(((len) + NETLINK_ALIGNTO - 1), ~(NETLINK_ALIGNTO - 1)) #define NETLINK_NLATTR_LEN(_a, _b) (unsigned int)((char *)_a - (char *)_b) #endif /* defined(HAVE_NETLINK) */ @@ -60,7 +66,7 @@ static struct nlmsghdr *initiate_nlh(char *buf, unsigned int *seq, int type) nlh->nlmsg_type = type; nlh->nlmsg_flags = NLM_F_REQUEST; if (type == RTM_NEWNSID) - nlh->nlmsg_flags |= NLM_F_ACK; + SET_FLAG(nlh->nlmsg_flags, NLM_F_ACK); nlh->nlmsg_seq = *seq = frr_sequence32_next(); return nlh; } diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 4260d29c43a5..3ac4fdd73716 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -5,6 +5,7 @@ */ #include +#include #ifdef HAVE_NETLINK #ifdef HAVE_NETNS @@ -14,6 +15,7 @@ #include #endif #include +#include #include #include @@ -40,6 +42,10 @@ #define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000 #define ZEBRA_NS_POLLING_MAX_RETRIES 200 +#if !defined(__GLIBC__) +#define basename(src) (strrchr(src, '/') ? strrchr(src, '/') + 1 : src) +#endif + DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo"); static struct event *zebra_netns_notify_current; @@ -233,6 +239,7 @@ static void zebra_ns_ready_read(struct event *t) { struct zebra_netns_info *zns_info = EVENT_ARG(t); const char *netnspath; + const char *netnspath_basename; int err, stop_retry = 0; if (!zns_info) @@ -260,23 +267,24 @@ static void zebra_ns_ready_read(struct event *t) zebra_ns_continue_read(zns_info, stop_retry); return; } + netnspath_basename = basename(strdupa(netnspath)); /* check default name is not already set */ - if (strmatch(VRF_DEFAULT_NAME, basename(netnspath))) { - zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", basename(netnspath)); + if (strmatch(VRF_DEFAULT_NAME, netnspath_basename)) { + zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", netnspath_basename); zebra_ns_continue_read(zns_info, 1); return; } - if (zebra_ns_notify_is_default_netns(basename(netnspath))) { + if (zebra_ns_notify_is_default_netns(netnspath_basename)) { zlog_warn( "NS notify : NS %s is default VRF. Ignore VRF creation", - basename(netnspath)); + netnspath_basename); zebra_ns_continue_read(zns_info, 1); return; } /* success : close fd and create zns context */ - zebra_ns_notify_create_context_from_entry_name(basename(netnspath)); + zebra_ns_notify_create_context_from_entry_name(netnspath_basename); zebra_ns_continue_read(zns_info, 1); } @@ -303,7 +311,7 @@ static void zebra_ns_notify_read(struct event *t) char *netnspath; struct zebra_netns_info *netnsinfo; - if (!(event->mask & (IN_CREATE | IN_DELETE))) + if (!CHECK_FLAG(event->mask, (IN_CREATE | IN_DELETE))) continue; if (offsetof(struct inotify_event, name) + event->len @@ -349,7 +357,7 @@ static void zebra_ns_notify_read(struct event *t) memcpy(event_name, event->name, event->len); event_name[event->len - 1] = 0; - if (event->mask & IN_DELETE) { + if (CHECK_FLAG(event->mask, IN_DELETE)) { zebra_ns_delete(event_name); continue; } @@ -395,7 +403,7 @@ void zebra_ns_notify_parse(void) continue; } /* check default name is not already set */ - if (strmatch(VRF_DEFAULT_NAME, basename(dent->d_name))) { + if (strmatch(VRF_DEFAULT_NAME, basename(strdupa(dent->d_name)))) { zlog_warn("NS notify : NS %s is already default VRF.Cancel VRF Creation", dent->d_name); continue; } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9588f65fc676..8164e2a56fae 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -72,25 +72,13 @@ static uint32_t nhg_get_next_id(void) while (1) { id_counter++; - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: ID %u checking", __func__, id_counter); - if (id_counter == ZEBRA_NHG_PROTO_LOWER) { - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: ID counter wrapped", __func__); - id_counter = 0; continue; } - if (zebra_nhg_lookup_id(id_counter)) { - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: ID already exists", __func__); - - continue; - } - - break; + if (!zebra_nhg_lookup_id(id_counter)) + break; } return id_counter; @@ -321,8 +309,10 @@ static int zebra_nhg_insert_id(struct nhg_hash_entry *nhe) static void zebra_nhg_set_if(struct nhg_hash_entry *nhe, struct interface *ifp) { + struct zebra_if *zif = (struct zebra_if *)ifp->info; + nhe->ifp = ifp; - if_nhg_dependents_add(ifp, nhe); + nhg_connected_tree_add_nhe(&zif->nhg_dependents, nhe); } static void @@ -535,9 +525,18 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) struct nexthop *nexthop1; struct nexthop *nexthop2; - /* No matter what if they equal IDs, assume equal */ - if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id)) - return true; + /* If both NHG's have id's then we can just know that + * they are either identical or not. This comparison + * is only ever used for hash equality. NHE's id + * is sufficient to distinguish them. This is especially + * true if NHG's are owned by an upper level protocol. + */ + if (nhe1->id && nhe2->id) { + if (nhe1->id == nhe2->id) + return true; + + return false; + } if (nhe1->type != nhe2->type) return false; @@ -690,12 +689,6 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ struct nhg_hash_entry *newnhe, *backup_nhe; struct nexthop *nh = NULL; - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug( - "%s: id %u, lookup %p, vrf %d, type %d, depends %p%s", - __func__, lookup->id, lookup, lookup->vrf_id, - lookup->type, nhg_depends, - (from_dplane ? " (from dplane)" : "")); if (lookup->id) (*nhe) = zebra_nhg_lookup_id(lookup->id); @@ -703,7 +696,10 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */ (*nhe) = hash_lookup(zrouter.nhgs, lookup); if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: lookup => %p (%pNG)", __func__, *nhe, *nhe); + zlog_debug("%s: id %u, lookup %p, vrf %d, type %d, depends %p%s => Found %p(%pNG)", + __func__, lookup->id, lookup, lookup->vrf_id, + lookup->type, nhg_depends, + (from_dplane ? " (from dplane)" : ""), *nhe, *nhe); /* If we found an existing object, we're done */ if (*nhe) @@ -1046,31 +1042,44 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, return ctx; } -static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe) +static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe, bool valid) { struct nhg_connected *rb_node_dep; - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + if (valid) + SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + else { + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); - frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) - zebra_nhg_set_valid(rb_node_dep->nhe); -} + /* If we're in shutdown, this interface event needs to clean + * up installed NHGs, so don't clear that flag directly. + */ + if (!zebra_router_in_shutdown()) + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + } -static void zebra_nhg_set_invalid(struct nhg_hash_entry *nhe) -{ - struct nhg_connected *rb_node_dep; + /* Update validity of nexthops depending on it */ + frr_each (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { + if (!valid) { + /* + * Grab the first nexthop from the depending nexthop group + * then let's find the nexthop in that group that matches + * my individual nexthop and mark it as no longer ACTIVE + */ + struct nexthop *nexthop = rb_node_dep->nhe->nhg.nexthop; - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + while (nexthop) { + if (nexthop_same(nexthop, nhe->nhg.nexthop)) + break; - /* If we're in shutdown, this interface event needs to clean - * up installed NHGs, so don't clear that flag directly. - */ - if (!zebra_router_in_shutdown()) - UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); + nexthop = nexthop->next; + } - /* Update validity of nexthops depending on it */ - frr_each(nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) - zebra_nhg_check_valid(rb_node_dep->nhe); + if (nexthop) + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } + zebra_nhg_set_valid(rb_node_dep->nhe, valid); + } } void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) @@ -1078,19 +1087,22 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) struct nhg_connected *rb_node_dep = NULL; bool valid = false; + /* + * If I have other nhe's depending on me, then this is a + * singleton nhe so set this nexthops flag as appropriate. + */ + if (nhg_connected_tree_count(&nhe->nhg_depends)) + UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE); + /* If anthing else in the group is valid, the group is valid */ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { if (CHECK_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID)) { valid = true; - goto done; + break; } } -done: - if (valid) - zebra_nhg_set_valid(nhe); - else - zebra_nhg_set_invalid(nhe); + zebra_nhg_set_valid(nhe, valid); } static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe) @@ -1098,8 +1110,11 @@ static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe) /* Remove it from any lists it may be on */ zebra_nhg_depends_release(nhe); zebra_nhg_dependents_release(nhe); - if (nhe->ifp) - if_nhg_dependents_del(nhe->ifp, nhe); + if (nhe->ifp) { + struct zebra_if *zif = nhe->ifp->info; + + nhg_connected_tree_del_nhe(&zif->nhg_dependents, nhe); + } } static void zebra_nhg_release(struct nhg_hash_entry *nhe) @@ -1131,7 +1146,7 @@ static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install) struct nhg_connected *rb_node_dep; frr_each_safe (nhg_connected_tree, &nhe->nhg_dependents, rb_node_dep) { - zebra_nhg_set_valid(rb_node_dep->nhe); + zebra_nhg_set_valid(rb_node_dep->nhe, true); /* install dependent NHG into kernel */ if (install) { if (IS_ZEBRA_DEBUG_NHG_DETAIL) @@ -1310,6 +1325,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx) break; case NHG_CTX_OP_DEL: ret = nhg_ctx_process_del(ctx); + break; case NHG_CTX_OP_NONE: break; } @@ -1525,19 +1541,23 @@ zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi) { struct nhg_hash_entry *nhe = NULL; - if (!(rt_nhe && rt_nhe->nhg.nexthop)) { + if (!rt_nhe) { flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, - "No nexthop passed to %s", __func__); + "No nhg_hash_entry passed to %s", __func__); return NULL; } - if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: rt_nhe %p (%pNG)", __func__, rt_nhe, rt_nhe); + if (!rt_nhe->nhg.nexthop) { + flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED, + "No nexthop passed to %s", __func__); + return NULL; + } zebra_nhe_find(&nhe, rt_nhe, NULL, rt_afi, false); if (IS_ZEBRA_DEBUG_NHG_DETAIL) - zlog_debug("%s: => nhe %p (%pNG)", __func__, nhe, nhe); + zlog_debug("%s: rt_nhe %p(%pNG) => nhe %p(%pNG)", __func__, + rt_nhe, rt_nhe, nhe, nhe); return nhe; } @@ -1762,6 +1782,12 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); resolved_hop->vrf_id = nexthop->vrf_id; + + /* Using weighted ECMP, we should respect the weight and use + * the same value for non-recursive next-hop. + */ + resolved_hop->weight = nexthop->weight; + switch (newhop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: @@ -1810,8 +1836,8 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, break; } - if (newhop->flags & NEXTHOP_FLAG_ONLINK) - resolved_hop->flags |= NEXTHOP_FLAG_ONLINK; + if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_ONLINK)) + SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ONLINK); /* Copy labels of the resolved route and the parent resolving to it */ if (policy) { @@ -2128,7 +2154,8 @@ zebra_nhg_connected_ifindex(struct route_node *rn, struct route_entry *match, * of those ifindexes match as well. */ RNODE_FOREACH_RE (rn, re) { - if (re->type != ZEBRA_ROUTE_CONNECT) + if (re->type != ZEBRA_ROUTE_CONNECT && + re->type != ZEBRA_ROUTE_LOCAL) continue; if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) @@ -2247,20 +2274,6 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, return 1; } - if (top && - ((top->family == AF_INET && top->prefixlen == IPV4_MAX_BITLEN && - nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr) || - (top->family == AF_INET6 && top->prefixlen == IPV6_MAX_BITLEN && - memcmp(&nexthop->gate.ipv6, &top->u.prefix6, IPV6_MAX_BYTELEN) == - 0)) && - nexthop->vrf_id == vrf_id) { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - " :%s: Attempting to install a max prefixlength route through itself", - __func__); - return 0; - } - /* Validation for ipv4 mapped ipv6 nexthop. */ if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) { afi = AFI_IP; @@ -2363,7 +2376,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, zlog_debug( " %s: Matched against ourself and prefix length is not max bit length", __func__); - return 0; + goto continue_up_tree; } /* Pick up selected route. */ @@ -2390,20 +2403,12 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, /* If there is no selected route or matched route is EGP, go up * tree. */ - if (!match) { - do { - rn = rn->parent; - } while (rn && rn->info == NULL); - if (rn) - route_lock_node(rn); - continue; - } /* If the candidate match's type is considered "connected", * we consider it first. */ - if (RIB_CONNECTED_ROUTE(match) || - (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) { + if (match && (RIB_CONNECTED_ROUTE(match) || + (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type)))) { match = zebra_nhg_connected_ifindex(rn, match, nexthop->ifindex); @@ -2419,11 +2424,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, zlog_debug( "%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv", __func__, nexthop, newhop); - /* - * NEXTHOP_TYPE_*_IFINDEX but ifindex - * doesn't match what we found. - */ - return 0; + goto continue_up_tree; } /* NHRP special case: need to indicate onlink */ @@ -2436,7 +2437,7 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, __func__, match, match->nhe, newhop); return 1; - } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) { + } else if (match && CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) { struct nexthop_group *nhg; struct nexthop *resolver; struct backup_nh_map_s map = {}; @@ -2472,6 +2473,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, "%s: match %p (%pNG) not installed or being Route Replaced", __func__, match, match->nhe); + if (CHECK_FLAG(match->status, + ROUTE_ENTRY_QUEUED)) + goto continue_up_tree; + goto done_with_match; } @@ -2540,25 +2545,37 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, if (pmtu) *pmtu = match->mtu; - } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) - zlog_debug( - " %s: Recursion failed to find", - __func__); - - return resolved; - } else { - if (IS_ZEBRA_DEBUG_RIB_DETAILED) { - zlog_debug( - " %s: Route Type %s has not turned on recursion", - __func__, zebra_route_string(type)); - if (type == ZEBRA_ROUTE_BGP - && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP)) + } else { + if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( - " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); + " %s: Recursion failed to find while looking at %pRN", + __func__, rn); + goto continue_up_tree; } - return 0; + + return 1; + } else if (IS_ZEBRA_DEBUG_RIB_DETAILED) { + zlog_debug( + " %s: Route Type %s has not turned on recursion %pRN failed to match", + __func__, zebra_route_string(type), rn); + if (type == ZEBRA_ROUTE_BGP + && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP)) + zlog_debug( + " EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\""); } + + continue_up_tree: + /* + * If there is no selected route or matched route is EGP, go up + * tree. + */ + do { + rn = rn->parent; + } while (rn && rn->info == NULL); + if (rn) + route_lock_node(rn); } + if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug(" %s: Nexthop did not lookup in table", __func__); @@ -3114,14 +3131,15 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) zebra_nhg_install_kernel(rb_node_dep->nhe); } - if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) - && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID) && + (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED) || + CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL)) && + !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) { /* Change its type to us since we are installing it */ if (!ZEBRA_NHG_CREATED(nhe)) nhe->type = ZEBRA_ROUTE_NHG; - int ret = dplane_nexthop_add(nhe); + enum zebra_dplane_result ret = dplane_nexthop_add(nhe); switch (ret) { case ZEBRA_DPLANE_REQUEST_QUEUED: @@ -3134,8 +3152,9 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe) nhe); break; case ZEBRA_DPLANE_REQUEST_SUCCESS: - SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); - zebra_nhg_handle_install(nhe, false); + flog_err(EC_ZEBRA_DP_INVALID_RC, + "DPlane returned an invalid result code for attempt of installation of %pNG into the kernel", + nhe); break; } } @@ -3182,8 +3201,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) "Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s", ctx, dplane_op2str(op), id, dplane_res2str(status)); - switch (op) { - case DPLANE_OP_NH_DELETE: + if (op == DPLANE_OP_NH_DELETE) { if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) flog_err( EC_ZEBRA_DP_DELETE_FAIL, @@ -3191,23 +3209,21 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) id); /* We already free'd the data, nothing to do */ - break; - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: + } else if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE) { nhe = zebra_nhg_lookup_id(id); if (!nhe) { if (IS_ZEBRA_DEBUG_NHG) - zlog_debug( - "%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table", - dplane_op2str(op), id); + zlog_debug("%s operation performed on Nexthop ID (%u) in the kernel, that we no longer have in our table", + dplane_op2str(op), id); - break; + return; } UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED); - if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { - SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID); + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL); + switch (status) { + case ZEBRA_DPLANE_REQUEST_SUCCESS: SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); zebra_nhg_handle_install(nhe, true); @@ -3216,7 +3232,9 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) zsend_nhg_notify(nhe->type, nhe->zapi_instance, nhe->zapi_session, nhe->id, ZAPI_NHG_INSTALLED); - } else { + break; + case ZEBRA_DPLANE_REQUEST_FAILURE: + UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED); /* If daemon nhg, send it an update */ if (PROTO_OWNED(nhe)) zsend_nhg_notify(nhe->type, nhe->zapi_instance, @@ -3229,62 +3247,13 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) EC_ZEBRA_DP_INSTALL_FAIL, "Failed to install Nexthop (%pNG) into the kernel", nhe); + break; + case ZEBRA_DPLANE_REQUEST_QUEUED: + flog_err(EC_ZEBRA_DP_INVALID_RC, + "Dplane returned an invalid result code for a result from the dplane for %pNG into the kernel", + nhe); + break; } - break; - - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: - case DPLANE_OP_ROUTE_DELETE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_NONE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: - break; } } @@ -3736,8 +3705,9 @@ void zebra_interface_nhg_reinstall(struct interface *ifp) "%s: Setting the valid flag for nhe %pNG, interface: %s", __func__, rb_node_dep->nhe, ifp->name); } + /* Check for singleton NHG associated to interface */ - if (nexthop_is_ifindex_type(nh) && + if (!nexthop_is_blackhole(nh) && zebra_nhg_depends_is_empty(rb_node_dep->nhe)) { struct nhg_connected *rb_node_dependent; @@ -3748,19 +3718,23 @@ void zebra_interface_nhg_reinstall(struct interface *ifp) rb_node_dep->nhe->flags); zebra_nhg_install_kernel(rb_node_dep->nhe); - /* mark depedent uninstall, when interface associated - * singleton is installed, install depedent + /* Don't need to modify dependents if installed */ + if (CHECK_FLAG(rb_node_dep->nhe->flags, + NEXTHOP_GROUP_INSTALLED)) + continue; + + /* mark dependent uninstalled; when interface associated + * singleton is installed, install dependent */ frr_each_safe (nhg_connected_tree, &rb_node_dep->nhe->nhg_dependents, rb_node_dependent) { if (IS_ZEBRA_DEBUG_NHG) - zlog_debug( - "%s dependent nhe %pNG unset installed flag", - __func__, - rb_node_dependent->nhe); - UNSET_FLAG(rb_node_dependent->nhe->flags, - NEXTHOP_GROUP_INSTALLED); + zlog_debug("%s dependent nhe %pNG Setting Reinstall flag", + __func__, + rb_node_dependent->nhe); + SET_FLAG(rb_node_dependent->nhe->flags, + NEXTHOP_GROUP_REINSTALL); } } } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 6179be3442e7..3bb697aa753c 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -85,7 +85,7 @@ struct nhg_hash_entry { * nhg(1)->nhg_dependents is 3 in the tree * * nhg(2)->nhg_depends is empty - * nhg(3)->nhg_dependents is 3 in the tree + * nhg(2)->nhg_dependents is 3 in the tree */ struct nhg_connected_tree_head nhg_depends, nhg_dependents; @@ -143,7 +143,15 @@ struct nhg_hash_entry { /* * Track FPM installation status.. */ -#define NEXTHOP_GROUP_FPM (1 << 6) +#define NEXTHOP_GROUP_FPM (1 << 7) + +/* + * When an interface comes up install the + * singleton's and schedule the NHG's that + * are using this nhg to be reinstalled + * when installation is successful. + */ +#define NEXTHOP_GROUP_REINSTALL (1 << 8) }; /* Upper 4 bits of the NHG are reserved for indicating the NHG type */ diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index ffdb9df531ef..803d8f0034c0 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -42,11 +42,6 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id) return (info == NULL) ? dzns : info; } -static struct zebra_ns *zebra_ns_alloc(void) -{ - return XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); -} - static int zebra_ns_new(struct ns *ns) { struct zebra_ns *zns; @@ -57,7 +52,7 @@ static int zebra_ns_new(struct ns *ns) if (IS_ZEBRA_DEBUG_EVENT) zlog_info("ZNS %s with id %u (created)", ns->name, ns->ns_id); - zns = zebra_ns_alloc(); + zns = XCALLOC(MTYPE_ZEBRA_NS, sizeof(struct zebra_ns)); ns->info = zns; zns->ns = ns; zns->ns_id = ns->ns_id; @@ -194,6 +189,8 @@ int zebra_ns_final_shutdown(struct ns *ns, kernel_terminate(zns, true); + zebra_ns_delete(ns); + return NS_WALK_CONTINUE; } @@ -241,10 +238,3 @@ int zebra_ns_init(void) return 0; } - -int zebra_ns_config_write(struct vty *vty, struct ns *ns) -{ - if (ns && ns->name != NULL) - vty_out(vty, " netns %s\n", ns->name); - return 0; -} diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index edf261197190..8d988c3f82d0 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -18,6 +18,8 @@ extern "C" { #endif #ifdef HAVE_NETLINK +#include + /* Socket interface to kernel */ struct nlsock { int sock; @@ -47,6 +49,8 @@ struct zebra_ns { struct nlsock netlink_dplane_out; struct nlsock netlink_dplane_in; struct event *t_netlink; + + struct nlsock ge_netlink_cmd; /* command channel for generic netlink */ #endif struct route_table *if_table; @@ -66,7 +70,6 @@ int zebra_ns_early_shutdown(struct ns *ns, int zebra_ns_final_shutdown(struct ns *ns, void *param_in __attribute__((unused)), void **param_out __attribute__((unused))); -int zebra_ns_config_write(struct vty *vty, struct ns *ns); void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 5124768a7c50..7f3635702f82 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -172,10 +172,13 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg) key = jhash_3words(rule->rule.filter.pcp, rule->rule.filter.vlan_id, rule->rule.filter.vlan_flags, key); - return jhash_3words(rule->rule.filter.src_port, - rule->rule.filter.dst_port, - prefix_hash_key(&rule->rule.filter.dst_ip), - jhash_1word(rule->rule.unique, key)); + key = jhash_3words(rule->rule.filter.src_port, + rule->rule.filter.dst_port, + prefix_hash_key(&rule->rule.filter.dst_ip), key); + + key = jhash_2words(rule->rule.unique, rule->sock, key); + + return key; } bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) @@ -191,6 +194,9 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) if (r1->rule.priority != r2->rule.priority) return false; + if (r1->sock != r2->sock) + return false; + if (r1->rule.unique != r2->rule.unique) return false; @@ -226,8 +232,9 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) struct pbr_rule_unique_lookup { struct zebra_pbr_rule *rule; + int sock; uint32_t unique; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; vrf_id_t vrf_id; }; @@ -236,9 +243,9 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) struct pbr_rule_unique_lookup *pul = data; struct zebra_pbr_rule *rule = b->data; - if (pul->unique == rule->rule.unique - && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0 - && pul->vrf_id == rule->vrf_id) { + if (pul->sock == rule->sock && pul->unique == rule->rule.unique && + strmatch(pul->ifname, rule->rule.ifname) && + pul->vrf_id == rule->vrf_id) { pul->rule = rule; return HASHWALK_ABORT; } @@ -252,9 +259,10 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) struct pbr_rule_unique_lookup pul; pul.unique = zrule->rule.unique; - strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ); + strlcpy(pul.ifname, zrule->rule.ifname, IFNAMSIZ); pul.rule = NULL; pul.vrf_id = zrule->vrf_id; + pul.sock = zrule->sock; hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); return pul.rule; diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index ddc1460d40af..1e4b5cd0f375 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -46,7 +46,7 @@ struct zebra_pbr_rule { struct pbr_rule rule; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; struct zebra_pbr_action action; diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index a678e7173471..d7d752f01e61 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -86,7 +86,6 @@ struct zebra_ptm_cb ptm_cb; static int zebra_ptm_socket_init(void); void zebra_ptm_sock_read(struct event *thread); -static void zebra_ptm_install_commands(void); static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt); void zebra_bfd_peer_replay_req(void); void zebra_ptm_send_status_req(void); @@ -115,7 +114,6 @@ void zebra_ptm_init(void) } ptm_cb.pid = getpid(); - zebra_ptm_install_commands(); snprintf(buf, sizeof(buf), "%s", FRR_PTM_NAME); ptm_hdl = ptm_lib_register(buf, NULL, zebra_ptm_handle_msg_cb, @@ -240,10 +238,7 @@ void zebra_ptm_connect(struct event *t) } } -DEFUN (zebra_ptm_enable, - zebra_ptm_enable_cmd, - "ptm-enable", - "Enable neighbor check with specified topology\n") +void zebra_global_ptm_enable(void) { struct vrf *vrf; struct interface *ifp; @@ -266,27 +261,16 @@ DEFUN (zebra_ptm_enable, } zebra_ptm_connect(NULL); - - return CMD_SUCCESS; } -DEFUN (no_zebra_ptm_enable, - no_zebra_ptm_enable_cmd, - "no ptm-enable", - NO_STR - "Enable neighbor check with specified topology\n") +void zebra_global_ptm_disable(void) { ptm_cb.ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; zebra_ptm_reset_status(1); - return CMD_SUCCESS; } -DEFUN (zebra_ptm_enable_if, - zebra_ptm_enable_if_cmd, - "ptm-enable", - "Enable neighbor check with specified topology\n") +void zebra_if_ptm_enable(struct interface *ifp) { - VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *if_data; int old_ptm_enable; int send_linkdown = 0; @@ -295,7 +279,7 @@ DEFUN (zebra_ptm_enable_if, if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_UNSPEC; if (ifp->ifindex == IFINDEX_INTERNAL) { - return CMD_SUCCESS; + return; } old_ptm_enable = ifp->ptm_enable; @@ -312,19 +296,12 @@ DEFUN (zebra_ptm_enable_if, if_down(ifp); } } - - return CMD_SUCCESS; } -DEFUN (no_zebra_ptm_enable_if, - no_zebra_ptm_enable_if_cmd, - "no ptm-enable", - NO_STR - "Enable neighbor check with specified topology\n") +void zebra_if_ptm_disable(struct interface *ifp) { - VTY_DECLVAR_CONTEXT(interface, ifp); - int send_linkup = 0; struct zebra_if *if_data; + int send_linkup = 0; if ((ifp->ifindex != IFINDEX_INTERNAL) && (ifp->ptm_enable)) { if (!if_is_operative(ifp)) @@ -341,17 +318,6 @@ DEFUN (no_zebra_ptm_enable_if, if_data = ifp->info; if_data->ptm_enable = ZEBRA_IF_PTM_ENABLE_OFF; - - return CMD_SUCCESS; -} - - -void zebra_ptm_write(struct vty *vty) -{ - if (ptm_cb.ptm_enable) - vty_out(vty, "ptm-enable\n"); - - return; } static int zebra_ptm_socket_init(void) @@ -394,14 +360,6 @@ static int zebra_ptm_socket_init(void) return sock; } -static void zebra_ptm_install_commands(void) -{ - install_element(CONFIG_NODE, &zebra_ptm_enable_cmd); - install_element(CONFIG_NODE, &no_zebra_ptm_enable_cmd); - install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd); - install_element(INTERFACE_NODE, &no_zebra_ptm_enable_if_cmd); -} - /* BFD session goes down, send message to the protocols. */ static void if_bfd_session_update(struct interface *ifp, struct prefix *dp, struct prefix *sp, int status, @@ -678,7 +636,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS) uint8_t detect_mul; unsigned int min_rx_timer; unsigned int min_tx_timer; - char if_name[INTERFACE_NAMSIZ]; + char if_name[IFNAMSIZ]; uint8_t len; void *out_ctxt; char buf[INET6_ADDRSTRLEN]; @@ -841,7 +799,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS) struct prefix src_p; struct prefix dst_p; uint8_t multi_hop; - char if_name[INTERFACE_NAMSIZ]; + char if_name[IFNAMSIZ]; uint8_t len; char buf[INET6_ADDRSTRLEN]; char tmp_buf[64]; @@ -1165,12 +1123,6 @@ void zebra_ptm_if_set_ptm_state(struct interface *ifp, ifp->ptm_enable = zebra_ifp->ptm_enable; } -void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp) -{ - if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF) - vty_out(vty, " no ptm-enable\n"); -} - #else /* HAVE_BFDD */ /* @@ -1533,16 +1485,6 @@ void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)), /* NOTHING */ } -void zebra_ptm_write(struct vty *vty __attribute__((__unused__))) -{ - /* NOTHING */ -} - -void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)), - struct zebra_if *zifp __attribute__((__unused__))) -{ - /* NOTHING */ -} void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)), struct zebra_if *zi __attribute__((__unused__))) { diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h index 4d09474b7f22..20a53e2fea46 100644 --- a/zebra/zebra_ptm.h +++ b/zebra/zebra_ptm.h @@ -58,9 +58,15 @@ struct zebra_ptm_cb { void zebra_ptm_init(void); void zebra_ptm_finish(void); void zebra_ptm_connect(struct event *t); -void zebra_ptm_write(struct vty *vty); int zebra_ptm_get_enable_state(void); +#if HAVE_BFDD == 0 +void zebra_global_ptm_enable(void); +void zebra_global_ptm_disable(void); +void zebra_if_ptm_enable(struct interface *ifp); +void zebra_if_ptm_disable(struct interface *ifp); +#endif + /* ZAPI message handlers */ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS); void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS); @@ -74,7 +80,6 @@ void zebra_ptm_show_status(struct vty *vty, json_object *json, void zebra_ptm_if_init(struct zebra_if *zebra_ifp); void zebra_ptm_if_set_ptm_state(struct interface *ifp, struct zebra_if *zebra_ifp); -void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp); #ifdef __cplusplus } diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index f76bf747d6a6..deed3b6ad3c3 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -377,15 +377,18 @@ static int zebra_pw_client_close(struct zserv *client) return 0; } -void zebra_pw_init(struct zebra_vrf *zvrf) +static void zebra_pw_init(void) +{ + hook_register(zserv_client_close, zebra_pw_client_close); +} + +void zebra_pw_init_vrf(struct zebra_vrf *zvrf) { RB_INIT(zebra_pw_head, &zvrf->pseudowires); RB_INIT(zebra_static_pw_head, &zvrf->static_pseudowires); - - hook_register(zserv_client_close, zebra_pw_client_close); } -void zebra_pw_exit(struct zebra_vrf *zvrf) +void zebra_pw_exit_vrf(struct zebra_vrf *zvrf) { struct zebra_pw *pw; @@ -396,6 +399,11 @@ void zebra_pw_exit(struct zebra_vrf *zvrf) } } +void zebra_pw_terminate(void) +{ + hook_unregister(zserv_client_close, zebra_pw_client_close); +} + DEFUN_NOSH (pseudowire_if, pseudowire_if_cmd, "pseudowire IFNAME", @@ -837,4 +845,6 @@ void zebra_pw_vty_init(void) install_element(VIEW_NODE, &show_pseudowires_cmd); install_element(VIEW_NODE, &show_pseudowires_detail_cmd); + + zebra_pw_init(); } diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index fd94d5e5edfe..431d663f7ce1 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -24,7 +24,7 @@ extern "C" { struct zebra_pw { RB_ENTRY(zebra_pw) pw_entry, static_pw_entry; vrf_id_t vrf_id; - char ifname[INTERFACE_NAMSIZ]; + char ifname[IFNAMSIZ]; ifindex_t ifindex; int type; int af; @@ -60,8 +60,9 @@ void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *, struct zebra_pw *zebra_pw_find(struct zebra_vrf *, const char *); void zebra_pw_update(struct zebra_pw *); void zebra_pw_install_failure(struct zebra_pw *pw, int pwstatus); -void zebra_pw_init(struct zebra_vrf *); -void zebra_pw_exit(struct zebra_vrf *); +void zebra_pw_init_vrf(struct zebra_vrf *); +void zebra_pw_exit_vrf(struct zebra_vrf *); +void zebra_pw_terminate(void); void zebra_pw_vty_init(void); #ifdef __cplusplus diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c05d69a2dd39..59190e9dd330 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -5,6 +5,10 @@ #include +#ifdef GNU_LINUX +#include +#endif + #include "command.h" #include "if.h" #include "linklist.h" @@ -25,6 +29,7 @@ #include "frr_pthread.h" #include "printfrr.h" #include "frrscript.h" +#include "frrdistance.h" #include "zebra/zebra_router.h" #include "zebra/connected.h" @@ -103,6 +108,9 @@ static const struct { [ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, ZEBRA_CONNECT_DISTANCE_DEFAULT, META_QUEUE_CONNECTED}, + [ZEBRA_ROUTE_LOCAL] = {ZEBRA_ROUTE_LOCAL, + ZEBRA_CONNECT_DISTANCE_DEFAULT, + META_QUEUE_CONNECTED}, [ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, ZEBRA_STATIC_DISTANCE_DEFAULT, META_QUEUE_STATIC}, @@ -130,6 +138,7 @@ static const struct { [ZEBRA_ROUTE_OLSR] = {ZEBRA_ROUTE_OLSR, ZEBRA_MAX_DISTANCE_DEFAULT, META_QUEUE_OTHER}, [ZEBRA_ROUTE_TABLE] = {ZEBRA_ROUTE_TABLE, ZEBRA_TABLE_DISTANCE_DEFAULT, META_QUEUE_STATIC}, + [ZEBRA_ROUTE_TABLE_DIRECT] = {ZEBRA_ROUTE_TABLE_DIRECT, ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT, META_QUEUE_STATIC}, [ZEBRA_ROUTE_LDP] = {ZEBRA_ROUTE_LDP, ZEBRA_LDP_DISTANCE_DEFAULT, META_QUEUE_OTHER}, [ZEBRA_ROUTE_VNC] = {ZEBRA_ROUTE_VNC, ZEBRA_EBGP_DISTANCE_DEFAULT, @@ -177,6 +186,7 @@ struct wq_nhg_wrapper { struct nhg_ctx *ctx; struct nhg_hash_entry *nhe; } u; + bool deletion; }; #define WQ_NHG_WRAPPER_TYPE_CTX 0x01 @@ -330,7 +340,7 @@ static char *_dump_re_status(const struct route_entry *re, char *buf, : "", CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "", CHECK_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING) - ? "Replacing" + ? "Replacing " : "", CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed " : "", @@ -521,7 +531,8 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id, if (rn) route_lock_node(rn); } else { - if (match->type != ZEBRA_ROUTE_CONNECT) { + if (match->type != ZEBRA_ROUTE_CONNECT && + match->type != ZEBRA_ROUTE_LOCAL) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) return NULL; @@ -623,7 +634,8 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) if (!match) return NULL; - if (match->type == ZEBRA_ROUTE_CONNECT) + if (match->type == ZEBRA_ROUTE_CONNECT || + match->type == ZEBRA_ROUTE_LOCAL) return match; if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) @@ -1122,27 +1134,15 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); } -/* Check if 'alternate' RIB entry is better than 'current'. */ -static struct route_entry *rib_choose_best(struct route_entry *current, - struct route_entry *alternate) +static struct route_entry *rib_choose_best_type(uint8_t route_type, + struct route_entry *current, + struct route_entry *alternate) { - if (current == NULL) - return alternate; - - /* filter route selection in following order: - * - connected beats other types - * - if both connected, loopback or vrf wins - * - lower distance beats higher - * - lower metric beats higher for equal distance - * - last, hence oldest, route wins tie break. - */ - - /* Connected routes. Check to see if either are a vrf - * or loopback interface. If not, pick the last connected - * route of the set of lowest metric connected routes. + /* + * We know that alternate and current are now non-NULL */ - if (alternate->type == ZEBRA_ROUTE_CONNECT) { - if (current->type != ZEBRA_ROUTE_CONNECT) + if (alternate->type == route_type) { + if (current->type != route_type) return alternate; /* both are connected. are either loop or vrf? */ @@ -1171,7 +1171,41 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return current; } - if (current->type == ZEBRA_ROUTE_CONNECT) + return NULL; +} + +/* Check if 'alternate' RIB entry is better than 'current'. */ +static struct route_entry *rib_choose_best(struct route_entry *current, + struct route_entry *alternate) +{ + struct route_entry *possible; + + if (current == NULL) + return alternate; + + /* filter route selection in following order: + * - Local beats Connected + * - connected beats other types + * - if both connected, loopback or vrf wins + * - lower distance beats higher + * - lower metric beats higher for equal distance + * - last, hence oldest, route wins tie break. + */ + + /* Connected or Local routes. Check to see if either are a vrf + * or loopback interface. If not, pick the last connected + * route of the set of lowest metric connected routes. + */ + possible = rib_choose_best_type(ZEBRA_ROUTE_LOCAL, current, alternate); + if (possible) + return possible; + + possible = rib_choose_best_type(ZEBRA_ROUTE_CONNECT, current, alternate); + if (possible) + return possible; + + if (current->type == ZEBRA_ROUTE_CONNECT || + current->type == ZEBRA_ROUTE_LOCAL) return current; /* higher distance loses */ @@ -1200,6 +1234,7 @@ static void rib_process(struct route_node *rn) rib_dest_t *dest; struct zebra_vrf *zvrf = NULL; struct vrf *vrf; + struct route_entry *proto_re_changed = NULL; vrf_id_t vrf_id = VRF_UNKNOWN; @@ -1269,6 +1304,7 @@ static void rib_process(struct route_node *rn) * skip it. */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { + proto_re_changed = re; if (!nexthop_active_update(rn, re)) { const struct prefix *p; struct rib_table_info *info; @@ -1354,6 +1390,8 @@ static void rib_process(struct route_node *rn) * new_selected --- RE entry that is newly SELECTED * old_fib --- RE entry currently in kernel FIB * new_fib --- RE entry that is newly to be in kernel FIB + * proto_re_changed -- RE that is the last changed entry in the + * list of RE's. * * new_selected will get SELECTED flag, and is going to be redistributed * the zclients. new_fib (which can be new_selected) will be installed @@ -1408,6 +1446,22 @@ static void rib_process(struct route_node *rn) } } + /* + * If zebra has a new_selected and a proto_re_changed + * entry that was not the old selected and the protocol + * is different, zebra should notify the upper level + * protocol that the sent down entry was not selected + */ + if (new_selected && proto_re_changed && + proto_re_changed != old_selected && + new_selected->type != proto_re_changed->type) { + struct rib_table_info *info = srcdest_rnode_table_info(rn); + + zsend_route_notify_owner(rn, proto_re_changed, + ZAPI_ROUTE_BETTER_ADMIN_WON, info->afi, + info->safi); + } + /* Update fib according to selection results */ if (new_fib && old_fib) rib_process_update_fib(zvrf, rn, old_fib, new_fib); @@ -1506,7 +1560,8 @@ static bool rib_route_match_ctx(const struct route_entry *re, } else if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != dplane_ctx_get_metric(ctx)) { result = false; - } else if (re->type == ZEBRA_ROUTE_CONNECT) { + } else if (re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL) { result = nexthop_group_equal_no_recurse( &re->nhe->nhg, dplane_ctx_get_ng(ctx)); } @@ -1564,7 +1619,7 @@ static bool rib_compare_routes(const struct route_entry *re1, * v6 link-locals, and we also support multiple addresses in the same * subnet on a single interface. */ - if (re1->type != ZEBRA_ROUTE_CONNECT) + if (re1->type != ZEBRA_ROUTE_CONNECT && re1->type != ZEBRA_ROUTE_LOCAL) return true; return false; @@ -1604,6 +1659,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg, if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; + /* Check for a FIB nexthop corresponding to the RIB nexthop */ if (!nexthop_same(ctx_nexthop, nexthop)) { /* If the FIB doesn't know about the nexthop, @@ -2014,9 +2072,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) UNSET_FLAG(old_re->status, ROUTE_ENTRY_QUEUED); } - switch (op) { - case DPLANE_OP_ROUTE_INSTALL: - case DPLANE_OP_ROUTE_UPDATE: + if (op == DPLANE_OP_ROUTE_INSTALL || op == DPLANE_OP_ROUTE_UPDATE) { if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) { if (re) { UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED); @@ -2107,8 +2163,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) VRF_LOGNAME(vrf), dplane_ctx_get_vrf(ctx), dplane_ctx_get_table(ctx), rn); } - break; - case DPLANE_OP_ROUTE_DELETE: + } else if (op == DPLANE_OP_ROUTE_DELETE) { rt_delete = true; if (re) SET_FLAG(re->status, ROUTE_ENTRY_FAILED); @@ -2147,61 +2202,6 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) if ((re && RIB_SYSTEM_ROUTE(re)) || (old_re && RIB_SYSTEM_ROUTE(old_re))) zebra_rib_fixup_system(rn); - break; - - case DPLANE_OP_NONE: - case DPLANE_OP_ROUTE_NOTIFY: - case DPLANE_OP_NH_INSTALL: - case DPLANE_OP_NH_UPDATE: - case DPLANE_OP_NH_DELETE: - case DPLANE_OP_LSP_INSTALL: - case DPLANE_OP_LSP_UPDATE: - case DPLANE_OP_LSP_DELETE: - case DPLANE_OP_LSP_NOTIFY: - case DPLANE_OP_PW_INSTALL: - case DPLANE_OP_PW_UNINSTALL: - case DPLANE_OP_SYS_ROUTE_ADD: - case DPLANE_OP_SYS_ROUTE_DELETE: - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_MAC_INSTALL: - case DPLANE_OP_MAC_DELETE: - case DPLANE_OP_NEIGH_INSTALL: - case DPLANE_OP_NEIGH_UPDATE: - case DPLANE_OP_NEIGH_DELETE: - case DPLANE_OP_VTEP_ADD: - case DPLANE_OP_VTEP_DELETE: - case DPLANE_OP_RULE_ADD: - case DPLANE_OP_RULE_DELETE: - case DPLANE_OP_RULE_UPDATE: - case DPLANE_OP_NEIGH_DISCOVER: - case DPLANE_OP_BR_PORT_UPDATE: - case DPLANE_OP_IPTABLE_ADD: - case DPLANE_OP_IPTABLE_DELETE: - case DPLANE_OP_IPSET_ADD: - case DPLANE_OP_IPSET_DELETE: - case DPLANE_OP_IPSET_ENTRY_ADD: - case DPLANE_OP_IPSET_ENTRY_DELETE: - case DPLANE_OP_NEIGH_IP_INSTALL: - case DPLANE_OP_NEIGH_IP_DELETE: - case DPLANE_OP_NEIGH_TABLE_UPDATE: - case DPLANE_OP_GRE_SET: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_NETCONFIG: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - case DPLANE_OP_TC_QDISC_INSTALL: - case DPLANE_OP_TC_QDISC_UNINSTALL: - case DPLANE_OP_TC_CLASS_ADD: - case DPLANE_OP_TC_CLASS_DELETE: - case DPLANE_OP_TC_CLASS_UPDATE: - case DPLANE_OP_TC_FILTER_ADD: - case DPLANE_OP_TC_FILTER_DELETE: - case DPLANE_OP_TC_FILTER_UPDATE: - case DPLANE_OP_STARTUP_STAGE: - break; } zebra_rib_evaluate_rn_nexthops(rn, seq, rt_delete); @@ -2535,7 +2535,7 @@ static void process_subq_evpn(struct listnode *lnode) static void process_subq_nhg(struct listnode *lnode) { struct nhg_ctx *ctx; - struct nhg_hash_entry *nhe, *newnhe; + struct nhg_hash_entry *nhe, *newnhe, *oldnhe; struct wq_nhg_wrapper *w; uint8_t qindex = META_QUEUE_NHG; @@ -2567,15 +2567,33 @@ static void process_subq_nhg(struct listnode *lnode) subqueue2str(qindex)); /* Process incoming nhg update, probably from a proto daemon */ - newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, - nhe->zapi_instance, - nhe->zapi_session, &nhe->nhg, 0); + if (w->deletion) { + /* + * Delete the received nhg id + */ + oldnhe = zebra_nhg_proto_del(nhe->id, nhe->type); + if (oldnhe) { + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_REMOVED); + zebra_nhg_decrement_ref(oldnhe); + } else + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_REMOVE_FAIL); - /* Report error to daemon via ZAPI */ - if (newnhe == NULL) - zsend_nhg_notify(nhe->type, nhe->zapi_instance, - nhe->zapi_session, nhe->id, - ZAPI_NHG_FAIL_INSTALL); + } else { + newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, + nhe->zapi_instance, + nhe->zapi_session, + &nhe->nhg, 0); + + /* Report error to daemon via ZAPI */ + if (newnhe == NULL) + zsend_nhg_notify(nhe->type, nhe->zapi_instance, + nhe->zapi_session, nhe->id, + ZAPI_NHG_FAIL_INSTALL); + } /* Free temp nhe - we own that memory. */ zebra_nhg_free(nhe); @@ -2678,7 +2696,7 @@ static void early_route_memory_free(struct zebra_early_route *ere) if (ere->re_nhe) zebra_nhg_free(ere->re_nhe); - XFREE(MTYPE_RE, ere->re); + zebra_rib_route_entry_free(ere->re); XFREE(MTYPE_WQ_WRAPPER, ere); } @@ -2859,11 +2877,10 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); rib_addnode(rn, re, 1); + dest = rib_dest_from_rnode(rn); /* Free implicit route.*/ if (same) { - rib_dest_t *dest = rn->info; - - if (same == dest->selected_fib) + if (dest && same == dest->selected_fib) SET_FLAG(same->status, ROUTE_ENTRY_ROUTE_REPLACING); rib_delnode(rn, same); } @@ -2871,7 +2888,6 @@ static void process_subq_early_route_add(struct zebra_early_route *ere) /* See if we can remove some RE entries that are queued for * removal, but won't be considered in rib processing. */ - dest = rib_dest_from_rnode(rn); RNODE_FOREACH_RE_SAFE (rn, re, same) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { /* If the route was used earlier, must retain it. */ @@ -2948,8 +2964,8 @@ static void process_subq_early_route_delete(struct zebra_early_route *ere) struct nexthop *nh = NULL; - if (ere->re->nhe) - nh = ere->re->nhe->nhg.nexthop; + if (ere->re_nhe) + nh = ere->re_nhe->nhg.nexthop; /* Lookup same type route. */ RNODE_FOREACH_RE (rn, re) { @@ -2967,7 +2983,9 @@ static void process_subq_early_route_delete(struct zebra_early_route *ere) if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != ere->re->metric) continue; - if (re->type == ZEBRA_ROUTE_CONNECT && (rtnh = nh) && + if ((re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL) && + (rtnh = re->nhe->nhg.nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; @@ -3143,6 +3161,7 @@ struct meta_q_gr_run { vrf_id_t vrf_id; uint8_t proto; uint8_t instance; + time_t restart_time; }; static void process_subq_gr_run(struct listnode *lnode) @@ -3150,7 +3169,7 @@ static void process_subq_gr_run(struct listnode *lnode) struct meta_q_gr_run *gr_run = listgetdata(lnode); zebra_gr_process_client(gr_run->afi, gr_run->vrf_id, gr_run->proto, - gr_run->instance); + gr_run->instance, gr_run->restart_time); XFREE(MTYPE_WQ_WRAPPER, gr_run); } @@ -3341,7 +3360,8 @@ static int rib_meta_queue_nhg_ctx_add(struct meta_queue *mq, void *data) return 0; } -static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) +static int rib_meta_queue_nhg_process(struct meta_queue *mq, void *data, + bool deletion) { struct nhg_hash_entry *nhe = NULL; uint8_t qindex = META_QUEUE_NHG; @@ -3356,6 +3376,7 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) w->type = WQ_NHG_WRAPPER_TYPE_NHG; w->u.nhe = nhe; + w->deletion = deletion; listnode_add(mq->subq[qindex], w); mq->size++; @@ -3367,6 +3388,16 @@ static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) return 0; } +static int rib_meta_queue_nhg_add(struct meta_queue *mq, void *data) +{ + return rib_meta_queue_nhg_process(mq, data, false); +} + +static int rib_meta_queue_nhg_del(struct meta_queue *mq, void *data) +{ + return rib_meta_queue_nhg_process(mq, data, true); +} + static int rib_meta_queue_evpn_add(struct meta_queue *mq, void *data) { listnode_add(mq->subq[META_QUEUE_EVPN], data); @@ -3474,6 +3505,17 @@ int rib_queue_nhe_add(struct nhg_hash_entry *nhe) return mq_add_handler(nhe, rib_meta_queue_nhg_add); } +/* + * Enqueue incoming nhg from proto daemon for processing + */ +int rib_queue_nhe_del(struct nhg_hash_entry *nhe) +{ + if (nhe == NULL) + return -1; + + return mq_add_handler(nhe, rib_meta_queue_nhg_del); +} + /* * Enqueue evpn route for processing */ @@ -3794,7 +3836,8 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l, } static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, - struct zebra_vrf *zvrf) + const struct zebra_vrf *zvrf, + uint8_t proto, uint8_t instance) { struct zebra_early_route *ere; struct listnode *node, *nnode; @@ -3803,6 +3846,10 @@ static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id) continue; + if (proto != ZEBRA_ROUTE_ALL && + (proto != ere->re->type && instance != ere->re->instance)) + continue; + early_route_memory_free(ere); node->data = NULL; list_delete_node(l, node); @@ -3841,7 +3888,8 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) evpn_meta_queue_free(mq, mq->subq[i], zvrf); break; case META_QUEUE_EARLY_ROUTE: - early_route_meta_queue_free(mq, mq->subq[i], zvrf); + early_route_meta_queue_free(mq, mq->subq[i], zvrf, + ZEBRA_ROUTE_ALL, 0); break; case META_QUEUE_EARLY_LABEL: early_label_meta_queue_free(mq, mq->subq[i], zvrf); @@ -4021,9 +4069,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) rib_re_nhg_free(re); - zapi_re_opaque_free(re->opaque); - - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } void rib_delnode(struct route_node *rn, struct route_entry *re) @@ -4082,7 +4128,6 @@ static void _route_entry_dump_nh(const struct route_entry *re, ifp ? ifp->name : "Unknown"); break; case NEXTHOP_TYPE_IPV4: - /* fallthrough */ case NEXTHOP_TYPE_IPV4_IFINDEX: inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN); break; @@ -4228,7 +4273,8 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) return 0; } -int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) +int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance, + time_t restart_time) { struct meta_q_gr_run *gr_run; @@ -4238,6 +4284,7 @@ int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) gr_run->proto = proto; gr_run->vrf_id = vrf_id; gr_run->instance = instance; + gr_run->restart_time = restart_time; return mq_add_handler(gr_run, rib_meta_queue_gr_run_add); } @@ -4266,6 +4313,13 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, return re; } + +void zebra_rib_route_entry_free(struct route_entry *re) +{ + zapi_re_opaque_free(re); + XFREE(MTYPE_RE, re); +} + /* * Internal route-add implementation; there are a couple of different public * signatures. Callers in this path are responsible for the memory they @@ -4333,7 +4387,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* In error cases, free the route also */ if (ret < 0) - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return ret; } @@ -4650,6 +4704,10 @@ void rib_sweep_route(struct event *t) struct vrf *vrf; struct zebra_vrf *zvrf; + zrouter.rib_sweep_time = monotime(NULL); + /* TODO: Change to debug */ + zlog_info("Sweeping the RIB for stale routes..."); + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { if ((zvrf = vrf->info) == NULL) continue; @@ -4698,6 +4756,10 @@ unsigned long rib_score_proto(uint8_t proto, unsigned short instance) if (!zvrf) continue; + early_route_meta_queue_free(zrouter.mq, + zrouter.mq->subq[META_QUEUE_EARLY_ROUTE], + zvrf, proto, instance); + cnt += rib_score_proto_table(proto, instance, zvrf->table[AFI_IP][SAFI_UNICAST]) + rib_score_proto_table( @@ -4916,6 +4978,7 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: break; case DPLANE_OP_STARTUP_STAGE: @@ -4978,7 +5041,7 @@ static void check_route_info(void) } /* Routing information base initialize. */ -void rib_init(void) +void zebra_rib_init(void) { check_route_info(); @@ -4990,6 +5053,20 @@ void rib_init(void) zebra_dplane_init(rib_dplane_results); } +void zebra_rib_terminate(void) +{ + struct zebra_dplane_ctx *ctx; + + EVENT_OFF(t_dplane); + + ctx = dplane_ctx_dequeue(&rib_dplane_q); + while (ctx) { + dplane_ctx_fini(&ctx); + + ctx = dplane_ctx_dequeue(&rib_dplane_q); + } +} + /* * vrf_id_get_next * @@ -5043,7 +5120,7 @@ struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter) iter->vrf_id = VRF_DEFAULT; iter->afi_safi_ix = -1; - /* Fall through */ + fallthrough; case RIB_TABLES_ITER_S_ITERATING: iter->afi_safi_ix++; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 30d92c30f4d5..303a81bb3e2b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -513,10 +513,14 @@ static bool rnh_check_re_nexthops(const struct route_entry *re, goto done; } - /* Some special checks if registration asked for them. */ + /* + * Some special checks if registration asked for them. + * LOCAL routes are by their definition not CONNECTED + * and as such should not be considered here + */ if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) { - if ((re->type == ZEBRA_ROUTE_CONNECT) - || (re->type == ZEBRA_ROUTE_STATIC)) + if ((re->type == ZEBRA_ROUTE_CONNECT) || + (re->type == ZEBRA_ROUTE_STATIC)) ret = true; if (re->type == ZEBRA_ROUTE_NHRP) { @@ -822,7 +826,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, /* free RE and nexthops */ zebra_nhg_free(re->nhe); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } static void copy_state(struct rnh *rnh, const struct route_entry *re, @@ -1262,327 +1266,42 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, */ void show_nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, + const struct route_node *rn, const struct route_entry *re) { - json_object *json_labels = NULL; - json_object *json_backups = NULL; - json_object *json_seg6local = NULL; - json_object *json_seg6 = NULL; - json_object *json_segs = NULL; - int i; - - json_object_int_add(json_nexthop, "flags", nexthop->flags); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) - json_object_boolean_true_add(json_nexthop, "duplicate"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) - json_object_boolean_true_add(json_nexthop, "fib"); - - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - json_object_string_addf(json_nexthop, "ip", "%pI4", - &nexthop->gate.ipv4); - json_object_string_add(json_nexthop, "afi", "ipv4"); - - if (nexthop->ifindex) { - json_object_int_add(json_nexthop, "interfaceIndex", - nexthop->ifindex); - json_object_string_add(json_nexthop, "interfaceName", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - } - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - json_object_string_addf(json_nexthop, "ip", "%pI6", - &nexthop->gate.ipv6); - json_object_string_add(json_nexthop, "afi", "ipv6"); - - if (nexthop->ifindex) { - json_object_int_add(json_nexthop, "interfaceIndex", - nexthop->ifindex); - json_object_string_add(json_nexthop, "interfaceName", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - } - break; - - case NEXTHOP_TYPE_IFINDEX: - json_object_boolean_true_add(json_nexthop, "directlyConnected"); - json_object_int_add(json_nexthop, "interfaceIndex", - nexthop->ifindex); - json_object_string_add( - json_nexthop, "interfaceName", - ifindex2ifname(nexthop->ifindex, nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - json_object_boolean_true_add(json_nexthop, "unreachable"); - switch (nexthop->bh_type) { - case BLACKHOLE_REJECT: - json_object_boolean_true_add(json_nexthop, "reject"); - break; - case BLACKHOLE_ADMINPROHIB: - json_object_boolean_true_add(json_nexthop, - "adminProhibited"); - break; - case BLACKHOLE_NULL: - json_object_boolean_true_add(json_nexthop, "blackhole"); - break; - case BLACKHOLE_UNSPEC: - break; - } - break; - } - - /* This nexthop is a resolver for the parent nexthop. - * Set resolver flag for better clarity and delimiter - * in flat list of nexthops in json. - */ - if (nexthop->rparent) - json_object_boolean_true_add(json_nexthop, "resolver"); + bool display_vrfid = false; + uint8_t rn_family; - if ((re == NULL || (nexthop->vrf_id != re->vrf_id))) - json_object_string_add(json_nexthop, "vrf", - vrf_id_to_name(nexthop->vrf_id)); + if (re == NULL || nexthop->vrf_id != re->vrf_id) + display_vrfid = true; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) - json_object_boolean_true_add(json_nexthop, "duplicate"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - json_object_boolean_true_add(json_nexthop, "active"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) - json_object_boolean_true_add(json_nexthop, "onLink"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN)) - json_object_boolean_true_add(json_nexthop, "linkDown"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - json_object_boolean_true_add(json_nexthop, "recursive"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { - json_backups = json_object_new_array(); - for (i = 0; i < nexthop->backup_num; i++) { - json_object_array_add( - json_backups, - json_object_new_int(nexthop->backup_idx[i])); - } - - json_object_object_add(json_nexthop, "backupIndex", - json_backups); - } - - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->src.ipv4.s_addr) - json_object_string_addf(json_nexthop, "source", "%pI4", - &nexthop->src.ipv4); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) - json_object_string_addf(json_nexthop, "source", "%pI6", - &nexthop->src.ipv6); - break; - case NEXTHOP_TYPE_IFINDEX: - case NEXTHOP_TYPE_BLACKHOLE: - break; - } - - if (nexthop->nh_label && nexthop->nh_label->num_labels) { - json_labels = json_object_new_array(); - - for (int label_index = 0; - label_index < nexthop->nh_label->num_labels; label_index++) - json_object_array_add( - json_labels, - json_object_new_int(( - (nexthop->nh_label_type == - ZEBRA_LSP_EVPN) - ? label2vni( - &nexthop->nh_label->label - [label_index]) - : nexthop->nh_label->label - [label_index]))); - - json_object_object_add(json_nexthop, "labels", json_labels); - } + if (rn) + rn_family = rn->p.family; + else + rn_family = AF_UNSPEC; - if (nexthop->weight) - json_object_int_add(json_nexthop, "weight", nexthop->weight); - - if (nexthop->srte_color) - json_object_int_add(json_nexthop, "srteColor", - nexthop->srte_color); - - if (nexthop->nh_srv6) { - json_seg6local = json_object_new_object(); - json_object_string_add( - json_seg6local, "action", - seg6local_action2str( - nexthop->nh_srv6->seg6local_action)); - json_object_object_add(json_nexthop, "seg6local", - json_seg6local); - if (nexthop->nh_srv6->seg6_segs && - nexthop->nh_srv6->seg6_segs->num_segs == 1) { - json_seg6 = json_object_new_object(); - json_object_string_addf(json_seg6, "segs", "%pI6", - &nexthop->nh_srv6->seg6_segs - ->seg[0]); - json_object_object_add(json_nexthop, "seg6", json_seg6); - } else { - json_segs = json_object_new_array(); - if (nexthop->nh_srv6->seg6_segs) { - for (int seg_idx = 0; - seg_idx < - nexthop->nh_srv6->seg6_segs->num_segs; - seg_idx++) - json_object_array_add( - json_segs, - json_object_new_stringf( - "%pI6", - &nexthop->nh_srv6 - ->seg6_segs - ->seg[seg_idx])); - json_object_object_add(json_nexthop, "seg6", - json_segs); - } - } - } + nexthop_json_helper(json_nexthop, nexthop, display_vrfid, rn_family); } /* * Helper for nexthop output, used in the 'show ip route' path */ -void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re, +void show_route_nexthop_helper(struct vty *vty, const struct route_node *rn, + const struct route_entry *re, const struct nexthop *nexthop) { - char buf[MPLS_LABEL_STRLEN]; - char seg_buf[SRV6_SEG_STRLEN]; - struct seg6_segs segs; - uint8_t i; - - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, " via %pI4", &nexthop->gate.ipv4); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, " via %s", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, - sizeof(buf))); - if (nexthop->ifindex) - vty_out(vty, ", %s", - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); - break; - - case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, " is directly connected, %s", - ifindex2ifname(nexthop->ifindex, nexthop->vrf_id)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out(vty, " unreachable"); - switch (nexthop->bh_type) { - case BLACKHOLE_REJECT: - vty_out(vty, " (ICMP unreachable)"); - break; - case BLACKHOLE_ADMINPROHIB: - vty_out(vty, " (ICMP admin-prohibited)"); - break; - case BLACKHOLE_NULL: - vty_out(vty, " (blackhole)"); - break; - case BLACKHOLE_UNSPEC: - break; - } - break; - } - - if ((re == NULL || (nexthop->vrf_id != re->vrf_id))) - vty_out(vty, " (vrf %s)", vrf_id_to_name(nexthop->vrf_id)); - - if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - vty_out(vty, " inactive"); + bool display_vrfid = false; + uint8_t rn_family; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) - vty_out(vty, " onlink"); + if (re == NULL || nexthop->vrf_id != re->vrf_id) + display_vrfid = true; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN)) - vty_out(vty, " linkdown"); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - vty_out(vty, " (recursive)"); - - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->src.ipv4.s_addr) { - vty_out(vty, ", src %pI4", &nexthop->src.ipv4); - /* SR-TE information */ - if (nexthop->srte_color) - vty_out(vty, ", SR-TE color %u", - nexthop->srte_color); - } - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) - vty_out(vty, ", src %pI6", &nexthop->src.ipv6); - break; - case NEXTHOP_TYPE_IFINDEX: - case NEXTHOP_TYPE_BLACKHOLE: - break; - } - - /* Label information */ - if (nexthop->nh_label && nexthop->nh_label->num_labels) { - vty_out(vty, ", label %s", - mpls_label2str(nexthop->nh_label->num_labels, - nexthop->nh_label->label, buf, - sizeof(buf), nexthop->nh_label_type, 1)); - } - - if (nexthop->nh_srv6) { - seg6local_context2str(buf, sizeof(buf), - &nexthop->nh_srv6->seg6local_ctx, - nexthop->nh_srv6->seg6local_action); - if (nexthop->nh_srv6->seg6local_action != - ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) - vty_out(vty, ", seg6local %s %s", - seg6local_action2str( - nexthop->nh_srv6->seg6local_action), - buf); - if (nexthop->nh_srv6->seg6_segs && - IPV6_ADDR_CMP(&nexthop->nh_srv6->seg6_segs->seg[0], - &in6addr_any)) { - segs.num_segs = nexthop->nh_srv6->seg6_segs->num_segs; - for (i = 0; i < segs.num_segs; i++) - memcpy(&segs.segs[i], - &nexthop->nh_srv6->seg6_segs->seg[i], - sizeof(struct in6_addr)); - snprintf_seg6_segs(seg_buf, SRV6_SEG_STRLEN, &segs); - vty_out(vty, ", seg6 %s", seg_buf); - } - } - - if (nexthop->weight) - vty_out(vty, ", weight %u", nexthop->weight); - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { - vty_out(vty, ", backup %d", nexthop->backup_idx[0]); + if (rn) + rn_family = rn->p.family; + else + rn_family = AF_UNSPEC; - for (i = 1; i < nexthop->backup_num; i++) - vty_out(vty, ",%d", nexthop->backup_idx[i]); - } + nexthop_vty_helper(vty, nexthop, display_vrfid, rn_family); } static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json) @@ -1640,9 +1359,10 @@ static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json) json_object_array_add(json_nexthop_array, json_nexthop); show_nexthop_json_helper(json_nexthop, nexthop, - NULL); + rn, NULL); } else { - show_route_nexthop_helper(vty, NULL, nexthop); + show_route_nexthop_helper(vty, rn, NULL, + nexthop); vty_out(vty, "\n"); } } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 07db7bbd7a10..f0b10d825c84 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -45,8 +45,10 @@ bool rnh_get_hide_backups(void); void show_nexthop_json_helper(json_object *json_nexthop, const struct nexthop *nexthop, + const struct route_node *rn, const struct route_entry *re); -void show_route_nexthop_helper(struct vty *vty, const struct route_entry *re, +void show_route_nexthop_helper(struct vty *vty, const struct route_node *rn, + const struct route_entry *re, const struct nexthop *nexthop); #ifdef __cplusplus diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 21aaf1d06658..46afbcecfa98 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -14,7 +14,6 @@ #include "filter.h" #include "plist.h" #include "nexthop.h" -#include "northbound_cli.h" #include "lib/route_types.h" #include "vrf.h" #include "frrstr.h" @@ -24,6 +23,7 @@ #include "zebra/debug.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" +#include "zebra/zebra_vrf.h" #include "zebra/zebra_routemap_clippy.c" @@ -36,8 +36,6 @@ struct zebra_rmap_obj { struct route_entry *re; }; -static void zebra_route_map_set_delay_timer(uint32_t value); - /* 'match tag TAG' * Match function return 1 if match is success else return 0 */ @@ -284,8 +282,8 @@ static const struct route_map_rule_cmd route_match_interface_cmd = { route_match_interface_free }; -static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, - int rtype, afi_t afi, safi_t safi) +int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, + afi_t afi, safi_t safi) { struct route_table *table; @@ -301,8 +299,7 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, route_map_lookup_by_name(PROTO_RM_NAME(zvrf, afi, rtype)); route_map_counter_increment(PROTO_RM_MAP(zvrf, afi, rtype)); - if (PROTO_RM_MAP(zvrf, afi, rtype)) { - + if (PROTO_RM_NAME(zvrf, afi, rtype)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "%u: IPv4 Routemap config for protocol %d scheduling RIB processing", @@ -317,8 +314,8 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, return CMD_SUCCESS; } -static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, - int rtype, afi_t afi, safi_t safi) +int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, + afi_t afi, safi_t safi) { struct route_table *table; @@ -328,7 +325,7 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, if (!rmap || strcmp(rmap, PROTO_RM_NAME(zvrf, afi, rtype)) == 0) { route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); - if (PROTO_RM_MAP(zvrf, afi, rtype)) { + if (PROTO_RM_NAME(zvrf, afi, rtype)) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug( "%u: IPv4 Routemap unconfig for protocol %d, scheduling RIB processing", @@ -346,8 +343,7 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, return CMD_SUCCESS; } -static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, - int afi) +int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, int afi) { if (NHT_RM_NAME(zvrf, afi, rtype)) { @@ -368,8 +364,7 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, return CMD_SUCCESS; } -static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, - int afi) +int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, int afi) { if (!NHT_RM_NAME(zvrf, afi, rtype)) @@ -391,351 +386,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, return CMD_SUCCESS; } -DEFPY_YANG( - match_ip_address_prefix_len, match_ip_address_prefix_len_cmd, - "match ip address prefix-len (0-32)$length", - MATCH_STR - IP_STR - "Match prefix length of IP address\n" - "Match prefix length of IP address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd, - "no match ip address prefix-len [(0-32)]", - NO_STR - MATCH_STR - IP_STR - "Match prefix length of IP address\n" - "Match prefix length of IP address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd, - "match ipv6 address prefix-len (0-128)$length", - MATCH_STR - IPV6_STR - "Match prefix length of IPv6 address\n" - "Match prefix length of IPv6 address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd, - "no match ipv6 address prefix-len [(0-128)]", - NO_STR - MATCH_STR - IPV6_STR - "Match prefix length of IPv6 address\n" - "Match prefix length of IPv6 address\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd, - "match ip next-hop prefix-len (0-32)$length", - MATCH_STR - IP_STR - "Match prefixlen of nexthop IP address\n" - "Match prefixlen of given nexthop\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd, - "no match ip next-hop prefix-len [(0-32)]", - NO_STR - MATCH_STR - IP_STR - "Match prefixlen of nexthop IP address\n" - "Match prefix length of nexthop\n" - "Prefix length\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_source_protocol, match_source_protocol_cmd, - "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto", - MATCH_STR - "Match protocol via which the route was learnt\n" - FRR_REDIST_HELP_STR_ZEBRA) -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-protocol']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:source-protocol", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_source_protocol, no_match_source_protocol_cmd, - "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]", - NO_STR - MATCH_STR - "Match protocol via which the route was learnt\n" - FRR_REDIST_HELP_STR_ZEBRA) -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-protocol']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - match_source_instance, match_source_instance_cmd, - "match source-instance (0-255)$instance", - MATCH_STR - "Match the protocol's instance number\n" - "The instance number\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-instance']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/rmap-match-condition/frr-zebra-route-map:source-instance", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_match_source_instance, no_match_source_instance_cmd, - "no match source-instance [(0-255)]", - NO_STR MATCH_STR - "Match the protocol's instance number\n" - "The instance number\n") -{ - const char *xpath = - "./match-condition[condition='frr-zebra-route-map:source-instance']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -/* set functions */ - -DEFPY_YANG( - set_src, set_src_cmd, - "set src ", - SET_STR - "src address for route\n" - "IPv4 src address\n" - "IPv6 src address\n") -{ - const char *xpath = - "./set-action[action='frr-zebra-route-map:src-address']"; - char xpath_value[XPATH_MAXLEN]; - - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - if (addrv4_str) { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - addrv4_str); - } else { - snprintf( - xpath_value, sizeof(xpath_value), - "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - addrv6_str); - } - - return nb_cli_apply_changes(vty, NULL); -} - -DEFPY_YANG( - no_set_src, no_set_src_cmd, - "no set src []", - NO_STR - SET_STR - "Source address for route\n" - "IPv4 address\n" - "IPv6 address\n") -{ - const char *xpath = - "./set-action[action='frr-zebra-route-map:src-address']"; - - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN_YANG (zebra_route_map_timer, - zebra_route_map_timer_cmd, - "zebra route-map delay-timer (0-600)", - ZEBRA_STR - "Set route-map parameters\n" - "Time to wait before route-map updates are processed\n" - "0 means route-map changes are run immediately instead of delaying\n") -{ - int idx_number = 3; - uint32_t rmap_delay_timer; - - rmap_delay_timer = strtoul(argv[idx_number]->arg, NULL, 10); - zebra_route_map_set_delay_timer(rmap_delay_timer); - - return (CMD_SUCCESS); -} - -DEFUN_YANG (no_zebra_route_map_timer, - no_zebra_route_map_timer_cmd, - "no zebra route-map delay-timer [(0-600)]", - NO_STR - ZEBRA_STR - "Set route-map parameters\n" - "Reset delay-timer to default value, 30 secs\n" - "0 means route-map changes are run immediately instead of delaying\n") -{ - zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER); - - return (CMD_SUCCESS); -} - -DEFPY_YANG (ip_protocol, - ip_protocol_cmd, - "ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP_STR - "Filter routing info exchanged between zebra and protocol\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - assert(rmap); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (no_ip_protocol, - no_ip_protocol_cmd, - "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto [route-map ROUTE-MAP$rmap]", - NO_STR - IP_STR - "Stop filtering routing info between zebra and protocol\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (show_ip_protocol, +DEFPY (show_ip_protocol, show_ip_protocol_cmd, "show ip protocol [vrf ]", SHOW_STR @@ -748,75 +399,7 @@ DEFPY_YANG (show_ip_protocol, return ret; } -DEFPY_YANG (ipv6_protocol, - ipv6_protocol_cmd, - "ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP6_STR - "Filter IPv6 routing info exchanged between zebra and protocol\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(rmap); - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (no_ipv6_protocol, - no_ipv6_protocol_cmd, - "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto [route-map ROUTE-MAP$rmap]", - NO_STR - IP6_STR - "Stop filtering IPv6 routing info between zebra and protocol\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route-map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST); - - return ret; -} - -DEFPY_YANG (show_ipv6_protocol, +DEFPY (show_ipv6_protocol, show_ipv6_protocol_cmd, "show ipv6 protocol [vrf ]", SHOW_STR @@ -829,76 +412,7 @@ DEFPY_YANG (show_ipv6_protocol, return ret; } -DEFPY_YANG (ip_protocol_nht_rmap, - ip_protocol_nht_rmap_cmd, - "ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - - int ret, rtype; - - assert(proto); - assert(rmap); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP); - - return ret; -} - -DEFPY_YANG (no_ip_protocol_nht_rmap, - no_ip_protocol_nht_rmap_cmd, - "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map [ROUTE-MAP$rmap]", - NO_STR - IP_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP); - - return ret; -} - -DEFPY_YANG (show_ip_protocol_nht, +DEFPY (show_ip_protocol_nht, show_ip_protocol_nht_cmd, "show ip nht route-map [vrf ] [json]", SHOW_STR @@ -917,75 +431,7 @@ DEFPY_YANG (show_ip_protocol_nht, return ret; } -DEFPY_YANG (ipv6_protocol_nht_rmap, - ipv6_protocol_nht_rmap_cmd, - "ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto route-map ROUTE-MAP$rmap", - IP6_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(rmap); - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP6); - - return ret; -} - -DEFPY_YANG (no_ipv6_protocol_nht_rmap, - no_ipv6_protocol_nht_rmap_cmd, - "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA - " $proto [route-map ROUTE-MAP$rmap]", - NO_STR - IP6_STR - "Filter Next Hop tracking route resolution\n" - FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA - "Specify route map\n" - "Route map name\n") -{ - int ret, rtype; - - assert(proto); - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (strcasecmp(proto, "any") == 0) - rtype = ZEBRA_ROUTE_MAX; - else - rtype = proto_name2num(proto); - if (rtype < 0) { - vty_out(vty, "invalid protocol name \"%s\"\n", proto); - return CMD_WARNING_CONFIG_FAILED; - } - - ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP6); - - return ret; -} - -DEFPY_YANG (show_ipv6_protocol_nht, +DEFPY (show_ipv6_protocol_nht, show_ipv6_protocol_nht_cmd, "show ipv6 nht route-map [vrf ] [json]", SHOW_STR @@ -1204,9 +650,8 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } @@ -1736,7 +1181,7 @@ static void zebra_route_map_update_timer(struct event *thread) */ } -static void zebra_route_map_set_delay_timer(uint32_t value) +void zebra_route_map_set_delay_timer(uint32_t value) { zebra_rmap_update_timer = value; if (!value && zebra_t_rmap_update) { @@ -1903,88 +1348,14 @@ void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf) } } -/* ip protocol configuration write function */ -void zebra_routemap_config_write_protocol(struct vty *vty, - struct zebra_vrf *zvrf) -{ - int i; - char space[2]; - - memset(space, 0, sizeof(space)); - - if (zvrf_id(zvrf) != VRF_DEFAULT) - snprintf(space, sizeof(space), "%s", " "); - - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (PROTO_RM_NAME(zvrf, AFI_IP, i)) - vty_out(vty, "%sip protocol %s route-map %s\n", space, - zebra_route_string(i), - PROTO_RM_NAME(zvrf, AFI_IP, i)); - - if (PROTO_RM_NAME(zvrf, AFI_IP6, i)) - vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, - zebra_route_string(i), - PROTO_RM_NAME(zvrf, AFI_IP6, i)); - - if (NHT_RM_NAME(zvrf, AFI_IP, i)) - vty_out(vty, "%sip nht %s route-map %s\n", space, - zebra_route_string(i), - NHT_RM_NAME(zvrf, AFI_IP, i)); - - if (NHT_RM_NAME(zvrf, AFI_IP6, i)) - vty_out(vty, "%sipv6 nht %s route-map %s\n", space, - zebra_route_string(i), - NHT_RM_NAME(zvrf, AFI_IP6, i)); - } - - if (PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sip protocol %s route-map %s\n", space, "any", - PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)); - - if (PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, "any", - PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)); - - if (NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sip nht %s route-map %s\n", space, "any", - NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)); - - if (NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)) - vty_out(vty, "%sipv6 nht %s route-map %s\n", space, "any", - NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)); - - if (zvrf_id(zvrf) == VRF_DEFAULT - && zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER) - vty_out(vty, "zebra route-map delay-timer %d\n", - zebra_rmap_update_timer); -} - void zebra_route_map_init(void) { - install_element(CONFIG_NODE, &ip_protocol_cmd); - install_element(CONFIG_NODE, &no_ip_protocol_cmd); - install_element(VRF_NODE, &ip_protocol_cmd); - install_element(VRF_NODE, &no_ip_protocol_cmd); install_element(VIEW_NODE, &show_ip_protocol_cmd); - install_element(CONFIG_NODE, &ipv6_protocol_cmd); - install_element(CONFIG_NODE, &no_ipv6_protocol_cmd); - install_element(VRF_NODE, &ipv6_protocol_cmd); - install_element(VRF_NODE, &no_ipv6_protocol_cmd); install_element(VIEW_NODE, &show_ipv6_protocol_cmd); - install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd); - install_element(CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &ip_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &no_ip_protocol_nht_rmap_cmd); install_element(VIEW_NODE, &show_ip_protocol_nht_cmd); - install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd); - install_element(CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &ipv6_protocol_nht_rmap_cmd); - install_element(VRF_NODE, &no_ipv6_protocol_nht_rmap_cmd); install_element(VIEW_NODE, &show_ipv6_protocol_nht_cmd); - install_element(CONFIG_NODE, &zebra_route_map_timer_cmd); - install_element(CONFIG_NODE, &no_zebra_route_map_timer_cmd); - route_map_init(); + route_map_init_new(true); route_map_add_hook(zebra_route_map_add); route_map_delete_hook(zebra_route_map_delete); @@ -2038,19 +1409,4 @@ void zebra_route_map_init(void) /* */ route_map_install_set(&route_set_src_cmd); - /* */ - install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd); - install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd); - install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd); - install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd); - install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd); - install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd); - install_element(RMAP_NODE, &match_source_protocol_cmd); - install_element(RMAP_NODE, &no_match_source_protocol_cmd); - install_element(RMAP_NODE, &match_source_instance_cmd); - install_element(RMAP_NODE, &no_match_source_instance_cmd); - - /* */ - install_element(RMAP_NODE, &set_src_cmd); - install_element(RMAP_NODE, &no_set_src_cmd); } diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index fceb53c8412f..2039e80e3a74 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -14,8 +14,6 @@ extern "C" { #endif extern void zebra_route_map_init(void); -extern void zebra_routemap_config_write_protocol(struct vty *vty, - struct zebra_vrf *vrf); extern char *zebra_get_import_table_route_map(afi_t afi, uint32_t table); extern void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name, uint32_t table); @@ -35,6 +33,16 @@ extern route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto, struct route_entry *re, struct nexthop *nexthop); +extern void zebra_route_map_set_delay_timer(uint32_t value); +extern int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, + int rtype, afi_t afi, safi_t safi); +extern int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, + int rtype, afi_t afi, safi_t safi); +extern int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, + int afi); +extern int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, + int afi); + extern void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf); #ifdef __cplusplus diff --git a/zebra/zebra_routemap_nb_config.c b/zebra/zebra_routemap_nb_config.c index 5bcfb720e17e..ad012da4c2cc 100644 --- a/zebra/zebra_routemap_nb_config.c +++ b/zebra/zebra_routemap_nb_config.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #include #include "lib/command.h" diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 4caaf8a9e27f..4022c1a26fc6 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -70,6 +70,26 @@ struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf, return zrt; } +struct zebra_router_table *zebra_router_find_next_zrt(struct zebra_vrf *zvrf, + uint32_t tableid, + afi_t afi, safi_t safi) +{ + struct zebra_router_table finder; + struct zebra_router_table *zrt; + + memset(&finder, 0, sizeof(finder)); + finder.afi = afi; + finder.safi = safi; + finder.tableid = tableid; + finder.ns_id = zvrf->zns->ns_id; + zrt = RB_NFIND(zebra_router_table_head, &zrouter.tables, &finder); + if (zrt->afi == afi && zrt->safi == safi && zrt->tableid == tableid && + zrt->ns_id == finder.ns_id) + zrt = RB_NEXT(zebra_router_table_head, zrt); + + return zrt; +} + struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi) @@ -218,7 +238,7 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; - EVENT_OFF(zrouter.sweeper); + EVENT_OFF(zrouter.t_rib_sweep); RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); @@ -241,11 +261,15 @@ void zebra_router_terminate(void) zebra_pbr_ipset_entry_free); hash_clean_and_free(&zrouter.ipset_hash, zebra_pbr_ipset_free); hash_clean_and_free(&zrouter.iptable_hash, zebra_pbr_iptable_free); + hash_clean_and_free(&zrouter.filter_hash, (void (*)(void *)) zebra_tc_filter_free); + hash_clean_and_free(&zrouter.qdisc_hash, (void (*)(void *)) zebra_tc_qdisc_free); + hash_clean_and_free(&zrouter.class_hash, (void (*)(void *)) zebra_tc_class_free); #ifdef HAVE_SCRIPTING zebra_script_destroy(); #endif + zebra_vxlan_terminate(); /* OS-specific deinit */ kernel_router_terminate(); } @@ -295,10 +319,6 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack, hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal, "Zebra Router Nexthop Groups ID index"); - zrouter.rules_hash = - hash_create_size(8, zebra_pbr_rules_hash_key, - zebra_pbr_rules_hash_equal, "Rules Hash"); - zrouter.qdisc_hash = hash_create_size(8, zebra_tc_qdisc_hash_key, zebra_tc_qdisc_hash_equal, "TC (qdisc) Hash"); @@ -323,6 +343,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack, #endif zrouter.asic_notification_nexthop_control = false; + zrouter.nexthop_weight_scale_value = 254; + #ifdef HAVE_SCRIPTING zebra_script_init(); #endif diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index bd86cfb49519..c86c6be1ef56 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -191,10 +191,16 @@ struct zebra_router { enum multicast_mode ipv4_multicast_mode; /* - * Time for when we sweep the rib from old routes + * zebra start time and time of sweeping RIB of old routes */ time_t startup_time; - struct event *sweeper; + time_t rib_sweep_time; + + /* FRR fast/graceful restart info */ + bool graceful_restart; + int gr_cleanup_time; +#define ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME 500 + struct event *t_rib_sweep; /* * The hash of nexthop groups associated with this router @@ -209,6 +215,8 @@ struct zebra_router { bool notify_on_ack; bool v6_with_v4_nexthop; + bool v6_rr_semantics; + /* * If the asic is notifying us about successful nexthop * allocation/control. Some developers have made their @@ -231,6 +239,8 @@ struct zebra_router { bool allow_delete; uint8_t protodown_r_bit; + + uint64_t nexthop_weight_scale_value; }; #define GRACEFUL_RESTART_TIME 60 @@ -246,6 +256,9 @@ extern void zebra_router_terminate(void); extern struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi); +extern struct zebra_router_table * +zebra_router_find_next_zrt(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, + safi_t safi); extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi, safi_t safi); diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index 9f8490ac66ff..6c34d12c6409 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -396,6 +396,7 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) lua_setfield(L, -2, "mtu"); } lua_setfield(L, -2, "gre"); + break; case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: @@ -414,6 +415,7 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) case DPLANE_OP_TC_FILTER_UPDATE: /* Not currently handled */ case DPLANE_OP_INTF_NETCONFIG: /*NYI*/ + case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: break; diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 8cab1849535b..1c6d58159e79 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -223,6 +223,8 @@ static int proto_trans(int type) return 1; /* other */ case ZEBRA_ROUTE_CONNECT: return 2; /* local interface */ + case ZEBRA_ROUTE_LOCAL: + return 2; case ZEBRA_ROUTE_STATIC: return 3; /* static route */ case ZEBRA_ROUTE_RIP: diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index 94b93e5e8dbb..082d4609aacd 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -17,11 +17,7 @@ #include "zebra/zebra_router.h" #include "zebra/zebra_srv6.h" #include "zebra/zebra_errors.h" -#include -#include -#include -#include -#include +#include "zebra/ge_netlink.h" #include #include @@ -32,6 +28,16 @@ DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager"); DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, + "SRv6 uSID Wide LIB information"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context"); + +/* Prototypes */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func); /* define hooks for the basic API, so that it can be specialized or served * externally @@ -54,6 +60,18 @@ DEFINE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DEFINE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DEFINE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); + /* define wrappers to be called in zapi_msg.c (as hooks must be called in * source file where they were defined) */ @@ -84,11 +102,502 @@ int srv6_manager_client_disconnect_cb(struct zserv *client) return 0; } + +void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value, + locator_name); +} + +void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + hook_call(srv6_manager_release_sid, client, ctx); +} + +void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + hook_call(srv6_manager_get_locator, locator, client, locator_name); +} + static int zebra_srv6_cleanup(struct zserv *client) { + /* Client has disconnected, let's release all the SIDs allocated by it. */ + release_daemon_srv6_sids(client); return 0; } +/* --- Zebra SRv6 SID context management functions -------------------------- */ + +struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void) +{ + struct zebra_srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX, + sizeof(struct zebra_srv6_sid_ctx)); + + return ctx; +} + +void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx); +} + +/** + * Free an SRv6 SID context. + * + * @param val SRv6 SID context to be freed + */ +void delete_zebra_srv6_sid_ctx(void *val) +{ + zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val); +} + +/* --- Zebra SRv6 SID format management functions --------------------------- */ + +void srv6_sid_format_register(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + /* Ensure that the format is registered only once */ + assert(!srv6_sid_format_lookup(format->name)); + + listnode_add(srv6->sid_formats, format); +} + +void srv6_sid_format_unregister(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + listnode_delete(srv6->sid_formats, format); +} + +struct srv6_sid_format *srv6_sid_format_lookup(const char *name) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_sid_format *format; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) + if (!strncmp(name, format->name, sizeof(format->name))) + return format; + + return NULL; +} + +/* + * Called to change the SID format of a locator. + * + * After switching the locator to a different format, the SIDs allocated + * from the locator may no longer be valid; we need to notify the + * interested zclient that the locator has changed, so that the + * zclients can withdraw/uninstall the old SIDs, allocate/advertise/program + * the new SIDs. + */ +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block_old, *block_new; + struct prefix_ipv6 block_pfx_new; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (!locator) + return; + + locator->sid_format = format; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, old=%s new=%s", + __func__, locator->name, + locator->sid_format ? ((struct srv6_sid_format *) + locator->sid_format) + ->name + : NULL, + format ? format->name : NULL); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients", + __func__, locator->name); + + /* Release the current parent block */ + block_old = locator->sid_block; + if (block_old) { + block_old->refcnt--; + if (block_old->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block_old); + zebra_srv6_sid_block_free(block_old); + } + } + locator->sid_block = NULL; + + block_pfx_new = locator->prefix; + if (format) + block_pfx_new.prefixlen = format->block_len; + else + block_pfx_new.prefixlen = locator->block_bits_length; + apply_mask(&block_pfx_new); + + /* Allocate the new parent block */ + block_new = zebra_srv6_sid_block_lookup(&block_pfx_new); + if (!block_new) { + block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new); + listnode_add(srv6->sid_blocks, block_new); + } + + block_new->refcnt++; + locator->sid_block = block_new; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients", + __func__, locator->name); + + /* Notify zclients about the updated locator */ + zebra_srv6_locator_add(locator); +} + +/* + * Called when a SID format is modified by the user. + * + * After modifying a SID format, the SIDs that are using that format may no + * longer be valid. + * This function walks through the list of locators that are using the SID format + * and notifies the zclients that the locator has changed, so that the zclients + * can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs. + */ +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SID format %s has changed. Notifying zclients.", + __func__, format->name); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (locator->sid_format == format) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.", + __func__, locator->name, + format->name); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + /* Notify zclients about the updated locator */ + zebra_notify_srv6_locator_add(locator); + } + } +} + +/* + * Helper function to create the SRv6 compressed format `usid-f3216`. + */ +static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_USID; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + return format; +} + +/* + * Helper function to create the SRv6 uncompressed format. + */ +static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + return format; +} + +/* --- Zebra SRv6 SID function management functions ---------------------------- */ + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func) +{ + uint32_t *sid_func_ptr; + + sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t)); + *sid_func_ptr = func; + + return sid_func_ptr; +} + +void zebra_srv6_sid_func_free(uint32_t *func) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func); +} + +/** + * Free an SRv6 SID function. + * + * @param val SRv6 SID function to be freed + */ +void delete_zebra_srv6_sid_func(void *val) +{ + zebra_srv6_sid_func_free((uint32_t *)val); +} + +/* --- Zebra SRv6 SID block management functions ---------------------------- */ + +static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void) +{ + struct zebra_srv6_sid_block *block = NULL; + + block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK, + sizeof(struct zebra_srv6_sid_block)); + + return block; +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix) +{ + struct zebra_srv6_sid_block *block; + + block = zebra_srv6_sid_block_alloc_internal(); + block->sid_format = format; + block->prefix = *prefix; + + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Init uSID LIB */ + block->u.usid.lib.func_allocated = list_new(); + block->u.usid.lib.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.func_released = list_new(); + block->u.usid.lib.func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.first_available_func = + format->config.usid.lib_start; + + /* Init uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + block->u.usid.wide_lib = + XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB, + (wlib_end - wlib_start + 1) * + sizeof(struct wide_lib)); + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + block->u.usid.wide_lib[func].func_allocated = + list_new(); + block->u.usid.wide_lib[func].func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func_released = + list_new(); + block->u.usid.wide_lib[func].func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func = func; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + } else { + /* We should never arrive here */ + assert(0); + } + } else { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = 1; + } + + return block; +} + +void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block) +{ + if (block->sid_format) { + if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Free uSID LIB */ + list_delete(&block->u.usid.lib.func_allocated); + list_delete(&block->u.usid.lib.func_released); + + /* Free uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + list_delete(&block->u.usid.wide_lib[func] + .func_allocated); + list_delete(&block->u.usid.wide_lib[func] + .func_released); + } + XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB, + block->u.usid.wide_lib); + } else if (block->sid_format->type == + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } + + XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block); +} + +/** + * Free an SRv6 SID block. + * + * @param val SRv6 SID block to be freed + */ +void delete_zebra_srv6_sid_block(void *val) +{ + zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val); +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block)) + if (prefix_match(prefix, &block->prefix)) + return block; + + return NULL; +} + +/* --- Zebra SRv6 SID management functions ---------------------------------- */ + +/** + * Alloc and fill an SRv6 SID. + * + * @param ctx Context associated with the SID to be created + * @param sid_value IPv6 address associated with the SID to be created + * @param locator Parent locator of the SID to be created + * @param sid_block Block from which the SID value has been allocated + * @param sid_func Function part of the SID to be created + * @param alloc_mode Allocation mode of the Function (dynamic vs explicit) + * @return The requested SID + */ +struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode) +{ + struct zebra_srv6_sid *sid; + + if (!ctx || !sid_value) + return NULL; + + sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid)); + sid->ctx = ctx; + sid->value = *sid_value; + sid->locator = locator; + sid->block = sid_block; + sid->func = sid_func; + sid->alloc_mode = alloc_mode; + sid->client_list = list_new(); + + return sid; +} + +void zebra_srv6_sid_free(struct zebra_srv6_sid *sid) +{ + list_delete(&sid->client_list); + XFREE(MTYPE_ZEBRA_SRV6_SID, sid); +} + +/** + * Free an SRv6 SID. + * + * @param val SRv6 SID to be freed + */ +void delete_zebra_srv6_sid(void *val) +{ + zebra_srv6_sid_free((struct zebra_srv6_sid *)val); +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -120,7 +629,6 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct zserv *client; @@ -135,18 +643,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn( - "%s: Not found zclient(proto=%u, instance=%u).", - __func__, c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } listnode_delete(srv6->locators, locator); srv6_locator_free(locator); @@ -189,7 +687,6 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator) void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zserv *client; /* @@ -203,27 +700,41 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn("Not found zclient(proto=%u, instance=%u).", - c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } } +struct zebra_srv6 srv6; + struct zebra_srv6 *zebra_srv6_get_default(void) { - static struct zebra_srv6 srv6; static bool first_execution = true; + struct srv6_sid_format *format_usidf3216; + struct srv6_sid_format *format_uncompressed; if (first_execution) { first_execution = false; srv6.locators = list_new(); + + /* Initialize list of SID formats */ + srv6.sid_formats = list_new(); + srv6.sid_formats->del = delete_srv6_sid_format; + + /* Create SID format `usid-f3216` */ + format_usidf3216 = create_srv6_sid_format_usid_f3216(); + srv6_sid_format_register(format_usidf3216); + + /* Create SID format `uncompressed` */ + format_uncompressed = create_srv6_sid_format_uncompressed(); + srv6_sid_format_register(format_uncompressed); + + /* Init list to store SRv6 SIDs */ + srv6.sids = list_new(); + srv6.sids->del = delete_zebra_srv6_sid_ctx; + + /* Init list to store SRv6 SID blocks */ + srv6.sid_blocks = list_new(); + srv6.sid_blocks->del = delete_zebra_srv6_sid_block; } return &srv6; } @@ -408,13 +919,1539 @@ int release_daemon_srv6_locator_chunks(struct zserv *client) return count; } -void zebra_srv6_init(void) +void zebra_srv6_encap_src_addr_set(struct in6_addr *encap_src_addr) { - hook_register(zserv_client_close, zebra_srv6_cleanup); - hook_register(srv6_manager_get_chunk, - zebra_srv6_manager_get_locator_chunk); - hook_register(srv6_manager_release_chunk, - zebra_srv6_manager_release_locator_chunk); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + if (!encap_src_addr) + return; + + memcpy(&srv6->encap_src_addr, encap_src_addr, sizeof(struct in6_addr)); +} + +void zebra_srv6_encap_src_addr_unset(void) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); +} + +/* --- SRv6 SID Allocation/Release functions -------------------------------- */ + +/** + * Return the SRv6 SID obtained composing the locator and function. + * + * @param sid_value SRv6 SID address returned + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, + struct srv6_locator *locator, + uint32_t sid_func) +{ + uint8_t offset, func_len; + struct srv6_sid_format *format; + + if (!sid_value || !locator) + return false; + + format = locator->sid_format; + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = locator->block_bits_length + locator->node_bits_length; + func_len = locator->function_bits_length; + } + + *sid_value = locator->prefix.prefix; + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + + sid_value->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); + if (sid_func >> (func_len - 1 - idx) & 0x1) + sid_value->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); + } + + return true; +} + +/** + * Return the parent locator and function of an SRv6 SID. + * + * @param sid_value SRv6 SID address to be decomposed + * @param sid_block Parent block of the SRv6 SID + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @param sid_wide_func Wide function of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_decompose(struct in6_addr *sid_value, + struct zebra_srv6_sid_block **sid_block, + struct srv6_locator **locator, + uint32_t *sid_func, uint32_t *sid_wide_func) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *l; + struct zebra_srv6_sid_block *b; + struct srv6_sid_format *format; + struct listnode *node; + struct prefix_ipv6 tmp_prefix; + uint8_t offset, func_len; + + if (!sid_value || !sid_func) + return false; + + *sid_func = 0; + *sid_wide_func = 0; + + /* + * Build a temporary prefix_ipv6 object representing the SRv6 SID. + * This temporary prefix object is used below by the prefix_match + * function to check if the SID belongs to a specific locator. + */ + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = *sid_value; + + /* + * Lookup the parent locator of the SID and return the locator and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, l)) { + /* + * Check if the locator prefix includes the temporary prefix + * representing the SID. + */ + if (prefix_match((struct prefix *)&l->prefix, + (struct prefix *)&tmp_prefix)) { + format = l->sid_format; + + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = l->block_bits_length + + l->node_bits_length; + func_len = l->function_bits_length; + } + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((func_len - 1 - idx) / 8) * 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = l->sid_format; + + offset = format->block_len + + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / + 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * + 8); + } + } + } + + *locator = l; + *sid_block = l->sid_block; + + return true; + } + } + + /* + * If we arrive here, the SID does not belong to any locator. + * Then, let's try to find the parent block from which the SID + * has been allocated. + */ + + /* + * Lookup the parent block of the SID and return the block and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, b)) { + /* + * Check if the block prefix includes the temporary prefix + * representing the SID + */ + if (prefix_match((struct prefix *)&b->prefix, + (struct prefix *)&tmp_prefix)) { + format = b->sid_format; + + if (!format) + continue; + + offset = format->block_len + format->node_len; + func_len = format->function_len; + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << ((func_len - 1 - idx) / 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = b->sid_format; + + offset = format->block_len + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * 8); + } + } + + *sid_block = b; + + return true; + } + } + + return false; +} + +/** + * Allocate an explicit SID function (i.e. specific SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function to be allocated + * @param sid_wide_func SID wide function to be allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t wlib_end = format->config.usid.wlib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function has to be allocated from the ELIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = + zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.usid.lib.func_allocated, + sid_func_ptr); + block->u.usid.lib.num_func_allocated++; + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function has to be allocated from the EWLIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, + sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + if (sid_wide_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_wide_func_ptr = zebra_srv6_sid_func_alloc( + sid_wide_func); + listnode_add(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + block->u.usid.wide_lib[sid_func] + .num_func_allocated++; + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_err("%s: invalid SM request arguments: SID function %u out of explicit range (%u - %u)", + __func__, sid_func, explicit_start, + explicit_end); + return false; + } + + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, + sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return true; +} + +/** + * Allocate a dynamic SID function (i.e. any available SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t *sid_func) +{ + struct srv6_sid_format *format; + uint32_t *sid_func_ptr = NULL; + + if (!block || !sid_func) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate dynamic SID function from block %pFX", + __func__, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + /* Format is uSID and behavior => allocate SID function from LIB range */ + + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.usid.lib.first_available_func > dlib_end) { + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted", + __func__); + return false; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.usid.lib.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.usid.lib.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.usid.lib.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = + block->u.usid.lib.first_available_func; + block->u.usid.lib.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.usid.lib.num_func_allocated++; + + if (block->u.usid.lib.first_available_func > dlib_end) + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted and next SID request will fail", + __func__); + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + /* Format is uncompressed => allocate SID function from Dynamic range */ + + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.uncompressed.first_available_func > + dynamic_end) { + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted", + __func__); + return NULL; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed + .first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + + if (block->u.uncompressed.first_available_func > + dynamic_end) + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted and next SID request will fail", + __func__); + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed.first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated dynamic SID function %u from block %pFX", + __func__, *sid_func, &block->prefix); + + return true; +} + +/** + * Get an explicit SID (i.e., a specific SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value specific SRv6 SID value (i.e. IPv6 address) to be + * allocated explicitly + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx = NULL; + struct listnode *node; + uint32_t sid_func = 0, sid_func_wide = 0; + struct srv6_locator *locator = NULL; + struct zebra_srv6_sid_block *block = NULL; + char buf[256]; + + if (!ctx || !sid_value) + return -1; + + /* Check if we already have a SID associated with the provided context */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + /* + * If the context is already associated with a SID that has the same SID value, then + * return the existing SID + */ + if (sid_same(&s->sid->value, sid_value)) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SRv6 SID %pI6 ctx %s", + __func__, &s->sid->value, + srv6_sid_ctx2str(buf, + sizeof(buf), + ctx)); + *sid = s->sid; + return 0; + } + + /* + * It is not allowed to allocate an explicit SID for a given context if the context + * is already associated with an explicit SID + */ + if (s->sid->alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + zlog_err("%s: cannot alloc SID %pI6 for ctx %s: ctx already associated with SID %pI6", + __func__, sid_value, + srv6_sid_ctx2str(buf, sizeof(buf), + &s->ctx), + &s->sid->value); + return -1; + } + + zctx = s; + break; + } + } + + /* Get parent locator and function of the provided SID */ + if (!zebra_srv6_sid_decompose(sid_value, &block, &locator, &sid_func, + &sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: parent block/locator not found for SID %pI6", + __func__, sid_value); + return -1; + } + + if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", + __func__); + return -1; + } + + /* Allocate an explicit SID function for the SID */ + if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + if (!zctx) { + /* If we don't have a zebra SID context for this context, allocate a new one */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + } else { + /* + * If we already have a SID associated with this context, we need to + * deallocate the current SID function before allocating the new one + */ + if (zctx->sid) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: ctx %s already associated with a dynamic SID %pI6, releasing dynamic SID", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &zctx->sid->value); + + release_srv6_sid_func_dynamic(block, zctx->sid->func); + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + } + } + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_EXPLICIT); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get a dynamic SID (i.e., any available SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param locator SRv6 locator from which the SID has to be allocated + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct srv6_sid_format *format; + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node; + struct in6_addr sid_value; + uint32_t sid_func = 0; + char buf[256]; + + if (!ctx || !locator) + return -1; + + block = locator->sid_block; + format = locator->sid_format; + + /* + * If we already have a SID for the provided context, we return the existing + * SID instead of allocating a new one. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (locator && s->sid && s->sid->locator) { + if (strncmp(s->sid->locator->name, locator->name, + SRV6_LOCNAME_SIZE)) { + continue; + } + } + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SID %s %pI6", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &s->sid->value); + *sid = s->sid; + return 0; + } + } + + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID && + ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else if (!format && ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else { + /* Allocate a dynamic SID function for the SID */ + if (!alloc_srv6_sid_func_dynamic(block, &sid_func)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + /* Compose the SID as the locator followed by the SID function */ + zebra_srv6_sid_compose(&sid_value, locator, sid_func); + } + + /* Allocate a zebra SID context to store SID context information */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, &sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_DYNAMIC); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID ctx %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), &sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated new dynamic SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get an SRv6 SID for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * If the sid_value parameter is non-NULL, it allocates the requested SID value + * if it is available (explicit SID allocation). + * If the sid_value parameter is NULL, it allocates any available SID value + * (dynamic SID allocation). + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value SRv6 SID value to be allocated (for explicit SID allocation) + * @param locator_name Parent SRv6 locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name) +{ + int ret = -1; + struct srv6_locator *locator; + char buf[256]; + + enum srv6_sid_alloc_mode alloc_mode = + (sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT + : SRV6_SID_ALLOC_MODE_DYNAMIC; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: received SRv6 SID alloc request: SID ctx %s (%pI6), mode=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, srv6_sid_alloc_mode2str(alloc_mode)); + + if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + /* + * Explicit SID allocation: allocate a specific SID value + */ + + if (!sid_value) { + zlog_err("%s: invalid SM request arguments: missing SRv6 SID value, necessary for explicit allocation", + __func__); + return -1; + } + + ret = get_srv6_sid_explicit(sid, ctx, sid_value); + } else { + /* + * Dynamic SID allocation: allocate any available SID value + */ + + if (!locator_name) { + zlog_err("%s: invalid SM request arguments: missing SRv6 locator, necessary for dynamic allocation", + __func__); + return -1; + } + + locator = zebra_srv6_locator_lookup(locator_name); + if (!locator) { + zlog_err("%s: invalid SM request arguments: SRv6 locator '%s' does not exist", + __func__, locator_name); + return -1; + } + + ret = get_srv6_sid_dynamic(sid, ctx, locator); + } + + return ret; +} + +/** + * Release an explicit SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = format->config.usid.wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function comes from the ELIB range */ + + /* Lookup SID function in the functions allocated list of ELIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the ELIB range */ + listnode_delete(block->u.usid.lib.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function comes from the EWLIB range */ + + /* Lookup SID function in the functions allocated list of EWLIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_wide_func_ptr) { + zlog_warn("%s: failed to release wide SID function %u, function is not allocated", + __func__, sid_wide_func); + return -1; + } + + /* Release the SID function from the EWLIB range */ + listnode_delete(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + zebra_srv6_sid_func_free(sid_wide_func_ptr); + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_warn("%s: function %u is outside explicit alloc range [%u/%u]", + __func__, sid_func, explicit_start, + explicit_end); + return -1; + } + + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Release a dynamic SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func) +{ + struct srv6_sid_format *format; + struct listnode *node, *nnode; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t dlib_start = format->config.usid.lib_start; + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic LIB (DLIB) range */ + if (!(sid_func >= dlib_start && sid_func <= dlib_end)) { + zlog_warn("%s: function %u is outside Dynamic LIB range [%u/%u]", + __func__, sid_func, dlib_start, dlib_end); + return -1; + } + + if (sid_func == block->u.usid.lib.first_available_func - 1) { + /* + * The SID function to be released precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.usid.lib.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.usid.lib + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.usid.lib.first_available_func - + 1) { + listnode_delete(block->u.usid + .lib + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.usid.lib + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The SID function to be released does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.usid.lib.func_released, + sid_func_ptr); + } + } else if (format && format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t dynamic_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + /* The Dynamic range ends where the Explicit range begins */ + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic range */ + if (!(sid_func >= dynamic_start && sid_func <= dynamic_end)) { + zlog_warn("%s: function %u is outside dynamic range [%u/%u]", + __func__, sid_func, dynamic_start, + dynamic_end); + return -1; + } + + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } else if (!format) { + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Core function, release the SRv6 SID associated with a given context. + * + * @param client The client for which the SID has to be released + * @param ctx Context associated with the SRv6 SID to be released + * @return 0 on success, -1 otherwise + */ +int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + char buf[256]; + + if (!zctx || !zctx->sid) + return -1; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* Ensures the SID is in use by the client */ + if (!listnode_lookup(zctx->sid->client_list, client)) { + flog_err(EC_ZEBRA_SM_DAEMON_MISMATCH, "%s: Daemon mismatch!!", + __func__); + return -1; + } + + /* Remove the client from the list of clients using the SID */ + listnode_delete(zctx->sid->client_list, client); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* + * If the SID is not used by any other client, then deallocate it + * and remove it from the SRv6 database. + */ + if (listcount(zctx->sid->client_list) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SRv6 SID %pI6 associated with ctx %s is no longer in use, removing it from SRv6 database", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), + &zctx->ctx)); + + if (!(zctx->sid->block->sid_format && + zctx->sid->block->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) && + !(!zctx->sid->block->sid_format && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END)) { + if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_EXPLICIT) + /* Release SRv6 SID function */ + release_srv6_sid_func_explicit(zctx->sid->block, + zctx->sid->func, + zctx->sid->wide_func); + else if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_DYNAMIC) + /* Release SRv6 SID function */ + release_srv6_sid_func_dynamic(zctx->sid->block, + zctx->sid->func); + else + /* We should never arrive here */ + assert(0); + } + + /* Free the SID */ + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + + /* Remove the SID context from the list and free memory */ + listnode_delete(srv6->sids, zctx); + zebra_srv6_sid_ctx_free(zctx); + } + + return 0; +} + +/** + * Handle a get SRv6 Locator request received from a client. + * + * It looks up the requested locator and send it to the client. + * + * @param locator SRv6 locator returned by this function + * @param client The client that sent the Get SRv6 Locator request + * @param locator_name Name of the locator to look up + * + * @return 0 on success + */ +static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + *locator = zebra_srv6_locator_lookup(locator_name); + if (!*locator) + return -1; + + return zsend_zebra_srv6_locator_add(client, *locator); +} + +/** + * Handle a get SID request received from a client. + * + * It gets a SID for a given context. If there is no SID associated with the context yet, + * we allocate one and return it to the client. Otherwise, we return the existing SID. + * + * - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value + * if it is available (explicit SID allocation). + * - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value + * (dynamic SID allocation). + * + * Finally, notify the client whether the SID allocation was successful or failed. + * + * @param sid SID returned by this function + * @param client The client that requested the SID + * @param ctx Context for which the SID was requested + * @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID + * (for explicit SID allocation) + * @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 on success, -1 otherwise + */ +static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret = -1; + struct listnode *node; + struct zserv *c; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + ret = get_srv6_sid(sid, ctx, sid_value, locator_name); + if (ret < 0) { + zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + /* Notify client about SID alloc failure */ + zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, NULL, + ZAPI_SRV6_SID_FAIL_ALLOC); + } else if (ret == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func, + (*sid)->wide_func, + (*sid)->locator ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } else { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c)) + zsend_srv6_sid_notify(c, ctx, &(*sid)->value, + (*sid)->func, (*sid)->wide_func, + (*sid)->locator + ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } + + return ret; +} + +/** + * Release SRv6 SIDs from a client. + * + * Called on client disconnection or reconnection. + * + * @param client The client to release SIDs from + * @return Number of SIDs released + */ +int release_daemon_srv6_sids(struct zserv *client) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + int count = 0; + int ret; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u", + __func__, zebra_route_string(client->proto), + client->instance, client->session_id); + + /* Iterate over the SIDs and release SIDs used by the client daemon */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!listnode_lookup(ctx->sid->client_list, client)) + continue; + + ret = release_srv6_sid(client, ctx); + if (ret == 0) + count++; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released %d SRv6 SIDs", __func__, count); + + return count; +} + +/** + * Release SRv6 SIDs from a client. + * + * @param client The client zapi session + * @param ctx Context associated with the SRv6 SID + * @return 0 on success, -1 on failure + */ +static int srv6_manager_release_sid_internal(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + int ret = -1; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node, *nnode; + char buf[256]; + const char *locator_name = NULL; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID associated with ctx %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* Lookup Zebra SID context and release it */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx)) + if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (zctx->sid && zctx->sid->locator) + locator_name = + (const char *)zctx->sid->locator->name; + ret = release_srv6_sid(client, zctx); + break; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: no SID associated with ctx %s", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + if (ret == 0) + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_RELEASED); + else + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_FAIL_RELEASE); + + return ret; +} + +void zebra_srv6_terminate(void) +{ + struct srv6_locator *locator; + struct srv6_sid_format *format; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *sid_ctx; + + if (srv6.locators) { + while (listcount(srv6.locators)) { + locator = listnode_head(srv6.locators); + + listnode_delete(srv6.locators, locator); + srv6_locator_free(locator); + } + + list_delete(&srv6.locators); + } + + /* Free SRv6 SIDs */ + if (srv6.sids) { + while (listcount(srv6.sids)) { + sid_ctx = listnode_head(srv6.sids); + + listnode_delete(srv6.sids, sid_ctx); + zebra_srv6_sid_ctx_free(sid_ctx); + } + + list_delete(&srv6.sids); + } + + /* Free SRv6 SID blocks */ + if (srv6.sid_blocks) { + while (listcount(srv6.sid_blocks)) { + block = listnode_head(srv6.sid_blocks); + + listnode_delete(srv6.sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + + list_delete(&srv6.sid_blocks); + } + + /* Free SRv6 SID formats */ + if (srv6.sid_formats) { + while (listcount(srv6.sid_formats)) { + format = listnode_head(srv6.sid_formats); + + srv6_sid_format_unregister(format); + srv6_sid_format_free(format); + } + + list_delete(&srv6.sid_formats); + } +} + +void zebra_srv6_init(void) +{ + hook_register(zserv_client_close, zebra_srv6_cleanup); + hook_register(srv6_manager_get_chunk, + zebra_srv6_manager_get_locator_chunk); + hook_register(srv6_manager_release_chunk, + zebra_srv6_manager_release_locator_chunk); + + hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal); + hook_register(srv6_manager_release_sid, + srv6_manager_release_sid_internal); + hook_register(srv6_manager_get_locator, + srv6_manager_get_srv6_locator_internal); } bool zebra_srv6_is_enable(void) diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 51db83d6fb64..1599fd7adfbd 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -16,9 +16,197 @@ #include #include +/* Default config for SRv6 SID `usid-f3216` format */ +#define SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" +#define SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 +#define SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF +#define SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 +#define SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 +#define SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 + +/* Default config for SRv6 SID `uncompressed` format */ +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 + +/* uSID Wide LIB */ +struct wide_lib { + uint32_t func; + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; +}; + +/* + * SRv6 SID block. + * + * A SID block is an IPv6 prefix from which SRv6 SIDs are allocated. + * Example: + * SID block = fc00:0::/32 + * SID 1 = fc00:0:1:e000:: + * SID 2 = fc00:0:1:fe00:: + * ... + */ +struct zebra_srv6_sid_block { + /* Prefix of this block, e.g. fc00:0::/32 */ + struct prefix_ipv6 prefix; + + /* Reference counter */ + unsigned long refcnt; + + /* + * Pointer to the SID format that defines the structure of the SIDs + * allocated from this block + */ + struct srv6_sid_format *sid_format; + + /* + * Run-time information/state of this SID block. + * + * This includes stuff like how many SID functions have been allocated + * from this block, which functions are still available to be allocated + * and so on... + */ + union { + /* Information/state for compressed uSID format */ + struct { + /* uSID Local ID Block (LIB) */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } lib; + + /* uSID Wide LIB */ + struct wide_lib *wide_lib; + } usid; + + /* Information/state for uncompressed SID format */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } uncompressed; + } u; +}; + +/** + * The function part of an SRv6 SID can be allocated in one + * of the following ways: + * - dynamic: allocate any available function + * - explicit: allocate a specific function + */ +enum srv6_sid_alloc_mode { + SRV6_SID_ALLOC_MODE_UNSPEC = 0, + /* Dynamic SID allocation */ + SRV6_SID_ALLOC_MODE_DYNAMIC = 1, + /* Explicit SID allocation */ + SRV6_SID_ALLOC_MODE_EXPLICIT = 2, + SRV6_SID_ALLOC_MODE_MAX = 3, +}; + +/** + * Convert SID allocation mode to string. + * + * @param alloc_mode SID allocation mode + * @return String representing the allocation mode + */ +static inline const char * +srv6_sid_alloc_mode2str(enum srv6_sid_alloc_mode alloc_mode) +{ + switch (alloc_mode) { + case SRV6_SID_ALLOC_MODE_EXPLICIT: + return "explicit"; + case SRV6_SID_ALLOC_MODE_DYNAMIC: + return "dynamic"; + case SRV6_SID_ALLOC_MODE_UNSPEC: + return "unspec"; + case SRV6_SID_ALLOC_MODE_MAX: + default: + return "unknown"; + } +} + +/* SRv6 SID instance. */ +struct zebra_srv6_sid { + /* + * SID context associated with the SID. + * Defines behavior and attributes of the SID. + */ + struct zebra_srv6_sid_ctx *ctx; + + /* SID value (e.g. fc00:0:1:e000::) */ + struct in6_addr value; + + /* Pointer to the SRv6 locator from which the SID has been allocated */ + struct srv6_locator *locator; + + /* Pointer to the SRv6 block from which the SID has been allocated */ + struct zebra_srv6_sid_block *block; + + /* + * Function part of the SID + * Example: + * SID = fc00:0:1:e000:: => func = e000 + */ + uint32_t func; + + /* SID wide function. */ + uint32_t wide_func; + + /* SID allocation mode: dynamic or explicit */ + enum srv6_sid_alloc_mode alloc_mode; + + /* List of clients that are using the SID */ + struct list *client_list; +}; + +/* + * Zebra SRv6 SID context. + * A context defines a behavior and (optionally) some behavior-specific + * attributes. Client daemons (bgp, isis, ...) ask SRv6 Manager to allocate + * a SID for a particular context. SRv6 Manager is responsible for allocating + * a SID from a given SID block and associating with the context. + * + * Example: + * bgp asks to associate a SID to the context {behavior=End.DT46 vrf=Vrf10}. + * SRv6 Manager allocate SID fc00:0:1:e000:: for that context. + */ +struct zebra_srv6_sid_ctx { + /* SRv6 SID context information. */ + struct srv6_sid_ctx ctx; + + /* SID associated with the context. */ + struct zebra_srv6_sid *sid; +}; + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; + + /* Source address for SRv6 encapsulation */ + struct in6_addr encap_src_addr; + + /* SRv6 SID formats */ + struct list *sid_formats; + + /* SRv6 SIDs */ + struct list *sids; + + /* SRv6 SID blocks */ + struct list *sid_blocks; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -43,6 +231,17 @@ DECLARE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DECLARE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DECLARE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DECLARE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); extern void zebra_srv6_locator_add(struct srv6_locator *locator); extern void zebra_srv6_locator_delete(struct srv6_locator *locator); @@ -52,6 +251,7 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator); void zebra_notify_srv6_locator_delete(struct srv6_locator *locator); extern void zebra_srv6_init(void); +extern void zebra_srv6_terminate(void); extern struct zebra_srv6 *zebra_srv6_get_default(void); extern bool zebra_srv6_is_enable(void); @@ -67,4 +267,58 @@ extern void srv6_manager_release_locator_chunk_call(struct zserv *client, extern int srv6_manager_client_disconnect_cb(struct zserv *client); extern int release_daemon_srv6_locator_chunks(struct zserv *client); +extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); +extern void zebra_srv6_encap_src_addr_unset(void); + +void srv6_sid_format_register(struct srv6_sid_format *format); +void srv6_sid_format_unregister(struct srv6_sid_format *format); +struct srv6_sid_format *srv6_sid_format_lookup(const char *name); +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format); +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format); + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func); +void zebra_srv6_sid_func_free(uint32_t *func); +void delete_zebra_srv6_sid_func(void *val); + +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix); +extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block); +extern void delete_zebra_srv6_sid_block(void *val); +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix); + +extern struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode); +extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); +extern void delete_zebra_srv6_sid(void *val); + +extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx); + +extern void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name); + +extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name); +extern int release_srv6_sid(struct zserv *client, + struct zebra_srv6_sid_ctx *zctx); +extern int release_daemon_srv6_sids(struct zserv *client); +extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid, + struct zserv *client); + +extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); +extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); +extern void delete_zebra_srv6_sid_ctx(void *val); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 3775d3dcdfc4..5a8052414902 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -61,6 +61,73 @@ static struct cmd_node srv6_loc_node = { .prompt = "%s(config-srv6-locator)# " }; +static struct cmd_node srv6_encap_node = { + .name = "srv6-encap", + .node = SRV6_ENCAP_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-encap)# " +}; + +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +DEFPY (show_srv6_manager, + show_srv6_manager_cmd, + "show segment-routing srv6 manager [json]", + SHOW_STR + "Segment Routing\n" + "Segment Routing SRv6\n" + "Verify SRv6 Manager\n" + JSON_STR) +{ + const bool uj = use_json(argc, argv); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + json_object *json = NULL; + json_object *json_parameters = NULL; + json_object *json_encapsulation = NULL; + json_object *json_source_address = NULL; + + if (uj) { + json = json_object_new_object(); + json_parameters = json_object_new_object(); + json_object_object_add(json, "parameters", json_parameters); + json_encapsulation = json_object_new_object(); + json_object_object_add(json_parameters, "encapsulation", + json_encapsulation); + json_source_address = json_object_new_object(); + json_object_object_add(json_encapsulation, "sourceAddress", + json_source_address); + json_object_string_addf(json_source_address, "configured", + "%pI6", &srv6->encap_src_addr); + vty_json(vty, json); + } else { + vty_out(vty, "Parameters:\n"); + vty_out(vty, " Encapsulation:\n"); + vty_out(vty, " Source Address:\n"); + vty_out(vty, " Configured: %pI6\n", &srv6->encap_src_addr); + } + + return CMD_SUCCESS; +} + DEFUN (show_srv6_locator, show_srv6_locator_cmd, "show segment-routing srv6 locator [json]", @@ -152,15 +219,32 @@ DEFUN (show_srv6_locator_detail, prefix2str(&locator->prefix, str, sizeof(str)); vty_out(vty, "Name: %s\n", locator->name); vty_out(vty, "Prefix: %s\n", str); - vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length); - vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length); - vty_out(vty, "Function-Bit-Len: %u\n", - locator->function_bits_length); - vty_out(vty, "Argument-Bit-Len: %u\n", - locator->argument_bits_length); + if (locator->sid_format) { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->sid_format->block_len); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->sid_format->node_len); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->sid_format->function_len); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->sid_format->argument_len); - if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) - vty_out(vty, "Behavior: uSID\n"); + if (locator->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID) + vty_out(vty, "Behavior: uSID\n"); + } else { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->block_bits_length); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->node_bits_length); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->argument_bits_length); + + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, "Behavior: uSID\n"); + } vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, @@ -202,9 +286,30 @@ DEFUN (no_srv6, struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_locator *locator; struct listnode *node, *nnode; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *ctx; + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) { + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } - for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) zebra_srv6_locator_delete(locator); + } return CMD_SUCCESS; } @@ -251,12 +356,37 @@ DEFUN (no_srv6_locator, "Segment Routing SRv6 locator\n" "Specify locator-name\n") { + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); if (!locator) { vty_out(vty, "%% Can't find SRv6 locator\n"); return CMD_WARNING_CONFIG_FAILED; } + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } + zebra_srv6_locator_delete(locator); return CMD_SUCCESS; } @@ -277,14 +407,37 @@ DEFPY (locator_prefix, VTY_DECLVAR_CONTEXT(srv6_locator, locator); struct srv6_locator_chunk *chunk = NULL; struct listnode *node = NULL; + uint8_t expected_prefixlen; + struct srv6_sid_format *format; locator->prefix = *prefix; func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; + expected_prefixlen = prefix->prefixlen; + format = locator->sid_format; + if (format) { + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format->name, + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + } + + if (prefix->prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + prefix->prefixlen, format->name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Resolve optional arguments */ if (block_bit_len == 0 && node_bit_len == 0) { - block_bit_len = - prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; + block_bit_len = prefix->prefixlen - + ZEBRA_SRV6_LOCATOR_NODE_LENGTH; node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; } else if (block_bit_len == 0) { block_bit_len = prefix->prefixlen - node_bit_len; @@ -355,7 +508,8 @@ DEFPY (locator_prefix, } } - zebra_srv6_locator_add(locator); + zebra_srv6_locator_format_set(locator, locator->sid_format); + return CMD_SUCCESS; } @@ -376,8 +530,9 @@ DEFPY (locator_behavior, /* SRv6 locator uSID flag already set, nothing to do */ return CMD_SUCCESS; - /* Remove old locator from zclients */ - zebra_notify_srv6_locator_delete(locator); + if (!locator->sid_format) + /* Remove old locator from zclients */ + zebra_notify_srv6_locator_delete(locator); /* Set/Unset the SRV6_LOCATOR_USID */ if (no) @@ -385,8 +540,407 @@ DEFPY (locator_behavior, else SET_FLAG(locator->flags, SRV6_LOCATOR_USID); - /* Notify the new locator to zclients */ - zebra_notify_srv6_locator_add(locator); + if (!locator->sid_format) + /* Notify the new locator to zclients */ + zebra_srv6_locator_add(locator); + + return CMD_SUCCESS; +} + +DEFPY(locator_sid_format, + locator_sid_format_cmd, + "format $format", + "Configure SRv6 SID format\n" + "Specify usid-f3216 format\n" + "Specify uncompressed-f4024 format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct srv6_sid_format *sid_format = NULL; + uint8_t expected_prefixlen; + + expected_prefixlen = locator->prefix.prefixlen; + if (strmatch(format, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + + if (IPV6_ADDR_SAME(&locator->prefix, &in6addr_any)) { + vty_out(vty, + "%% Unexpected configuration sequence: the prefix of the locator is required before configuring the format. Please configure the prefix first and then configure the format.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (locator->prefix.prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + locator->prefix.prefixlen, format); + return CMD_WARNING_CONFIG_FAILED; + } + + sid_format = srv6_sid_format_lookup(format); + if (!sid_format) { + vty_out(vty, "%% Cannot find SRv6 SID format '%s'\n", format); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sid_format == locator->sid_format) + /* Format has not changed, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, sid_format); + + return CMD_SUCCESS; +} + +DEFPY (no_locator_sid_format, + no_locator_sid_format_cmd, + "no format [WORD]", + NO_STR + "Configure SRv6 SID format\n" + "Specify SRv6 SID format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + if (!locator->sid_format) + /* SID format already unset, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, NULL); + + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_encap, + srv6_encap_cmd, + "encapsulation", + "Segment Routing SRv6 encapsulation\n") +{ + vty->node = SRV6_ENCAP_NODE; + return CMD_SUCCESS; +} + +DEFPY (srv6_src_addr, + srv6_src_addr_cmd, + "source-address X:X::X:X$encap_src_addr", + "Segment Routing SRv6 source address\n" + "Specify source address for SRv6 encapsulation\n") +{ + zebra_srv6_encap_src_addr_set(&encap_src_addr); + dplane_srv6_encap_srcaddr_set(&encap_src_addr, NS_DEFAULT); + return CMD_SUCCESS; +} + +DEFPY (no_srv6_src_addr, + no_srv6_src_addr_cmd, + "no source-address [X:X::X:X$encap_src_addr]", + NO_STR + "Segment Routing SRv6 source address\n" + "Specify source address for SRv6 encapsulation\n") +{ + zebra_srv6_encap_src_addr_unset(); + dplane_srv6_encap_srcaddr_set(&in6addr_any, NS_DEFAULT); + return CMD_SUCCESS; +} + +DEFUN_NOSH(srv6_sid_formats, + srv6_sid_formats_cmd, + "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f3216_usid, + srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_USID_F3216_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f3216_usid, + no_srv6_sid_format_f3216_usid_cmd, + "no format usid-f3216", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f4024_uncompressed, + srv6_sid_format_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f4024_uncompressed, + no_srv6_sid_format_f4024_uncompressed_cmd, + "no format uncompressed-f4024", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib, + srv6_sid_format_usid_lib_cmd, + "local-id-block start (0-4294967295)$start", + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.lib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib, + no_srv6_sid_format_usid_lib_cmd, + "no local-id-block [start (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.lib_start = + SRV6_SID_FORMAT_USID_F3216_LIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib_explicit, + srv6_sid_format_usid_lib_explicit_cmd, + "local-id-block explicit start (0-4294967295)$start end (0-4294967295)$end", + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.elib_start = start; + format->config.usid.elib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib_explicit, + no_srv6_sid_format_usid_lib_explicit_cmd, + "no local-id-block explicit [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.elib_start = + SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = + SRV6_SID_FORMAT_USID_F3216_ELIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wlib, + srv6_sid_format_usid_wlib_cmd, + "wide-local-id-block start (0-4294967295)$start end (0-4294967295)$end", + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.wlib_start = start; + format->config.usid.wlib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wlib, + no_srv6_sid_format_usid_wlib_cmd, + "no wide-local-id-block [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.wlib_start = + SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = + SRV6_SID_FORMAT_USID_F3216_WLIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wide_lib_explicit, + srv6_sid_format_usid_wide_lib_explicit_cmd, + "wide-local-id-block explicit start (0-4294967295)$start", + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.ewlib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wide_lib_explicit, + no_srv6_sid_format_usid_wide_lib_explicit_cmd, + "no wide-local-id-block explicit [start (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_explicit, + srv6_sid_format_explicit_cmd, + "explicit start (0-4294967295)$start", + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.uncompressed.explicit_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_explicit, + no_srv6_sid_format_explicit_cmd, + "no explicit [start (0-4294967295)$start]", + NO_STR + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); return CMD_SUCCESS; } @@ -396,12 +950,26 @@ static int zebra_sr_config(struct vty *vty) struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct listnode *node; struct srv6_locator *locator; + struct srv6_sid_format *format; char str[256]; + bool display_source_srv6 = false; + + if (srv6 && !IPV6_ADDR_SAME(&srv6->encap_src_addr, &in6addr_any)) + display_source_srv6 = true; vty_out(vty, "!\n"); - if (zebra_srv6_is_enable()) { + if (display_source_srv6 || zebra_srv6_is_enable()) { vty_out(vty, "segment-routing\n"); vty_out(vty, " srv6\n"); + } + if (display_source_srv6) { + if (!IPV6_ADDR_SAME(&srv6->encap_src_addr, &in6addr_any)) { + vty_out(vty, " encapsulation\n"); + vty_out(vty, " source-address %pI6\n", + &srv6->encap_src_addr); + } + } + if (srv6 && zebra_srv6_is_enable()) { vty_out(vty, " locators\n"); for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { inet_ntop(AF_INET6, &locator->prefix.prefix, @@ -424,6 +992,54 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, "\n"); if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, " behavior usid\n"); + if (locator->sid_format) { + format = locator->sid_format; + vty_out(vty, " format %s\n", format->name); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + vty_out(vty, " formats\n"); + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) { + if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + vty_out(vty, " format %s\n", format->name); + if (format->config.uncompressed.explicit_start != + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START) + vty_out(vty, " explicit start %u\n", + format->config.uncompressed + .explicit_start); + } + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + vty_out(vty, " format %s\n", format->name); + if (format->config.usid.lib_start != + SRV6_SID_FORMAT_USID_F3216_LIB_START) + vty_out(vty, + " local-id-block start %u\n", + format->config.usid.lib_start); + if (format->config.usid.elib_start != + SRV6_SID_FORMAT_USID_F3216_ELIB_START || + format->config.usid.elib_end != + SRV6_SID_FORMAT_USID_F3216_ELIB_END) + vty_out(vty, + " local-id-block explicit start %u end %u\n", + format->config.usid.elib_start, + format->config.usid.elib_end); + if (format->config.usid.wlib_start != + SRV6_SID_FORMAT_USID_F3216_WLIB_START || + format->config.usid.wlib_end != + SRV6_SID_FORMAT_USID_F3216_WLIB_END) + vty_out(vty, + " wide-local-id-block start %u end %u\n", + format->config.usid.wlib_start, + format->config.usid.wlib_end); + if (format->config.usid.ewlib_start != + SRV6_SID_FORMAT_USID_F3216_EWLIB_START) + vty_out(vty, + " wide-local-id-block explicit start %u\n", + format->config.usid.ewlib_start); + } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } @@ -431,6 +1047,8 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, " !\n"); vty_out(vty, " exit\n"); vty_out(vty, " !\n"); + } + if (display_source_srv6 || zebra_srv6_is_enable()) { vty_out(vty, "exit\n"); vty_out(vty, "!\n"); } @@ -444,24 +1062,66 @@ void zebra_srv6_vty_init(void) install_node(&srv6_node); install_node(&srv6_locs_node); install_node(&srv6_loc_node); + install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); install_default(SEGMENT_ROUTING_NODE); install_default(SRV6_NODE); install_default(SRV6_LOCS_NODE); install_default(SRV6_LOC_NODE); + install_default(SRV6_ENCAP_NODE); + install_default(SRV6_SID_FORMATS_NODE); + install_default(SRV6_SID_FORMAT_USID_F3216_NODE); + install_default(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE); /* Command for change node */ install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_encap_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f4024_uncompressed_cmd); /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); + install_element(SRV6_LOC_NODE, &locator_sid_format_cmd); + install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd); + install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); + install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &srv6_sid_format_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &no_srv6_sid_format_explicit_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); install_element(VIEW_NODE, &show_srv6_locator_detail_cmd); + install_element(VIEW_NODE, &show_srv6_manager_cmd); } diff --git a/zebra/zebra_tc.c b/zebra/zebra_tc.c index 3d7e03b63ee2..1b5a57ae5313 100644 --- a/zebra/zebra_tc.c +++ b/zebra/zebra_tc.c @@ -132,13 +132,18 @@ static void *tc_qdisc_alloc_intern(void *arg) return new; } +void zebra_tc_qdisc_free(struct zebra_tc_qdisc *qdisc) +{ + XFREE(MTYPE_TC_QDISC, qdisc); +} + static struct zebra_tc_qdisc *tc_qdisc_free(struct zebra_tc_qdisc *hash_data, bool free_data) { hash_release(zrouter.qdisc_hash, hash_data); if (free_data) { - XFREE(MTYPE_TC_QDISC, hash_data); + zebra_tc_qdisc_free(hash_data); return NULL; } @@ -178,7 +183,7 @@ void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc) new = hash_get(zrouter.qdisc_hash, qdisc, tc_qdisc_alloc_intern); (void)dplane_tc_qdisc_install(new); - XFREE(MTYPE_TC_QDISC, old); + zebra_tc_qdisc_free(old); } } else { new = hash_get(zrouter.qdisc_hash, qdisc, @@ -243,13 +248,18 @@ static void *tc_class_alloc_intern(void *arg) return new; } +void zebra_tc_class_free(struct zebra_tc_class *class) +{ + XFREE(MTYPE_TC_CLASS, class); +} + static struct zebra_tc_class *tc_class_free(struct zebra_tc_class *hash_data, bool free_data) { hash_release(zrouter.class_hash, hash_data); if (free_data) { - XFREE(MTYPE_TC_CLASS, hash_data); + zebra_tc_class_free(hash_data); return NULL; } @@ -353,13 +363,18 @@ bool zebra_tc_filter_hash_equal(const void *arg1, const void *arg2) return true; } +void zebra_tc_filter_free(struct zebra_tc_filter *filter) +{ + XFREE(MTYPE_TC_FILTER, filter); +} + static struct zebra_tc_filter *tc_filter_free(struct zebra_tc_filter *hash_data, bool free_data) { hash_release(zrouter.filter_hash, hash_data); if (free_data) { - XFREE(MTYPE_TC_FILTER, hash_data); + zebra_tc_filter_free(hash_data); return NULL; } diff --git a/zebra/zebra_tc.h b/zebra/zebra_tc.h index 335430c93dbf..814b453ec51b 100644 --- a/zebra/zebra_tc.h +++ b/zebra/zebra_tc.h @@ -42,16 +42,19 @@ uint32_t zebra_tc_qdisc_hash_key(const void *arg); bool zebra_tc_qdisc_hash_equal(const void *arg1, const void *arg2); void zebra_tc_qdisc_install(struct zebra_tc_qdisc *qdisc); void zebra_tc_qdisc_uninstall(struct zebra_tc_qdisc *qdisc); +void zebra_tc_qdisc_free(struct zebra_tc_qdisc *qdisc); uint32_t zebra_tc_class_hash_key(const void *arg); bool zebra_tc_class_hash_equal(const void *arg1, const void *arg2); void zebra_tc_class_add(struct zebra_tc_class *class); void zebra_tc_class_delete(struct zebra_tc_class *class); +void zebra_tc_class_free(struct zebra_tc_class *class); const char *tc_filter_kind2str(uint32_t type); enum tc_qdisc_kind tc_filter_str2kind(const char *type); void zebra_tc_filter_add(struct zebra_tc_filter *filter); void zebra_tc_filter_delete(struct zebra_tc_filter *filter); +void zebra_tc_filter_free(struct zebra_tc_filter *filter); void zebra_tc_filters_free(void *arg); uint32_t zebra_tc_filter_hash_key(const void *arg); diff --git a/zebra/zebra_trace.c b/zebra/zebra_trace.c index fef5ad20ac5c..7b0fb3279b22 100644 --- a/zebra/zebra_trace.c +++ b/zebra/zebra_trace.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 25e65139894f..e464e47b1f0c 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -195,7 +195,7 @@ static int zebra_vrf_disable(struct vrf *vrf) /* Cleanup Vxlan, MPLS and PW tables. */ zebra_vxlan_cleanup_tables(zvrf); zebra_mpls_cleanup_tables(zvrf); - zebra_pw_exit(zvrf); + zebra_pw_exit_vrf(zvrf); /* Remove link-local IPv4 addresses created for BGP unnumbered peering. */ @@ -265,6 +265,12 @@ static int zebra_vrf_delete(struct vrf *vrf) otable_fini(&zvrf->other_tables); XFREE(MTYPE_ZEBRA_VRF, zvrf); + + if (vrf->ns_ctxt) { + ns_delete(vrf->ns_ctxt); + vrf->ns_ctxt = NULL; + } + vrf->info = NULL; return 0; @@ -370,7 +376,7 @@ struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf) zebra_vxlan_init_tables(zvrf); zebra_mpls_init_tables(zvrf); - zebra_pw_init(zvrf); + zebra_pw_init_vrf(zvrf); zvrf->table_id = rt_table_main_id; /* by default table ID is default one */ @@ -444,141 +450,6 @@ struct route_table *zebra_vrf_table(afi_t afi, safi_t safi, vrf_id_t vrf_id) return zvrf->table[afi][safi]; } -static int vrf_config_write(struct vty *vty) -{ - struct vrf *vrf; - struct zebra_vrf *zvrf; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - zvrf = vrf->info; - - if (!zvrf) - continue; - - if (zvrf_id(zvrf) == VRF_DEFAULT) { - if (zvrf->l3vni) - vty_out(vty, "vni %u%s\n", zvrf->l3vni, - is_l3vni_for_prefix_routes_only( - zvrf->l3vni) - ? " prefix-routes-only" - : ""); - - if (zvrf->zebra_rnh_ip_default_route != - SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) - vty_out(vty, "%sip nht resolve-via-default\n", - zvrf->zebra_rnh_ip_default_route - ? "" - : "no "); - - if (zvrf->zebra_rnh_ipv6_default_route != - SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) - vty_out(vty, "%sipv6 nht resolve-via-default\n", - zvrf->zebra_rnh_ipv6_default_route - ? "" - : "no "); - - if (zvrf->tbl_mgr - && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) - vty_out(vty, "ip table range %u %u\n", - zvrf->tbl_mgr->start, - zvrf->tbl_mgr->end); - } else { - vty_frame(vty, "vrf %s\n", zvrf_name(zvrf)); - if (zvrf->l3vni) - vty_out(vty, " vni %u%s\n", zvrf->l3vni, - is_l3vni_for_prefix_routes_only( - zvrf->l3vni) - ? " prefix-routes-only" - : ""); - zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); - if (zvrf->zebra_rnh_ip_default_route != - SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) - vty_out(vty, " %sip nht resolve-via-default\n", - zvrf->zebra_rnh_ip_default_route - ? "" - : "no "); - - if (zvrf->zebra_rnh_ipv6_default_route != - SAVE_ZEBRA_IP_NHT_RESOLVE_VIA_DEFAULT) - vty_out(vty, " %sipv6 nht resolve-via-default\n", - zvrf->zebra_rnh_ipv6_default_route - ? "" - : "no "); - - if (zvrf->tbl_mgr && vrf_is_backend_netns() - && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)) - vty_out(vty, " ip table range %u %u\n", - zvrf->tbl_mgr->start, - zvrf->tbl_mgr->end); - } - - - zebra_routemap_config_write_protocol(vty, zvrf); - router_id_write(vty, zvrf); - - if (zvrf_id(zvrf) != VRF_DEFAULT) - vty_endframe(vty, "exit-vrf\n!\n"); - else - vty_out(vty, "!\n"); - } - return 0; -} - -DEFPY (vrf_netns, - vrf_netns_cmd, - "netns NAME$netns_name", - "Attach VRF to a Namespace\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - char *pathname = ns_netns_pathname(vty, netns_name); - int ret; - - VTY_DECLVAR_CONTEXT(vrf, vrf); - - if (!pathname) - return CMD_WARNING_CONFIG_FAILED; - - frr_with_privs(&zserv_privs) { - ret = zebra_vrf_netns_handler_create( - vty, vrf, pathname, NS_UNKNOWN, NS_UNKNOWN, NS_UNKNOWN); - } - - return ret; -} - -DEFUN (no_vrf_netns, - no_vrf_netns_cmd, - "no netns [NAME]", - NO_STR - "Detach VRF from a Namespace\n" - "The file name in " NS_RUN_DIR ", or a full pathname\n") -{ - struct ns *ns = NULL; - - VTY_DECLVAR_CONTEXT(vrf, vrf); - - if (!vrf_is_backend_netns()) { - vty_out(vty, "VRF backend is not Netns. Aborting\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (!vrf->ns_ctxt) { - vty_out(vty, "VRF %s(%u) is not configured with NetNS\n", - vrf->name, vrf->vrf_id); - return CMD_WARNING_CONFIG_FAILED; - } - - ns = (struct ns *)vrf->ns_ctxt; - - ns->vrf_ctxt = NULL; - vrf_disable(vrf); - /* vrf ID from VRF is necessary for Zebra - * so that propagate to other clients is done - */ - ns_delete(ns); - vrf->ns_ctxt = NULL; - return CMD_SUCCESS; -} - /* if ns_id is different and not VRF_UNKNOWN, * then update vrf identifier, and enable VRF */ @@ -677,12 +548,4 @@ void zebra_vrf_init(void) zebra_vrf_delete); hook_register(zserv_client_close, release_daemon_table_chunks); - - vrf_cmd_init(vrf_config_write); - - if (vrf_is_backend_netns() && ns_have_netns()) { - /* Install NS commands. */ - install_element(VRF_NODE, &vrf_netns_cmd); - install_element(VRF_NODE, &no_vrf_netns_cmd); - } } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index d36c2f81c789..5742c38e23ee 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -20,6 +20,7 @@ #include "vxlan.h" #include "termtable.h" #include "affinitymap.h" +#include "frrdistance.h" #include "zebra/zebra_router.h" #include "zebra/zserv.h" @@ -50,6 +51,7 @@ #include "zebra/zebra_script.h" #include "zebra/rtadv.h" #include "zebra/zebra_neigh.h" +#include "zebra/zebra_ptm.h" /* context to manage dumps in multiple tables or vrfs */ struct route_show_ctx { @@ -66,20 +68,25 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, bool show_ng, struct route_show_ctx *ctx); static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng); -static void vty_show_ip_route_summary(struct vty *vty, - struct route_table *table, bool use_json); +static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json); static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json); /* Helper api to format a nexthop in the 'detailed' output path. */ static void show_nexthop_detail_helper(struct vty *vty, + const struct route_node *rn, const struct route_entry *re, const struct nexthop *nexthop, bool is_backup); static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table); -static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop, - struct route_entry *re, unsigned int num); +static void show_ip_route_nht_dump(struct vty *vty, + const struct nexthop *nexthop, + const struct route_node *rn, + const struct route_entry *re, + unsigned int num); DEFUN (ip_multicast_mode, ip_multicast_mode_cmd, @@ -208,7 +215,7 @@ static char re_status_output_char(const struct route_entry *re, if (is_fib) { star_p = !!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_FIB); - } else + } else if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE)) star_p = true; } @@ -249,7 +256,7 @@ static char re_status_output_char(const struct route_entry *re, /* * Show backup nexthop info, in the 'detailed' output path */ -static void show_nh_backup_helper(struct vty *vty, +static void show_nh_backup_helper(struct vty *vty, const struct route_node *rn, const struct route_entry *re, const struct nexthop *nexthop) { @@ -279,7 +286,7 @@ static void show_nh_backup_helper(struct vty *vty, temp = backup; while (backup) { vty_out(vty, " "); - show_nexthop_detail_helper(vty, re, backup, + show_nexthop_detail_helper(vty, rn, re, backup, true /*backup*/); vty_out(vty, "\n"); @@ -300,11 +307,11 @@ static void show_nh_backup_helper(struct vty *vty, * output path. */ static void show_nexthop_detail_helper(struct vty *vty, + const struct route_node *rn, const struct route_entry *re, const struct nexthop *nexthop, bool is_backup) { - char addrstr[32]; char buf[MPLS_LABEL_STRLEN]; int i; @@ -388,23 +395,21 @@ static void show_nexthop_detail_helper(struct vty *vty, switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - if (nexthop->src.ipv4.s_addr) { - if (inet_ntop(AF_INET, &nexthop->src.ipv4, - addrstr, sizeof(addrstr))) - vty_out(vty, ", src %s", - addrstr); - } + if (nexthop->rmap_src.ipv4.s_addr) + vty_out(vty, ", rmapsrc %pI4", &nexthop->rmap_src.ipv4); + else if (nexthop->src.ipv4.s_addr) + vty_out(vty, ", src %pI4", &nexthop->src.ipv4); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, - &in6addr_any)) { - if (inet_ntop(AF_INET6, &nexthop->src.ipv6, - addrstr, sizeof(addrstr))) - vty_out(vty, ", src %s", - addrstr); - } + /* Allow for 5549 ipv4 prefix with ipv6 nexthop */ + if (rn->p.family == AF_INET && nexthop->rmap_src.ipv4.s_addr) + vty_out(vty, ", rmapsrc %pI4", &nexthop->rmap_src.ipv4); + else if (!IPV6_ADDR_SAME(&nexthop->rmap_src.ipv6, &in6addr_any)) + vty_out(vty, ", rmapsrc %pI6", &nexthop->rmap_src.ipv6); + else if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) + vty_out(vty, ", src %pI6", &nexthop->src.ipv6); break; case NEXTHOP_TYPE_IFINDEX: @@ -588,13 +593,13 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { /* Use helper to format each nexthop */ - show_nexthop_detail_helper(vty, re, nexthop, + show_nexthop_detail_helper(vty, rn, re, nexthop, false /*not backup*/); vty_out(vty, "\n"); /* Include backup(s), if present */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) - show_nh_backup_helper(vty, re, nexthop); + show_nh_backup_helper(vty, rn, re, nexthop); } zebra_show_ip_route_opaque(vty, re, NULL); @@ -701,8 +706,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { json_nexthop = json_object_new_object(); - show_nexthop_json_helper(json_nexthop, - nexthop, re); + show_nexthop_json_helper(json_nexthop, nexthop, rn, re); json_object_array_add(json_nexthops, json_nexthop); @@ -722,8 +726,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { json_nexthop = json_object_new_object(); - show_nexthop_json_helper(json_nexthop, - nexthop, re); + show_nexthop_json_helper(json_nexthop, nexthop, + rn, re); json_object_array_add(json_nexthops, json_nexthop); } @@ -764,9 +768,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, } /* Distance and metric display. */ - if (((re->type == ZEBRA_ROUTE_CONNECT) && + if (((re->type == ZEBRA_ROUTE_CONNECT || + re->type == ZEBRA_ROUTE_LOCAL) && (re->distance || re->metric)) || - (re->type != ZEBRA_ROUTE_CONNECT)) + (re->type != ZEBRA_ROUTE_CONNECT && re->type != ZEBRA_ROUTE_LOCAL)) len += vty_out(vty, " [%u/%u]", re->distance, re->metric); @@ -787,7 +792,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, len - 3 + (2 * nexthop_level(nexthop)), ' '); } - show_route_nexthop_helper(vty, re, nexthop); + show_route_nexthop_helper(vty, rn, re, nexthop); vty_out(vty, ", %s\n", up_str); } @@ -818,7 +823,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, vty_out(vty, " b%c %*c", (star_p ? '*' : ' '), len - 3 + (2 * nexthop_level(nexthop)), ' '); - show_route_nexthop_helper(vty, re, nexthop); + show_route_nexthop_helper(vty, rn, re, nexthop); vty_out(vty, "\n"); } @@ -864,9 +869,9 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, { struct route_node *rn; struct route_entry *re; + bool first_json = true; int first = 1; rib_dest_t *dest; - json_object *json = NULL; json_object *json_prefix = NULL; uint32_t addr; char buf[BUFSIZ]; @@ -882,9 +887,6 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, * => display the VRF and table if specific */ - if (use_json) - json = json_object_new_object(); - /* Show all routes. */ for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) { dest = rib_dest_from_rnode(rn); @@ -957,17 +959,15 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, if (json_prefix) { prefix2str(&rn->p, buf, sizeof(buf)); - json_object_object_add(json, buf, json_prefix); + vty_json_key(vty, buf, &first_json); + vty_json_no_pretty(vty, json_prefix); + json_prefix = NULL; } } - /* - * This is an extremely expensive operation at scale - * and non-pretty reduces memory footprint significantly. - */ if (use_json) - vty_json_no_pretty(vty, json); + vty_json_close(vty, first_json); } static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, @@ -1161,27 +1161,6 @@ DEFPY (show_ip_nht, return CMD_SUCCESS; } -DEFUN (ip_nht_default_route, - ip_nht_default_route_cmd, - "ip nht resolve-via-default", - IP_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (zvrf->zebra_rnh_ip_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ip_default_route = true; - - zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, json_object *json_nhe_hdr) { @@ -1238,7 +1217,12 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, json_object_boolean_true_add(json, "valid"); else vty_out(vty, " Valid"); - + if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL)) { + if (json) + json_object_boolean_true_add(json, "reInstall"); + else + vty_out(vty, ", Reinstall"); + } if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) { if (json) json_object_boolean_true_add(json, "installed"); @@ -1285,14 +1269,15 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, for (ALL_NEXTHOPS(nhe->nhg, nexthop)) { if (json_nexthop_array) { json_nexthops = json_object_new_object(); - show_nexthop_json_helper(json_nexthops, nexthop, NULL); + show_nexthop_json_helper(json_nexthops, nexthop, NULL, + NULL); } else { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out(vty, " "); else /* Make recursive nexthops a bit more clear */ vty_out(vty, " "); - show_route_nexthop_helper(vty, NULL, nexthop); + show_route_nexthop_helper(vty, NULL, NULL, nexthop); } if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) { @@ -1350,7 +1335,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, if (json_backup_nexthop_array) { json_backup_nexthops = json_object_new_object(); show_nexthop_json_helper(json_backup_nexthops, - nexthop, NULL); + nexthop, NULL, NULL); json_object_array_add(json_backup_nexthop_array, json_backup_nexthops); } else { @@ -1363,7 +1348,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe, * clear */ vty_out(vty, " "); - show_route_nexthop_helper(vty, NULL, nexthop); + show_route_nexthop_helper(vty, NULL, NULL, + nexthop); vty_out(vty, "\n"); } } @@ -1494,17 +1480,18 @@ static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp) { struct zebra_if *zebra_if = NULL; struct nhg_connected *rb_node_dep = NULL; + bool first = true; zebra_if = ifp->info; - if (!if_nhg_dependents_is_empty(ifp)) { - vty_out(vty, "Interface %s:\n", ifp->name); - - frr_each(nhg_connected_tree, &zebra_if->nhg_dependents, - rb_node_dep) { - vty_out(vty, " "); - show_nexthop_group_out(vty, rb_node_dep->nhe, NULL); + frr_each (nhg_connected_tree, &zebra_if->nhg_dependents, rb_node_dep) { + if (first) { + vty_out(vty, "Interface %s:\n", ifp->name); + first = false; } + + vty_out(vty, " "); + show_nexthop_group_out(vty, rb_node_dep->nhe, NULL); } } @@ -1680,68 +1667,6 @@ DEFPY_HIDDEN(backup_nexthop_recursive_use_enable, return CMD_SUCCESS; } -DEFUN (no_ip_nht_default_route, - no_ip_nht_default_route_cmd, - "no ip nht resolve-via-default", - NO_STR - IP_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (!zvrf->zebra_rnh_ip_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ip_default_route = false; - zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - -DEFUN (ipv6_nht_default_route, - ipv6_nht_default_route_cmd, - "ipv6 nht resolve-via-default", - IP6_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (zvrf->zebra_rnh_ipv6_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ipv6_default_route = true; - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - -DEFUN (no_ipv6_nht_default_route, - no_ipv6_nht_default_route_cmd, - "no ipv6 nht resolve-via-default", - NO_STR - IP6_STR - "Filter Next Hop tracking route resolution\n" - "Resolve via default route\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (!zvrf->zebra_rnh_ipv6_default_route) - return CMD_SUCCESS; - - zvrf->zebra_rnh_ipv6_default_route = false; - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); - return CMD_SUCCESS; -} - DEFPY_HIDDEN(rnh_hide_backups, rnh_hide_backups_cmd, "[no] ip nht hide-backup-events", NO_STR @@ -1809,6 +1734,7 @@ DEFPY (show_route, "Nexthop Group Information\n") { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; + bool first_vrf_json = true; struct vrf *vrf; int type = 0; struct zebra_vrf *zvrf; @@ -1840,21 +1766,26 @@ DEFPY (show_route, if ((zvrf = vrf->info) == NULL || (zvrf->table[afi][SAFI_UNICAST] == NULL)) continue; - + if (json) + vty_json_key(vty, zvrf_name(zvrf), + &first_vrf_json); if (table_all) - do_show_ip_route_all( - vty, zvrf, afi, !!fib, !!json, tag, - prefix_str ? prefix : NULL, - !!supernets_only, type, - ospf_instance_id, !!ng, &ctx); + do_show_ip_route_all(vty, zvrf, afi, !!fib, + !!json, tag, + prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, !!ng, + &ctx); else - do_show_ip_route( - vty, zvrf_name(zvrf), afi, SAFI_UNICAST, - !!fib, !!json, tag, - prefix_str ? prefix : NULL, - !!supernets_only, type, - ospf_instance_id, table, !!ng, &ctx); + do_show_ip_route(vty, zvrf_name(zvrf), afi, + SAFI_UNICAST, !!fib, !!json, + tag, prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, table, !!ng, + &ctx); } + if (json) + vty_json_close(vty, first_vrf_json); } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -2047,11 +1978,15 @@ DEFPY (show_route_summary, afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct route_table *table; bool uj = use_json(argc, argv); + json_object *vrf_json = NULL; if (vrf_all) { struct vrf *vrf; struct zebra_vrf *zvrf; + if (uj && !vrf_json) + vrf_json = json_object_new_object(); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if ((zvrf = vrf->info) == NULL) continue; @@ -2069,10 +2004,14 @@ DEFPY (show_route_summary, if (prefix) vty_show_ip_route_summary_prefix(vty, table, - uj); + vrf_json, uj); else - vty_show_ip_route_summary(vty, table, uj); + vty_show_ip_route_summary(vty, table, vrf_json, + uj); } + + if (uj) + vty_json(vty, vrf_json); } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -2088,9 +2027,9 @@ DEFPY (show_route_summary, return CMD_SUCCESS; if (prefix) - vty_show_ip_route_summary_prefix(vty, table, uj); + vty_show_ip_route_summary_prefix(vty, table, NULL, uj); else - vty_show_ip_route_summary(vty, table, uj); + vty_show_ip_route_summary(vty, table, NULL, uj); } return CMD_SUCCESS; @@ -2145,8 +2084,11 @@ DEFUN_HIDDEN (show_route_zebra_dump, return CMD_SUCCESS; } -static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop, - struct route_entry *re, unsigned int num) +static void show_ip_route_nht_dump(struct vty *vty, + const struct nexthop *nexthop, + const struct route_node *rn, + const struct route_entry *re, + unsigned int num) { char buf[SRCDEST2STR_BUFFER]; @@ -2170,10 +2112,12 @@ static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop, nexthop->vrf_id)); } - if (nexthop->src.ipv4.s_addr - && (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, - sizeof(buf)))) - vty_out(vty, " source: %s\n", buf); + if (nexthop->rmap_src.ipv4.s_addr) + vty_out(vty, " rmapsrc: %pI4\n", + &nexthop->rmap_src.ipv4); + else if (nexthop->src.ipv4.s_addr) + vty_out(vty, " source: %pI4\n", + &nexthop->src.ipv4.s_addr); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: @@ -2190,11 +2134,15 @@ static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop, nexthop->vrf_id)); } - if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) { - if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, - sizeof(buf))) - vty_out(vty, " source: %s\n", buf); - } + /* Allow for 5549 ipv4 prefix with ipv6 nexthop */ + if (rn->p.family == AF_INET && nexthop->rmap_src.ipv4.s_addr) + vty_out(vty, " rmapsrc: %pI4\n", + &nexthop->rmap_src.ipv4); + else if (!IPV6_ADDR_SAME(&nexthop->rmap_src.ipv6, &in6addr_any)) + vty_out(vty, " rmapsrc: %pI6\n", + &nexthop->rmap_src.ipv6); + else if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) + vty_out(vty, " source: %pI6\n", &nexthop->src.ipv6); break; case NEXTHOP_TYPE_IFINDEX: vty_out(vty, @@ -2251,7 +2199,8 @@ static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table) vrf_id_to_name(re->vrf_id)); vty_out(vty, " flags: %u\n", re->flags); - if (re->type != ZEBRA_ROUTE_CONNECT) { + if (re->type != ZEBRA_ROUTE_CONNECT && + re->type != ZEBRA_ROUTE_LOCAL) { vty_out(vty, " distance: %u\n", re->distance); vty_out(vty, " metric: %u\n", re->metric); } @@ -2285,7 +2234,7 @@ static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table) for (ALL_NEXTHOPS_PTR(&(re->nhe->nhg), nexthop)) { nexthop_num++; - show_ip_route_nht_dump(vty, nexthop, re, + show_ip_route_nht_dump(vty, nexthop, rn, re, nexthop_num); } @@ -2295,8 +2244,8 @@ static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table) } } -static void vty_show_ip_route_summary(struct vty *vty, - struct route_table *table, bool use_json) +static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json) { struct route_node *rn; struct route_entry *re; @@ -2310,6 +2259,8 @@ static void vty_show_ip_route_summary(struct vty *vty, uint32_t is_ibgp; json_object *json_route_summary = NULL; json_object *json_route_routes = NULL; + const char *vrf_name = zvrf_name( + ((struct rib_table_info *)route_table_get_info(table))->zvrf); memset(&rib_cnt, 0, sizeof(rib_cnt)); memset(&fib_cnt, 0, sizeof(fib_cnt)); @@ -2360,10 +2311,7 @@ static void vty_show_ip_route_summary(struct vty *vty, if (!use_json) vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source", - "Routes", "FIB", - zvrf_name(((struct rib_table_info *) - route_table_get_info(table)) - ->zvrf)); + "Routes", "FIB", vrf_name); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if ((rib_cnt[i] > 0) || (i == ZEBRA_ROUTE_BGP @@ -2455,7 +2403,11 @@ static void vty_show_ip_route_summary(struct vty *vty, json_object_int_add(json_route_summary, "routesTotalFib", fib_cnt[ZEBRA_ROUTE_TOTAL]); - vty_json(vty, json_route_summary); + if (!vrf_json) + vty_json(vty, json_route_summary); + else + json_object_object_add(vrf_json, vrf_name, + json_route_summary); } else { vty_out(vty, "------\n"); vty_out(vty, "%-20s %-20d %-20d \n", "Totals", @@ -2473,6 +2425,7 @@ static void vty_show_ip_route_summary(struct vty *vty, */ static void vty_show_ip_route_summary_prefix(struct vty *vty, struct route_table *table, + json_object *vrf_json, bool use_json) { struct route_node *rn; @@ -2486,6 +2439,8 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, int cnt; json_object *json_route_summary = NULL; json_object *json_route_routes = NULL; + const char *vrf_name = zvrf_name( + ((struct rib_table_info *)route_table_get_info(table))->zvrf); memset(&rib_cnt, 0, sizeof(rib_cnt)); memset(&fib_cnt, 0, sizeof(fib_cnt)); @@ -2525,10 +2480,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, if (!use_json) vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source", - "Prefix Routes", "FIB", - zvrf_name(((struct rib_table_info *) - route_table_get_info(table)) - ->zvrf)); + "Prefix Routes", "FIB", vrf_name); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (rib_cnt[i] > 0) { @@ -2603,7 +2555,11 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, json_object_int_add(json_route_summary, "prefixRoutesTotalFib", fib_cnt[ZEBRA_ROUTE_TOTAL]); - vty_json(vty, json_route_summary); + if (!vrf_json) + vty_json(vty, json_route_summary); + else + json_object_object_add(vrf_json, vrf_name, + json_route_summary); } else { vty_out(vty, "------\n"); vty_out(vty, "%-20s %-20d %-20d \n", "Totals", @@ -2724,146 +2680,6 @@ DEFPY(evpn_mh_redirect_off, evpn_mh_redirect_off_cmd, return zebra_evpn_mh_redirect_off(vty, redirect_off); } -DEFUN (default_vrf_vni_mapping, - default_vrf_vni_mapping_cmd, - "vni " CMD_VNI_RANGE "[prefix-routes-only]", - "VNI corresponding to the DEFAULT VRF\n" - "VNI-ID\n" - "Prefix routes only \n") -{ - char xpath[XPATH_MAXLEN]; - int filter = 0; - - if (argc == 3) - filter = 1; - - snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg); - - if (filter) { - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true"); - } - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN (no_default_vrf_vni_mapping, - no_default_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE "[prefix-routes-only]", - NO_STR - "VNI corresponding to DEFAULT VRF\n" - "VNI-ID\n" - "Prefix routes only \n") -{ - char xpath[XPATH_MAXLEN]; - int filter = 0; - vni_t vni = strtoul(argv[2]->arg, NULL, 10); - struct zebra_vrf *zvrf = NULL; - - zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - - if (argc == 4) - filter = 1; - - if (zvrf->l3vni != vni) { - vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, - zvrf->vrf->name); - return CMD_WARNING; - } - - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg); - - if (filter) { - snprintf(xpath, sizeof(xpath), - FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true"); - } - - snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", - VRF_DEFAULT_NAME); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN (vrf_vni_mapping, - vrf_vni_mapping_cmd, - "vni " CMD_VNI_RANGE "[prefix-routes-only]", - "VNI corresponding to tenant VRF\n" - "VNI-ID\n" - "prefix-routes-only\n") -{ - int filter = 0; - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - assert(vrf); - assert(zvrf); - - if (argc == 3) - filter = 1; - - nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_MODIFY, - argv[1]->arg); - - if (filter) - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", - NB_OP_MODIFY, "true"); - - return nb_cli_apply_changes(vty, NULL); -} - -DEFUN (no_vrf_vni_mapping, - no_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE "[prefix-routes-only]", - NO_STR - "VNI corresponding to tenant VRF\n" - "VNI-ID\n" - "prefix-routes-only\n") -{ - int filter = 0; - - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - vni_t vni = strtoul(argv[2]->arg, NULL, 10); - - assert(vrf); - assert(zvrf); - - if (argc == 4) - filter = 1; - - if (zvrf->l3vni != vni) { - vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, - zvrf->vrf->name); - return CMD_WARNING; - } - - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/l3vni-id", NB_OP_DESTROY, - argv[2]->arg); - - if (filter) - nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", - NB_OP_DESTROY, "true"); - - nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - /* show vrf */ DEFPY (show_vrf_vni, show_vrf_vni_cmd, @@ -3726,56 +3542,17 @@ DEFPY (clear_evpn_dup_addr, "IPv4 address\n" "IPv6 address\n") { - struct ipaddr host_ip = {.ipa_type = IPADDR_NONE }; - int ret = CMD_SUCCESS; - struct list *input; - struct yang_data *yang_dup = NULL, *yang_dup_ip = NULL, - *yang_dup_mac = NULL; - - input = list_new(); - if (!vni_str) { - yang_dup = yang_data_new( - "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice", - "all-case"); + nb_cli_rpc_enqueue(vty, "all-vnis", NULL); } else { - yang_dup = yang_data_new_uint32( - "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id", - vni); - if (!is_zero_mac(&mac->eth_addr)) { - yang_dup_mac = yang_data_new_mac( - "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id/mac-addr", - &mac->eth_addr); - if (yang_dup_mac) - listnode_add(input, yang_dup_mac); - } else if (ip) { - if (sockunion_family(ip) == AF_INET) { - host_ip.ipa_type = IPADDR_V4; - host_ip.ipaddr_v4.s_addr = sockunion2ip(ip); - } else { - host_ip.ipa_type = IPADDR_V6; - memcpy(&host_ip.ipaddr_v6, &ip->sin6.sin6_addr, - sizeof(struct in6_addr)); - } - - yang_dup_ip = yang_data_new_ip( - "/frr-zebra:clear-evpn-dup-addr/input/clear-dup-choice/single-case/vni-id/vni-ipaddr", - &host_ip); - - if (yang_dup_ip) - listnode_add(input, yang_dup_ip); - } + nb_cli_rpc_enqueue(vty, "vni-id", vni_str); + if (mac_str) + nb_cli_rpc_enqueue(vty, "mac-addr", mac_str); + else if (ip_str) + nb_cli_rpc_enqueue(vty, "vni-ipaddr", ip_str); } - if (yang_dup) { - listnode_add(input, yang_dup); - ret = nb_cli_rpc(vty, "/frr-zebra:clear-evpn-dup-addr", input, - NULL); - } - - list_delete(&input); - - return ret; + return nb_cli_rpc(vty, "/frr-zebra:clear-evpn-dup-addr", NULL); } DEFPY_HIDDEN (evpn_accept_bgp_seq, @@ -4028,6 +3805,17 @@ static int config_write_protocol(struct vty *vty) return 1; } +static inline bool zebra_vty_v6_rr_semantics_used(void) +{ + if (zebra_nhg_kernel_nexthops_enabled()) + return true; + + if (zrouter.v6_rr_semantics) + return true; + + return false; +} + DEFUN (show_zebra, show_zebra_cmd, "show zebra", @@ -4037,6 +3825,20 @@ DEFUN (show_zebra, struct vrf *vrf; struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); char *out; + char timebuf[MONOTIME_STRLEN]; + + time_to_string(zrouter.startup_time, timebuf); + vty_out(vty, "Zebra started%s at time %s", + zrouter.graceful_restart ? " gracefully" : "", timebuf); + + if (zrouter.t_rib_sweep) + vty_out(vty, + "Zebra RIB sweep timer running, remaining time %lds\n", + event_timer_remain_second(zrouter.t_rib_sweep)); + else { + time_to_string(zrouter.rib_sweep_time, timebuf); + vty_out(vty, "Zebra RIB sweep happened at %s", timebuf); + } ttable_rowseps(table, 0, BOTTOM, true, '-'); ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); @@ -4047,7 +3849,9 @@ DEFUN (show_zebra, ttable_add_row(table, "MPLS|%s", mpls_enabled ? "On" : "Off"); ttable_add_row(table, "EVPN|%s", is_evpn_enabled() ? "On" : "Off"); ttable_add_row(table, "Kernel socket buffer size|%d", rcvbufsize); - + ttable_add_row(table, "v6 Route Replace Semantics|%s", + zebra_vty_v6_rr_semantics_used() ? "Replace" + : "Delete then Add"); #ifdef GNU_LINUX if (!vrf_is_backend_netns()) @@ -4482,31 +4286,6 @@ DEFPY (no_zebra_protodown_bit, #endif /* HAVE_NETLINK */ -DEFUN(ip_table_range, ip_table_range_cmd, - "[no] ip table range (1-4294967295) (1-4294967295)", - NO_STR IP_STR - "table configuration\n" - "Configure table range\n" - "Start Routing Table\n" - "End Routing Table\n") -{ - ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); - - if (!zvrf) - return CMD_WARNING; - - if (zvrf_id(zvrf) != VRF_DEFAULT && !vrf_is_backend_netns()) { - vty_out(vty, - "VRF subcommand does not make any sense in l3mdev based vrf's\n"); - return CMD_WARNING; - } - - if (strmatch(argv[0]->text, "no")) - return table_manager_range(vty, false, zvrf, NULL, NULL); - - return table_manager_range(vty, true, zvrf, argv[3]->arg, argv[4]->arg); -} - #ifdef HAVE_SCRIPTING DEFUN(zebra_on_rib_process_script, zebra_on_rib_process_script_cmd, @@ -4618,14 +4397,6 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_ip_rpf_addr_cmd); install_element(VIEW_NODE, &show_ipv6_rpf_addr_cmd); - install_element(CONFIG_NODE, &ip_nht_default_route_cmd); - install_element(CONFIG_NODE, &no_ip_nht_default_route_cmd); - install_element(CONFIG_NODE, &ipv6_nht_default_route_cmd); - install_element(CONFIG_NODE, &no_ipv6_nht_default_route_cmd); - install_element(VRF_NODE, &ip_nht_default_route_cmd); - install_element(VRF_NODE, &no_ip_nht_default_route_cmd); - install_element(VRF_NODE, &ipv6_nht_default_route_cmd); - install_element(VRF_NODE, &no_ipv6_nht_default_route_cmd); install_element(CONFIG_NODE, &rnh_hide_backups_cmd); install_element(VIEW_NODE, &show_frr_cmd); @@ -4677,19 +4448,12 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &evpn_mh_neigh_holdtime_cmd); install_element(CONFIG_NODE, &evpn_mh_startup_delay_cmd); install_element(CONFIG_NODE, &evpn_mh_redirect_off_cmd); - install_element(CONFIG_NODE, &default_vrf_vni_mapping_cmd); - install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd); - install_element(VRF_NODE, &vrf_vni_mapping_cmd); - install_element(VRF_NODE, &no_vrf_vni_mapping_cmd); install_element(VIEW_NODE, &show_dataplane_cmd); install_element(VIEW_NODE, &show_dataplane_providers_cmd); install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd); install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd); - install_element(CONFIG_NODE, &ip_table_range_cmd); - install_element(VRF_NODE, &ip_table_range_cmd); - #ifdef HAVE_NETLINK install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd); install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 50a7462d89cc..f1ae42e32043 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -82,7 +82,7 @@ static int zl3vni_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n); static struct zebra_neigh *svd_nh_add(const struct ipaddr *vtep_ip, const struct ethaddr *rmac); -static int svd_nh_del(struct zebra_neigh *n); +static void svd_nh_del(struct zebra_neigh *n); static int svd_nh_install(struct zebra_l3vni *zl3vni, struct zebra_neigh *n); static int svd_nh_uninstall(struct zebra_l3vni *zl3vni, struct zebra_neigh *n); @@ -108,10 +108,11 @@ static void zevpn_build_hash_table(void); static unsigned int zebra_vxlan_sg_hash_key_make(const void *p); static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2); static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, - struct in_addr sip, struct in_addr mcast_grp); -static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf, - struct in_addr sip, - struct in_addr mcast_grp); + const struct ipaddr *sip, + const struct in_addr mcast_grp); +static struct zebra_vxlan_sg * +zebra_vxlan_sg_do_ref(struct zebra_vrf *vrf, const struct ipaddr *sip, + const struct in_addr mcast_grp); static void zebra_vxlan_cleanup_sg_table(struct zebra_vrf *zvrf); bool zebra_evpn_do_dup_addr_detect(struct zebra_vrf *zvrf) @@ -308,7 +309,7 @@ static void zevpn_print_neigh_hash_all_evpn_detail(struct hash_bucket *bucket, zevpn = (struct zebra_evpn *)bucket->data; if (!zevpn) { if (json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, json); return; } num_neigh = hashcount(zevpn->neigh_table); @@ -515,7 +516,7 @@ static void zevpn_print_mac_hash_all_evpn_detail(struct hash_bucket *bucket, zevpn = (struct zebra_evpn *)bucket->data; if (!zevpn) { if (json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, json); return; } wctx->zevpn = zevpn; @@ -769,10 +770,6 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx) json_evpn_list = json_object_new_array(); json_object_int_add(json, "vni", zl3vni->vni); json_object_string_add(json, "type", "L3"); -#if CONFDATE > 20240210 -CPP_NOTICE("Drop `vrf` from JSON outputs") -#endif - json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); json_object_string_add(json, "tenantVrf", zl3vni_vrf_name(zl3vni)); json_object_string_addf(json, "localVtepIp", "%pI4", @@ -1359,6 +1356,18 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, { struct zebra_mac *zrmac = NULL; struct ipaddr *vtep = NULL; + struct ipaddr ipv4_vtep; + + /* vtep_ip may be v4 or v6-mapped-v4. But zrmac->fwd_info + * can only contain v4 version. So convert if needed + */ + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4); zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { @@ -1372,7 +1381,7 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1386,14 +1395,14 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &vtep_ip->ipaddr_v4)) { + &(ipv4_vtep.ipaddr_v4))) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA", zl3vni->vni, &zrmac->fwd_info.r_vtep_ip, vtep_ip, rmac); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1413,36 +1422,29 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac, struct ipaddr *vtep_ip) { - struct ipaddr ipv4_vtep; - if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) { - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &ipv4_vtep.ipaddr_v4); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - /* remove nh from rmac's list */ - l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep); - /* delete nh is same as current selected, fall back to - * one present in the list - */ - if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &ipv4_vtep.ipaddr_v4) && - listcount(zrmac->nh_list)) { + l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, vtep_ip); + /* If there are remaining entries, use IPv4 from one */ + if (listcount(zrmac->nh_list)) { struct ipaddr *vtep; + struct ipaddr ipv4_vtep; vtep = listgetdata(listhead(zrmac->nh_list)); - zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4; + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), + &vtep->ipaddr_v4); + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", - zl3vni->vni, &ipv4_vtep, - &zrmac->fwd_info.r_vtep_ip, - &zrmac->macaddr); + zlog_debug("L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", + zl3vni->vni, vtep_ip, + &zrmac->fwd_info.r_vtep_ip, + &zrmac->macaddr); /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); @@ -1590,17 +1592,24 @@ static struct zebra_neigh *svd_nh_add(const struct ipaddr *ip, /* * Del Single VXlan Device neighbor entry. */ -static int svd_nh_del(struct zebra_neigh *n) +static void svd_nh_del(struct zebra_neigh *n) { if (n->refcnt > 0) - return -1; + return; hash_release(svd_nh_table, n); XFREE(MTYPE_L3NEIGH, n); +} - return 0; +static void svd_nh_del_terminate(void *ptr) +{ + struct zebra_neigh *n = ptr; + + n->refcnt = 0; + svd_nh_del(n); } + /* * Common code to install remote nh as neigh into the kernel. */ @@ -1756,9 +1765,9 @@ static int svd_remote_nh_add(struct zebra_l3vni *zl3vni, } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "SVD RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX", - &nh->emac, rmac, vtep_ip, host_prefix); + zlog_debug("SVD RMAC change(%pEA --> %pEA) for nexthop %pIA, prefix %pFX refcnt %u", + &nh->emac, rmac, vtep_ip, host_prefix, + nh->refcnt); memcpy(&nh->emac, rmac, ETH_ALEN); /* install (update) the nh neigh in kernel */ @@ -2258,14 +2267,13 @@ static int zl3vni_send_add_to_client(struct zebra_l3vni *zl3vni) stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Send L3_VNI_ADD %u VRF %s RMAC %pEA VRR %pEA local-ip %pI4 filter %s to %s", - zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), - &svi_rmac, &vrr_rmac, &zl3vni->local_vtep_ip, - CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) - ? "prefix-routes-only" - : "none", - zebra_route_string(client->proto)); + zlog_debug("Send L3VNI ADD %u VRF %s RMAC %pEA VRR %pEA local-ip %pI4 filter %s to %s", + zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), + &svi_rmac, &vrr_rmac, &zl3vni->local_vtep_ip, + CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) + ? "prefix-routes-only" + : "none", + zebra_route_string(client->proto)); client->l3vniadd_cnt++; return zserv_send_message(client, s); @@ -2293,7 +2301,7 @@ static int zl3vni_send_del_to_client(struct zebra_l3vni *zl3vni) stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", zl3vni->vni, + zlog_debug("Send L3VNI DEL %u VRF %s to %s", zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), zebra_route_string(client->proto)); @@ -2467,11 +2475,26 @@ static void zl3vni_del_rmac_hash_entry(struct hash_bucket *bucket, void *ctx) /* delete and uninstall nh hash entry */ static void zl3vni_del_nh_hash_entry(struct hash_bucket *bucket, void *ctx) { - struct zebra_neigh *n = NULL; + struct zebra_neigh *n = NULL, *svd_nh = NULL; struct zebra_l3vni *zl3vni = NULL; n = (struct zebra_neigh *)bucket->data; zl3vni = (struct zebra_l3vni *)ctx; + + /* remove SVD based remote nexthop neigh entry */ + svd_nh = svd_nh_lookup(&n->ip); + if (svd_nh) { + svd_nh->refcnt--; + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s L3VNI %u remove svd nh %pIA refcnt %u", + __func__, zl3vni->vni, &n->ip, + svd_nh->refcnt); + if (svd_nh->refcnt == 0) { + svd_nh_uninstall(zl3vni, svd_nh); + svd_nh_del(svd_nh); + } + } + zl3vni_nh_uninstall(zl3vni, n); zl3vni_nh_del(zl3vni, n); } @@ -2513,7 +2536,6 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, const struct prefix *host_prefix) { struct zebra_l3vni *zl3vni = NULL; - struct ipaddr ipv4_vtep; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni || !is_l3vni_oper_up(zl3vni)) @@ -2529,24 +2551,10 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); /* - * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 - * address. Rmac is programmed against the ipv4 vtep because we only - * support ipv4 tunnels in the h/w right now - */ - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &(ipv4_vtep.ipaddr_v4)); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - - /* - * add the rmac - remote rmac to be installed is against the ipv4 + * add the rmac - remote rmac to be installed is against the * nexthop address */ - zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep); + zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip); } /* handle evpn vrf route delete */ @@ -2590,14 +2598,15 @@ void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni); return; @@ -2631,14 +2640,15 @@ void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); return; @@ -2672,7 +2682,8 @@ void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2698,7 +2709,8 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2709,7 +2721,7 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_out(vty, "{}\n"); + vty_json(vty, json); else vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); @@ -2721,7 +2733,7 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, if (!n) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, json); else vty_out(vty, "%% Requested next-hop not present for L3-VNI %u\n", @@ -2742,13 +2754,16 @@ static void l3vni_print_nh_table(struct hash *nh_table, struct vty *vty, struct nh_walk_ctx wctx; json_object *json = NULL; - num_nh = hashcount(nh_table); - if (!num_nh) - return; - if (use_json) json = json_object_new_object(); + num_nh = hashcount(nh_table); + if (!num_nh) { + if (use_json) + vty_json_empty(vty, json); + return; + } + wctx.vty = vty; wctx.json = json; if (!use_json) { @@ -2770,14 +2785,14 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json) if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } zl3vni = zl3vni_lookup(l3vni); if (!zl3vni) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); else vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); return; @@ -2790,7 +2805,7 @@ void zebra_vxlan_print_nh_svd(struct vty *vty, bool use_json) { if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } @@ -2806,7 +2821,8 @@ void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2834,14 +2850,15 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zl3vni = zl3vni_lookup(vni); if (!zl3vni) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -2905,14 +2922,15 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -2959,7 +2977,8 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -2989,7 +3008,8 @@ void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3020,14 +3040,15 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -3064,14 +3085,15 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -3113,14 +3135,15 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_json(vty, json); + vty_json_empty(vty, json); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; @@ -3177,21 +3200,24 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = num_valid_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } if (use_json) { json = json_object_new_object(); @@ -3250,7 +3276,8 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3278,7 +3305,8 @@ void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3307,7 +3335,8 @@ void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3337,7 +3366,8 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3377,22 +3407,34 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty, json_object *json = NULL; json_object *json_mac = NULL; - if (!is_evpn_enabled()) + if (!is_evpn_enabled()) { + if (use_json) + vty_json_empty(vty, NULL); return; + } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_json_empty(vty, NULL); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = num_valid_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } num_macs = num_dup_detected_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } if (use_json) { json = json_object_new_object(); @@ -3727,21 +3769,25 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, json_object *json_mac = NULL; if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, NULL); return; } zevpn = zebra_evpn_lookup(vni); if (!zevpn) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); else vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = num_valid_macs(zevpn); - if (!num_macs) + if (!num_macs) { + if (use_json) + vty_json_empty(vty, NULL); return; + } if (use_json) { json = json_object_new_object(); @@ -3785,7 +3831,8 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3829,7 +3876,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj) json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (uj) + vty_json(vty, json); return; } @@ -3906,7 +3954,8 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); if (!is_evpn_enabled()) { - vty_json(vty, json); + if (use_json) + vty_json_empty(vty, json); return; } @@ -3990,7 +4039,7 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, if (!is_evpn_enabled()) { if (use_json) - vty_out(vty, "{}\n"); + vty_json_empty(vty, NULL); return; } @@ -5110,7 +5159,21 @@ void zebra_vxlan_macvlan_up(struct interface *ifp) zif = ifp->info; assert(zif); + + if (zif->link_nsid) + /* the link interface is another namespace */ + return; + link_ifp = zif->link; + if (!link_ifp) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "macvlan parent link is not found. Parent index %d ifp %s", + zif->link_ifindex, + ifindex2ifname(zif->link_ifindex, + ifp->vrf->vrf_id)); + return; + } link_zif = link_ifp->info; assert(link_zif); @@ -5127,9 +5190,8 @@ void zebra_vxlan_macvlan_up(struct interface *ifp) } } -int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, - char *err, int err_str_sz, int filter, - int add) +void zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, + int filter, int add) { struct zebra_l3vni *zl3vni = NULL; struct zebra_vrf *zvrf_evpn = NULL; @@ -5141,21 +5203,6 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, add ? "ADD" : "DEL"); if (add) { - /* check if the vni is already present under zvrf */ - if (zvrf->l3vni) { - snprintf(err, err_str_sz, - "VNI is already configured under the vrf"); - return -1; - } - - /* check if this VNI is already present in the system */ - zl3vni = zl3vni_lookup(vni); - if (zl3vni) { - snprintf(err, err_str_sz, - "VNI is already configured as L3-VNI"); - return -1; - } - /* Remove L2VNI if present */ zebra_vxlan_handle_vni_transition(zvrf, vni, add); @@ -5201,23 +5248,7 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, } else { zl3vni = zl3vni_lookup(vni); - if (!zl3vni) { - snprintf(err, err_str_sz, "VNI doesn't exist"); - return -1; - } - - if (zvrf->l3vni != vni) { - snprintf(err, err_str_sz, - "VNI %d doesn't exist in VRF: %s", - vni, zvrf->vrf->name); - return -1; - } - - if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) { - snprintf(err, ERR_STR_SZ, - "prefix-routes-only is not set for the vni"); - return -1; - } + assert(zl3vni); zebra_vxlan_process_l3vni_oper_down(zl3vni); @@ -5235,7 +5266,6 @@ int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, /* Add L2VNI for this VNI */ zebra_vxlan_handle_vni_transition(zvrf, vni, add); } - return 0; } int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf) @@ -5772,6 +5802,11 @@ void zebra_vxlan_init(void) zebra_evpn_mh_init(); } +void zebra_vxlan_terminate(void) +{ + hash_clean_and_free(&svd_nh_table, svd_nh_del_terminate); +} + /* free l3vni table */ void zebra_vxlan_disable(void) { @@ -5847,7 +5882,10 @@ static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, zclient_create_header(s, cmd, VRF_DEFAULT); stream_putl(s, IPV4_MAX_BYTELEN); - stream_put(s, &sg->src.s_addr, IPV4_MAX_BYTELEN); + /* + * There is currently no support for IPv6 VTEPs with PIM. + */ + stream_put(s, &sg->src.ipaddr_v4, IPV4_MAX_BYTELEN); stream_put(s, &sg->grp.s_addr, IPV4_MAX_BYTELEN); /* Write packet size. */ @@ -5870,9 +5908,17 @@ static int zebra_vxlan_sg_send(struct zebra_vrf *zvrf, static unsigned int zebra_vxlan_sg_hash_key_make(const void *p) { const struct zebra_vxlan_sg *vxlan_sg = p; + uint32_t hash1; - return (jhash_2words(vxlan_sg->sg.src.s_addr, - vxlan_sg->sg.grp.s_addr, 0)); + if (IS_IPADDR_V4(&vxlan_sg->sg.src)) { + return (jhash_2words(vxlan_sg->sg.src.ipaddr_v4.s_addr, + vxlan_sg->sg.grp.s_addr, 0)); + } else { + hash1 = jhash_1word(vxlan_sg->sg.grp.s_addr, 0); + return jhash2(vxlan_sg->sg.src.ipaddr_v6.s6_addr32, + array_size(vxlan_sg->sg.src.ipaddr_v6.s6_addr32), + hash1); + } } static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2) @@ -5880,8 +5926,8 @@ static bool zebra_vxlan_sg_hash_eq(const void *p1, const void *p2) const struct zebra_vxlan_sg *sg1 = p1; const struct zebra_vxlan_sg *sg2 = p2; - return ((sg1->sg.src.s_addr == sg2->sg.src.s_addr) - && (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); + return (ipaddr_is_same(&sg1->sg.src, &sg2->sg.src) && + (sg1->sg.grp.s_addr == sg2->sg.grp.s_addr)); } static struct zebra_vxlan_sg *zebra_vxlan_sg_new(struct zebra_vrf *zvrf, @@ -5917,7 +5963,7 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, { struct zebra_vxlan_sg *vxlan_sg; struct zebra_vxlan_sg *parent = NULL; - struct in_addr sip; + struct ipaddr sip; vxlan_sg = zebra_vxlan_sg_find(zvrf, sg); if (vxlan_sg) @@ -5928,9 +5974,9 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, * 2. the XG entry is used by pimd to setup the * vxlan-termination-mroute */ - if (sg->src.s_addr != INADDR_ANY) { + if (!ipaddr_is_zero(&sg->src)) { memset(&sip, 0, sizeof(sip)); - parent = zebra_vxlan_sg_do_ref(zvrf, sip, sg->grp); + parent = zebra_vxlan_sg_do_ref(zvrf, &sip, sg->grp); if (!parent) return NULL; } @@ -5945,7 +5991,7 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_add(struct zebra_vrf *zvrf, static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) { - struct in_addr sip; + struct ipaddr sip; struct zebra_vrf *zvrf; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -5953,13 +5999,13 @@ static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) /* On SG entry deletion remove the reference to its parent XG * entry */ - if (vxlan_sg->sg.src.s_addr != INADDR_ANY) { + if (!ipaddr_is_zero(&vxlan_sg->sg.src)) { memset(&sip, 0, sizeof(sip)); - zebra_vxlan_sg_do_deref(zvrf, sip, vxlan_sg->sg.grp); + zebra_vxlan_sg_do_deref(zvrf, &sip, vxlan_sg->sg.grp); } - zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg, - vxlan_sg->sg_str, ZEBRA_VXLAN_SG_DEL); + zebra_vxlan_sg_send(zvrf, &vxlan_sg->sg, vxlan_sg->sg_str, + ZEBRA_VXLAN_SG_DEL); hash_release(vxlan_sg->zvrf->vxlan_sg_table, vxlan_sg); @@ -5970,14 +6016,15 @@ static void zebra_vxlan_sg_del(struct zebra_vxlan_sg *vxlan_sg) } static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, - struct in_addr sip, struct in_addr mcast_grp) + const struct ipaddr *sip, + const struct in_addr mcast_grp) { struct zebra_vxlan_sg *vxlan_sg; struct prefix_sg sg; sg.family = AF_INET; sg.prefixlen = IPV4_MAX_BYTELEN; - sg.src = sip; + sg.src = *sip; sg.grp = mcast_grp; vxlan_sg = zebra_vxlan_sg_find(zvrf, &sg); if (!vxlan_sg) @@ -5990,16 +6037,16 @@ static void zebra_vxlan_sg_do_deref(struct zebra_vrf *zvrf, zebra_vxlan_sg_del(vxlan_sg); } -static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, - struct in_addr sip, - struct in_addr mcast_grp) +static struct zebra_vxlan_sg * +zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, const struct ipaddr *sip, + const struct in_addr mcast_grp) { struct zebra_vxlan_sg *vxlan_sg; struct prefix_sg sg; sg.family = AF_INET; sg.prefixlen = IPV4_MAX_BYTELEN; - sg.src = sip; + sg.src = *sip; sg.grp = mcast_grp; vxlan_sg = zebra_vxlan_sg_add(zvrf, &sg); if (vxlan_sg) @@ -6008,10 +6055,10 @@ static struct zebra_vxlan_sg *zebra_vxlan_sg_do_ref(struct zebra_vrf *zvrf, return vxlan_sg; } -void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, - struct in_addr mcast_grp) +void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, struct in_addr mcast_grp) { struct zebra_vrf *zvrf; + struct ipaddr local_vtep_ipaddr; if (local_vtep_ip.s_addr == INADDR_ANY || mcast_grp.s_addr == INADDR_ANY) @@ -6019,20 +6066,26 @@ void zebra_vxlan_sg_deref(struct in_addr local_vtep_ip, zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_sg_do_deref(zvrf, local_vtep_ip, mcast_grp); + SET_IPADDR_V4(&local_vtep_ipaddr); + local_vtep_ipaddr.ipaddr_v4 = local_vtep_ip; + + zebra_vxlan_sg_do_deref(zvrf, &local_vtep_ipaddr, mcast_grp); } void zebra_vxlan_sg_ref(struct in_addr local_vtep_ip, struct in_addr mcast_grp) { struct zebra_vrf *zvrf; + struct ipaddr local_vtep_ipaddr; - if (local_vtep_ip.s_addr == INADDR_ANY - || mcast_grp.s_addr == INADDR_ANY) + if (local_vtep_ip.s_addr == INADDR_ANY || mcast_grp.s_addr == INADDR_ANY) return; zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_sg_do_ref(zvrf, local_vtep_ip, mcast_grp); + SET_IPADDR_V4(&local_vtep_ipaddr); + local_vtep_ipaddr.ipaddr_v4 = local_vtep_ip; + + zebra_vxlan_sg_do_ref(zvrf, &local_vtep_ipaddr, mcast_grp); } static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *bucket, void *arg) @@ -6042,7 +6095,7 @@ static void zebra_vxlan_xg_pre_cleanup(struct hash_bucket *bucket, void *arg) /* increment the ref count against (*,G) to prevent them from being * deleted */ - if (vxlan_sg->sg.src.s_addr == INADDR_ANY) + if (ipaddr_is_zero(&vxlan_sg->sg.src)) ++vxlan_sg->ref_cnt; } @@ -6051,7 +6104,7 @@ static void zebra_vxlan_xg_post_cleanup(struct hash_bucket *bucket, void *arg) struct zebra_vxlan_sg *vxlan_sg = (struct zebra_vxlan_sg *)bucket->data; /* decrement the dummy ref count against (*,G) to delete them */ - if (vxlan_sg->sg.src.s_addr == INADDR_ANY) { + if (ipaddr_is_zero(&vxlan_sg->sg.src)) { if (vxlan_sg->ref_cnt) --vxlan_sg->ref_cnt; if (!vxlan_sg->ref_cnt) diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 98c2767eb2bb..eb02de6f7b40 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -178,13 +178,13 @@ extern int zebra_vxlan_if_add(struct interface *ifp); extern int zebra_vxlan_if_update(struct interface *ifp, struct zebra_vxlan_if_update_ctx *ctx); extern int zebra_vxlan_if_del(struct interface *ifp); -extern int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, - char *err, int err_str_sz, - int filter, int add); +extern void zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, + int filter, int add); extern void zebra_vxlan_init_tables(struct zebra_vrf *zvrf); extern void zebra_vxlan_close_tables(struct zebra_vrf *); extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *); extern void zebra_vxlan_init(void); +extern void zebra_vxlan_terminate(void); extern void zebra_vxlan_disable(void); extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index 3cc7e499bf6b..17ab05c1f3f5 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -208,13 +208,13 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); return 0; } - if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_MAC_CHANGE) && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -224,7 +224,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; @@ -242,7 +242,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * local-ip change - process oper down, associate with new * local-ip and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->local_vtep_ip = vxl->vtep_ip; @@ -262,7 +262,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) { if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } @@ -285,7 +285,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ /* Also, free up all MACs and neighbors. */ @@ -298,7 +298,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, } /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { /* Remove all existing local neigh and MACs for this VNI * (including from BGP) */ @@ -341,9 +341,10 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, return 0; /* Inform BGP, if there is a change of interest. */ - if (chgflags & - (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | - ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) + if (CHECK_FLAG(chgflags, (ZEBRA_VXLIF_MASTER_CHANGE | + ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE | + ZEBRA_VXLIF_VLAN_CHANGE))) zebra_evpn_send_add_to_client(zevpn); /* If there is a valid new master or a VLAN mapping change, @@ -351,9 +352,9 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * Also, reinstall any remote MACs and neighbors * for this VNI (based on new VLAN). */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) zebra_evpn_read_mac_neigh(zevpn, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + else if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { struct neigh_walk_ctx n_wctx; zebra_evpn_read_mac_neigh(zevpn, ifp); @@ -506,7 +507,7 @@ static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif, if ((hashcount(ctx->old_vni_table) == 0) || !(old_vni = hash_release(ctx->old_vni_table, &vni_tmp))) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("vxlan %s adding vni(%d, %d)", + zlog_debug("%s vxlan %s adding vni(%d, %d)", __func__, zif->ifp->name, vni->vni, vni->access_vlan); zebra_vxlan_if_vni_entry_add(zif, &vni_tmp); @@ -521,17 +522,39 @@ static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif, if (old_vni->access_vlan != vni->access_vlan) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "vxlan %s updating vni(%d, %d) -> vni(%d, %d)", - zif->ifp->name, old_vni->vni, - old_vni->access_vlan, vni->vni, - vni->access_vlan); + zlog_debug("%s vxlan %s updating vni(%d, %d) -> vni(%d, %d)", + __func__, zif->ifp->name, old_vni->vni, + old_vni->access_vlan, vni->vni, + vni->access_vlan); zebra_evpn_vl_vxl_deref(old_vni->access_vlan, old_vni->vni, zif); zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); zebra_vxlan_vni_free(old_vni); + } else { + int ret; + + ret = zebra_evpn_vl_vxl_bridge_lookup(vni->access_vlan, zif); + /* Here ret value 0 implied bridge vlan mapping is not present + * repopulated. Ignore ret value 1 as it means vlan mapping is + * present in bridge table. + */ + if (ret < 0) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s vxlan %s vni %u has error accessing bridge table.", + __func__, zif->ifp->name, vni->vni); + } else if (ret == 0) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s vxlan %s vni (%u, %u) not present in bridge table", + __func__, zif->ifp->name, vni->vni, + vni->access_vlan); + zebra_evpn_vl_vxl_deref(old_vni->access_vlan, + old_vni->vni, zif); + zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); + zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); + zebra_vxlan_vni_free(old_vni); + } } return 0; @@ -768,6 +791,7 @@ vni_t zebra_vxlan_if_access_vlan_vni_find(struct zebra_if *zif, return vni->vni; } +/* SVD VLAN-VNI mapping update */ int zebra_vxlan_if_vni_table_add_update(struct interface *ifp, struct hash *vni_table) { diff --git a/zebra/zserv.c b/zebra/zserv.c index 2db228b158d1..a731f7f278fd 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -306,6 +306,14 @@ static void zserv_write(struct event *thread) * this task reschedules itself. * * Any failure in any of these actions is handled by terminating the client. + * + * The client's input buffer ibuf_fifo can have a maximum items as configured + * in the packets_to_process. This way we are not filling up the FIFO more + * than the maximum when the zebra main is busy. If the fifo has space, we + * reschedule ourselves to read more. + * + * The main thread processes the items in ibuf_fifo and always signals the + * client IO thread. */ static void zserv_read(struct event *thread) { @@ -313,15 +321,25 @@ static void zserv_read(struct event *thread) int sock; size_t already; struct stream_fifo *cache; - uint32_t p2p_orig; - - uint32_t p2p; + uint32_t p2p; /* Temp p2p used to process */ + uint32_t p2p_orig; /* Configured p2p (Default-1000) */ + int p2p_avail; /* How much space is available for p2p */ struct zmsghdr hdr; + size_t client_ibuf_fifo_cnt = stream_fifo_count_safe(client->ibuf_fifo); p2p_orig = atomic_load_explicit(&zrouter.packets_to_process, memory_order_relaxed); + p2p_avail = p2p_orig - client_ibuf_fifo_cnt; + + /* + * Do nothing if ibuf_fifo count has reached its max limit. Otherwise + * proceed and reschedule ourselves if there is space in the ibuf_fifo. + */ + if (p2p_avail <= 0) + return; + + p2p = p2p_avail; cache = stream_fifo_new(); - p2p = p2p_orig; sock = EVENT_FD(thread); while (p2p) { @@ -421,7 +439,7 @@ static void zserv_read(struct event *thread) p2p--; } - if (p2p < p2p_orig) { + if (p2p < (uint32_t)p2p_avail) { uint64_t time_now = monotime(NULL); /* update session statistics */ @@ -435,19 +453,23 @@ static void zserv_read(struct event *thread) while (cache->head) stream_fifo_push(client->ibuf_fifo, stream_fifo_pop(cache)); + /* Need to update count as main thread could have processed few */ + client_ibuf_fifo_cnt = + stream_fifo_count_safe(client->ibuf_fifo); } /* Schedule job to process those packets */ zserv_event(client, ZSERV_PROCESS_MESSAGES); - } if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("Read %d packets from client: %s", p2p_orig - p2p, - zebra_route_string(client->proto)); + zlog_debug("Read %d packets from client: %s. Current ibuf fifo count: %zu. Conf P2p %d", + p2p_avail - p2p, zebra_route_string(client->proto), + client_ibuf_fifo_cnt, p2p_orig); - /* Reschedule ourselves */ - zserv_client_event(client, ZSERV_CLIENT_READ); + /* Reschedule ourselves since we have space in ibuf_fifo */ + if (client_ibuf_fifo_cnt < p2p_orig) + zserv_client_event(client, ZSERV_CLIENT_READ); stream_fifo_free(cache); @@ -483,14 +505,20 @@ static void zserv_client_event(struct zserv *client, * as the task argument. * * Each message is popped off the client's input queue and the action associated - * with the message is executed. This proceeds until there are no more messages, - * an error occurs, or the processing limit is reached. + * with the message is executed. This proceeds until an error occurs, or the + * processing limit is reached. * * The client's I/O thread can push at most zrouter.packets_to_process messages * onto the input buffer before notifying us there are packets to read. As long * as we always process zrouter.packets_to_process messages here, then we can * rely on the read thread to handle queuing this task enough times to process * everything on the input queue. + * + * If the client ibuf always schedules a wakeup to the client IO to read more + * items from the socked buffer. This way we ensure + * - Client IO thread always tries to read the socket buffer and add more + * items to the ibuf_fifo (until max limit) + * - the hidden config change (zebra zapi-packets <>) is taken into account. */ static void zserv_process_messages(struct event *thread) { @@ -524,6 +552,9 @@ static void zserv_process_messages(struct event *thread) /* Reschedule ourselves if necessary */ if (need_resched) zserv_event(client, ZSERV_PROCESS_MESSAGES); + + /* Ensure to include the read socket in the select/poll/etc.. */ + zserv_client_event(client, ZSERV_CLIENT_READ); } int zserv_send_message(struct zserv *client, struct stream *msg) @@ -637,17 +668,21 @@ static void zserv_client_free(struct zserv *client) vrf_bitmap_free(&client->redist_default[afi]); vrf_bitmap_free(&client->ridinfo[afi]); - vrf_bitmap_free(&client->nhrp_neighinfo[afi]); + vrf_bitmap_free(&client->neighinfo[afi]); } /* * If any instance are graceful restart enabled, * client is not deleted */ - if (DYNAMIC_CLIENT_GR_DISABLED(client)) { + if (DYNAMIC_CLIENT_GR_DISABLED(client) || zebra_router_in_shutdown()) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: Deleting client %s", __func__, zebra_route_string(client->proto)); + + if (zebra_router_in_shutdown()) + zebra_gr_client_final_shutdown(client); + zserv_client_delete(client); } else { /* Handle cases where client has GR instance. */ @@ -758,7 +793,7 @@ static struct zserv *zserv_client_create(int sock) vrf_bitmap_init(&client->redist[afi][i]); vrf_bitmap_init(&client->redist_default[afi]); vrf_bitmap_init(&client->ridinfo[afi]); - vrf_bitmap_init(&client->nhrp_neighinfo[afi]); + vrf_bitmap_init(&client->neighinfo[afi]); } /* Add this client to linked list. */ @@ -996,6 +1031,7 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) /* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { + struct client_gr_info *info; char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; @@ -1061,6 +1097,8 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) 0, client->redist_v4_del_cnt); vty_out(vty, "Redist:v6 %-12u%-12u%-12u\n", client->redist_v6_add_cnt, 0, client->redist_v6_del_cnt); + vty_out(vty, "NHG %-12u%-12u%-12u\n", client->nhg_add_cnt, + client->nhg_upd8_cnt, client->nhg_del_cnt); vty_out(vty, "VRF %-12u%-12u%-12u\n", client->vrfadd_cnt, 0, client->vrfdel_cnt); vty_out(vty, "Connected %-12u%-12u%-12u\n", client->ifadd_cnt, 0, @@ -1089,11 +1127,48 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); -#if defined DEV_BUILD + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + afi_t afi; + bool route_sync_done = true; + char timebuf[MONOTIME_STRLEN]; + + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (info->af_enabled[afi]) { + if (info->route_sync[afi]) + vty_out(vty, + "AFI %d enabled, route sync DONE\n", + afi); + else { + vty_out(vty, + "AFI %d enabled, route sync NOT DONE\n", + afi); + route_sync_done = false; + } + } + } + if (route_sync_done) { + time_to_string(info->route_sync_done_time, timebuf); + vty_out(vty, "Route sync finished at %s", timebuf); + } + } + vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); -#endif + vty_out(vty, "\n"); } diff --git a/zebra/zserv.h b/zebra/zserv.h index 90aa4d53f46d..87d2b4adbf81 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -31,9 +31,6 @@ extern "C" { struct zebra_vrf; -/* Default port information. */ -#define ZEBRA_VTY_PORT 2601 - /* Default configuration filename. */ #define DEFAULT_CONFIG_FILE "zebra.conf" @@ -67,6 +64,8 @@ struct client_gr_info { /* Book keeping */ void *stale_client_ptr; struct event *t_stale_removal; + void *client_ptr; + time_t route_sync_done_time; TAILQ_ENTRY(client_gr_info) gr_info; }; @@ -121,7 +120,7 @@ struct zserv { vrf_bitmap_t ridinfo[AFI_MAX]; /* Router-id information. */ - vrf_bitmap_t nhrp_neighinfo[AFI_MAX]; + vrf_bitmap_t neighinfo[AFI_MAX]; bool notify_owner; @@ -185,6 +184,9 @@ struct zserv { uint32_t local_es_evi_add_cnt; uint32_t local_es_evi_del_cnt; uint32_t error_cnt; + uint32_t nhg_add_cnt; + uint32_t nhg_upd8_cnt; + uint32_t nhg_del_cnt; time_t nh_reg_time; time_t nh_dereg_time; @@ -237,8 +239,7 @@ DECLARE_HOOK(zserv_client_connect, (struct zserv *client), (client)); DECLARE_KOOH(zserv_client_close, (struct zserv *client), (client)); #define DYNAMIC_CLIENT_GR_DISABLED(_client) \ - ((_client->proto <= ZEBRA_ROUTE_CONNECT) \ - || !(_client->gr_instance_count)) + ((_client->proto <= ZEBRA_ROUTE_LOCAL) || !(_client->gr_instance_count)) /* * Initialize Zebra API server. @@ -379,6 +380,7 @@ __attribute__((__noreturn__)) void zebra_finalize(struct event *event); /* * Graceful restart functions. */ +extern void zebra_gr_client_final_shutdown(struct zserv *client); extern int zebra_gr_client_disconnect(struct zserv *client); extern void zebra_gr_client_reconnect(struct zserv *client); extern void zebra_gr_stale_client_cleanup(struct list *client_list);