]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #7866 from kishorekunal01/fpm_dump_issue
authorMark Stapp <mjs@voltanet.io>
Thu, 14 Jan 2021 19:13:31 +0000 (14:13 -0500)
committerGitHub <noreply@github.com>
Thu, 14 Jan 2021 19:13:31 +0000 (14:13 -0500)
zebra: Scale setup RMAC is send multiple time to fpm

199 files changed:
bgpd/bgp_damp.c
bgpd/bgp_damp.h
bgpd/bgp_debug.c
bgpd/bgp_fsm.c
bgpd/bgp_main.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_packet.c
bgpd/bgp_packet.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
doc/developer/index.rst
doc/developer/logging.rst
doc/developer/subdir.am
doc/developer/tracing.rst
doc/developer/workflow.rst
doc/user/bgp.rst
doc/user/isisd.rst
doc/user/overview.rst
doc/user/pathd.rst
eigrpd/eigrp_cli.c
eigrpd/eigrp_cli.h [new file with mode: 0644]
eigrpd/eigrp_const.h
eigrpd/eigrp_dump.c
eigrpd/eigrp_dump.h
eigrpd/eigrp_fsm.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_interface.h
eigrpd/eigrp_main.c
eigrpd/eigrp_memory.c
eigrpd/eigrp_memory.h
eigrpd/eigrp_metric.c [new file with mode: 0644]
eigrpd/eigrp_metric.h [new file with mode: 0644]
eigrpd/eigrp_neighbor.c
eigrpd/eigrp_neighbor.h
eigrpd/eigrp_network.c
eigrpd/eigrp_network.h
eigrpd/eigrp_northbound.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_packet.h
eigrpd/eigrp_query.c
eigrpd/eigrp_reply.c
eigrpd/eigrp_routemap.c
eigrpd/eigrp_siaquery.c
eigrpd/eigrp_siareply.c
eigrpd/eigrp_structs.h
eigrpd/eigrp_topology.c
eigrpd/eigrp_topology.h
eigrpd/eigrp_types.h [new file with mode: 0644]
eigrpd/eigrp_update.c
eigrpd/eigrp_vty.c
eigrpd/eigrp_yang.h [new file with mode: 0644]
eigrpd/eigrp_zebra.c
eigrpd/eigrpd.h
eigrpd/subdir.am
isisd/isis_circuit.h
isisd/isis_cli.c
isisd/isis_lfa.c
isisd/isis_lfa.h
isisd/isis_main.c
isisd/isis_memory.c
isisd/isis_memory.h
isisd/isis_nb.c
isisd/isis_nb.h
isisd/isis_nb_config.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_spf_private.h
isisd/isis_zebra.c
isisd/isis_zebra.h
isisd/isisd.c
isisd/isisd.h
ldpd/adjacency.c
ldpd/hello.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_zebra.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/rlfa.c [new file with mode: 0644]
ldpd/rlfa.h [new file with mode: 0644]
ldpd/subdir.am
lib/sockunion.c [changed mode: 0755->0644]
lib/sockunion.h [changed mode: 0755->0644]
lib/zclient.c
lib/zclient.h
nhrpd/nhrp_cache.c [changed mode: 0755->0644]
nhrpd/nhrp_interface.c [changed mode: 0755->0644]
nhrpd/nhrp_nhs.c [changed mode: 0755->0644]
nhrpd/nhrp_peer.c [changed mode: 0755->0644]
nhrpd/nhrp_route.c [changed mode: 0755->0644]
nhrpd/nhrpd.h [changed mode: 0755->0644]
ospfd/ospf_vty.c
tests/bgpd/test_aspath.c
tests/bgpd/test_capability.c
tests/bgpd/test_mp_attr.c
tests/bgpd/test_mpath.c
tests/bgpd/test_packet.c
tests/bgpd/test_peer_attr.c
tests/isisd/test_common.c
tests/isisd/test_common.h
tests/isisd/test_isis_spf.c
tests/isisd/test_isis_spf.in
tests/isisd/test_isis_spf.refout
tests/topotests/bgp_features/exabgp.env [new file with mode: 0644]
tests/topotests/bgp_features/peer1/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer1/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/peer2/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer2/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/peer3/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer3/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/peer4/exa_readpipe.py [new file with mode: 0644]
tests/topotests/bgp_features/peer4/exabgp.cfg [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_damp_announced.json [new file with mode: 0644]
tests/topotests/bgp_features/r1/bgp_damp_setup.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_damp_announced.json [new file with mode: 0644]
tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json [new file with mode: 0644]
tests/topotests/bgp_features/test_bgp_features.py
tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json [new file with mode: 0644]
tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py [new file with mode: 0755]
tests/topotests/isis-rlfa-topo1/__init__.py [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt1/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt2/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt2/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt3/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt3/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt4/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt4/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt5/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt5/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt6/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt6/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt7/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt7/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt8/isisd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/rt8/zebra.conf [new file with mode: 0644]
tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py [new file with mode: 0755]
tests/topotests/lib/common_config.py
tests/topotests/lib/ospf.py
tests/topotests/ospf_basic_functionality/ospf_p2mp.json [new file with mode: 0644]
tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
tests/topotests/ospf_basic_functionality/test_ospf_lan.py
tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py [new file with mode: 0644]
tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json [new file with mode: 0644]
tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py [new file with mode: 0644]
tools/frr-reload.py
yang/frr-isisd.yang
zebra/sample_plugin.c
zebra/subdir.am
zebra/zebra_dplane.c
zebra/zebra_evpn_mac.c
zebra/zebra_evpn_mac.h
zebra/zebra_nhg.c
zebra/zebra_rib.c

index f46d416c3c75a944aff2081ba056c4dc47902e3f..b740979b82a993f509d2af989b54749026341c58 100644 (file)
 #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)
+{
+       struct reuselist_node *new_node;
+
+       assert(info);
+       new_node = XCALLOC(MTYPE_BGP_DAMP_REUSELIST, sizeof(*new_node));
+       new_node->info = info;
+       SLIST_INSERT_HEAD(list, new_node, entry);
+}
+
+static void bgp_reuselist_del(struct reuselist *list,
+                             struct reuselist_node **node)
+{
+       if ((*node) == NULL)
+               return;
+       assert(list && node && *node);
+       SLIST_REMOVE(list, (*node), reuselist_node, entry);
+       XFREE(MTYPE_BGP_DAMP_REUSELIST, (*node));
+       *node = NULL;
+}
 
-/* 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 reuselist_node *node,
+                                struct reuselist *target)
+{
+       assert(source && target && node);
+       SLIST_REMOVE(source, node, reuselist_node, entry);
+       SLIST_INSERT_HEAD(target, node, entry);
+}
+
+static void bgp_reuselist_free(struct reuselist *list)
+{
+       struct reuselist_node *rn;
+
+       assert(list);
+       while ((rn = SLIST_FIRST(list)) != NULL)
+               bgp_reuselist_del(list, &rn);
+}
+
+static struct reuselist_node *bgp_reuselist_find(struct reuselist *list,
+                                                struct bgp_damp_info *info)
+{
+       struct reuselist_node *rn;
+
+       assert(list && info);
+       SLIST_FOREACH (rn, list, entry) {
+               if (rn->info == info)
+                       return rn;
+       }
+       return NULL;
+}
+
+static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi)
+{
+       struct reuselist_node *node;
+
+       assert(bdi && bdi->config);
+       if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) {
+               node = bgp_reuselist_find(&bdi->config->no_reuse_list, bdi);
+               if (node)
+                       bgp_reuselist_del(&bdi->config->no_reuse_list, &node);
+       } else {
+               node = bgp_reuselist_find(&bdi->config->reuse_list[bdi->index],
+                                         bdi);
+               if (node)
+                       bgp_reuselist_del(&bdi->config->reuse_list[bdi->index],
+                                         &node);
+       }
+       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);
+       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
@@ -72,27 +168,45 @@ 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,
                                  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;
+       struct reuselist *list;
+       struct reuselist_node *rn;
+
+       list = &bdc->reuse_list[bdi->index];
+       rn = bgp_reuselist_find(list, bdi);
+       bgp_damp_info_unclaim(bdi);
+       bgp_reuselist_del(list, &rn);
+}
+
+static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi,
+                                 struct bgp_damp_config *bdc)
+{
+       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,
+                                    struct bgp_damp_config *bdc)
+{
+       struct reuselist_node *rn;
+
+       assert(bdc && bdi);
+       if (bdi->config == NULL) {
+               bgp_damp_info_unclaim(bdi);
+               return;
+       }
+       bdi->config = NULL;
+       rn = bgp_reuselist_find(&bdc->no_reuse_list, bdi);
+       bgp_reuselist_del(&bdc->no_reuse_list, &rn);
 }
 
 /* Return decayed penalty value.  */
@@ -115,32 +229,34 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
    is evaluated.  RFC2439 Section 4.8.7.  */
 static int bgp_reuse_timer(struct thread *t)
 {
+       struct bgp_damp_config *bdc = THREAD_ARG(t);
        struct bgp_damp_info *bdi;
-       struct bgp_damp_info *next;
+       struct reuselist plist;
+       struct reuselist_node *node;
+       struct bgp *bgp;
        time_t t_now, t_diff;
 
-       struct bgp_damp_config *bdc = THREAD_ARG(t);
-
-       bdc->t_reuse = NULL;
        thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
                         &bdc->t_reuse);
 
        t_now = bgp_clock();
 
-       /* 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];
+       node = SLIST_FIRST(&plist);
+       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;
+       while ((node = SLIST_FIRST(&plist)) != NULL) {
+               bdi = node->info;
+               bgp = bdi->path->peer->bgp;
 
                /* Set t-diff = t-now - t-updated.  */
                t_diff = t_now - bdi->t_updated;
@@ -169,16 +285,27 @@ static int bgp_reuse_timer(struct thread *t)
                                            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, bdc, 1, bdi->afi,
+                                                  bdi->safi);
+                               bgp_reuselist_del(&plist, &node);
+                       } else {
+                               node->info->index =
+                                       BGP_DAMP_NO_REUSE_LIST_INDEX;
+                               bgp_reuselist_switch(&plist, node,
+                                                    &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, node,
+                                            &bdc->reuse_list[bdi->index]);
+               }
        }
 
+       assert(SLIST_EMPTY(&plist));
+
        return 0;
 }
 
@@ -189,10 +316,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 = bgp_clock();
+       bdc = get_active_bdc_from_pi(path, afi, safi);
+       if (!bdc)
+               return BGP_DAMP_USED;
 
+       t_now = bgp_clock();
        /* Processing Unreachable Messages.  */
        if (path->extra)
                bdi = path->extra->damp_info;
@@ -214,12 +344,13 @@ 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 {
+               bgp_damp_info_claim(bdi, bdc);
                last_penalty = bdi->penalty;
 
                /* 1. Set t-diff = t-now - t-updated.  */
@@ -245,7 +376,7 @@ 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) {
+               if (bdi->penalty != last_penalty) {
                        bgp_reuse_list_delete(bdi, bdc);
                        bgp_reuse_list_add(bdi, bdc);
                }
@@ -257,10 +388,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, bdc);
                bgp_reuse_list_add(bdi, bdc);
        }
-
        return BGP_DAMP_USED;
 }
 
@@ -270,7 +400,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;
@@ -289,7 +422,7 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
                 && (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_no_reuse_list_add(bdi, bdc);
                bdi->suppress_time = 0;
                status = BGP_DAMP_USED;
        } else
@@ -297,36 +430,29 @@ 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);
+       else {
+               bgp_damp_info_unclaim(bdi);
+               bgp_damp_info_free(&bdi, bdc, 0, afi, safi);
+       }
 
        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 bgp_damp_config *bdc,
+                       int withdraw, afi_t afi, safi_t safi)
 {
-       struct bgp_path_info *path;
-       struct bgp_damp_config *bdc = &damp[afi][safi];
+       assert(bdc && bdi && *bdi);
 
-       if (!bdi)
+       if ((*bdi)->path == NULL) {
+               XFREE(MTYPE_BGP_DAMP_INFO, (*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,
+       (*bdi)->path->extra->damp_info = NULL;
+       bgp_path_info_unset_flag((*bdi)->dest, (*bdi)->path,
                                 BGP_PATH_HISTORY | BGP_PATH_DAMPED);
-
-       if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
-               bgp_path_info_delete(bdi->dest, path);
-
-       XFREE(MTYPE_BGP_DAMP_INFO, bdi);
+       if ((*bdi)->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
+               bgp_path_info_delete((*bdi)->dest, (*bdi)->path);
 }
 
 static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
@@ -369,8 +495,7 @@ static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
 
        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);
@@ -397,7 +522,7 @@ static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
 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
@@ -409,6 +534,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.  */
        thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
@@ -417,8 +544,30 @@ 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_damp_config *bdc, afi_t afi, safi_t safi)
 {
+       struct bgp_damp_info *bdi;
+       struct reuselist_node *rn;
+       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 ((rn = SLIST_FIRST(list)) != NULL) {
+                       bdi = rn->info;
+                       bgp_reuselist_del(list, &rn);
+                       bgp_damp_info_free(&bdi, bdc, 1, afi, safi);
+               }
+       }
+
+       while ((rn = SLIST_FIRST(&bdc->no_reuse_list)) != NULL) {
+               bdi = rn->info;
+               bgp_reuselist_del(&bdc->no_reuse_list, &rn);
+               bgp_damp_info_free(&bdi, bdc, 1, afi, safi);
+       }
+
        /* Free decay array */
        XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
        bdc->decay_array_size = 0;
@@ -428,96 +577,81 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
        bdc->reuse_index_size = 0;
 
        /* Free reuse list array. */
+       for (i = 0; i < bdc->reuse_list_size; ++i)
+               bgp_reuselist_free(&bdc->reuse_list[i]);
+
        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;
+       THREAD_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;
 
        /* Cancel reuse event. */
-       thread_cancel(&(bdc->t_reuse));
+       thread_cancel(&bdc->t_reuse);
 
        /* Clean BGP dampening information.  */
-       bgp_damp_info_clean(afi, safi);
-
-       /* Clear configuration */
-       bgp_damp_config_clean(bdc);
+       bgp_damp_info_clean(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) {
+       if (penalty > bdc->reuse_limit) {
                reuse_time = (int)(DELTA_T
-                                  * ((log((double)damp[afi][safi].reuse_limit
-                                          / penalty))
-                                     / (log(damp[afi][safi].decay_array[1]))));
+                                  * ((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
@@ -569,14 +703,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;
@@ -602,8 +737,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",
@@ -614,14 +749,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,
@@ -630,7 +766,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;
@@ -648,24 +788,23 @@ 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)
 {
+       struct bgp_damp_config *bdc;
        if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
+               bdc = &bgp->damp[afi][safi];
                vty_out(vty, "Half-life time: %lld min\n",
-                       (long long)damp[afi][safi].half_life / 60);
-               vty_out(vty, "Reuse penalty: %d\n",
-                       damp[afi][safi].reuse_limit);
-               vty_out(vty, "Suppress penalty: %d\n",
-                       damp[afi][safi].suppress_value);
+                       (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)damp[afi][safi].max_suppress_time / 60);
-               vty_out(vty, "Max suppress penalty: %u\n",
-                       damp[afi][safi].ceiling);
+                       (long long)bdc->max_suppress_time / 60);
+               vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling);
                vty_out(vty, "\n");
        } else
                vty_out(vty, "dampening not enabled for %s\n",
@@ -678,8 +817,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
                                  uint8_t show_flags)
 {
        struct bgp *bgp;
-       bgp = bgp_get_default();
 
+       bgp = bgp_get_default();
        if (bgp == NULL) {
                vty_out(vty, "No BGP process is configured\n");
                return CMD_WARNING;
@@ -718,3 +857,132 @@ 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;
+       thread_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(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);
+       }
+}
index 604706300bc89ebb4165279e4c00404c0ae24d78..521f59b296553901fafc1870a433f1bbf9075022 100644 (file)
 
 /* 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;
 
@@ -45,6 +40,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;
 
@@ -53,6 +51,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;
@@ -63,6 +63,13 @@ struct bgp_damp_info {
        safi_t safi;
 };
 
+struct reuselist_node {
+       SLIST_ENTRY(reuselist_node) entry;
+       struct bgp_damp_info *info;
+};
+
+SLIST_HEAD(reuselist, reuselist_node);
+
 /* Specified parameter set configuration. */
 struct bgp_damp_config {
        /* Value over which routes suppressed.  */
@@ -100,11 +107,11 @@ 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;
 
        /* 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 thread *t_reuse;
@@ -132,6 +139,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 *, afi_t, safi_t, time_t, unsigned int,
                           unsigned int, time_t);
 extern int bgp_damp_disable(struct bgp *, afi_t, safi_t);
@@ -139,13 +148,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,
+extern void bgp_damp_info_free(struct bgp_damp_info **path,
+                              struct bgp_damp_config *bdc, 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_clean(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, int, struct bgp_damp_config *damp);
-extern void bgp_config_write_damp(struct 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);
+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,
@@ -153,5 +167,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, safi_t,
                                         uint8_t);
+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 */
index cd5bef179856628bca9fbaf048b19e49321c43c1..3afa6eaf09ee7a6bad0174bb243baf614531d579 100644 (file)
@@ -119,7 +119,7 @@ static const struct message bgp_notify_msg[] = {
        {BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"},
        {BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"},
        {BGP_NOTIFY_CEASE, "Cease"},
-       {BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"},
+       {BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"},
        {0}};
 
 static const struct message bgp_notify_head_msg[] = {
@@ -167,11 +167,9 @@ static const struct message bgp_notify_cease_msg[] = {
        {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resource"},
        {0}};
 
-static const struct message bgp_notify_capability_msg[] = {
+static const struct message bgp_notify_route_refresh_msg[] = {
        {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},
-       {BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value"},
-       {BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"},
-       {BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"},
+       {BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN, "/Invalid Message Length"},
        {0}};
 
 static const struct message bgp_notify_fsm_msg[] = {
@@ -493,8 +491,8 @@ const char *bgp_notify_subcode_str(char code, char subcode)
        case BGP_NOTIFY_CEASE:
                return lookup_msg(bgp_notify_cease_msg, subcode,
                                  "Unrecognized Error Subcode");
-       case BGP_NOTIFY_CAPABILITY_ERR:
-               return lookup_msg(bgp_notify_capability_msg, subcode,
+       case BGP_NOTIFY_ROUTE_REFRESH_ERR:
+               return lookup_msg(bgp_notify_route_refresh_msg, subcode,
                                  "Unrecognized Error Subcode");
        }
        return "";
index a4d17cac4047b88645a58d58ff42d7dbc609a860..cec4a9339ab3bce77be406b14e8cc1f6aae86392 100644 (file)
@@ -469,6 +469,7 @@ void bgp_timer_set(struct peer *peer)
                BGP_TIMER_OFF(peer->t_gr_restart);
                BGP_TIMER_OFF(peer->t_gr_stale);
                BGP_TIMER_OFF(peer->t_pmax_restart);
+               BGP_TIMER_OFF(peer->t_refresh_stalepath);
        /* fallthru */
        case Clearing:
                BGP_TIMER_OFF(peer->t_start);
@@ -1283,6 +1284,16 @@ int bgp_stop(struct peer *peer)
                                        peer->nsf[afi][safi] = 0;
                }
 
+               /* Stop route-refresh stalepath timer */
+               if (peer->t_refresh_stalepath) {
+                       BGP_TIMER_OFF(peer->t_refresh_stalepath);
+
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s: route-refresh restart stalepath timer stopped",
+                                       peer->host);
+               }
+
                /* If peer reset before receiving EOR, decrement EOR count and
                 * cancel the selection deferral timer if there are no
                 * pending EOR messages to be received
@@ -2066,14 +2077,16 @@ static int bgp_establish(struct peer *peer)
                               PEER_CAP_ORF_PREFIX_SM_ADV)) {
                        if (CHECK_FLAG(peer->af_cap[afi][safi],
                                       PEER_CAP_ORF_PREFIX_RM_RCV))
-                               bgp_route_refresh_send(peer, afi, safi,
-                                                      ORF_TYPE_PREFIX,
-                                                      REFRESH_IMMEDIATE, 0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, ORF_TYPE_PREFIX,
+                                       REFRESH_IMMEDIATE, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        else if (CHECK_FLAG(peer->af_cap[afi][safi],
                                            PEER_CAP_ORF_PREFIX_RM_OLD_RCV))
-                               bgp_route_refresh_send(peer, afi, safi,
-                                                      ORF_TYPE_PREFIX_OLD,
-                                                      REFRESH_IMMEDIATE, 0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, ORF_TYPE_PREFIX_OLD,
+                                       REFRESH_IMMEDIATE, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                }
        }
 
index f961647778b063bcfb128f6a937efccf60eb237f..287555b1fc549241f625647911bf6c0f7f7b97e1 100644 (file)
@@ -253,6 +253,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
 
        bf_free(bm->rd_idspace);
        list_delete(&bm->bgp);
+       list_delete(&bm->addresses);
 
        bgp_lp_finish();
 
@@ -404,12 +405,16 @@ int main(int argc, char **argv)
        int tmp_port;
 
        int bgp_port = BGP_PORT_DEFAULT;
-       char *bgp_address = NULL;
+       struct list *addresses = list_new();
        int no_fib_flag = 0;
        int no_zebra_flag = 0;
        int skip_runas = 0;
        int instance = 0;
        int buffer_size = BGP_SOCKET_SNDBUF_SIZE;
+       char *address;
+       struct listnode *node;
+
+       addresses->cmp = (int (*)(void *, void *))strcmp;
 
        frr_preinit(&bgpd_di, argc, argv);
        frr_opt_add(
@@ -463,7 +468,7 @@ int main(int argc, char **argv)
                        break;
                }
                case 'l':
-                       bgp_address = optarg;
+                       listnode_add_sort_nodup(addresses, optarg);
                /* listenon implies -n */
                /* fallthru */
                case 'n':
@@ -493,11 +498,10 @@ int main(int argc, char **argv)
                memset(&bgpd_privs, 0, sizeof(bgpd_privs));
 
        /* BGP master init. */
-       bgp_master_init(frr_init(), buffer_size);
+       bgp_master_init(frr_init(), buffer_size, addresses);
        bm->port = bgp_port;
        if (bgp_port == 0)
                bgp_option_set(BGP_OPT_NO_LISTEN);
-       bm->address = bgp_address;
        if (no_fib_flag || no_zebra_flag)
                bgp_option_set(BGP_OPT_NO_FIB);
        if (no_zebra_flag)
@@ -513,8 +517,16 @@ int main(int argc, char **argv)
        /* BGP related initialization.  */
        bgp_init((unsigned short)instance);
 
-       snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo), ", bgp@%s:%d",
-                (bm->address ? bm->address : "<all>"), bm->port);
+       if (list_isempty(bm->addresses)) {
+               snprintf(bgpd_di.startinfo, sizeof(bgpd_di.startinfo),
+                        ", bgp@<all>:%d", bm->port);
+       } else {
+               for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
+                       snprintf(bgpd_di.startinfo + strlen(bgpd_di.startinfo),
+                                sizeof(bgpd_di.startinfo)
+                                        - strlen(bgpd_di.startinfo),
+                                ", bgp@%s:%d", address, bm->port);
+       }
 
        frr_config_fork();
        /* must be called after fork() */
index f9aac35d057a65e4be2d130235d783a0cce30ac1..0013eb2df2a575239799c407513e8f956d3f1bd2 100644 (file)
@@ -98,6 +98,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")
index a95d9ef931f1743d045ef2f80d1e473fb3013c39..63998e95acb5e7d469154d45ba139b750063874f 100644 (file)
@@ -94,6 +94,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)
index 6cfcb9cc3d2331d8cb4e2fee64d75075e4812e06..533518cf93654fce19d20b6d73459ebc438ba7c8 100644 (file)
@@ -760,6 +760,7 @@ static const struct message capcode_str[] = {
        {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"},
        {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"},
        {CAPABILITY_CODE_FQDN, "FQDN"},
+       {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"},
        {0}};
 
 /* Minimum sizes for length field of each cap (so not inc. the header) */
@@ -776,6 +777,7 @@ static const size_t cap_minsizes[] = {
                [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
                [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN,
                [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN,
+               [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN,
 };
 
 /* value the capability must be a multiple of.
@@ -796,6 +798,7 @@ static const size_t cap_modsizes[] = {
                [CAPABILITY_CODE_REFRESH_OLD] = 1,
                [CAPABILITY_CODE_ORF_OLD] = 1,
                [CAPABILITY_CODE_FQDN] = 1,
+               [CAPABILITY_CODE_ENHANCED_RR] = 1,
 };
 
 /**
@@ -863,6 +866,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
                case CAPABILITY_CODE_DYNAMIC_OLD:
                case CAPABILITY_CODE_ENHE:
                case CAPABILITY_CODE_FQDN:
+               case CAPABILITY_CODE_ENHANCED_RR:
                        /* Check length. */
                        if (caphdr.length < cap_minsizes[caphdr.code]) {
                                zlog_info(
@@ -913,10 +917,13 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
                                ret = 0; /* Don't return error for this */
                        }
                } break;
+               case CAPABILITY_CODE_ENHANCED_RR:
                case CAPABILITY_CODE_REFRESH:
                case CAPABILITY_CODE_REFRESH_OLD: {
                        /* BGP refresh capability */
-                       if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
+                       if (caphdr.code == CAPABILITY_CODE_ENHANCED_RR)
+                               SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_RCV);
+                       else if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD)
                                SET_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV);
                        else
                                SET_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV);
@@ -1450,6 +1457,13 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
        stream_putc(s, CAPABILITY_CODE_REFRESH);
        stream_putc(s, CAPABILITY_CODE_REFRESH_LEN);
 
+       /* Enhanced Route Refresh. */
+       SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_ADV);
+       stream_putc(s, BGP_OPEN_OPT_CAP);
+       stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2);
+       stream_putc(s, CAPABILITY_CODE_ENHANCED_RR);
+       stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN);
+
        /* AS4 */
        SET_FLAG(peer->cap, PEER_CAP_AS4_ADV);
        stream_putc(s, BGP_OPEN_OPT_CAP);
index 5250a68581090d6dc870b20f821bbfa1bad9c6e8..471ac05c7cf0686abe90eae94d22c2a6996260a0 100644 (file)
@@ -49,6 +49,7 @@ struct graceful_restart_af {
 #define CAPABILITY_CODE_DYNAMIC_OLD    66 /* Dynamic Capability, deprecated since 2003 */
 #define CAPABILITY_CODE_DYNAMIC        67 /* Dynamic Capability */
 #define CAPABILITY_CODE_ADDPATH        69 /* Addpath Capability */
+#define CAPABILITY_CODE_ENHANCED_RR    70 /* Enhanced Route Refresh capability */
 #define CAPABILITY_CODE_FQDN           73 /* Advertise hostname capability */
 #define CAPABILITY_CODE_ENHE            5 /* Extended Next Hop Encoding */
 #define CAPABILITY_CODE_REFRESH_OLD   128 /* Route Refresh Capability(cisco) */
@@ -63,6 +64,7 @@ struct graceful_restart_af {
 #define CAPABILITY_CODE_ADDPATH_LEN     4
 #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
 #define CAPABILITY_CODE_ORF_LEN         5
 
 /* Cooperative Route Filtering Capability.  */
index b2b9e04bc3455246588285bc2cdaeb963d4b5f38..b7ecd8a49bfe05da6b858d85d629eed57801e37e 100644 (file)
@@ -444,13 +444,45 @@ int bgp_generate_updgrp_packets(struct thread *thread)
                         * yet.
                         */
                        if (!next_pkt || !next_pkt->buffer) {
-                               /* Make sure we supress BGP UPDATES
-                                * for normal processing later again.
-                                */
-                               if (!paf->t_announce_route)
+                               if (!paf->t_announce_route) {
+                                       /* Make sure we supress BGP UPDATES
+                                        * for normal processing later again.
+                                        */
                                        UNSET_FLAG(paf->subgroup->sflags,
                                                   SUBGRP_STATUS_FORCE_UPDATES);
 
+                                       /* If route-refresh BoRR message was
+                                        * already sent and we are done with
+                                        * re-announcing tables for a decent
+                                        * afi/safi, we ready to send
+                                        * EoRR request.
+                                        */
+                                       if (CHECK_FLAG(
+                                                   peer->af_sflags[afi][safi],
+                                                   PEER_STATUS_BORR_SEND)) {
+                                               bgp_route_refresh_send(
+                                                       peer, afi, safi, 0, 0,
+                                                       0,
+                                                       BGP_ROUTE_REFRESH_EORR);
+
+                                               SET_FLAG(peer->af_sflags[afi]
+                                                                       [safi],
+                                                        PEER_STATUS_EORR_SEND);
+                                               UNSET_FLAG(
+                                                       peer->af_sflags[afi]
+                                                                      [safi],
+                                                       PEER_STATUS_BORR_SEND);
+
+                                               if (bgp_debug_neighbor_events(
+                                                           peer))
+                                                       zlog_debug(
+                                                               "%s sending route-refresh (EoRR) for %s/%s",
+                                                               peer->host,
+                                                               afi2str(afi),
+                                                               safi2str(safi));
+                                       }
+                               }
+
                                if (CHECK_FLAG(peer->cap,
                                               PEER_CAP_RESTART_RCV)) {
                                        if (!(PAF_SUBGRP(paf))->t_coalesce
@@ -816,7 +848,7 @@ void bgp_notify_send(struct peer *peer, uint8_t code, uint8_t sub_code)
  */
 void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
                            uint8_t orf_type, uint8_t when_to_refresh,
-                           int remove)
+                           int remove, uint8_t subtype)
 {
        struct stream *s;
        struct bgp_filter *filter;
@@ -842,7 +874,10 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
 
        /* Encode Route Refresh message. */
        stream_putw(s, pkt_afi);
-       stream_putc(s, 0);
+       if (subtype)
+               stream_putc(s, subtype);
+       else
+               stream_putc(s, 0);
        stream_putc(s, pkt_safi);
 
        if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD)
@@ -1460,6 +1495,29 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
        return Receive_KEEPALIVE_message;
 }
 
+static int bgp_refresh_stalepath_timer_expire(struct thread *thread)
+{
+       struct peer_af *paf;
+
+       paf = THREAD_ARG(thread);
+
+       afi_t afi = paf->afi;
+       safi_t safi = paf->safi;
+       struct peer *peer = paf->peer;
+
+       peer->t_refresh_stalepath = NULL;
+
+       if (peer->nsf[afi][safi])
+               bgp_clear_stale_route(peer, afi, safi);
+
+       if (bgp_debug_neighbor_events(peer))
+               zlog_debug("%s: route-refresh (BoRR) timer for %s/%s expired",
+                          peer->host, afi2str(afi), safi2str(safi));
+
+       bgp_timer_set(peer);
+
+       return 0;
+}
 
 /**
  * Process BGP UPDATE message for peer.
@@ -1888,6 +1946,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
        struct peer_af *paf;
        struct update_group *updgrp;
        struct peer *updgrp_peer;
+       uint8_t subtype;
+       bgp_size_t msg_length =
+               size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE);
 
        /* If peer does not have the capability, send notification. */
        if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_ADV)) {
@@ -1915,14 +1976,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
 
        /* Parse packet. */
        pkt_afi = stream_getw(s);
-       (void)stream_getc(s);
+       subtype = stream_getc(s);
        pkt_safi = stream_getc(s);
 
-       if (bgp_debug_update(peer, NULL, NULL, 0))
-               zlog_debug("%s rcvd REFRESH_REQ for afi/safi: %s/%s",
-                          peer->host, iana_afi2str(pkt_afi),
-                          iana_safi2str(pkt_safi));
-
        /* Convert AFI, SAFI to internal values and check. */
        if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
                zlog_info(
@@ -1938,8 +1994,34 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                uint8_t orf_type;
                uint16_t orf_len;
 
-               if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE)
-                   < 5) {
+               if (subtype) {
+                       /* If the length, excluding the fixed-size message
+                        * header, of the received ROUTE-REFRESH message with
+                        * Message Subtype 1 and 2 is not 4, then the BGP
+                        * speaker MUST send a NOTIFICATION message with the
+                        * Error Code of "ROUTE-REFRESH Message Error" and the
+                        * subcode of "Invalid Message Length".
+                        */
+                       if (msg_length != 4) {
+                               zlog_err(
+                                       "%s Enhanced Route Refresh message length error",
+                                       peer->host);
+                               bgp_notify_send(
+                                       peer, BGP_NOTIFY_ROUTE_REFRESH_ERR,
+                                       BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN);
+                       }
+
+                       /* When the BGP speaker receives a ROUTE-REFRESH message
+                        * with a "Message Subtype" field other than 0, 1, or 2,
+                        * it MUST ignore the received ROUTE-REFRESH message.
+                        */
+                       if (subtype > 2)
+                               zlog_err(
+                                       "%s Enhanced Route Refresh invalid subtype",
+                                       peer->host);
+               }
+
+               if (msg_length < 5) {
                        zlog_info("%s ORF route refresh length error",
                                  peer->host);
                        bgp_notify_send(peer, BGP_NOTIFY_CEASE,
@@ -2139,6 +2221,124 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                                   SUBGRP_STATUS_DEFAULT_ORIGINATE);
        }
 
+       if (subtype == BGP_ROUTE_REFRESH_BORR) {
+               /* A BGP speaker that has received the Graceful Restart
+                * Capability from its neighbor MUST ignore any BoRRs for
+                * an <AFI, SAFI> from the neighbor before the speaker
+                * receives the EoR for the given <AFI, SAFI> from the
+                * neighbor.
+                */
+               if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)
+                   && !CHECK_FLAG(peer->af_sflags[afi][safi],
+                                  PEER_STATUS_EOR_RECEIVED)) {
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s rcvd route-refresh (BoRR) for %s/%s before EoR",
+                                       peer->host, afi2str(afi),
+                                       safi2str(safi));
+                       return BGP_PACKET_NOOP;
+               }
+
+               if (peer->t_refresh_stalepath) {
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s rcvd route-refresh (BoRR) for %s/%s, whereas BoRR already received",
+                                       peer->host, afi2str(afi),
+                                       safi2str(safi));
+                       return BGP_PACKET_NOOP;
+               }
+
+               SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_BORR_RECEIVED);
+               UNSET_FLAG(peer->af_sflags[afi][safi],
+                          PEER_STATUS_EORR_RECEIVED);
+
+               /* When a BGP speaker receives a BoRR message from
+                * a peer, it MUST mark all the routes with the given
+                * Address Family Identifier and Subsequent Address
+                * Family Identifier, <AFI, SAFI> [RFC2918], from
+                * that peer as stale.
+                */
+               if (peer_active_nego(peer)) {
+                       SET_FLAG(peer->af_sflags[afi][safi],
+                                PEER_STATUS_ENHANCED_REFRESH);
+                       bgp_set_stale_route(peer, afi, safi);
+               }
+
+               if (peer->status == Established)
+                       thread_add_timer(bm->master,
+                                        bgp_refresh_stalepath_timer_expire,
+                                        paf, peer->bgp->stalepath_time,
+                                        &peer->t_refresh_stalepath);
+
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug(
+                               "%s rcvd route-refresh (BoRR) for %s/%s, triggering timer for %u seconds",
+                               peer->host, afi2str(afi), safi2str(safi),
+                               peer->bgp->stalepath_time);
+       } else if (subtype == BGP_ROUTE_REFRESH_EORR) {
+               if (!peer->t_refresh_stalepath) {
+                       zlog_err(
+                               "%s rcvd route-refresh (EoRR) for %s/%s, whereas no BoRR received",
+                               peer->host, afi2str(afi), safi2str(safi));
+                       return BGP_PACKET_NOOP;
+               }
+
+               BGP_TIMER_OFF(peer->t_refresh_stalepath);
+
+               SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EORR_RECEIVED);
+               UNSET_FLAG(peer->af_sflags[afi][safi],
+                          PEER_STATUS_BORR_RECEIVED);
+
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug(
+                               "%s rcvd route-refresh (EoRR) for %s/%s, stopping BoRR timer",
+                               peer->host, afi2str(afi), safi2str(safi));
+
+               if (peer->nsf[afi][safi])
+                       bgp_clear_stale_route(peer, afi, safi);
+       } else {
+               if (bgp_debug_neighbor_events(peer))
+                       zlog_debug("%s rcvd route-refresh (REQUEST) for %s/%s",
+                                  peer->host, afi2str(afi), safi2str(safi));
+
+               /* In response to a "normal route refresh request" from the
+                * peer, the speaker MUST send a BoRR message.
+                */
+               if (CHECK_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_RCV)) {
+                       /* For a BGP speaker that supports the BGP Graceful
+                        * Restart, it MUST NOT send a BoRR for an <AFI, SAFI>
+                        * to a neighbor before it sends the EoR for the
+                        * <AFI, SAFI> to the neighbor.
+                        */
+                       if (!CHECK_FLAG(peer->af_sflags[afi][safi],
+                                       PEER_STATUS_EOR_SEND)) {
+                               if (bgp_debug_neighbor_events(peer))
+                                       zlog_debug(
+                                               "%s rcvd route-refresh (REQUEST) for %s/%s before EoR",
+                                               peer->host, afi2str(afi),
+                                               safi2str(safi));
+                               return BGP_PACKET_NOOP;
+                       }
+
+                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+                                              BGP_ROUTE_REFRESH_BORR);
+
+                       if (bgp_debug_neighbor_events(peer))
+                               zlog_debug(
+                                       "%s sending route-refresh (BoRR) for %s/%s",
+                                       peer->host, afi2str(afi),
+                                       safi2str(safi));
+
+                       /* Set flag Ready-To-Send to know when we can send EoRR
+                        * message.
+                        */
+                       SET_FLAG(peer->af_sflags[afi][safi],
+                                PEER_STATUS_BORR_SEND);
+                       UNSET_FLAG(peer->af_sflags[afi][safi],
+                                  PEER_STATUS_EORR_SEND);
+               }
+       }
+
        /* Perform route refreshment to the peer */
        bgp_announce_route(peer, afi, safi);
 
index e83f7d950c8f172aa6b38f419bfc1fcc932d290c..525859a2da68a777abc0a229d9da8766299c75a9 100644 (file)
@@ -62,8 +62,9 @@ extern void bgp_open_send(struct peer *);
 extern void bgp_notify_send(struct peer *, uint8_t, uint8_t);
 extern void bgp_notify_send_with_data(struct peer *, uint8_t, uint8_t,
                                      uint8_t *, size_t);
-extern void bgp_route_refresh_send(struct peer *, afi_t, safi_t, uint8_t,
-                                  uint8_t, int);
+extern void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi,
+                                  uint8_t orf_type, uint8_t when_to_refresh,
+                                  int remove, uint8_t subtype);
 extern void bgp_capability_send(struct peer *, afi_t, safi_t, int, int);
 
 extern int bgp_capability_receive(struct peer *, bgp_size_t);
index 0760bbd6a2434a82f59f8247a15feb3813cb805d..c4ab223b7f5956b54904638b2170e50e95f99a57 100644 (file)
@@ -208,9 +208,6 @@ 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);
 
        e->damp_info = NULL;
        if (e->parent) {
@@ -3331,14 +3328,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) {
@@ -3763,8 +3762,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                    && (overlay_index_equal(
                               afi, pi,
                               evpn == NULL ? NULL : &evpn->gw_ip))) {
-                       if (CHECK_FLAG(bgp->af_flags[afi][safi],
-                                      BGP_CONFIG_DAMPENING)
+                       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)) {
@@ -3858,11 +3856,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                bgp_aggregate_decrement(bgp, p, pi, afi, safi);
 
                /* Update bgp route dampening information.  */
-               if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
+               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);
                }
@@ -3985,7 +3983,7 @@ int 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)
+               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);
@@ -4601,8 +4599,10 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data)
                        continue;
 
                /* graceful restart STALE flag set. */
-               if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)
-                   && peer->nsf[afi][safi]
+               if (((CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)
+                     && peer->nsf[afi][safi])
+                    || CHECK_FLAG(peer->af_sflags[afi][safi],
+                                  PEER_STATUS_ENHANCED_REFRESH))
                    && !CHECK_FLAG(pi->flags, BGP_PATH_STALE)
                    && !CHECK_FLAG(pi->flags, BGP_PATH_UNUSEABLE))
                        bgp_path_info_set_flag(dest, pi, BGP_PATH_STALE);
@@ -4853,7 +4853,7 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
        struct bgp_path_info *pi;
        struct bgp_table *table;
 
-       if (safi == SAFI_MPLS_VPN) {
+       if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
                for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
                     dest = bgp_route_next(dest)) {
                        struct bgp_dest *rm;
@@ -4892,6 +4892,81 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi)
        }
 }
 
+void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi)
+{
+       struct bgp_dest *dest, *ndest;
+       struct bgp_path_info *pi;
+       struct bgp_table *table;
+
+       if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) {
+               for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
+                    dest = bgp_route_next(dest)) {
+                       table = bgp_dest_get_bgp_table_info(dest);
+                       if (!table)
+                               continue;
+
+                       for (ndest = bgp_table_top(table); ndest;
+                            ndest = bgp_route_next(ndest)) {
+                               for (pi = bgp_dest_get_bgp_path_info(ndest); pi;
+                                    pi = pi->next) {
+                                       if (pi->peer != peer)
+                                               continue;
+
+                                       if ((CHECK_FLAG(
+                                                   peer->af_sflags[afi][safi],
+                                                   PEER_STATUS_ENHANCED_REFRESH))
+                                           && !CHECK_FLAG(pi->flags,
+                                                          BGP_PATH_STALE)
+                                           && !CHECK_FLAG(
+                                                      pi->flags,
+                                                      BGP_PATH_UNUSEABLE)) {
+                                               if (bgp_debug_neighbor_events(
+                                                           peer))
+                                                       zlog_debug(
+                                                               "%s: route-refresh for %s/%s, marking prefix %pFX as stale",
+                                                               peer->host,
+                                                               afi2str(afi),
+                                                               safi2str(safi),
+                                                               bgp_dest_get_prefix(
+                                                                       ndest));
+
+                                               bgp_path_info_set_flag(
+                                                       ndest, pi,
+                                                       BGP_PATH_STALE);
+                                       }
+                               }
+                       }
+               }
+       } 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) {
+                               if (pi->peer != peer)
+                                       continue;
+
+                               if ((CHECK_FLAG(peer->af_sflags[afi][safi],
+                                               PEER_STATUS_ENHANCED_REFRESH))
+                                   && !CHECK_FLAG(pi->flags, BGP_PATH_STALE)
+                                   && !CHECK_FLAG(pi->flags,
+                                                  BGP_PATH_UNUSEABLE)) {
+                                       if (bgp_debug_neighbor_events(peer))
+                                               zlog_debug(
+                                                       "%s: route-refresh for %s/%s, marking prefix %pFX as stale",
+                                                       peer->host,
+                                                       afi2str(afi),
+                                                       safi2str(safi),
+                                                       bgp_dest_get_prefix(
+                                                               dest));
+
+                                       bgp_path_info_set_flag(dest, pi,
+                                                              BGP_PATH_STALE);
+                               }
+                       }
+               }
+       }
+}
+
 bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter)
 {
        if (peer->sort == BGP_PEER_IBGP)
@@ -10135,7 +10210,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
        }
 
        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])
@@ -14085,7 +14160,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
                                        if (pi->extra && pi->extra->damp_info) {
                                                pi_temp = pi->next;
                                                bgp_damp_info_free(
-                                                       pi->extra->damp_info,
+                                                       &pi->extra->damp_info,
+                                                       &bgp->damp[afi][safi],
                                                        1, afi, safi);
                                                pi = pi_temp;
                                        } else
@@ -14107,7 +14183,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
                                        if (pi->extra && pi->extra->damp_info) {
                                                pi_temp = pi->next;
                                                bgp_damp_info_free(
-                                                       pi->extra->damp_info,
+                                                       &pi->extra->damp_info,
+                                                       &bgp->damp[afi][safi],
                                                        1, afi, safi);
                                                pi = pi_temp;
                                        } else
@@ -14130,7 +14207,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->damp[AFI_IP][SAFI_UNICAST], AFI_IP,
+                           SAFI_UNICAST);
        return CMD_SUCCESS;
 }
 
index ec08eb9c657c1f37b0373aa2d47473c993ef24b4..bdbf4743ab595940c7da450d734716c8ed48c2f5 100644 (file)
@@ -575,6 +575,7 @@ extern void bgp_clear_route(struct peer *, afi_t, safi_t);
 extern void bgp_clear_route_all(struct peer *);
 extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t);
 extern void bgp_clear_stale_route(struct peer *, afi_t, safi_t);
+extern void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi);
 extern bool bgp_outbound_policy_exists(struct peer *, struct bgp_filter *);
 extern bool bgp_inbound_policy_exists(struct peer *, struct bgp_filter *);
 
index 637eaca397740fa6e5b29ec273eef3a6dd42efae..0f4f26e3ee82ae44c7e7b971762d7312417acc22 100644 (file)
@@ -3503,8 +3503,9 @@ static void bgp_route_map_process_peer(const char *rmap_name,
                                        zlog_debug(
                                                "Processing route_map %s update on peer %s (inbound, route-refresh)",
                                                rmap_name, peer->host);
-                               bgp_route_refresh_send(peer, afi, safi, 0, 0,
-                                                      0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, 0, 0, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        }
                }
        }
index 4cdd4d2e629b66e446e8f1f3c4ccfb9260ab9c56..114a00cc36e3a6c88d6988c99a3c6441ab152c7f 100644 (file)
@@ -8896,6 +8896,93 @@ DEFPY(
        return CMD_SUCCESS;
 }
 
+DEFPY(neighbor_damp,
+      neighbor_damp_cmd,
+      "neighbor <A.B.C.D|X:X::X:X|WORD>$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 <A.B.C.D|X:X::X:X|WORD>$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 [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD>$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)
 {
@@ -13153,6 +13240,37 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                                        "received");
                                }
 
+                               /* Enhanced Route Refresh */
+                               if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV)
+                                   || CHECK_FLAG(p->cap,
+                                                 PEER_CAP_ENHANCED_RR_RCV)) {
+                                       if (CHECK_FLAG(p->cap,
+                                                      PEER_CAP_ENHANCED_RR_ADV)
+                                           && CHECK_FLAG(
+                                                   p->cap,
+                                                   PEER_CAP_ENHANCED_RR_RCV))
+                                               json_object_string_add(
+                                                       json_cap,
+                                                       "enhancedRouteRefresh",
+                                                       "advertisedAndReceived");
+                                       else if (
+                                               CHECK_FLAG(
+                                                       p->cap,
+                                                       PEER_CAP_ENHANCED_RR_ADV))
+                                               json_object_string_add(
+                                                       json_cap,
+                                                       "enhancedRouteRefresh",
+                                                       "advertised");
+                                       else if (
+                                               CHECK_FLAG(
+                                                       p->cap,
+                                                       PEER_CAP_ENHANCED_RR_RCV))
+                                               json_object_string_add(
+                                                       json_cap,
+                                                       "enhancedRouteRefresh",
+                                                       "received");
+                               }
+
                                /* Multiprotocol Extensions */
                                json_object *json_multi = NULL;
                                json_multi = json_object_new_object();
@@ -13525,6 +13643,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                        vty_out(vty, "\n");
                                }
 
+                               /* Enhanced Route Refresh */
+                               if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV)
+                                   || CHECK_FLAG(p->cap,
+                                                 PEER_CAP_ENHANCED_RR_RCV)) {
+                                       vty_out(vty,
+                                               "    Enhanced Route Refresh:");
+                                       if (CHECK_FLAG(
+                                                   p->cap,
+                                                   PEER_CAP_ENHANCED_RR_ADV))
+                                               vty_out(vty, " advertised");
+                                       if (CHECK_FLAG(
+                                                   p->cap,
+                                                   PEER_CAP_ENHANCED_RR_RCV))
+                                               vty_out(vty, " %sreceived",
+                                                       CHECK_FLAG(
+                                                               p->cap,
+                                                               PEER_CAP_REFRESH_ADV)
+                                                               ? "and "
+                                                               : "");
+                                       vty_out(vty, "\n");
+                               }
+
                                /* Multiprotocol Extensions */
                                FOREACH_AFI_SAFI (afi, safi)
                                        if (p->afc_adv[afi][safi]
@@ -16947,7 +17087,15 @@ 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 (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);
@@ -18712,6 +18860,23 @@ void bgp_vty_init(void)
        install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd);
        install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_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);
index cd1873054e105d3518c20ef1b04a61987ef0f179..f7c4b04adffa5d40beb18701fab22da571d8c5dd 100644 (file)
@@ -1347,11 +1347,21 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 
                        nexthop = bgp_path_info_to_ipv6_nexthop(mpinfo_cp,
                                                                &ifindex);
-                       nh_updated = update_ipv6nh_for_route_install(
-                                       nh_othervrf, nh_othervrf ?
-                                       info->extra->bgp_orig : bgp,
-                                       nexthop, ifindex,
-                                       mpinfo, info, is_evpn, api_nh);
+
+                       if (!nexthop)
+                               nh_updated = update_ipv4nh_for_route_install(
+                                       nh_othervrf,
+                                       nh_othervrf ? info->extra->bgp_orig
+                                                   : bgp,
+                                       &mpinfo_cp->attr->nexthop,
+                                       mpinfo_cp->attr, is_evpn, api_nh);
+                       else
+                               nh_updated = update_ipv6nh_for_route_install(
+                                       nh_othervrf,
+                                       nh_othervrf ? info->extra->bgp_orig
+                                                   : bgp,
+                                       nexthop, ifindex, mpinfo, info, is_evpn,
+                                       api_nh);
                }
 
                /* Did we get proper nexthop info to update zebra? */
index 026b57193edc114d426d8acf19db0f1390b747b7..9a2693fd56359a0e07a3799a0a90f65a1c0b78cd 100644 (file)
@@ -121,12 +121,20 @@ extern struct zclient *zclient;
 static int bgp_check_main_socket(bool create, struct bgp *bgp)
 {
        static int bgp_server_main_created;
+       struct listnode *node;
+       char *address;
 
        if (create) {
                if (bgp_server_main_created)
                        return 0;
-               if (bgp_socket(bgp, bm->port, bm->address) < 0)
-                       return BGP_ERR_INVALID_VALUE;
+               if (list_isempty(bm->addresses)) {
+                       if (bgp_socket(bgp, bm->port, NULL) < 0)
+                               return BGP_ERR_INVALID_VALUE;
+               } else {
+                       for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
+                               if (bgp_socket(bgp, bm->port, address) < 0)
+                                       return BGP_ERR_INVALID_VALUE;
+               }
                bgp_server_main_created = 1;
                return 0;
        }
@@ -2379,6 +2387,14 @@ int peer_delete(struct peer *peer)
 
        bgp_bfd_deregister_peer(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) {
@@ -3280,7 +3296,8 @@ struct bgp *bgp_get_evpn(void)
 int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
                      bool create)
 {
-       int ret = 0;
+       struct listnode *node;
+       char *address;
 
        /* Create BGP server socket, if listen mode not disabled */
        if (!bgp || bgp_option_check(BGP_OPT_NO_LISTEN))
@@ -3309,9 +3326,14 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
                 */
                if (vrf->vrf_id == VRF_UNKNOWN)
                        return 0;
-               ret = bgp_socket(bgp, bm->port, bm->address);
-               if (ret < 0)
-                       return BGP_ERR_INVALID_VALUE;
+               if (list_isempty(bm->addresses)) {
+                       if (bgp_socket(bgp, bm->port, NULL) < 0)
+                               return BGP_ERR_INVALID_VALUE;
+               } else {
+                       for (ALL_LIST_ELEMENTS_RO(bm->addresses, node, address))
+                               if (bgp_socket(bgp, bm->port, address) < 0)
+                                       return BGP_ERR_INVALID_VALUE;
+               }
                return 0;
        } else
                return bgp_check_main_socket(create, bgp);
@@ -3500,6 +3522,11 @@ int bgp_delete(struct bgp *bgp)
                BGP_TIMER_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");
@@ -4012,7 +4039,8 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
        } else if (type == peer_change_reset_in) {
                if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
                    || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
-                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0);
+                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+                                              BGP_ROUTE_REFRESH_NORMAL);
                else {
                        if ((peer->doppelganger)
                            && (peer->doppelganger->status != Deleted)
@@ -5090,7 +5118,8 @@ static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
                        bgp_soft_reconfig_in(peer, afi, safi);
                else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
                         || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
-                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0);
+                       bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+                                              BGP_ROUTE_REFRESH_NORMAL);
        }
 }
 
@@ -7338,19 +7367,23 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
                                               PEER_STATUS_ORF_PREFIX_SEND))
                                        bgp_route_refresh_send(
                                                peer, afi, safi, prefix_type,
-                                               REFRESH_DEFER, 1);
-                               bgp_route_refresh_send(peer, afi, safi,
-                                                      prefix_type,
-                                                      REFRESH_IMMEDIATE, 0);
+                                               REFRESH_DEFER, 1,
+                                               BGP_ROUTE_REFRESH_NORMAL);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, prefix_type,
+                                       REFRESH_IMMEDIATE, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        } else {
                                if (CHECK_FLAG(peer->af_sflags[afi][safi],
                                               PEER_STATUS_ORF_PREFIX_SEND))
                                        bgp_route_refresh_send(
                                                peer, afi, safi, prefix_type,
-                                               REFRESH_IMMEDIATE, 1);
+                                               REFRESH_IMMEDIATE, 1,
+                                               BGP_ROUTE_REFRESH_NORMAL);
                                else
-                                       bgp_route_refresh_send(peer, afi, safi,
-                                                              0, 0, 0);
+                                       bgp_route_refresh_send(
+                                               peer, afi, safi, 0, 0, 0,
+                                               BGP_ROUTE_REFRESH_NORMAL);
                        }
                        return 0;
                }
@@ -7369,8 +7402,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
                           message to the peer. */
                        if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
                            || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
-                               bgp_route_refresh_send(peer, afi, safi, 0, 0,
-                                                      0);
+                               bgp_route_refresh_send(
+                                       peer, afi, safi, 0, 0, 0,
+                                       BGP_ROUTE_REFRESH_NORMAL);
                        else
                                return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED;
                }
@@ -7425,7 +7459,8 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
        return buf;
 }
 
-void bgp_master_init(struct thread_master *master, const int buffer_size)
+void bgp_master_init(struct thread_master *master, const int buffer_size,
+                    struct list *addresses)
 {
        qobj_init();
 
@@ -7435,6 +7470,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
        bm->bgp = list_new();
        bm->listen_sockets = list_new();
        bm->port = BGP_PORT_DEFAULT;
+       bm->addresses = addresses;
        bm->master = master;
        bm->start_time = bgp_clock();
        bm->t_rmap_update = NULL;
index 16210bed153f143c9acd9a9eed2d4f9623828c8e..9089608062aa5128dc8ced5dccc9f756d4e306f2 100644 (file)
@@ -43,6 +43,7 @@
 #include "bgp_labelpool.h"
 #include "bgp_addpath_types.h"
 #include "bgp_nexthop.h"
+#include "bgp_damp.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
 #define BGP_PEER_MAX_HASH_SIZE 16384
@@ -124,8 +125,8 @@ struct bgp_master {
        /* BGP port number.  */
        uint16_t port;
 
-       /* Listener address */
-       char *address;
+       /* Listener addresses */
+       struct list *addresses;
 
        /* The Mac table */
        struct hash *self_mac_hash;
@@ -695,6 +696,9 @@ struct bgp {
        uint32_t condition_filter_count;
        struct thread *t_condition_check;
 
+       /* BGP route flap dampening configuration */
+       struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
+
        QOBJ_FIELDS
 };
 DECLARE_QOBJ_TYPE(bgp)
@@ -1063,6 +1067,8 @@ struct peer {
 #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 */
 
        /* Capability flags (reset in bgp_stop) */
        uint32_t af_cap[AFI_MAX][SAFI_MAX];
@@ -1197,6 +1203,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
@@ -1234,6 +1243,8 @@ struct peer {
 #define PEER_FLAG_SEND_LARGE_COMMUNITY      (1U << 26) /* Send large Communities */
 #define PEER_FLAG_MAX_PREFIX_OUT            (1U << 27) /* outgoing maximum prefix */
 #define PEER_FLAG_MAX_PREFIX_FORCE          (1U << 28) /* maximum-prefix <num> force */
+#define PEER_FLAG_CONFIG_DAMPENING (1U << 29) /* route flap dampening */
+
 
        enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
 
@@ -1264,6 +1275,11 @@ struct peer {
 #define PEER_STATUS_PREFIX_LIMIT      (1U << 3) /* exceed prefix-limit */
 #define PEER_STATUS_EOR_SEND          (1U << 4) /* end-of-rib send to peer */
 #define PEER_STATUS_EOR_RECEIVED      (1U << 5) /* end-of-rib received from peer */
+#define PEER_STATUS_ENHANCED_REFRESH (1U << 6) /* Enhanced Route Refresh */
+#define PEER_STATUS_BORR_SEND (1U << 7) /* BoRR send to peer */
+#define PEER_STATUS_BORR_RECEIVED (1U << 8) /* BoRR received from peer */
+#define PEER_STATUS_EORR_SEND (1U << 9) /* EoRR send to peer */
+#define PEER_STATUS_EORR_RECEIVED (1U << 10) /* EoRR received from peer */
 
        /* Configured timer values. */
        _Atomic uint32_t holdtime;
@@ -1297,6 +1313,7 @@ struct peer {
        struct thread *t_gr_stale;
        struct thread *t_generate_updgrp_packets;
        struct thread *t_process_packet;
+       struct thread *t_refresh_stalepath;
 
        /* Thread flags. */
        _Atomic uint32_t thread_flags;
@@ -1621,7 +1638,7 @@ struct bgp_nlri {
 #define BGP_NOTIFY_HOLD_ERR                      4
 #define BGP_NOTIFY_FSM_ERR                       5
 #define BGP_NOTIFY_CEASE                         6
-#define BGP_NOTIFY_CAPABILITY_ERR                7
+#define BGP_NOTIFY_ROUTE_REFRESH_ERR             7
 
 /* Subcodes for BGP Finite State Machine Error */
 #define BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC  0
@@ -1669,10 +1686,13 @@ struct bgp_nlri {
 #define BGP_NOTIFY_CEASE_COLLISION_RESOLUTION    7
 #define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE         8
 
-/* BGP_NOTIFY_CAPABILITY_ERR sub codes (draft-ietf-idr-dynamic-cap-02). */
-#define BGP_NOTIFY_CAPABILITY_INVALID_ACTION     1
-#define BGP_NOTIFY_CAPABILITY_INVALID_LENGTH     2
-#define BGP_NOTIFY_CAPABILITY_MALFORMED_CODE     3
+/* BGP_NOTIFY_ROUTE_REFRESH_ERR sub codes (RFC 7313). */
+#define BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN 1
+
+/* BGP route refresh optional subtypes. */
+#define BGP_ROUTE_REFRESH_NORMAL 0
+#define BGP_ROUTE_REFRESH_BORR 1
+#define BGP_ROUTE_REFRESH_EORR 2
 
 /* BGP timers default value.  */
 #define BGP_INIT_START_TIMER                     1
@@ -1852,8 +1872,8 @@ extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
 
 extern int bgp_config_write(struct vty *);
 
-extern void bgp_master_init(struct thread_master *master,
-                           const int buffer_size);
+extern void bgp_master_init(struct thread_master *master, const int buffer_size,
+                           struct list *addresses);
 
 extern void bgp_init(unsigned short instance);
 extern void bgp_pthreads_run(void);
index 60a7d505a764e5ee026750c88e5f655295597f50..8e7913419f2d982c77b1d7cfbe149da69fe58777 100644 (file)
@@ -18,4 +18,5 @@ FRRouting Developer's Guide
    ospf
    zebra
    vtysh
-   pathd
+   path
+   link-state
index 2f2444373c842d23378bdeccae0493a771a0812e..cf3aa8d17f0741cee84eb3a8fc3813b26f130c04 100644 (file)
@@ -83,7 +83,7 @@ Extensions
 +-----------+--------------------------+----------------------------------------------+
 | ``%pNHs`` | ``struct nexthop *``     | ``1.2.3.4 if 15``                            |
 +-----------+--------------------------+----------------------------------------------+
-| ``%pFX``  + ``struct bgp_dest *``    | ``fe80::1234/64`` available in BGP only      |
+| ``%pFX``  | ``struct bgp_dest *``    | ``fe80::1234/64`` (available in BGP only)    |
 +-----------+--------------------------+----------------------------------------------+
 
 Printf features like field lengths can be used normally with these extensions,
index f131ba89d9ace4e26988563138c318f483fc9795..0129be6bf1a2ad7a24dec2ae340dc43f14d14f7a 100644 (file)
@@ -33,6 +33,7 @@ dev_RSTFILES = \
        doc/developer/include-compile.rst \
        doc/developer/index.rst \
        doc/developer/library.rst \
+       doc/developer/link-state.rst \
        doc/developer/lists.rst \
        doc/developer/locking.rst \
        doc/developer/logging.rst \
@@ -52,6 +53,7 @@ dev_RSTFILES = \
        doc/developer/path.rst \
        doc/developer/rcu.rst \
        doc/developer/static-linking.rst \
+       doc/developer/tracing.rst \
        doc/developer/testing.rst \
        doc/developer/topotests-snippets.rst \
        doc/developer/topotests.rst \
index ee0a6be008d2d4e2ee7c5a54d05837200ff90e78..d54f6c7aaa8c9144ad8b05cd4f3ab07f66f1fc15 100644 (file)
@@ -57,7 +57,7 @@ run the target in non-forking mode (no ``-d``) and use LTTng as usual (refer to
 LTTng user manual). When using USDT probes with LTTng, follow the example in
 `this article
 <https://lttng.org/blog/2019/10/15/new-dynamic-user-space-tracing-in-lttng/>`_.
-To trace with dtrace or SystemTap, compile with :option:`--enable-usdt=yes` and
+To trace with dtrace or SystemTap, compile with `--enable-usdt=yes` and
 use your tracer as usual.
 
 To see available USDT probes::
index 4183ac6480c7a78d954aa4b959a8651c1d895ddb..861d87b998a62fc17ae16c66c911c62686b1e501 100644 (file)
@@ -1262,6 +1262,9 @@ When documented this way, CLI commands can be cross referenced with the
 This is very helpful for users who want to quickly remind themselves what a
 particular command does.
 
+When documenting a cli that has a ``no`` form, please do not include
+the ``no`` in the ``.. index::`` line.
+
 Configuration Snippets
 ^^^^^^^^^^^^^^^^^^^^^^
 
index 7bef7d19c8ba3a300238a41a65155de86c11764e..e609761e1c7071f30fb94fa57c0a4ae021cc3569 100644 (file)
@@ -31,12 +31,23 @@ be specified (:ref:`common-invocation-options`).
 
 .. option:: -l, --listenon
 
-   Specify a specific IP address for bgpd to listen on, rather than its default
+   Specify specific IP addresses for bgpd to listen on, rather than its default
    of ``0.0.0.0`` / ``::``. This can be useful to constrain bgpd to an internal
-   address, or to run multiple bgpd processes on one host.
+   address, or to run multiple bgpd processes on one host. Multiple addresses
+   can be specified.
+
+   In the following example, bgpd is started listening for connections on the
+   addresses 100.0.1.2 and fd00::2:2. The options -d (runs in daemon mode) and
+   -f (uses specific configuration file) are also used in this example as we
+   are likely to run multiple bgpd instances, each one with different
+   configurations, when using -l option.
 
    Note that this option implies the --no_kernel option, and no learned routes will be installed into the linux kernel.
 
+.. code-block:: shell
+
+   # /usr/lib/frr/bgpd -d -f /some-folder/bgpd.conf -l 100.0.1.2 -l fd00::2:2
+
 .. option:: -n, --no_kernel
 
    Do not install learned routes into the linux kernel.  This option is useful
@@ -457,7 +468,7 @@ Reject routes with AS_SET or AS_CONFED_SET types
 Suppress duplicate updates
 --------------------------
 
-.. index:: [no] bgp suppress-duplicates
+.. index:: bgp suppress-duplicates
 .. clicmd:: [no] bgp suppress-duplicates
 
    For example, BGP routers can generate multiple identical announcements with
@@ -480,28 +491,57 @@ Disable checking if nexthop is connected on EBGP sessions
 Route Flap Dampening
 --------------------
 
-.. clicmd:: bgp dampening (1-45) (1-20000) (1-20000) (1-255)
+.. index:: [no] bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+.. clicmd:: [no] bgp 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 of a BGP instance.
+
+.. index:: [no] neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+.. clicmd:: [no] 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.
+
+.. index:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
+.. clicmd:: [no] neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (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 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
 
@@ -894,6 +934,19 @@ However, it MUST defer route selection for an address family until it either.
 
    This is command, will set the time for which stale routes are kept in RIB.
 
+.. index:: bgp graceful-restart stalepath-time (1-4095)
+.. 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-per-peer-graceful-restart:
 
 BGP Per Peer Graceful Restart
@@ -1639,7 +1692,7 @@ Configuring Peers
    peer in question.  This number is between 0 and 600 seconds,
    with the default advertisement interval being 0.
 
-.. index:: [no] neighbor PEER timers delayopen (1-240)
+.. index:: neighbor PEER timers delayopen (1-240)
 .. clicmd:: [no] neighbor PEER timers delayopen (1-240)
 
    This command allows the user enable the
@@ -3539,7 +3592,7 @@ starting the daemon and the configuration gets saved, the option will persist
 unless removed from the configuration with the negating command prior to the
 configuration write operation.
 
-.. index:: [no] bgp send-extra-data zebra
+.. index:: bgp send-extra-data zebra
 .. clicmd:: [no] bgp send-extra-data zebra
 
 This Command turns off the ability of BGP to send extra data to zebra.
index f991e3f07397e2cd6f72057494d043af1609eb94..7e198564b5022342892a5a93c0e931fc8ad52706 100644 (file)
@@ -204,6 +204,12 @@ ISIS Fast-Reroute
 
    Disable load sharing across multiple LFA backups.
 
+.. index:: fast-reroute remote-lfa prefix-list WORD [level-1 | level-2]
+.. clicmd:: [no] fast-reroute remote-lfa prefix-list [WORD] [level-1 | level-2]
+
+   Configure a prefix-list to select eligible PQ nodes (valid for all protected
+   interfaces).
+
 .. _isis-region:
 
 ISIS region
@@ -400,6 +406,18 @@ ISIS interface
 
    Enable per-prefix TI-LFA fast reroute link or node protection.
 
+.. index:: isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2]
+.. clicmd:: [no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1 | level-2]
+
+   Enable per-prefix Remote LFA fast reroute link protection. Note that other
+   routers in the network need to be configured to accept LDP targeted hello
+   messages in order for RLFA to work.
+
+.. index:: isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2]
+.. clicmd:: [no] isis fast-reroute remote-lfa maximum-metric (1-16777215) [level-1 | level-2]
+
+   Limit Remote LFA PQ node selection within the specified metric.
+
 .. _showing-isis-information:
 
 Showing ISIS information
index a2ce67068f6d87896f8fbbdfb4bdcc60c3619990..f67698e4046efe535d2f9d845d37a09f7be1a298 100644 (file)
@@ -321,6 +321,8 @@ BGP
   :t:`The Resource Public Key Infrastructure (RPKI) to Router Protocol. R. Bush, R. Austein. January 2013.`
 - :rfc:`6811`
   :t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.`
+- :rfc:`7313`
+  :t:`Enhanced Route Refresh Capability for BGP-4. K. Patel, E. Chen, B. Venkatachalapathy. July 2014.`
 - :rfc:`7606`
   :t:`Revised Error Handling for BGP UPDATE Messages. E. Chen, J. Scudder, P. Mohapatra, K. Patel. August 2015.`
 - :rfc:`7607`
index 5e210e2489f25b8131478b5060c6cf5700fb9388..0815a6c41486224a8adeb4ca27c301d1ca76a551 100644 (file)
@@ -115,19 +115,19 @@ Configuration Commands
 
    Configure segment routing traffic engineering.
 
-.. index:: [no] segment-list NAME
+.. index:: segment-list NAME
 .. clicmd:: [no] segment-list NAME
 
    Delete or start a segment list definition.
 
 
-.. index:: [no] index INDEX mpls label LABEL [nai node ADDRESS]
+.. index:: index INDEX mpls label LABEL [nai node ADDRESS]
 .. clicmd:: [no] index INDEX mpls label LABEL [nai node ADDRESS]
 
    Delete or specify a segment in a segment list definition.
 
 
-.. index:: [no] policy color COLOR endpoint ENDPOINT
+.. index:: policy color COLOR endpoint ENDPOINT
 .. clicmd:: [no] policy color COLOR endpoint ENDPOINT
 
    Delete or start a policy definition.
@@ -145,31 +145,31 @@ Configuration Commands
    Specify the policy SID.
 
 
-.. index:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
+.. index:: candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
 .. clicmd:: [no] candidate-path preference PREFERENCE name NAME explicit segment-list SEGMENT-LIST-NAME
 
    Delete or define an explicit candidate path.
 
 
-.. index:: [no] candidate-path preference PREFERENCE name NAME dynamic
+.. index:: candidate-path preference PREFERENCE name NAME dynamic
 .. clicmd:: [no] candidate-path preference PREFERENCE name NAME dynamic
 
    Delete or start a dynamic candidate path definition.
 
 
-.. index:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN
+.. index:: affinity {exclude-any|include-any|include-all} BITPATTERN
 .. clicmd:: [no] affinity {exclude-any|include-any|include-all} BITPATTERN
 
    Delete or specify an affinity constraint for a dynamic candidate path.
 
 
-.. index:: [no] bandwidth BANDWIDTH [required]
+.. index:: bandwidth BANDWIDTH [required]
 .. clicmd:: [no] bandwidth BANDWIDTH [required]
 
    Delete or specify a bandwidth constraint for a dynamic candidate path.
 
 
-.. index:: [no] metric [bound] METRIC VALUE [required]
+.. index:: metric [bound] METRIC VALUE [required]
 .. clicmd:: [no] metric [bound] METRIC VALUE [required]
 
    Delete or specify a metric constraint for a dynamic candidate path.
@@ -198,7 +198,7 @@ Configuration Commands
     - bnc: Border Node Count metric
 
 
-.. index:: [no] objective-function OBJFUN1 [required]
+.. index:: objective-function OBJFUN1 [required]
 .. clicmd:: [no] objective-function OBJFUN1 [required]
 
    Delete or specify a PCEP objective function constraint for a dynamic
@@ -224,7 +224,7 @@ Configuration Commands
      - msn: Minimize the number of Shared Nodes [RFC8800]
 
 
-.. index:: [no] debug pathd pcep [basic|path|message|pceplib]
+.. index:: debug pathd pcep [basic|path|message|pceplib]
 .. clicmd:: [no] debug pathd pcep [basic|path|message|pceplib]
 
    Enable or disable debugging for the pcep module:
@@ -241,14 +241,14 @@ Configuration Commands
    Configure PCEP support.
 
 
-.. index:: [no] cep-config NAME
+.. index:: cep-config NAME
 .. clicmd:: [no] pce-config NAME
 
    Define a shared PCE configuration that can be used in multiple PCE
    declarations.
 
 
-.. index:: [no] pce NAME
+.. index:: pce NAME
 .. clicmd:: [no] pce NAME
 
    Define or delete a PCE definition.
@@ -321,7 +321,7 @@ Configuration Commands
    configuration group.
 
 
-.. index:: [no] pcc
+.. index:: pcc
 .. clicmd:: [no] pcc
 
    Disable or start the definition of a PCC.
@@ -333,7 +333,7 @@ Configuration Commands
    Specify the maximum SID depth in a PCC definition.
 
 
-.. index:: [no] peer WORD [precedence (1-255)]
+.. index:: peer WORD [precedence (1-255)]
 .. clicmd:: [no] peer WORD [precedence (1-255)]
 
    Specify a peer and its precedence in a PCC definition.
index 3610b3a869803dae2a9c84ed44ab538a13738d2d..00d8ea8867284b2161c7bb618557e32fd2dff7ce 100644 (file)
@@ -29,6 +29,7 @@
 #include "eigrp_structs.h"
 #include "eigrpd.h"
 #include "eigrp_zebra.h"
+#include "eigrp_cli.h"
 
 #ifndef VTYSH_EXTRACT_PL
 #include "eigrpd/eigrp_cli_clippy.c"
diff --git a/eigrpd/eigrp_cli.h b/eigrpd/eigrp_cli.h
new file mode 100644 (file)
index 0000000..c5f2fd8
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * EIGRP CLI Functions.
+ * Copyright (C) 2019
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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
+ */
+
+#ifndef _EIGRP_CLI_H_
+#define _EIGRP_CLI_H_
+
+/*Prototypes*/
+extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
+                                 bool show_defaults);
+extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
+extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void eigrp_cli_show_passive_interface(struct vty *vty,
+                                            struct lyd_node *dnode,
+                                            bool show_defaults);
+extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
+                                      bool show_defaults);
+extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void eigrp_cli_show_maximum_paths(struct vty *vty,
+                                        struct lyd_node *dnode,
+                                        bool show_defaults);
+extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
+                                  bool show_defaults);
+extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
+                                  bool show_defaults);
+extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
+extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults);
+extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void eigrp_cli_show_hello_interval(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults);
+extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
+                                    bool show_defaults);
+extern void eigrp_cli_show_summarize_address(struct vty *vty,
+                                            struct lyd_node *dnode,
+                                            bool show_defaults);
+extern void eigrp_cli_show_authentication(struct vty *vty,
+                                         struct lyd_node *dnode,
+                                         bool show_defaults);
+extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
+                                   bool show_defaults);
+extern void eigrp_cli_init(void);
+
+#endif /*EIGRP_CLI_H_ */
index d3d9bca82aed1b03467316090ffe1ff5a918d4b0..149cf00efca772c4a0187f44c56904128c98a5d9 100644 (file)
@@ -122,10 +122,10 @@ enum metric_change { METRIC_DECREASE, METRIC_SAME, METRIC_INCREASE };
 #define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL     2 // Remote external network
 
 /*EIGRP TT entry flags*/
-#define EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG     (1 << 0)
-#define EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG    (1 << 1)
-#define EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG       (1 << 2)
-#define EIGRP_NEXTHOP_ENTRY_EXTERNAL_FLAG      (1 << 3)
+#define EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG (1 << 0)
+#define EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG (1 << 1)
+#define EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG (1 << 2)
+#define EIGRP_ROUTE_DESCRIPTOR_EXTERNAL_FLAG (1 << 3)
 
 /*EIGRP FSM state count, event count*/
 #define EIGRP_FSM_STATE_MAX                  5
index dfce2acad4885ed7462f447222a42a2bc4a7cbc5..e1ad51a9dbb1f7d4350accd2788e75a4310e8601 100644 (file)
@@ -236,7 +236,8 @@ void show_ip_eigrp_topology_header(struct vty *vty, struct eigrp *eigrp)
                "Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply\n       r - reply Status, s - sia Status\n\n");
 }
 
-void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
+void show_ip_eigrp_prefix_descriptor(struct vty *vty,
+                                    struct eigrp_prefix_descriptor *tn)
 {
        struct list *successors = eigrp_topology_get_successor(tn);
 
@@ -251,14 +252,15 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
                list_delete(&successors);
 }
 
-void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
-                                struct eigrp_nexthop_entry *te, bool *first)
+void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp,
+                                   struct eigrp_route_descriptor *te,
+                                   bool *first)
 {
        if (te->reported_distance == EIGRP_MAX_METRIC)
                return;
 
        if (*first) {
-               show_ip_eigrp_prefix_entry(vty, te->prefix);
+               show_ip_eigrp_prefix_descriptor(vty, te->prefix);
                *first = false;
        }
 
index 348356bb3c74bff2fa7939acdbd97f581bbdfefc..0d512fc63fdd1b1fd7b9acfcb979adc8b7592f08 100644 (file)
@@ -151,11 +151,11 @@ extern void show_ip_eigrp_interface_sub(struct vty *, struct eigrp *,
                                        struct eigrp_interface *);
 extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *,
                                       int);
-extern void show_ip_eigrp_prefix_entry(struct vty *,
-                                      struct eigrp_prefix_entry *);
-extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
-                                       struct eigrp_nexthop_entry *ne,
-                                       bool *first);
+extern void show_ip_eigrp_prefix_descriptor(struct vty *vty,
+                                           struct eigrp_prefix_descriptor *tn);
+extern void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp,
+                                          struct eigrp_route_descriptor *ne,
+                                          bool *first);
 
 extern void eigrp_debug_init(void);
 
index a69a3eec0a214535e098f70cf209f0f5359182d4..d2d435bf2d5d8cba6e128fab48e21683bf1b8773 100644 (file)
@@ -77,6 +77,7 @@
 #include "linklist.h"
 #include "vty.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
@@ -88,6 +89,7 @@
 #include "eigrpd/eigrp_dump.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_metric.h"
 
 /*
  * Prototypes
@@ -262,13 +264,13 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 {
        // Loading base information from message
        // struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *entry = msg->entry;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *entry = msg->entry;
        uint8_t actual_state = prefix->state;
        enum metric_change change;
 
        if (entry == NULL) {
-               entry = eigrp_nexthop_entry_new();
+               entry = eigrp_route_descriptor_new();
                entry->adv_router = msg->adv_router;
                entry->ei = msg->adv_router->ei;
                entry->prefix = prefix;
@@ -286,7 +288,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 
        switch (actual_state) {
        case EIGRP_FSM_STATE_PASSIVE: {
-               struct eigrp_nexthop_entry *head =
+               struct eigrp_route_descriptor *head =
                        listnode_head(prefix->entries);
 
                if (head->reported_distance < prefix->fdistance) {
@@ -307,7 +309,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
        }
        case EIGRP_FSM_STATE_ACTIVE_0: {
                if (msg->packet_type == EIGRP_OPC_REPLY) {
-                       struct eigrp_nexthop_entry *head =
+                       struct eigrp_route_descriptor *head =
                                listnode_head(prefix->entries);
 
                        listnode_delete(prefix->rij, entry->adv_router);
@@ -322,7 +324,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                        return EIGRP_FSM_EVENT_LR_FCN;
                } else if (msg->packet_type == EIGRP_OPC_QUERY
                           && (entry->flags
-                              & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                              & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_QACT;
                }
 
@@ -332,14 +334,14 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
        }
        case EIGRP_FSM_STATE_ACTIVE_1: {
                if (msg->packet_type == EIGRP_OPC_QUERY
-                   && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                   && (entry->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_QACT;
                } else if (msg->packet_type == EIGRP_OPC_REPLY) {
                        listnode_delete(prefix->rij, entry->adv_router);
 
                        if (change == METRIC_INCREASE
                            && (entry->flags
-                               & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                               & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                                return EIGRP_FSM_EVENT_DINC;
                        } else if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
@@ -350,7 +352,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                } else if (msg->packet_type == EIGRP_OPC_UPDATE
                           && change == METRIC_INCREASE
                           && (entry->flags
-                              & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                              & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_DINC;
                }
                return EIGRP_FSM_KEEP_STATE;
@@ -359,7 +361,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
        }
        case EIGRP_FSM_STATE_ACTIVE_2: {
                if (msg->packet_type == EIGRP_OPC_REPLY) {
-                       struct eigrp_nexthop_entry *head =
+                       struct eigrp_route_descriptor *head =
                                listnode_head(prefix->entries);
 
                        listnode_delete(prefix->rij, entry->adv_router);
@@ -385,7 +387,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 
                        if (change == METRIC_INCREASE
                            && (entry->flags
-                               & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                               & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                                return EIGRP_FSM_EVENT_DINC;
                        } else if (prefix->rij->count) {
                                return EIGRP_FSM_KEEP_STATE;
@@ -396,7 +398,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
                } else if (msg->packet_type == EIGRP_OPC_UPDATE
                           && change == METRIC_INCREASE
                           && (entry->flags
-                              & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+                              & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
                        return EIGRP_FSM_EVENT_DINC;
                }
                return EIGRP_FSM_KEEP_STATE;
@@ -434,9 +436,9 @@ int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
        struct list *successors = eigrp_topology_get_successor(prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // If this is NULL we have shit the bed, fun huh?
 
@@ -461,9 +463,9 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
        struct list *successors = eigrp_topology_get_successor(prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // If this is NULL somebody poked us in the eye.
 
@@ -487,8 +489,8 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 
        if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
                if (!eigrp_metrics_is_same(prefix->reported_metric,
@@ -515,8 +517,8 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 
        prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance;
        prefix->reported_metric = ne->total_metric;
@@ -545,7 +547,7 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
 {
        struct list *successors = eigrp_topology_get_successor(msg->prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // Trump and his big hands
 
@@ -566,8 +568,8 @@ int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 
        prefix->state = EIGRP_FSM_STATE_PASSIVE;
        prefix->distance = prefix->rdistance = ne->distance;
@@ -598,8 +600,8 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *best_successor;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *best_successor;
        struct list *successors = eigrp_topology_get_successor(prefix);
 
        assert(successors); // Routing without a stack
@@ -628,7 +630,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
 int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
 {
        struct list *successors = eigrp_topology_get_successor(msg->prefix);
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
 
        assert(successors); // Cats and no Dogs
 
index dd43dd047857612d88b2f5e5b749557309dcfa46..74eff958da6b7591d822bd1e143095bf227a1f5d 100644 (file)
@@ -55,6 +55,8 @@
 #include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_types.h"
+#include "eigrpd/eigrp_metric.h"
 
 struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
                                     struct prefix *p)
@@ -229,8 +231,8 @@ void eigrp_del_if_params(struct eigrp_if_params *eip)
 
 int eigrp_if_up(struct eigrp_interface *ei)
 {
-       struct eigrp_prefix_entry *pe;
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_prefix_descriptor *pe;
+       struct eigrp_route_descriptor *ne;
        struct eigrp_metrics metric;
        struct eigrp_interface *ei2;
        struct listnode *node, *nnode;
@@ -263,14 +265,14 @@ int eigrp_if_up(struct eigrp_interface *ei)
 
        /*Add connected entry to topology table*/
 
-       ne = eigrp_nexthop_entry_new();
+       ne = eigrp_route_descriptor_new();
        ne->ei = ei;
        ne->reported_metric = metric;
        ne->total_metric = metric;
        ne->distance = eigrp_calculate_metrics(eigrp, metric);
        ne->reported_distance = 0;
        ne->adv_router = eigrp->neighbor_self;
-       ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+       ne->flags = EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
 
        struct prefix dest_addr;
 
@@ -280,7 +282,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
                                              &dest_addr);
 
        if (pe == NULL) {
-               pe = eigrp_prefix_entry_new();
+               pe = eigrp_prefix_descriptor_new();
                pe->serno = eigrp->serno;
                pe->destination = (struct prefix *)prefix_ipv4_new();
                prefix_copy(pe->destination, &dest_addr);
@@ -292,10 +294,10 @@ int eigrp_if_up(struct eigrp_interface *ei)
                pe->state = EIGRP_FSM_STATE_PASSIVE;
                pe->fdistance = eigrp_calculate_metrics(eigrp, metric);
                pe->req_action |= EIGRP_FSM_NEED_UPDATE;
-               eigrp_prefix_entry_add(eigrp->topology_table, pe);
+               eigrp_prefix_descriptor_add(eigrp->topology_table, pe);
                listnode_add(eigrp->topology_changes_internalIPV4, pe);
 
-               eigrp_nexthop_entry_add(eigrp, pe, ne);
+               eigrp_route_descriptor_add(eigrp, pe, ne);
 
                for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) {
                        eigrp_update_send(ei2);
@@ -307,7 +309,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
                struct eigrp_fsm_action_message msg;
 
                ne->prefix = pe;
-               eigrp_nexthop_entry_add(eigrp, pe, ne);
+               eigrp_route_descriptor_add(eigrp, pe, ne);
 
                msg.packet_type = EIGRP_OPC_UPDATE;
                msg.eigrp = eigrp;
@@ -416,7 +418,7 @@ uint8_t eigrp_default_iftype(struct interface *ifp)
 void eigrp_if_free(struct eigrp_interface *ei, int source)
 {
        struct prefix dest_addr;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct eigrp *eigrp = ei->eigrp;
 
        if (source == INTERFACE_DOWN_BY_VTY) {
@@ -429,7 +431,8 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
        pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
                                              &dest_addr);
        if (pe)
-               eigrp_prefix_entry_delete(eigrp, eigrp->topology_table, pe);
+               eigrp_prefix_descriptor_delete(eigrp, eigrp->topology_table,
+                                              pe);
 
        eigrp_if_down(ei);
 
@@ -494,33 +497,3 @@ struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *eigrp,
 
        return NULL;
 }
-
-uint32_t eigrp_bandwidth_to_scaled(uint32_t bandwidth)
-{
-       uint64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
-
-       temp_bandwidth = temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth
-                                                          : EIGRP_MAX_METRIC;
-
-       return (uint32_t)temp_bandwidth;
-}
-
-uint32_t eigrp_scaled_to_bandwidth(uint32_t scaled)
-{
-       uint64_t temp_scaled = scaled * (256ull * 10000000);
-
-       temp_scaled =
-               temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
-
-       return (uint32_t)temp_scaled;
-}
-
-uint32_t eigrp_delay_to_scaled(uint32_t delay)
-{
-       return delay * 256;
-}
-
-uint32_t eigrp_scaled_to_delay(uint32_t scaled)
-{
-       return scaled / 256;
-}
index 1e66dafde254595c54f7e1e6b1409b31882a7a85..68ab5125e3e587d18b7808c7331ca2cfb1efb522 100644 (file)
@@ -58,9 +58,4 @@ extern struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *,
 /* Simulate down/up on the interface. */
 extern void eigrp_if_reset(struct interface *);
 
-extern uint32_t eigrp_bandwidth_to_scaled(uint32_t);
-extern uint32_t eigrp_scaled_to_bandwidth(uint32_t);
-extern uint32_t eigrp_delay_to_scaled(uint32_t);
-extern uint32_t eigrp_scaled_to_delay(uint32_t);
-
 #endif /* ZEBRA_EIGRP_INTERFACE_H_ */
index 6c44ce361c7e51bae2805cefabf3ddcea83a5890..b1a6498cbcb189dc43ddf8e7b47e250e07b3d188 100644 (file)
@@ -66,6 +66,8 @@
 #include "eigrpd/eigrp_filter.h"
 #include "eigrpd/eigrp_errors.h"
 #include "eigrpd/eigrp_vrf.h"
+#include "eigrpd/eigrp_cli.h"
+#include "eigrpd/eigrp_yang.h"
 //#include "eigrpd/eigrp_routemap.h"
 
 /* eigprd privileges */
index 85b14c28cec402b7a4c465f07362dfa1b5985940..57ca785340d63cc5108c9fd4a9e1d867fc0dec87 100644 (file)
@@ -37,6 +37,6 @@ DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV")
 DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV")
 DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV")
 DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix")
-DEFINE_MTYPE(EIGRPD, EIGRP_NEXTHOP_ENTRY, "EIGRP Nexthop Entry")
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix")
+DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry")
 DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message")
index e4d02c09d490926d7e16420e54ca6764c97aa51c..21ecba2aaed00c8f8c23d75db91635fe34973ca8 100644 (file)
@@ -36,8 +36,8 @@ DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
 DECLARE_MTYPE(EIGRP_SEQ_TLV)
 DECLARE_MTYPE(EIGRP_AUTH_TLV)
 DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
-DECLARE_MTYPE(EIGRP_PREFIX_ENTRY)
-DECLARE_MTYPE(EIGRP_NEXTHOP_ENTRY)
+DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR)
+DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR)
 DECLARE_MTYPE(EIGRP_FSM_MSG)
 
 #endif /* _FRR_EIGRP_MEMORY_H */
diff --git a/eigrpd/eigrp_metric.c b/eigrpd/eigrp_metric.c
new file mode 100644 (file)
index 0000000..2b05db7
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * EIGRP Metric Math Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra 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 "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_types.h"
+#include "eigrpd/eigrp_metric.h"
+
+eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bandwidth)
+{
+       eigrp_bandwidth_t scaled = EIGRP_BANDWIDTH_MAX;
+
+       if (bandwidth != EIGRP_BANDWIDTH_MAX) {
+               scaled = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER);
+               scaled = scaled / bandwidth;
+
+               scaled = scaled ? scaled : EIGRP_BANDWIDTH_MIN;
+       }
+
+       scaled = (scaled < EIGRP_METRIC_MAX) ? scaled : EIGRP_METRIC_MAX;
+       return (eigrp_scaled_t)scaled;
+}
+
+eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scaled)
+{
+       eigrp_bandwidth_t bandwidth = EIGRP_BANDWIDTH_MAX;
+
+       if (scaled != EIGRP_CLASSIC_MAX) {
+               bandwidth = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER);
+               bandwidth = scaled * bandwidth;
+               bandwidth = (bandwidth < EIGRP_METRIC_MAX)
+                                   ? bandwidth
+                                   : EIGRP_BANDWIDTH_MAX;
+       }
+
+       return bandwidth;
+}
+
+eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay)
+{
+       delay = delay ? delay : EIGRP_DELAY_MIN;
+       return delay * EIGRP_CLASSIC_SCALER;
+}
+
+eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scaled)
+{
+       scaled = scaled / EIGRP_CLASSIC_SCALER;
+       scaled = scaled ? scaled : EIGRP_DELAY_MIN;
+
+       return scaled;
+}
+
+eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp,
+                                      struct eigrp_metrics metric)
+{
+       eigrp_metric_t composite = 0;
+
+       if (metric.delay == EIGRP_MAX_METRIC)
+               return EIGRP_METRIC_MAX;
+
+       /*
+        * EIGRP Composite =
+        * {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
+        */
+
+       if (eigrp->k_values[0])
+               composite += (eigrp->k_values[0] * metric.bandwidth);
+       if (eigrp->k_values[1])
+               composite += ((eigrp->k_values[1] * metric.bandwidth)
+                             / (256 - metric.load));
+       if (eigrp->k_values[2])
+               composite += (eigrp->k_values[2] * metric.delay);
+       if (eigrp->k_values[3] && !eigrp->k_values[4])
+               composite *= eigrp->k_values[3];
+       if (!eigrp->k_values[3] && eigrp->k_values[4])
+               composite *= (eigrp->k_values[4] / metric.reliability);
+       if (eigrp->k_values[3] && eigrp->k_values[4])
+               composite *= ((eigrp->k_values[4] / metric.reliability)
+                             + eigrp->k_values[3]);
+
+       composite =
+               (composite <= EIGRP_METRIC_MAX) ? composite : EIGRP_METRIC_MAX;
+
+       return composite;
+}
+
+eigrp_metric_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+                             struct eigrp_route_descriptor *entry)
+{
+       struct eigrp_interface *ei = entry->ei;
+       eigrp_delay_t temp_delay;
+       eigrp_bandwidth_t bw;
+
+       entry->total_metric = entry->reported_metric;
+       temp_delay = entry->total_metric.delay
+                    + eigrp_delay_to_scaled(ei->params.delay);
+
+       entry->total_metric.delay = temp_delay > EIGRP_METRIC_MAX_CLASSIC
+                                           ? EIGRP_METRIC_MAX_CLASSIC
+                                           : temp_delay;
+
+       bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
+       entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
+                                               ? bw
+                                               : entry->total_metric.bandwidth;
+
+       return eigrp_calculate_metrics(eigrp, entry->total_metric);
+}
+
+bool eigrp_metrics_is_same(struct eigrp_metrics metric1,
+                          struct eigrp_metrics metric2)
+{
+       if ((metric1.bandwidth == metric2.bandwidth)
+           && (metric1.delay == metric2.delay)
+           && (metric1.hop_count == metric2.hop_count)
+           && (metric1.load == metric2.load)
+           && (metric1.reliability == metric2.reliability)
+           && (metric1.mtu[0] == metric2.mtu[0])
+           && (metric1.mtu[1] == metric2.mtu[1])
+           && (metric1.mtu[2] == metric2.mtu[2])) {
+               return true;
+       }
+
+       return false; /* if different */
+}
diff --git a/eigrpd/eigrp_metric.h b/eigrpd/eigrp_metric.h
new file mode 100644 (file)
index 0000000..8e9cd66
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * EIGRP Metric Math Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra 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, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra 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
+ */
+
+#ifndef _ZEBRA_EIGRP_METRIC_H_
+#define _ZEBRA_EIGRP_METRIC_H_
+
+/* Constants */
+#define EIGRP_BANDWIDTH_MIN 0x1ull               /* 1 */
+#define EIGRP_BANDWIDTH_SCALER 10000000ull       /* Inversion value */
+#define EIGRP_BANDWIDTH_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+
+#define EIGRP_DELAY_MIN 0x1ull /* 1 */
+#define EIGRP_DELAY_PICO 1000000ull
+#define EIGRP_DELAY_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+
+#define EIGRP_MAX_LOAD 256
+#define EIGRP_MAX_HOPS 100
+
+#define EIGRP_INACCESSIBLE 0xFFFFFFFFFFFFFFFFull
+
+#define EIGRP_METRIC_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+#define EIGRP_METRIC_MAX_CLASSIC 0xffffffff
+#define EIGRP_METRIC_SCALER 65536             /* CLASSIC to WIDE conversion */
+
+#define EIGRP_CLASSIC_MAX 0xffffffff /* 4294967295 */
+#define EIGRP_CLASSIC_SCALER 256     /* IGRP to EIGRP conversion */
+
+
+/* Prototypes */
+extern eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bw);
+extern eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scale);
+extern eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay);
+extern eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scale);
+
+extern eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp,
+                                             struct eigrp_metrics metric);
+extern eigrp_metric_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+                             struct eigrp_route_descriptor *rd);
+extern bool eigrp_metrics_is_same(struct eigrp_metrics m1,
+                                 struct eigrp_metrics m2);
+
+#endif /* _ZEBRA_EIGRP_METRIC_H_ */
index 2d5bb0a7d13e9969ff089abf2f0ead200086931e..1da2f7a10826df43036ec544552d852ce1591ee2 100644 (file)
@@ -343,7 +343,7 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
        eigrp_nbr_delete(nbr);
 }
 
-int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
+int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
                                  struct eigrp_interface *ei)
 {
        if (ne->distance == EIGRP_MAX_METRIC)
index 1c308fa981d69de5f53471b371063f827ec7dd12..80ab1eded51af5d88e1e3576250527252b45ae8e 100644 (file)
@@ -54,6 +54,6 @@ extern struct eigrp_neighbor *
 eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp, struct in_addr addr);
 extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
 
-extern int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
+extern int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
                                         struct eigrp_interface *ei);
 #endif /* _ZEBRA_EIGRP_NEIGHBOR_H */
index 51b499895946a504f2ae76f8f3ef319ebbeea10c..69dcc2025394af0efbf54910b2c2f053fe389b63 100644 (file)
@@ -346,76 +346,6 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
        return 1;
 }
 
-uint32_t eigrp_calculate_metrics(struct eigrp *eigrp,
-                                struct eigrp_metrics metric)
-{
-       uint64_t temp_metric;
-       temp_metric = 0;
-
-       if (metric.delay == EIGRP_MAX_METRIC)
-               return EIGRP_MAX_METRIC;
-
-       // EIGRP Metric =
-       // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
-
-       if (eigrp->k_values[0])
-               temp_metric += (eigrp->k_values[0] * metric.bandwidth);
-       if (eigrp->k_values[1])
-               temp_metric += ((eigrp->k_values[1] * metric.bandwidth)
-                               / (256 - metric.load));
-       if (eigrp->k_values[2])
-               temp_metric += (eigrp->k_values[2] * metric.delay);
-       if (eigrp->k_values[3] && !eigrp->k_values[4])
-               temp_metric *= eigrp->k_values[3];
-       if (!eigrp->k_values[3] && eigrp->k_values[4])
-               temp_metric *= (eigrp->k_values[4] / metric.reliability);
-       if (eigrp->k_values[3] && eigrp->k_values[4])
-               temp_metric *= ((eigrp->k_values[4] / metric.reliability)
-                               + eigrp->k_values[3]);
-
-       if (temp_metric <= EIGRP_MAX_METRIC)
-               return (uint32_t)temp_metric;
-       else
-               return EIGRP_MAX_METRIC;
-}
-
-uint32_t eigrp_calculate_total_metrics(struct eigrp *eigrp,
-                                      struct eigrp_nexthop_entry *entry)
-{
-       struct eigrp_interface *ei = entry->ei;
-
-       entry->total_metric = entry->reported_metric;
-       uint64_t temp_delay =
-               (uint64_t)entry->total_metric.delay
-               + (uint64_t)eigrp_delay_to_scaled(ei->params.delay);
-       entry->total_metric.delay = temp_delay > EIGRP_MAX_METRIC
-                                           ? EIGRP_MAX_METRIC
-                                           : (uint32_t)temp_delay;
-
-       uint32_t bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
-       entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
-                                               ? bw
-                                               : entry->total_metric.bandwidth;
-
-       return eigrp_calculate_metrics(eigrp, entry->total_metric);
-}
-
-uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1,
-                             struct eigrp_metrics metric2)
-{
-       if ((metric1.bandwidth == metric2.bandwidth)
-           && (metric1.delay == metric2.delay)
-           && (metric1.hop_count == metric2.hop_count)
-           && (metric1.load == metric2.load)
-           && (metric1.reliability == metric2.reliability)
-           && (metric1.mtu[0] == metric2.mtu[0])
-           && (metric1.mtu[1] == metric2.mtu[1])
-           && (metric1.mtu[2] == metric2.mtu[2]))
-               return 1;
-
-       return 0; // if different
-}
-
 void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
 {
 }
index 7839fc946b5e6fd398ed34e0d747c2142986a4db..eeb32ba3564145536c936f987b2d4e773aef5a2b 100644 (file)
@@ -43,11 +43,6 @@ extern int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
                                       unsigned int ifindex);
 extern void eigrp_adjust_sndbuflen(struct eigrp *, unsigned int);
 
-extern uint32_t eigrp_calculate_metrics(struct eigrp *, struct eigrp_metrics);
-extern uint32_t eigrp_calculate_total_metrics(struct eigrp *,
-                                             struct eigrp_nexthop_entry *);
-extern uint8_t eigrp_metrics_is_same(struct eigrp_metrics,
-                                    struct eigrp_metrics);
 extern void eigrp_external_routes_refresh(struct eigrp *, int);
 
 #endif /* EIGRP_NETWORK_H_ */
index 5b87f7264016c37d382c4a6cb328a12d4f69e5c1..482667f633c214effffed11e30b9b4cc6d382e40 100644 (file)
@@ -34,6 +34,7 @@
 #include "eigrp_interface.h"
 #include "eigrp_network.h"
 #include "eigrp_zebra.h"
+#include "eigrp_cli.h"
 
 /* Helper functions. */
 static void redistribute_get_metrics(const struct lyd_node *dnode,
index f5f6ab5dffe55bdcfc394e0513b4bb7340bdda0a..252cd647a2b5804d8ba7d3e2af7d7a1d4019593d 100644 (file)
@@ -1144,7 +1144,7 @@ struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
 }
 
 uint16_t eigrp_add_internalTLV_to_stream(struct stream *s,
-                                        struct eigrp_prefix_entry *pe)
+                                        struct eigrp_prefix_descriptor *pe)
 {
        uint16_t length;
 
index f354615fdb5f94cdd9ad91ab80307b6a575b4fe3..cb69bc26b294f5d0080afa311bfc6b261a1b100d 100644 (file)
 extern int eigrp_read(struct thread *);
 extern int eigrp_write(struct thread *);
 
-extern struct eigrp_packet *eigrp_packet_new(size_t, struct eigrp_neighbor *);
-extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *,
-                                                  struct eigrp_neighbor *);
-extern void eigrp_packet_free(struct eigrp_packet *);
-extern void eigrp_packet_delete(struct eigrp_interface *);
-extern void eigrp_packet_header_init(int, struct eigrp *, struct stream *,
-                                    uint32_t, uint32_t, uint32_t);
-extern void eigrp_packet_checksum(struct eigrp_interface *, struct stream *,
-                                 uint16_t);
+extern struct eigrp_packet *eigrp_packet_new(size_t size,
+                                            struct eigrp_neighbor *nbr);
+extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
+                                                  struct eigrp_neighbor *nbr);
+extern void eigrp_packet_free(struct eigrp_packet *ep);
+extern void eigrp_packet_delete(struct eigrp_interface *ei);
+extern void eigrp_packet_header_init(int type, struct eigrp *eigrp,
+                                    struct stream *s, uint32_t flags,
+                                    uint32_t sequence, uint32_t ack);
+extern void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s,
+                                 uint16_t length);
 
 extern struct eigrp_fifo *eigrp_fifo_new(void);
-extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *);
-extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *);
-extern void eigrp_fifo_push(struct eigrp_fifo *, struct eigrp_packet *);
-extern void eigrp_fifo_free(struct eigrp_fifo *);
-extern void eigrp_fifo_reset(struct eigrp_fifo *);
-
-extern void eigrp_send_packet_reliably(struct eigrp_neighbor *);
-
-extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *);
-extern uint16_t eigrp_add_internalTLV_to_stream(struct stream *,
-                                               struct eigrp_prefix_entry *);
-extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *,
-                                               struct eigrp_interface *);
-extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *,
-                                                  struct eigrp_interface *);
-
-extern int eigrp_unack_packet_retrans(struct thread *);
-extern int eigrp_unack_multicast_packet_retrans(struct thread *);
+extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo);
+extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo);
+extern void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep);
+extern void eigrp_fifo_free(struct eigrp_fifo *fifo);
+extern void eigrp_fifo_reset(struct eigrp_fifo *fifo);
+
+extern void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr);
+
+extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s);
+extern uint16_t
+eigrp_add_internalTLV_to_stream(struct stream *s,
+                               struct eigrp_prefix_descriptor *pe);
+extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s,
+                                               struct eigrp_interface *ei);
+extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s,
+                                                  struct eigrp_interface *ei);
+
+extern int eigrp_unack_packet_retrans(struct thread *thread);
+extern int eigrp_unack_multicast_packet_retrans(struct thread *thread);
 
 /*
  * untill there is reason to have their own header, these externs are found in
  * eigrp_hello.c
  */
 extern void eigrp_sw_version_initialize(void);
-extern void eigrp_hello_send(struct eigrp_interface *, uint8_t,
-                            struct in_addr *);
-extern void eigrp_hello_send_ack(struct eigrp_neighbor *);
-extern void eigrp_hello_receive(struct eigrp *, struct ip *,
-                               struct eigrp_header *, struct stream *,
-                               struct eigrp_interface *, int);
-extern int eigrp_hello_timer(struct thread *);
+extern void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags,
+                            struct in_addr *nbr_addr);
+extern void eigrp_hello_send_ack(struct eigrp_neighbor *nbr);
+extern void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
+                               struct eigrp_header *eigrph, struct stream *s,
+                               struct eigrp_interface *ei, int size);
+extern int eigrp_hello_timer(struct thread *thread);
 
 /*
  * These externs are found in eigrp_update.c
@@ -85,76 +88,83 @@ extern int eigrp_hello_timer(struct thread *);
 extern bool eigrp_update_prefix_apply(struct eigrp *eigrp,
                                      struct eigrp_interface *ei, int in,
                                      struct prefix *prefix);
-extern void eigrp_update_send(struct eigrp_interface *);
-extern void eigrp_update_receive(struct eigrp *, struct ip *,
-                                struct eigrp_header *, struct stream *,
-                                struct eigrp_interface *, int);
-extern void eigrp_update_send_all(struct eigrp *, struct eigrp_interface *);
-extern void eigrp_update_send_init(struct eigrp_neighbor *);
-extern void eigrp_update_send_EOT(struct eigrp_neighbor *);
-extern int eigrp_update_send_GR_thread(struct thread *);
-extern void eigrp_update_send_GR(struct eigrp_neighbor *, enum GR_type,
-                                struct vty *);
-extern void eigrp_update_send_interface_GR(struct eigrp_interface *,
-                                          enum GR_type, struct vty *);
-extern void eigrp_update_send_process_GR(struct eigrp *, enum GR_type,
-                                        struct vty *);
+extern void eigrp_update_send(struct eigrp_interface *ei);
+extern void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
+                                struct eigrp_header *eigrph, struct stream *s,
+                                struct eigrp_interface *ei, int size);
+extern void eigrp_update_send_all(struct eigrp *eigrp,
+                                 struct eigrp_interface *exception);
+extern void eigrp_update_send_init(struct eigrp_neighbor *nbr);
+extern void eigrp_update_send_EOT(struct eigrp_neighbor *nbr);
+extern int eigrp_update_send_GR_thread(struct thread *thread);
+extern void eigrp_update_send_GR(struct eigrp_neighbor *nbr,
+                                enum GR_type gr_type, struct vty *vty);
+extern void eigrp_update_send_interface_GR(struct eigrp_interface *ei,
+                                          enum GR_type gr_type,
+                                          struct vty *vty);
+extern void eigrp_update_send_process_GR(struct eigrp *eigrp,
+                                        enum GR_type gr_type, struct vty *vty);
 
 /*
  * These externs are found in eigrp_query.c
  */
 
-extern void eigrp_send_query(struct eigrp_interface *);
-extern void eigrp_query_receive(struct eigrp *, struct ip *,
-                               struct eigrp_header *, struct stream *,
-                               struct eigrp_interface *, int);
-extern uint32_t eigrp_query_send_all(struct eigrp *);
+extern void eigrp_send_query(struct eigrp_interface *ei);
+extern void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
+                               struct eigrp_header *eigrph, struct stream *s,
+                               struct eigrp_interface *ei, int size);
+extern uint32_t eigrp_query_send_all(struct eigrp *eigrp);
 
 /*
  * These externs are found in eigrp_reply.c
  */
-extern void eigrp_send_reply(struct eigrp_neighbor *,
-                            struct eigrp_prefix_entry *);
-extern void eigrp_reply_receive(struct eigrp *, struct ip *,
-                               struct eigrp_header *, struct stream *,
-                               struct eigrp_interface *, int);
+extern void eigrp_send_reply(struct eigrp_neighbor *nbr,
+                            struct eigrp_prefix_descriptor *pe);
+extern void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
+                               struct eigrp_header *eigrph, struct stream *s,
+                               struct eigrp_interface *ei, int size);
 
 /*
  * These externs are found in eigrp_siaquery.c
  */
-extern void eigrp_send_siaquery(struct eigrp_neighbor *,
-                               struct eigrp_prefix_entry *);
-extern void eigrp_siaquery_receive(struct eigrp *, struct ip *,
-                                  struct eigrp_header *, struct stream *,
-                                  struct eigrp_interface *, int);
+extern void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
+                               struct eigrp_prefix_descriptor *pe);
+extern void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
+                                  struct eigrp_header *eigrph,
+                                  struct stream *s, struct eigrp_interface *ei,
+                                  int size);
 
 /*
  * These externs are found in eigrp_siareply.c
  */
-extern void eigrp_send_siareply(struct eigrp_neighbor *,
-                               struct eigrp_prefix_entry *);
-extern void eigrp_siareply_receive(struct eigrp *, struct ip *,
-                                  struct eigrp_header *, struct stream *,
-                                  struct eigrp_interface *, int);
+extern void eigrp_send_siareply(struct eigrp_neighbor *nbr,
+                               struct eigrp_prefix_descriptor *pe);
+extern void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
+                                  struct eigrp_header *eigrph,
+                                  struct stream *s, struct eigrp_interface *ei,
+                                  int size);
 
 extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new(void);
-extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *);
+extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV);
 extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new(void);
-extern void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *);
-
-extern int eigrp_make_md5_digest(struct eigrp_interface *, struct stream *,
-                                uint8_t);
-extern int eigrp_check_md5_digest(struct stream *,
-                                 struct TLV_MD5_Authentication_Type *,
-                                 struct eigrp_neighbor *, uint8_t);
-extern int eigrp_make_sha256_digest(struct eigrp_interface *, struct stream *,
-                                   uint8_t);
-extern int eigrp_check_sha256_digest(struct stream *,
-                                    struct TLV_SHA256_Authentication_Type *,
-                                    struct eigrp_neighbor *, uint8_t);
-
-
-extern void eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *);
+extern void
+eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV);
+
+extern int eigrp_make_md5_digest(struct eigrp_interface *ei, struct stream *s,
+                                uint8_t flags);
+extern int eigrp_check_md5_digest(struct stream *s,
+                                 struct TLV_MD5_Authentication_Type *authTLV,
+                                 struct eigrp_neighbor *nbr, uint8_t flags);
+extern int eigrp_make_sha256_digest(struct eigrp_interface *ei,
+                                   struct stream *s, uint8_t flags);
+extern int
+eigrp_check_sha256_digest(struct stream *s,
+                         struct TLV_SHA256_Authentication_Type *authTLV,
+                         struct eigrp_neighbor *nbr, uint8_t flags);
+
+
+extern void
+eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *IPv4_InternalTLV);
 
 extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void);
 
index 84dcf5e2d55a081b6dae3685aea58e12b2cf092f..0ab7b59dbb323c777d973aff0e40497c7f3f496b 100644 (file)
@@ -58,7 +58,7 @@ uint32_t eigrp_query_send_all(struct eigrp *eigrp)
 {
        struct eigrp_interface *iface;
        struct listnode *node, *node2, *nnode2;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        uint32_t counter;
 
        if (eigrp == NULL) {
@@ -118,7 +118,7 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AF_INET;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -126,9 +126,9 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
                         * know)*/
                        if (dest != NULL) {
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
                                msg.packet_type = EIGRP_OPC_QUERY;
                                msg.eigrp = eigrp;
                                msg.data_type = EIGRP_INT;
@@ -164,7 +164,7 @@ void eigrp_send_query(struct eigrp_interface *ei)
        uint16_t length = EIGRP_HEADER_LEN;
        struct listnode *node, *nnode, *node2, *nnode2;
        struct eigrp_neighbor *nbr;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        bool has_tlv = false;
        bool new_packet = true;
        uint16_t eigrp_mtu = EIGRP_PACKET_MTU(ei->ifp->mtu);
index 26bb27d7ac6e9b30ca898211912d6f196ff09909..d16482173c009da82a418e2b6e472a065e5c7b2f 100644 (file)
 #include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_errors.h"
 
-void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+void eigrp_send_reply(struct eigrp_neighbor *nbr,
+                     struct eigrp_prefix_descriptor *pe)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
        struct eigrp_interface *ei = nbr->ei;
        struct eigrp *eigrp = ei->eigrp;
-       struct eigrp_prefix_entry *pe2;
+       struct eigrp_prefix_descriptor *pe2;
 
        // TODO: Work in progress
        /* Filtering */
        /* get list from eigrp process */
-       pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY,
-                     sizeof(struct eigrp_prefix_entry));
-       memcpy(pe2, pe, sizeof(struct eigrp_prefix_entry));
+       pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
+                     sizeof(struct eigrp_prefix_descriptor));
+       memcpy(pe2, pe, sizeof(struct eigrp_prefix_descriptor));
 
        if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_OUT,
                                      pe2->destination)) {
@@ -122,7 +123,7 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
                eigrp_send_packet_reliably(nbr);
        }
 
-       XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe2);
+       XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe2);
 }
 
 /*EIGRP REPLY read function*/
@@ -161,7 +162,7 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
                dest_addr.family = AF_INET;
                dest_addr.u.prefix4 = tlv->destination;
                dest_addr.prefixlen = tlv->prefix_length;
-               struct eigrp_prefix_entry *dest =
+               struct eigrp_prefix_descriptor *dest =
                        eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
                                                         &dest_addr);
                /*
@@ -177,8 +178,8 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
                }
 
                struct eigrp_fsm_action_message msg;
-               struct eigrp_nexthop_entry *entry =
-                       eigrp_prefix_entry_lookup(dest->entries, nbr);
+               struct eigrp_route_descriptor *entry =
+                       eigrp_route_descriptor_lookup(dest->entries, nbr);
 
                if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_IN,
                                              &dest_addr)) {
index e15f777954aad9e229c096593a90a7c86546dd87..5183e645e596c65123c5e12c7aba52dcb579d12f 100644 (file)
@@ -265,8 +265,8 @@ route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type,
        //  uint32_t *metric;
        //  uint32_t  check;
        //  struct rip_info *rinfo;
-       //  struct eigrp_nexthop_entry *te;
-       //  struct eigrp_prefix_entry *pe;
+       //  struct eigrp_route_descriptor *te;
+       //  struct eigrp_prefix_descriptor *pe;
        //  struct listnode *node, *node2, *nnode, *nnode2;
        //  struct eigrp *e;
        //
index ff383254651a7759fc4bc968ca90d73ee9d7e65a..027700fe11a95322fefcd2d920c303b629bbb6b0 100644 (file)
@@ -87,7 +87,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AFI_IP;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -95,9 +95,9 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
                         * know)*/
                        if (dest != NULL) {
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
                                msg.packet_type = EIGRP_OPC_SIAQUERY;
                                msg.eigrp = eigrp;
                                msg.data_type = EIGRP_INT;
@@ -114,7 +114,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
 }
 
 void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
-                        struct eigrp_prefix_entry *pe)
+                        struct eigrp_prefix_descriptor *pe)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
index d3dd123f909cb4f79862e77914b1ae10c370a777..590b224d68ec2c8e5ae2f39e020de05f530eccde 100644 (file)
@@ -86,7 +86,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AFI_IP;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -94,9 +94,9 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
                         * know)*/
                        if (dest != NULL) {
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
                                msg.packet_type = EIGRP_OPC_SIAQUERY;
                                msg.eigrp = eigrp;
                                msg.data_type = EIGRP_INT;
@@ -113,7 +113,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
 }
 
 void eigrp_send_siareply(struct eigrp_neighbor *nbr,
-                        struct eigrp_prefix_entry *pe)
+                        struct eigrp_prefix_descriptor *pe)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
index 82bddaaae3bbd5dbe51ecb6f857776278b5e48a3..cddab57dd54ee4c35f8209ffe66bf417d3a92d4b 100644 (file)
 #include "eigrpd/eigrp_const.h"
 #include "eigrpd/eigrp_macros.h"
 
-/* EIGRP master for system wide configuration and variables. */
-struct eigrp_master {
-       /* EIGRP instance. */
-       struct list *eigrp;
-
-       /* EIGRP thread master. */
-       struct thread_master *master;
-
-       /* Zebra interface list. */
-       struct list *iflist;
-
-       /* EIGRP start time. */
-       time_t start_time;
-
-       /* Various EIGRP global configuration. */
-       uint8_t options;
-
-#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
-};
-
 struct eigrp_metrics {
        uint32_t delay;
        uint32_t bandwidth;
@@ -68,6 +48,16 @@ struct eigrp_metrics {
        uint8_t flags;
 };
 
+struct eigrp_extdata {
+       uint32_t orig;
+       uint32_t as;
+       uint32_t tag;
+       uint32_t metric;
+       uint16_t reserved;
+       uint8_t protocol;
+       uint8_t flags;
+};
+
 struct eigrp {
        vrf_id_t vrf_id;
 
@@ -450,7 +440,7 @@ enum GR_type { EIGRP_GR_MANUAL, EIGRP_GR_FILTER };
 //---------------------------------------------------------------------------------------------------------------------------------------------
 
 /* EIGRP Topology table node structure */
-struct eigrp_prefix_entry {
+struct eigrp_prefix_descriptor {
        struct list *entries, *rij;
        uint32_t fdistance;                   // FD
        uint32_t rdistance;                   // RD
@@ -473,8 +463,14 @@ struct eigrp_prefix_entry {
 };
 
 /* EIGRP Topology table record structure */
-struct eigrp_nexthop_entry {
-       struct eigrp_prefix_entry *prefix;
+struct eigrp_route_descriptor {
+       uint16_t type;
+       uint16_t afi;
+
+       struct eigrp_prefix_descriptor *prefix;
+       struct eigrp_neighbor *adv_router;
+       struct in_addr nexthop;
+
        uint32_t reported_distance; // distance reported by neighbor
        uint32_t distance;        // sum of reported distance and link cost to
                                    // advertised neighbor
@@ -482,7 +478,9 @@ struct eigrp_nexthop_entry {
        struct eigrp_metrics reported_metric;
        struct eigrp_metrics total_metric;
 
-       struct eigrp_neighbor *adv_router; // ip address of advertising neighbor
+       struct eigrp_metrics metric;
+       struct eigrp_extdata extdata;
+
        uint8_t flags;                     // used for marking successor and FS
 
        struct eigrp_interface *ei; // pointer for case of connected entry
@@ -501,8 +499,8 @@ struct eigrp_fsm_action_message {
        uint8_t packet_type;               // UPDATE, QUERY, SIAQUERY, SIAREPLY
        struct eigrp *eigrp;               // which thread sent mesg
        struct eigrp_neighbor *adv_router; // advertising neighbor
-       struct eigrp_nexthop_entry *entry;
-       struct eigrp_prefix_entry *prefix;
+       struct eigrp_route_descriptor *entry;
+       struct eigrp_prefix_descriptor *prefix;
        msg_data_t data_type; // internal or external tlv type
        struct eigrp_metrics metrics;
        enum metric_change change;
index 2dbee166946f6003f238ea87de71d5ad0e6fd04f..1b7e9fc15bb37a94ed47da75bd260a67bd3fe38c 100644 (file)
@@ -39,6 +39,7 @@
 #include "vty.h"
 #include "lib_errors.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_metric.h"
 
-static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *,
-                                  struct eigrp_nexthop_entry *);
+static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1,
+                                     struct eigrp_route_descriptor *rd2);
 
 /*
  * Returns linkedlist used as topology table
@@ -70,14 +72,14 @@ struct route_table *eigrp_topology_new(void)
  * Returns new created toplogy node
  * cmp - assigned function for comparing topology entry
  */
-struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
+struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void)
 {
-       struct eigrp_prefix_entry *new;
-       new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY,
-                     sizeof(struct eigrp_prefix_entry));
+       struct eigrp_prefix_descriptor *new;
+       new = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
+                     sizeof(struct eigrp_prefix_descriptor));
        new->entries = list_new();
        new->rij = list_new();
-       new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp;
+       new->entries->cmp = (int (*)(void *, void *))eigrp_route_descriptor_cmp;
        new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
        new->destination = NULL;
 
@@ -87,8 +89,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
 /*
  * Topology entry comparison
  */
-static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
-                                  struct eigrp_nexthop_entry *entry2)
+static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *entry1,
+                                     struct eigrp_route_descriptor *entry2)
 {
        if (entry1->distance < entry2->distance)
                return -1;
@@ -102,12 +104,12 @@ static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
  * Returns new topology entry
  */
 
-struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void)
+struct eigrp_route_descriptor *eigrp_route_descriptor_new(void)
 {
-       struct eigrp_nexthop_entry *new;
+       struct eigrp_route_descriptor *new;
 
-       new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY,
-                     sizeof(struct eigrp_nexthop_entry));
+       new = XCALLOC(MTYPE_EIGRP_ROUTE_DESCRIPTOR,
+                     sizeof(struct eigrp_route_descriptor));
        new->reported_distance = EIGRP_MAX_METRIC;
        new->distance = EIGRP_MAX_METRIC;
 
@@ -126,8 +128,8 @@ void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table)
 /*
  * Adding topology node to topology table
  */
-void eigrp_prefix_entry_add(struct route_table *topology,
-                           struct eigrp_prefix_entry *pe)
+void eigrp_prefix_descriptor_add(struct route_table *topology,
+                                struct eigrp_prefix_descriptor *pe)
 {
        struct route_node *rn;
 
@@ -146,9 +148,9 @@ void eigrp_prefix_entry_add(struct route_table *topology,
 /*
  * Adding topology entry to topology node
  */
-void eigrp_nexthop_entry_add(struct eigrp *eigrp,
-                            struct eigrp_prefix_entry *node,
-                            struct eigrp_nexthop_entry *entry)
+void eigrp_route_descriptor_add(struct eigrp *eigrp,
+                               struct eigrp_prefix_descriptor *node,
+                               struct eigrp_route_descriptor *entry)
 {
        struct list *l = list_new();
 
@@ -168,10 +170,11 @@ void eigrp_nexthop_entry_add(struct eigrp *eigrp,
 /*
  * Deleting topology node from topology table
  */
-void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
-                              struct eigrp_prefix_entry *pe)
+void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
+                                   struct route_table *table,
+                                   struct eigrp_prefix_descriptor *pe)
 {
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_route_descriptor *ne;
        struct listnode *node, *nnode;
        struct route_node *rn;
 
@@ -189,7 +192,7 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
        listnode_delete(eigrp->topology_changes_internalIPV4, pe);
 
        for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne))
-               eigrp_nexthop_entry_delete(eigrp, pe, ne);
+               eigrp_route_descriptor_delete(eigrp, pe, ne);
        list_delete(&pe->entries);
        list_delete(&pe->rij);
        eigrp_zebra_route_delete(eigrp, pe->destination);
@@ -198,20 +201,20 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
        rn->info = NULL;
        route_unlock_node(rn); // Lookup above
        route_unlock_node(rn); // Initial creation
-       XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe);
+       XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe);
 }
 
 /*
  * Deleting topology entry from topology node
  */
-void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
-                               struct eigrp_prefix_entry *node,
-                               struct eigrp_nexthop_entry *entry)
+void eigrp_route_descriptor_delete(struct eigrp *eigrp,
+                                  struct eigrp_prefix_descriptor *node,
+                                  struct eigrp_route_descriptor *entry)
 {
        if (listnode_lookup(node->entries, entry) != NULL) {
                listnode_delete(node->entries, entry);
                eigrp_zebra_route_delete(eigrp, node->destination);
-               XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
+               XFREE(MTYPE_EIGRP_ROUTE_DESCRIPTOR, entry);
        }
 }
 
@@ -222,7 +225,7 @@ void eigrp_topology_delete_all(struct eigrp *eigrp,
                               struct route_table *topology)
 {
        struct route_node *rn;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
 
        for (rn = route_top(topology); rn; rn = route_next(rn)) {
                pe = rn->info;
@@ -230,15 +233,15 @@ void eigrp_topology_delete_all(struct eigrp *eigrp,
                if (!pe)
                        continue;
 
-               eigrp_prefix_entry_delete(eigrp, topology, pe);
+               eigrp_prefix_descriptor_delete(eigrp, topology, pe);
        }
 }
 
-struct eigrp_prefix_entry *
+struct eigrp_prefix_descriptor *
 eigrp_topology_table_lookup_ipv4(struct route_table *table,
                                 struct prefix *address)
 {
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct route_node *rn;
 
        rn = route_node_lookup(table, address);
@@ -259,14 +262,15 @@ eigrp_topology_table_lookup_ipv4(struct route_table *table,
  * That way we can clean up all the list_new and list_delete's
  * that we are doing.  DBS
  */
-struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
+struct list *
+eigrp_topology_get_successor(struct eigrp_prefix_descriptor *table_node)
 {
        struct list *successors = list_new();
-       struct eigrp_nexthop_entry *data;
+       struct eigrp_route_descriptor *data;
        struct listnode *node1, *node2;
 
        for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
-               if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) {
+               if (data->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) {
                        listnode_add(successors, data);
                }
        }
@@ -283,7 +287,7 @@ struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
 }
 
 struct list *
-eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
+eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *table_node,
                                 unsigned int maxpaths)
 {
        struct list *successors = eigrp_topology_get_successor(table_node);
@@ -300,10 +304,10 @@ eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
        return successors;
 }
 
-struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
+struct eigrp_route_descriptor *
+eigrp_route_descriptor_lookup(struct list *entries, struct eigrp_neighbor *nbr)
 {
-       struct eigrp_nexthop_entry *data;
+       struct eigrp_route_descriptor *data;
        struct listnode *node, *nnode;
        for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) {
                if (data->adv_router == nbr) {
@@ -319,8 +323,8 @@ struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
                                            struct eigrp_neighbor *nbr)
 {
        struct listnode *node2, *node22;
-       struct eigrp_nexthop_entry *entry;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_route_descriptor *entry;
+       struct eigrp_prefix_descriptor *pe;
        struct route_node *rn;
 
        /* create new empty list for prefixes storage */
@@ -348,8 +352,8 @@ enum metric_change
 eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
 {
        struct eigrp *eigrp = msg->eigrp;
-       struct eigrp_prefix_entry *prefix = msg->prefix;
-       struct eigrp_nexthop_entry *entry = msg->entry;
+       struct eigrp_prefix_descriptor *prefix = msg->prefix;
+       struct eigrp_route_descriptor *entry = msg->entry;
        enum metric_change change = METRIC_SAME;
        uint32_t new_reported_distance;
 
@@ -413,7 +417,7 @@ distance_done:
 
 void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
 {
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct route_node *rn;
 
        if (!eigrp)
@@ -430,10 +434,10 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
 }
 
 void eigrp_topology_update_node_flags(struct eigrp *eigrp,
-                                     struct eigrp_prefix_entry *dest)
+                                     struct eigrp_prefix_descriptor *dest)
 {
        struct listnode *node;
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_route_descriptor *entry;
 
        for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
                if (entry->reported_distance < dest->fdistance) {
@@ -444,29 +448,29 @@ void eigrp_topology_update_node_flags(struct eigrp *eigrp,
                            && entry->distance != EIGRP_MAX_METRIC) {
                                // is successor
                                entry->flags |=
-                                       EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                                       EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
                                entry->flags &=
-                                       ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
+                                       ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
                        } else {
                                // is feasible successor only
                                entry->flags |=
-                                       EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
+                                       EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
                                entry->flags &=
-                                       ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                                       ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
                        }
                } else {
-                       entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
-                       entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                       entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
+                       entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
                }
        }
 }
 
 void eigrp_update_routing_table(struct eigrp *eigrp,
-                               struct eigrp_prefix_entry *prefix)
+                               struct eigrp_prefix_descriptor *prefix)
 {
        struct list *successors;
        struct listnode *node;
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_route_descriptor *entry;
 
        successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
 
@@ -474,13 +478,13 @@ void eigrp_update_routing_table(struct eigrp *eigrp,
                eigrp_zebra_route_add(eigrp, prefix->destination, successors,
                                      prefix->fdistance);
                for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
-                       entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
+                       entry->flags |= EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
 
                list_delete(&successors);
        } else {
                eigrp_zebra_route_delete(eigrp, prefix->destination);
                for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
-                       entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
+                       entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
        }
 }
 
@@ -488,8 +492,8 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
                                  struct eigrp_neighbor *nbr)
 {
        struct listnode *node2, *node22;
-       struct eigrp_prefix_entry *pe;
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_prefix_descriptor *pe;
+       struct eigrp_route_descriptor *entry;
        struct route_node *rn;
 
        for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
@@ -521,18 +525,18 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
 
 void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
                                        struct route_table *table,
-                                       struct eigrp_prefix_entry *prefix)
+                                       struct eigrp_prefix_descriptor *prefix)
 {
        struct listnode *node1, *node2;
 
-       struct eigrp_nexthop_entry *entry;
+       struct eigrp_route_descriptor *entry;
        for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
                if (entry->distance == EIGRP_MAX_METRIC) {
-                       eigrp_nexthop_entry_delete(eigrp, prefix, entry);
+                       eigrp_route_descriptor_delete(eigrp, prefix, entry);
                }
        }
        if (prefix->distance == EIGRP_MAX_METRIC
            && prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
-               eigrp_prefix_entry_delete(eigrp, table, prefix);
+               eigrp_prefix_descriptor_delete(eigrp, table, prefix);
        }
 }
index 718cece40383ad9e814b18106982ea5d26b39b46..26fa1a11b0be1ed54317c8068bb3dc4a707368a5 100644 (file)
 /* EIGRP Topology table related functions. */
 extern struct route_table *eigrp_topology_new(void);
 extern void eigrp_topology_init(struct route_table *table);
-extern struct eigrp_prefix_entry *eigrp_prefix_entry_new(void);
-extern struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void);
+extern struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void);
+extern struct eigrp_route_descriptor *eigrp_route_descriptor_new(void);
 extern void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table);
-extern void eigrp_prefix_entry_add(struct route_table *table,
-                                  struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_add(struct eigrp *eigrp,
-                                   struct eigrp_prefix_entry *pe,
-                                   struct eigrp_nexthop_entry *ne);
-extern void eigrp_prefix_entry_delete(struct eigrp *eigrp,
-                                     struct route_table *table,
-                                     struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
-                                      struct eigrp_prefix_entry *pe,
-                                      struct eigrp_nexthop_entry *ne);
+extern void eigrp_prefix_descriptor_add(struct route_table *table,
+                                       struct eigrp_prefix_descriptor *pe);
+extern void eigrp_route_descriptor_add(struct eigrp *eigrp,
+                                      struct eigrp_prefix_descriptor *pe,
+                                      struct eigrp_route_descriptor *ne);
+extern void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
+                                          struct route_table *table,
+                                          struct eigrp_prefix_descriptor *pe);
+extern void eigrp_route_descriptor_delete(struct eigrp *eigrp,
+                                         struct eigrp_prefix_descriptor *pe,
+                                         struct eigrp_route_descriptor *ne);
 extern void eigrp_topology_delete_all(struct eigrp *eigrp,
                                      struct route_table *table);
-extern struct eigrp_prefix_entry *
+extern struct eigrp_prefix_descriptor *
 eigrp_topology_table_lookup_ipv4(struct route_table *table, struct prefix *p);
-extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *pe);
 extern struct list *
-eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe,
+eigrp_topology_get_successor(struct eigrp_prefix_descriptor *pe);
+extern struct list *
+eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *pe,
                                 unsigned int maxpaths);
-extern struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *neigh);
+extern struct eigrp_route_descriptor *
+eigrp_route_descriptor_lookup(struct list *entries,
+                             struct eigrp_neighbor *neigh);
 extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
                                                   struct eigrp_neighbor *n);
 extern void eigrp_topology_update_all_node_flags(struct eigrp *eigrp);
-extern void eigrp_topology_update_node_flags(struct eigrp *eigrp,
-                                            struct eigrp_prefix_entry *pe);
+extern void
+eigrp_topology_update_node_flags(struct eigrp *eigrp,
+                                struct eigrp_prefix_descriptor *pe);
 extern enum metric_change
 eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg);
 extern void eigrp_update_routing_table(struct eigrp *eigrp,
-                                      struct eigrp_prefix_entry *pe);
+                                      struct eigrp_prefix_descriptor *pe);
 extern void eigrp_topology_neighbor_down(struct eigrp *eigrp,
                                         struct eigrp_neighbor *neigh);
-extern void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
-                                              struct route_table *table,
-                                              struct eigrp_prefix_entry *pe);
+extern void
+eigrp_update_topology_table_prefix(struct eigrp *eigrp,
+                                  struct route_table *table,
+                                  struct eigrp_prefix_descriptor *pe);
 
 #endif
diff --git a/eigrpd/eigrp_types.h b/eigrpd/eigrp_types.h
new file mode 100644 (file)
index 0000000..bd65107
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * EIGRP Definition of Data Types
+ * Copyright (C) 2018
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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
+ */
+
+#ifndef _ZEBRA_EIGRP_TYPES_H_
+#define _ZEBRA_EIGRP_TYPES_H_
+
+typedef uint64_t eigrp_bandwidth_t;
+typedef uint64_t eigrp_delay_t;
+typedef uint64_t eigrp_metric_t;
+typedef uint32_t eigrp_scaled_t;
+
+typedef uint32_t eigrp_system_metric_t;
+typedef uint32_t eigrp_system_delay_t;
+typedef uint32_t eigrp_system_bandwidth_t;
+
+#endif /* _ZEBRA_EIGRP_TYPES_H_ */
index cd30eb5ab5f60fe0d4110ecfaed468aa70ae73bb..91f3b3218bca44063789d308990488b111a3a345 100644 (file)
@@ -49,6 +49,7 @@
 #include "routemap.h"
 #include "vty.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
@@ -62,6 +63,7 @@
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_metric.h"
 
 bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
                               int in, struct prefix *prefix)
@@ -101,11 +103,12 @@ bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
  * Function is used for removing received prefix
  * from list of neighbor prefixes
  */
-static void remove_received_prefix_gr(struct list *nbr_prefixes,
-                                     struct eigrp_prefix_entry *recv_prefix)
+static void
+remove_received_prefix_gr(struct list *nbr_prefixes,
+                         struct eigrp_prefix_descriptor *recv_prefix)
 {
        struct listnode *node1, *node11;
-       struct eigrp_prefix_entry *prefix = NULL;
+       struct eigrp_prefix_descriptor *prefix = NULL;
 
        /* iterate over all prefixes in list */
        for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) {
@@ -136,7 +139,7 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
                                        struct list *nbr_prefixes)
 {
        struct listnode *node1;
-       struct eigrp_prefix_entry *prefix;
+       struct eigrp_prefix_descriptor *prefix;
        struct eigrp_fsm_action_message fsm_msg;
 
        /* iterate over all prefixes which weren't advertised by neighbor */
@@ -148,8 +151,8 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
                /* set delay to MAX */
                fsm_msg.metrics.delay = EIGRP_MAX_METRIC;
 
-               struct eigrp_nexthop_entry *entry =
-                       eigrp_prefix_entry_lookup(prefix->entries, nbr);
+               struct eigrp_route_descriptor *entry =
+                       eigrp_route_descriptor_lookup(prefix->entries, nbr);
 
                fsm_msg.packet_type = EIGRP_OPC_UPDATE;
                fsm_msg.eigrp = eigrp;
@@ -172,8 +175,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
 {
        struct eigrp_neighbor *nbr;
        struct TLV_IPv4_Internal_type *tlv;
-       struct eigrp_prefix_entry *pe;
-       struct eigrp_nexthop_entry *ne;
+       struct eigrp_prefix_descriptor *pe;
+       struct eigrp_route_descriptor *ne;
        uint32_t flags;
        uint16_t type;
        uint16_t length;
@@ -304,7 +307,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                        dest_addr.family = AF_INET;
                        dest_addr.u.prefix4 = tlv->destination;
                        dest_addr.prefixlen = tlv->prefix_length;
-                       struct eigrp_prefix_entry *dest =
+                       struct eigrp_prefix_descriptor *dest =
                                eigrp_topology_table_lookup_ipv4(
                                        eigrp->topology_table, &dest_addr);
 
@@ -317,9 +320,9 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                                                  dest);
 
                                struct eigrp_fsm_action_message msg;
-                               struct eigrp_nexthop_entry *entry =
-                                       eigrp_prefix_entry_lookup(dest->entries,
-                                                                 nbr);
+                               struct eigrp_route_descriptor *entry =
+                                       eigrp_route_descriptor_lookup(
+                                               dest->entries, nbr);
 
                                msg.packet_type = EIGRP_OPC_UPDATE;
                                msg.eigrp = eigrp;
@@ -331,7 +334,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                eigrp_fsm_event(&msg);
                        } else {
                                /*Here comes topology information save*/
-                               pe = eigrp_prefix_entry_new();
+                               pe = eigrp_prefix_descriptor_new();
                                pe->serno = eigrp->serno;
                                pe->destination =
                                        (struct prefix *)prefix_ipv4_new();
@@ -340,7 +343,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                pe->state = EIGRP_FSM_STATE_PASSIVE;
                                pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
 
-                               ne = eigrp_nexthop_entry_new();
+                               ne = eigrp_route_descriptor_new();
                                ne->ei = ei;
                                ne->adv_router = nbr;
                                ne->reported_metric = tlv->metric;
@@ -361,11 +364,12 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
                                pe->fdistance = pe->distance = pe->rdistance =
                                        ne->distance;
                                ne->prefix = pe;
-                               ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+                               ne->flags =
+                                       EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
 
-                               eigrp_prefix_entry_add(eigrp->topology_table,
-                                                      pe);
-                               eigrp_nexthop_entry_add(eigrp, pe, ne);
+                               eigrp_prefix_descriptor_add(
+                                       eigrp->topology_table, pe);
+                               eigrp_route_descriptor_add(eigrp, pe, ne);
                                pe->distance = pe->fdistance = pe->rdistance =
                                        ne->distance;
                                pe->reported_metric = ne->total_metric;
@@ -527,8 +531,8 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
-       struct eigrp_nexthop_entry *te;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_route_descriptor *te;
+       struct eigrp_prefix_descriptor *pe;
        struct listnode *node2, *nnode2;
        struct eigrp_interface *ei = nbr->ei;
        struct eigrp *eigrp = ei->eigrp;
@@ -600,7 +604,7 @@ void eigrp_update_send(struct eigrp_interface *ei)
 {
        struct eigrp_packet *ep;
        struct listnode *node, *nnode;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        uint8_t has_tlv;
        struct eigrp *eigrp = ei->eigrp;
        struct prefix *dest_addr;
@@ -626,7 +630,7 @@ void eigrp_update_send(struct eigrp_interface *ei)
        has_tlv = 0;
        for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node,
                               nnode, pe)) {
-               struct eigrp_nexthop_entry *ne;
+               struct eigrp_route_descriptor *ne;
 
                if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE))
                        continue;
@@ -707,7 +711,7 @@ void eigrp_update_send_all(struct eigrp *eigrp,
 {
        struct eigrp_interface *iface;
        struct listnode *node, *node2, *nnode2;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
 
        for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
                if (iface != exception) {
@@ -745,7 +749,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
 {
        struct eigrp_packet *ep;
        uint16_t length = EIGRP_HEADER_LEN;
-       struct eigrp_prefix_entry *pe;
+       struct eigrp_prefix_descriptor *pe;
        struct prefix *dest_addr;
        struct eigrp_interface *ei = nbr->ei;
        struct eigrp *eigrp = ei->eigrp;
@@ -837,8 +841,8 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
                        /* prepare message for FSM */
                        struct eigrp_fsm_action_message fsm_msg;
 
-                       struct eigrp_nexthop_entry *entry =
-                               eigrp_prefix_entry_lookup(pe->entries, nbr);
+                       struct eigrp_route_descriptor *entry =
+                               eigrp_route_descriptor_lookup(pe->entries, nbr);
 
                        fsm_msg.packet_type = EIGRP_OPC_UPDATE;
                        fsm_msg.eigrp = eigrp;
@@ -956,7 +960,7 @@ int eigrp_update_send_GR_thread(struct thread *thread)
 void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
                          struct vty *vty)
 {
-       struct eigrp_prefix_entry *pe2;
+       struct eigrp_prefix_descriptor *pe2;
        struct list *prefixes;
        struct route_node *rn;
        struct eigrp_interface *ei = nbr->ei;
index 66dfbaa5385dc5dc98050d35bff73c4c11b6ebf7..0809ac2cf08e63cb07dec3de540433d419a2b0c0 100644 (file)
 #include "eigrpd/eigrp_vty_clippy.c"
 #endif
 
-static void eigrp_vty_display_prefix_entry(struct vty *vty,
-                                          struct eigrp *eigrp,
-                                          struct eigrp_prefix_entry *pe,
+static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp,
+                                          struct eigrp_prefix_descriptor *pe,
                                           bool all)
 {
        bool first = true;
-       struct eigrp_nexthop_entry *te;
+       struct eigrp_route_descriptor *te;
        struct listnode *node;
 
        for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) {
                if (all
-                   || (((te->flags
-                         & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
-                        == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
-                       || ((te->flags
-                            & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG)
-                           == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) {
-                       show_ip_eigrp_nexthop_entry(vty, eigrp, te,
-                                                   &first);
+                   || (((te->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)
+                        == EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)
+                       || ((te->flags & EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG)
+                           == EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG))) {
+                       show_ip_eigrp_route_descriptor(vty, eigrp, te, &first);
                        first = false;
                }
        }
@@ -104,7 +100,7 @@ static struct eigrp *eigrp_vty_get_eigrp(struct vty *vty, const char *vrf_name)
 static void eigrp_topology_helper(struct vty *vty, struct eigrp *eigrp,
                                  const char *all)
 {
-       struct eigrp_prefix_entry *tn;
+       struct eigrp_prefix_descriptor *tn;
        struct route_node *rn;
 
        show_ip_eigrp_topology_header(vty, eigrp);
@@ -168,7 +164,7 @@ DEFPY (show_ip_eigrp_topology,
        "For a specific prefix\n")
 {
        struct eigrp *eigrp;
-       struct eigrp_prefix_entry *tn;
+       struct eigrp_prefix_descriptor *tn;
        struct route_node *rn;
        struct prefix cmp;
 
diff --git a/eigrpd/eigrp_yang.h b/eigrpd/eigrp_yang.h
new file mode 100644 (file)
index 0000000..a95e531
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * EIGRP YANG Functions.
+ * Copyright (C) 2019
+ * Authors:
+ *   Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR 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, or (at your option) any
+ * later version.
+ *
+ * FRR 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
+ */
+
+#ifndef _EIGRP_YANG_H_
+#define _EIGRP_YANG_H_
+
+/*Prototypes*/
+
+/* eigrp_northbound.c */
+extern const struct frr_yang_module_info frr_eigrpd_info;
+
+#endif /*EIGRP_YANG_H_ */
index 0795fbd6df510892b4c3226d8bb0eb89bcb09536..e79123e6b4cf30b28869c42c8571615e03470344 100644 (file)
@@ -41,6 +41,7 @@
 #include "log.h"
 #include "nexthop.h"
 
+#include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_structs.h"
 #include "eigrpd/eigrpd.h"
 #include "eigrpd/eigrp_interface.h"
@@ -52,6 +53,7 @@
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_metric.h"
 
 static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS);
 static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
@@ -194,7 +196,7 @@ void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p,
 {
        struct zapi_route api;
        struct zapi_nexthop *api_nh;
-       struct eigrp_nexthop_entry *te;
+       struct eigrp_route_descriptor *te;
        struct listnode *node;
        int count = 0;
 
index 6b4d45d1fc271e45a15ac83b8c60b5a56582651e..01173768ba99c865f05dc1ce450c3d83499126e9 100644 (file)
 #define EIGRP_MAJOR_VERSION     1
 #define EIGRP_MINOR_VERSION    2
 
+#define EIGRP_TLV_32B_VERSION 1 /* Original 32bit scaled metrics */
+#define EIGRP_TLV_64B_VERSION 2 /* Current 64bit 'wide' metrics */
+#define EIGRP_TLV_MTR_VERSION 3 /* MTR TLVs with 32bit metric *Not Supported */
+#define EIGRP_TLV_SAF_VERSION 4 /* SAF TLVs with 64bit metric *Not Supported */
+
+struct eigrp_master {
+       /* EIGRP instance. */
+       struct list *eigrp;
+
+       /* EIGRP thread master. */
+       struct thread_master *master;
+
+       /* Zebra interface list. */
+       struct list *iflist;
+
+       /* EIGRP start time. */
+       time_t start_time;
+
+       /* Various EIGRP global configuration. */
+       uint8_t options;
+
+#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
+};
+
 /* Extern variables. */
 extern struct zclient *zclient;
 extern struct thread_master *master;
@@ -46,57 +70,10 @@ extern struct zebra_privs_t eigrpd_privs;
 /* Prototypes */
 extern void eigrp_master_init(void);
 extern void eigrp_terminate(void);
-extern void eigrp_finish_final(struct eigrp *);
-extern void eigrp_finish(struct eigrp *);
+extern void eigrp_finish_final(struct eigrp *eigrp);
+extern void eigrp_finish(struct eigrp *eigrp);
 extern struct eigrp *eigrp_get(uint16_t as, vrf_id_t vrf_id);
 extern struct eigrp *eigrp_lookup(vrf_id_t vrf_id);
-extern void eigrp_router_id_update(struct eigrp *);
-
-/* eigrp_cli.c */
-extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
-                                 bool show_defaults);
-extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
-extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
-                                    bool show_defaults);
-extern void eigrp_cli_show_passive_interface(struct vty *vty,
-                                            struct lyd_node *dnode,
-                                            bool show_defaults);
-extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
-                                      bool show_defaults);
-extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
-                                   bool show_defaults);
-extern void eigrp_cli_show_maximum_paths(struct vty *vty,
-                                        struct lyd_node *dnode,
-                                        bool show_defaults);
-extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
-                                  bool show_defaults);
-extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
-                                  bool show_defaults);
-extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
-                                   bool show_defaults);
-extern void eigrp_cli_show_redistribute(struct vty *vty,
-                                       struct lyd_node *dnode,
-                                       bool show_defaults);
-extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
-                                bool show_defaults);
-extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
-                                    bool show_defaults);
-extern void eigrp_cli_show_hello_interval(struct vty *vty,
-                                         struct lyd_node *dnode,
-                                         bool show_defaults);
-extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
-                                    bool show_defaults);
-extern void eigrp_cli_show_summarize_address(struct vty *vty,
-                                            struct lyd_node *dnode,
-                                            bool show_defaults);
-extern void eigrp_cli_show_authentication(struct vty *vty,
-                                         struct lyd_node *dnode,
-                                         bool show_defaults);
-extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
-                                   bool show_defaults);
-extern void eigrp_cli_init(void);
-
-/* eigrp_northbound.c */
-extern const struct frr_yang_module_info frr_eigrpd_info;
+extern void eigrp_router_id_update(struct eigrp *eigrp);
 
 #endif /* _ZEBRA_EIGRPD_H */
index 98f39440c36d8cc0b7935c67432a2cc00efa686e..13c9f7f8aeb072d261bfa779584490432acad41b 100644 (file)
@@ -25,6 +25,7 @@ eigrpd_libeigrp_a_SOURCES = \
        eigrpd/eigrp_hello.c \
        eigrpd/eigrp_interface.c \
        eigrpd/eigrp_memory.c \
+       eigrpd/eigrp_metric.c \
        eigrpd/eigrp_neighbor.c \
        eigrpd/eigrp_network.c \
        eigrpd/eigrp_northbound.c \
@@ -55,6 +56,7 @@ clippy_scan += \
        # end
 
 noinst_HEADERS += \
+       eigrpd/eigrp_cli.h \
        eigrpd/eigrp_const.h \
        eigrpd/eigrp_errors.h \
        eigrpd/eigrp_filter.h \
@@ -62,13 +64,16 @@ noinst_HEADERS += \
        eigrpd/eigrp_interface.h \
        eigrpd/eigrp_macros.h \
        eigrpd/eigrp_memory.h \
+       eigrpd/eigrp_metric.h \
        eigrpd/eigrp_neighbor.h \
        eigrpd/eigrp_network.h \
        eigrpd/eigrp_packet.h \
        eigrpd/eigrp_snmp.h \
        eigrpd/eigrp_structs.h \
+       eigrpd/eigrp_types.h \
        eigrpd/eigrp_vrf.h \
        eigrpd/eigrp_vty.h \
+       eigrpd/eigrp_yang.h \
        eigrpd/eigrp_zebra.h \
        # end
 
index e736d8fb1fb00980f55c842253b6e3898c91e973..9a8982dc06ef58231c34be178b747bf1c0b6ee1f 100644 (file)
@@ -142,6 +142,8 @@ struct isis_circuit {
        struct bfd_info *bfd_info;
        struct ldp_sync_info *ldp_sync_info;
        bool lfa_protection[ISIS_LEVELS];
+       bool rlfa_protection[ISIS_LEVELS];
+       uint32_t rlfa_max_metric[ISIS_LEVELS];
        struct hash *lfa_excluded_ifaces[ISIS_LEVELS];
        bool tilfa_protection[ISIS_LEVELS];
        bool tilfa_node_protection[ISIS_LEVELS];
index 1f0bebaf455e79375a6f03e83cba3e38a626aaf9..5ca70eab0f88ca81b7aa488f61ba1fbc249c79f3 100644 (file)
@@ -1915,22 +1915,22 @@ DEFPY_YANG (isis_frr_lfa_load_sharing,
                if (no) {
                        nb_cli_enqueue_change(
                                vty, "./fast-reroute/level-1/lfa/load-sharing",
-                               NB_OP_DESTROY, "true");
+                               NB_OP_MODIFY, "true");
                } else {
                        nb_cli_enqueue_change(
                                vty, "./fast-reroute/level-1/lfa/load-sharing",
-                               NB_OP_CREATE, "false");
+                               NB_OP_MODIFY, "false");
                }
        }
        if (!level || strmatch(level, "level-2")) {
                if (no) {
                        nb_cli_enqueue_change(
                                vty, "./fast-reroute/level-2/lfa/load-sharing",
-                               NB_OP_DESTROY, "true");
+                               NB_OP_MODIFY, "true");
                } else {
                        nb_cli_enqueue_change(
                                vty, "./fast-reroute/level-2/lfa/load-sharing",
-                               NB_OP_CREATE, "false");
+                               NB_OP_MODIFY, "false");
                }
        }
 
@@ -1947,6 +1947,62 @@ void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode,
                dnode->parent->parent->schema->name);
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-{1,2}/remote-lfa/prefix-list
+ */
+DEFPY_YANG (isis_frr_remote_lfa_plist,
+       isis_frr_remote_lfa_plist_cmd,
+       "fast-reroute remote-lfa prefix-list WORD$plist [<level-1|level-2>$level]",
+       "Configure Fast ReRoute\n"
+       "Enable remote LFA related configuration\n"
+       "Filter PQ node router ID based on prefix list\n"
+       "Prefix-list name\n"
+       "Enable router ID filtering for level-1 only\n"
+       "Enable router ID filtering for level-2 only\n")
+{
+       if (!level || strmatch(level, "level-1"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-1/remote-lfa/prefix-list",
+                       NB_OP_MODIFY, plist);
+       if (!level || strmatch(level, "level-2"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-2/remote-lfa/prefix-list",
+                       NB_OP_MODIFY, plist);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG (no_isis_frr_remote_lfa_plist,
+       no_isis_frr_remote_lfa_plist_cmd,
+       "no fast-reroute remote-lfa prefix-list [WORD] [<level-1|level-2>$level]",
+       NO_STR
+       "Configure Fast ReRoute\n"
+       "Enable remote LFA related configuration\n"
+       "Filter PQ node router ID based on prefix list\n"
+       "Prefix-list name\n"
+       "Enable router ID filtering for level-1 only\n"
+       "Enable router ID filtering for level-2 only\n")
+{
+       if (!level || strmatch(level, "level-1"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-1/remote-lfa/prefix-list",
+                       NB_OP_DESTROY, NULL);
+       if (!level || strmatch(level, "level-2"))
+               nb_cli_enqueue_change(
+                       vty, "./fast-reroute/level-2/remote-lfa/prefix-list",
+                       NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       vty_out(vty, " fast-reroute remote-lfa prefix-list %s %s\n",
+               yang_dnode_get_string(dnode, NULL),
+               dnode->parent->parent->schema->name);
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-isisd:isis/passive
  */
@@ -2630,6 +2686,25 @@ void cli_show_ip_isis_frr(struct vty *vty, 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");
+
+       if (l1_enabled || l2_enabled) {
+               if (l1_enabled == l2_enabled) {
+                       vty_out(vty,
+                               " isis fast-reroute remote-lfa tunnel mpls-ldp\n");
+                       vty_out(vty, "\n");
+               } else {
+                       if (l1_enabled)
+                               vty_out(vty,
+                                       " isis fast-reroute remote-lfa tunnel mpls-ldp level-1\n");
+                       if (l2_enabled)
+                               vty_out(vty,
+                                       " isis fast-reroute remote-lfa tunnel mpls-ldp level-2\n");
+               }
+       }
+
        /* 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");
@@ -2760,6 +2835,104 @@ void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode,
                yang_dnode_get_string(dnode, NULL));
 }
 
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/remote-lfa/enable
+ */
+DEFPY(isis_remote_lfa, isis_remote_lfa_cmd,
+      "[no] isis fast-reroute remote-lfa tunnel mpls-ldp [level-1|level-2]$level",
+      NO_STR
+      "IS-IS routing protocol\n"
+      "Interface IP Fast-reroute configuration\n"
+      "Enable remote LFA computation\n"
+      "Enable remote LFA computation using tunnels\n"
+      "Use MPLS LDP tunnel to reach the remote LFA node\n"
+      "Enable LFA computation for Level 1 only\n"
+      "Enable LFA computation for Level 2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
+                               NB_OP_MODIFY, "false");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
+                               NB_OP_MODIFY, "true");
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
+                               NB_OP_MODIFY, "false");
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
+                               NB_OP_MODIFY, "true");
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/remote-lfa/maximum-metric
+ */
+DEFPY(isis_remote_lfa_max_metric, isis_remote_lfa_max_metric_cmd,
+      "[no] isis fast-reroute remote-lfa maximum-metric (1-16777215)$metric [level-1|level-2]$level",
+      NO_STR
+      "IS-IS routing protocol\n"
+      "Interface IP Fast-reroute configuration\n"
+      "Enable remote LFA computation\n"
+      "Limit remote LFA node selection within the metric\n"
+      "Value of the metric\n"
+      "Enable LFA computation for Level 1 only\n"
+      "Enable LFA computation for Level 2 only\n")
+{
+       if (!level || strmatch(level, "level-1")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
+                               NB_OP_DESTROY, NULL);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
+                               NB_OP_MODIFY, metric_str);
+               }
+       }
+       if (!level || strmatch(level, "level-2")) {
+               if (no) {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
+                               NB_OP_DESTROY, NULL);
+               } else {
+                       nb_cli_enqueue_change(
+                               vty,
+                               "./frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
+                               NB_OP_MODIFY, metric_str);
+               }
+       }
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults)
+{
+       vty_out(vty, " isis fast-reroute remote-lfa maximum-metric %s %s\n",
+               yang_dnode_get_string(dnode, NULL),
+               dnode->parent->parent->schema->name);
+}
+
 /*
  * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-{1,2}/ti-lfa/enable
  */
@@ -3085,6 +3258,8 @@ void isis_cli_init(void)
        install_element(ISIS_NODE, &isis_frr_lfa_priority_limit_cmd);
        install_element(ISIS_NODE, &isis_frr_lfa_tiebreaker_cmd);
        install_element(ISIS_NODE, &isis_frr_lfa_load_sharing_cmd);
+       install_element(ISIS_NODE, &isis_frr_remote_lfa_plist_cmd);
+       install_element(ISIS_NODE, &no_isis_frr_remote_lfa_plist_cmd);
 
        install_element(INTERFACE_NODE, &isis_passive_cmd);
 
@@ -3122,6 +3297,8 @@ void isis_cli_init(void)
 
        install_element(INTERFACE_NODE, &isis_lfa_cmd);
        install_element(INTERFACE_NODE, &isis_lfa_exclude_interface_cmd);
+       install_element(INTERFACE_NODE, &isis_remote_lfa_cmd);
+       install_element(INTERFACE_NODE, &isis_remote_lfa_max_metric_cmd);
        install_element(INTERFACE_NODE, &isis_ti_lfa_cmd);
 
        install_element(ISIS_NODE, &log_adj_changes_cmd);
index fc6b435b62763ad2ebca0812b4916c52c4acd2c7..5b3a3827a24cf28412e5a5abf1b19bc965d5bf57 100644 (file)
@@ -25,6 +25,8 @@
 #include "vrf.h"
 #include "table.h"
 #include "srcdest_table.h"
+#include "plist.h"
+#include "zclient.h"
 
 #include "isis_common.h"
 #include "isisd.h"
 #include "isis_mt.h"
 #include "isis_tlvs.h"
 #include "isis_spf_private.h"
-#include "isisd/isis_errors.h"
+#include "isis_zebra.h"
+#include "isis_errors.h"
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_NODE, "ISIS SPF Node");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_TIEBREAKER, "ISIS LFA Tiebreaker");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_EXCL_IFACE, "ISIS LFA Excluded Interface");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_RLFA, "ISIS Remote LFA");
 
 static inline int isis_spf_node_compare(const struct isis_spf_node *a,
                                        const struct isis_spf_node *b)
@@ -316,7 +320,7 @@ bool isis_lfa_excise_adj_check(const struct isis_spftree *spftree,
 {
        const struct lfa_protected_resource *resource;
 
-       if (spftree->type != SPF_TYPE_TI_LFA)
+       if (spftree->type != SPF_TYPE_RLFA && spftree->type != SPF_TYPE_TI_LFA)
                return false;
 
        /*
@@ -832,14 +836,14 @@ spf_vertex_check_is_affected(const struct isis_vertex *vertex,
        return false;
 }
 
-/* Check if a given TI-LFA post-convergence SPF vertex needs protection. */
-static bool tilfa_check_needs_protection(const struct isis_spftree *spftree_pc,
-                                        const struct isis_vertex *vertex)
+/* Check if a given RLFA/TI-LFA post-convergence SPF vertex needs protection. */
+static bool lfa_check_needs_protection(const struct isis_spftree *spftree_pc,
+                                      const struct isis_vertex *vertex)
 {
        struct isis_vertex *vertex_old;
 
-       /* Only local adjacencies need Adj-SID protection. */
-       if (VTYPE_IS(vertex->type)
+       /* Only local adjacencies need TI-LFA Adj-SID protection. */
+       if (spftree_pc->type == SPF_TYPE_TI_LFA && VTYPE_IS(vertex->type)
            && !isis_adj_find(spftree_pc->area, spftree_pc->level,
                              vertex->N.id))
                return false;
@@ -849,6 +853,10 @@ static bool tilfa_check_needs_protection(const struct isis_spftree *spftree_pc,
        if (!vertex_old)
                return false;
 
+       /* Skip vertex if it's already protected by local LFA. */
+       if (CHECK_FLAG(vertex_old->flags, F_ISIS_VERTEX_LFA_PROTECTED))
+               return false;
+
        return spf_vertex_check_is_affected(
                vertex_old, spftree_pc->sysid,
                &spftree_pc->lfa.protected_resource);
@@ -874,14 +882,12 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
        if (!spftree_pc->area->srdb.enabled)
                return -1;
 
-       if (IS_DEBUG_LFA)
-               vid2string(vertex, buf, sizeof(buf));
-
-       if (!tilfa_check_needs_protection(spftree_pc, vertex)) {
+       if (!lfa_check_needs_protection(spftree_pc, vertex)) {
                if (IS_DEBUG_LFA)
                        zlog_debug(
                                "ISIS-LFA: %s %s unaffected by %s",
-                               vtype2string(vertex->type), buf,
+                               vtype2string(vertex->type),
+                               vid2string(vertex, buf, sizeof(buf)),
                                lfa_protected_resource2str(
                                        &spftree_pc->lfa.protected_resource));
 
@@ -902,7 +908,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
                        if (IS_DEBUG_LFA)
                                zlog_debug(
                                        "ISIS-LFA: %s %s already covered by node protection",
-                                       vtype2string(vertex->type), buf);
+                                       vtype2string(vertex->type),
+                                       vid2string(vertex, buf, sizeof(buf)));
 
                        return -1;
                }
@@ -915,7 +922,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
                        if (IS_DEBUG_LFA)
                                zlog_debug(
                                        "ISIS-LFA: %s %s already covered by node protection",
-                                       vtype2string(vertex->type), buf);
+                                       vtype2string(vertex->type),
+                                       vid2string(vertex, buf, sizeof(buf)));
 
                        return -1;
                }
@@ -924,7 +932,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
        if (IS_DEBUG_LFA)
                zlog_debug(
                        "ISIS-LFA: computing repair path(s) of %s %s w.r.t %s",
-                       vtype2string(vertex->type), buf,
+                       vtype2string(vertex->type),
+                       vid2string(vertex, buf, sizeof(buf)),
                        lfa_protected_resource2str(
                                &spftree_pc->lfa.protected_resource));
 
@@ -939,7 +948,8 @@ int isis_tilfa_check(struct isis_spftree *spftree_pc,
        if (ret != 0)
                zlog_warn(
                        "ISIS-LFA: failed to compute repair path(s) of %s %s w.r.t %s",
-                       vtype2string(vertex->type), buf,
+                       vtype2string(vertex->type),
+                       vid2string(vertex, buf, sizeof(buf)),
                        lfa_protected_resource2str(
                                &spftree_pc->lfa.protected_resource));
 
@@ -978,13 +988,6 @@ static bool vertex_is_affected(struct isis_spftree *spftree_root,
                struct isis_vertex *vertex_child;
                struct isis_vertex_adj *vadj;
                bool reverse = false;
-               char buf1[VID2STR_BUFFER];
-               char buf2[VID2STR_BUFFER];
-
-               if (IS_DEBUG_LFA)
-                       zlog_debug("ISIS-LFA: vertex %s parent %s",
-                                  vid2string(vertex, buf1, sizeof(buf1)),
-                                  vid2string(pvertex, buf2, sizeof(buf2)));
 
                if (p_space && resource->type == LFA_NODE_PROTECTION) {
                        if (isis_spf_node_find(&resource->nodes, vertex->N.id))
@@ -1059,10 +1062,6 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree,
                if (isis_spf_node_find(nodes, vertex->N.id))
                        continue;
 
-               if (IS_DEBUG_LFA)
-                       zlog_debug("ISIS-LFA: checking %s",
-                                  vid2string(vertex, buf, sizeof(buf)));
-
                if (!vertex_is_affected(spftree_root, adj_nodes, p_space,
                                        vertex, resource)) {
                        if (IS_DEBUG_LFA)
@@ -1166,7 +1165,7 @@ struct isis_spftree *isis_tilfa_compute(struct isis_area *area,
        struct isis_spf_node *adj_node;
 
        if (IS_DEBUG_LFA)
-               zlog_debug("ISIS-LFA: computing the P/Q spaces w.r.t. %s",
+               zlog_debug("ISIS-LFA: computing TI-LFAs for %s",
                           lfa_protected_resource2str(resource));
 
        /* Populate list of nodes affected by link failure. */
@@ -1238,6 +1237,497 @@ int isis_spf_run_neighbors(struct isis_spftree *spftree)
        return 0;
 }
 
+/* Find Router ID of PQ node. */
+static struct in_addr *rlfa_pq_node_rtr_id(struct isis_spftree *spftree,
+                                          const struct isis_vertex *vertex_pq)
+{
+       struct isis_lsp *lsp;
+
+       lsp = isis_root_system_lsp(spftree->lspdb, vertex_pq->N.id);
+       if (!lsp)
+               return NULL;
+
+       if (lsp->tlvs->router_cap->router_id.s_addr == INADDR_ANY)
+               return NULL;
+
+       return &lsp->tlvs->router_cap->router_id;
+}
+
+/* Find PQ node by intersecting the P/Q spaces. This is a recursive function. */
+static const struct in_addr *
+rlfa_find_pq_node(struct isis_spftree *spftree_pc,
+                 struct isis_vertex *vertex_dest,
+                 const struct isis_vertex *vertex,
+                 const struct isis_vertex *vertex_child)
+{
+       struct isis_area *area = spftree_pc->area;
+       int level = spftree_pc->level;
+       struct isis_vertex *pvertex;
+       struct listnode *node;
+       bool is_pnode, is_qnode;
+
+       if (!vertex_child)
+               goto parents;
+       if (vertex->type != VTYPE_NONPSEUDO_IS
+           && vertex->type != VTYPE_NONPSEUDO_TE_IS)
+               goto parents;
+       if (!VTYPE_IS(vertex_child->type))
+               vertex_child = NULL;
+
+       /* Check if node is part of the extended P-space and/or Q-space. */
+       is_pnode = lfa_ext_p_space_check(spftree_pc, vertex_dest, vertex);
+       is_qnode = lfa_q_space_check(spftree_pc, vertex);
+
+       if (is_pnode && is_qnode) {
+               const struct in_addr *rtr_id_pq;
+               uint32_t max_metric;
+               struct prefix_list *plist = NULL;
+
+               rtr_id_pq = rlfa_pq_node_rtr_id(spftree_pc, vertex);
+               if (!rtr_id_pq) {
+                       if (IS_DEBUG_LFA) {
+                               char buf[VID2STR_BUFFER];
+
+                               vid2string(vertex, buf, sizeof(buf));
+                               zlog_debug(
+                                       "ISIS-LFA: tentative PQ node (%s %s) doesn't have a router-ID",
+                                       vtype2string(vertex->type), buf);
+                       }
+                       goto parents;
+               }
+
+               max_metric = spftree_pc->lfa.remote.max_metric;
+               if (max_metric && vertex->d_N > max_metric) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: skipping PQ node %pI4 (maximum metric)",
+                                       rtr_id_pq);
+                       goto parents;
+               }
+
+               plist = area->rlfa_plist[level - 1];
+               if (plist) {
+                       struct prefix p;
+
+                       p.family = AF_INET;
+                       p.prefixlen = IPV4_MAX_BITLEN;
+                       p.u.prefix4 = *rtr_id_pq;
+                       if (prefix_list_apply(plist, &p) == PREFIX_DENY) {
+                               if (IS_DEBUG_LFA)
+                                       zlog_debug(
+                                               "ISIS-LFA: PQ node %pI4 filtered by prefix-list",
+                                               rtr_id_pq);
+                               goto parents;
+                       }
+               }
+
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: found PQ node: %pI4", rtr_id_pq);
+
+               return rtr_id_pq;
+       }
+
+parents:
+       for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, pvertex)) {
+               const struct in_addr *rtr_id_pq;
+
+               rtr_id_pq = rlfa_find_pq_node(spftree_pc, vertex_dest, pvertex,
+                                             vertex);
+               if (rtr_id_pq)
+                       return rtr_id_pq;
+       }
+
+       return NULL;
+}
+
+int rlfa_cmp(const struct rlfa *a, const struct rlfa *b)
+{
+       return prefix_cmp(&a->prefix, &b->prefix);
+}
+
+static struct rlfa *rlfa_add(struct isis_spftree *spftree,
+                            struct isis_vertex *vertex,
+                            struct in_addr pq_address)
+{
+       struct rlfa *rlfa;
+
+       assert(VTYPE_IP(vertex->type));
+       rlfa = XCALLOC(MTYPE_ISIS_RLFA, sizeof(*rlfa));
+       rlfa->prefix = vertex->N.ip.p.dest;
+       rlfa->vertex = vertex;
+       rlfa->pq_address = pq_address;
+       rlfa_tree_add(&spftree->lfa.remote.rlfas, rlfa);
+
+       return rlfa;
+}
+
+static void rlfa_delete(struct isis_spftree *spftree, struct rlfa *rlfa)
+{
+       rlfa_tree_del(&spftree->lfa.remote.rlfas, rlfa);
+       XFREE(MTYPE_ISIS_RLFA, rlfa);
+}
+
+static struct rlfa *rlfa_lookup(struct isis_spftree *spftree,
+                               union prefixconstptr pu)
+{
+       struct rlfa s = {};
+
+       s.prefix = *pu.p;
+       return rlfa_tree_find(&spftree->lfa.remote.rlfas, &s);
+}
+
+static int isis_area_verify_routes_cb(struct thread *thread)
+{
+       struct isis_area *area = THREAD_ARG(thread);
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: updating RLFAs in the RIB");
+
+       isis_area_verify_routes(area);
+
+       return 0;
+}
+
+static mpls_label_t rlfa_nexthop_label(struct isis_spftree *spftree,
+                                      struct isis_vertex_adj *vadj,
+                                      struct zapi_rlfa_response *response)
+{
+       struct isis_spf_adj *sadj = vadj->sadj;
+       struct isis_adjacency *adj = sadj->adj;
+
+       /*
+        * Special case to make unit tests work (use implicit-null labels
+        * instead of artifical ones).
+        */
+       if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+               return MPLS_LABEL_IMPLICIT_NULL;
+
+       for (unsigned int i = 0; i < response->nexthop_num; i++) {
+               switch (response->nexthops[i].family) {
+               case AF_INET:
+                       for (unsigned int j = 0; j < adj->ipv4_address_count;
+                            j++) {
+                               struct in_addr addr = adj->ipv4_addresses[j];
+
+                               if (!IPV4_ADDR_SAME(
+                                           &addr,
+                                           &response->nexthops[i].gate.ipv4))
+                                       continue;
+
+                               return response->nexthops[i].label;
+                       }
+                       break;
+               case AF_INET6:
+                       for (unsigned int j = 0; j < adj->ipv6_address_count;
+                            j++) {
+                               struct in6_addr addr = adj->ipv6_addresses[j];
+
+                               if (!IPV6_ADDR_SAME(
+                                           &addr,
+                                           &response->nexthops[i].gate.ipv6))
+                                       continue;
+
+                               return response->nexthops[i].label;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       return MPLS_INVALID_LABEL;
+}
+
+int isis_rlfa_activate(struct isis_spftree *spftree, struct rlfa *rlfa,
+                      struct zapi_rlfa_response *response)
+{
+       struct isis_area *area = spftree->area;
+       struct isis_vertex *vertex = rlfa->vertex;
+       struct isis_vertex_adj *vadj;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, vadj)) {
+               mpls_label_t ldp_label;
+               struct mpls_label_stack *label_stack;
+               size_t num_labels = 0;
+               size_t i = 0;
+
+               ldp_label = rlfa_nexthop_label(spftree, vadj, response);
+               if (ldp_label == MPLS_INVALID_LABEL) {
+                       if (IS_DEBUG_LFA)
+                               zlog_debug(
+                                       "ISIS-LFA: failed to activate RLFA: missing LDP label to reach PQ node through %s",
+                                       sysid_print(vadj->sadj->id));
+                       return -1;
+               }
+
+               if (ldp_label != MPLS_LABEL_IMPLICIT_NULL)
+                       num_labels++;
+               if (response->pq_label != MPLS_LABEL_IMPLICIT_NULL)
+                       num_labels++;
+               if (vadj->sr.present
+                   && vadj->sr.label != MPLS_LABEL_IMPLICIT_NULL)
+                       num_labels++;
+
+               /* Allocate label stack. */
+               label_stack =
+                       XCALLOC(MTYPE_ISIS_NEXTHOP_LABELS,
+                               sizeof(struct mpls_label_stack)
+                                       + num_labels * sizeof(mpls_label_t));
+               label_stack->num_labels = num_labels;
+
+               /* Push label allocated by the nexthop (outer label). */
+               if (ldp_label != MPLS_LABEL_IMPLICIT_NULL)
+                       label_stack->label[i++] = ldp_label;
+               /* Push label allocated by the PQ node (inner label). */
+               if (response->pq_label != MPLS_LABEL_IMPLICIT_NULL)
+                       label_stack->label[i++] = response->pq_label;
+               /* Preserve the original Prefix-SID label when it's present. */
+               if (vadj->sr.present
+                   && vadj->sr.label != MPLS_LABEL_IMPLICIT_NULL)
+                       label_stack->label[i++] = vadj->sr.label;
+
+               vadj->label_stack = label_stack;
+       }
+
+       isis_route_create(&vertex->N.ip.p.dest, &vertex->N.ip.p.src,
+                         vertex->d_N, vertex->depth, &vertex->N.ip.sr,
+                         vertex->Adj_N, true, area,
+                         spftree->route_table_backup);
+       spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] += 1;
+
+       thread_cancel(&area->t_rlfa_rib_update);
+       thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
+                        &area->t_rlfa_rib_update);
+
+       return 0;
+}
+
+void isis_rlfa_deactivate(struct isis_spftree *spftree, struct rlfa *rlfa)
+{
+       struct isis_area *area = spftree->area;
+       struct isis_vertex *vertex = rlfa->vertex;
+       struct route_node *rn;
+
+       rn = route_node_lookup(spftree->route_table_backup, &rlfa->prefix);
+       if (!rn)
+               return;
+       isis_route_delete(area, rn, spftree->route_table_backup);
+       spftree->lfa.protection_counters.rlfa[vertex->N.ip.priority] -= 1;
+
+       thread_cancel(&area->t_rlfa_rib_update);
+       thread_add_timer(master, isis_area_verify_routes_cb, area, 2,
+                        &area->t_rlfa_rib_update);
+}
+
+void isis_rlfa_list_init(struct isis_spftree *spftree)
+{
+       rlfa_tree_init(&spftree->lfa.remote.rlfas);
+}
+
+void isis_rlfa_list_clear(struct isis_spftree *spftree)
+{
+       while (rlfa_tree_count(&spftree->lfa.remote.rlfas) > 0) {
+               struct rlfa *rlfa;
+
+               rlfa = rlfa_tree_first(&spftree->lfa.remote.rlfas);
+               isis_rlfa_deactivate(spftree, rlfa);
+               rlfa_delete(spftree, rlfa);
+       }
+}
+
+void isis_rlfa_process_ldp_response(struct zapi_rlfa_response *response)
+{
+       struct isis *isis;
+       struct isis_area *area;
+       struct isis_spftree *spftree;
+       struct rlfa *rlfa;
+       enum spf_tree_id tree_id;
+       uint32_t spf_run_id;
+       int level;
+
+       if (response->igp.protocol != ZEBRA_ROUTE_ISIS)
+               return;
+
+       isis = isis_lookup_by_vrfid(response->igp.vrf_id);
+       if (!isis)
+               return;
+
+       area = isis_area_lookup(response->igp.isis.area_tag,
+                               response->igp.vrf_id);
+       if (!area)
+               return;
+
+       tree_id = response->igp.isis.spf.tree_id;
+       if (tree_id != SPFTREE_IPV4 && tree_id != SPFTREE_IPV6) {
+               zlog_warn("ISIS-LFA: invalid SPF tree ID received from LDP");
+               return;
+       }
+
+       level = response->igp.isis.spf.level;
+       if (level != ISIS_LEVEL1 && level != ISIS_LEVEL2) {
+               zlog_warn("ISIS-LFA: invalid IS-IS level received from LDP");
+               return;
+       }
+
+       spf_run_id = response->igp.isis.spf.run_id;
+       spftree = area->spftree[tree_id][level - 1];
+       if (spftree->runcount != spf_run_id)
+               /* Outdated RLFA, ignore... */
+               return;
+
+       rlfa = rlfa_lookup(spftree, &response->destination);
+       if (!rlfa) {
+               zlog_warn(
+                       "ISIS-LFA: couldn't find Remote-LFA %pFX received from LDP",
+                       &response->destination);
+               return;
+       }
+
+       if (response->pq_label != MPLS_INVALID_LABEL) {
+               if (IS_DEBUG_LFA)
+                       zlog_debug(
+                               "ISIS-LFA: activating/updating RLFA for %pFX",
+                               &rlfa->prefix);
+
+               if (isis_rlfa_activate(spftree, rlfa, response) != 0)
+                       isis_rlfa_deactivate(spftree, rlfa);
+       } else {
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: deactivating RLFA for %pFX",
+                                  &rlfa->prefix);
+
+               isis_rlfa_deactivate(spftree, rlfa);
+       }
+}
+
+void isis_ldp_rlfa_handle_client_close(struct zapi_client_close_info *info)
+{
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+       struct isis_area *area;
+       struct listnode *node;
+
+       if (!isis)
+               return;
+
+       /* Check if the LDP main client session closed */
+       if (info->proto != ZEBRA_ROUTE_LDP || info->session_id == 0)
+               return;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: LDP is down, deactivating all RLFAs");
+
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+               for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+                       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+                            level++) {
+                               struct isis_spftree *spftree;
+
+                               spftree = area->spftree[tree][level - 1];
+                               isis_rlfa_list_clear(spftree);
+                       }
+               }
+       }
+}
+
+/**
+ * Check if the given SPF vertex needs protection and, if so, attempt to
+ * compute a Remote LFA for it.
+ *
+ * @param spftree_pc   The post-convergence SPF tree
+ * @param vertex       IS-IS SPF vertex to check
+ */
+void isis_rlfa_check(struct isis_spftree *spftree_pc,
+                    struct isis_vertex *vertex)
+{
+       struct isis_spftree *spftree_old = spftree_pc->lfa.old.spftree;
+       struct rlfa *rlfa;
+       const struct in_addr *rtr_id_pq;
+       char buf[VID2STR_BUFFER];
+
+       if (!lfa_check_needs_protection(spftree_pc, vertex)) {
+               if (IS_DEBUG_LFA)
+                       zlog_debug(
+                               "ISIS-LFA: %s %s unaffected by %s",
+                               vtype2string(vertex->type),
+                               vid2string(vertex, buf, sizeof(buf)),
+                               lfa_protected_resource2str(
+                                       &spftree_pc->lfa.protected_resource));
+
+               return;
+       }
+
+       if (IS_DEBUG_LFA)
+               zlog_debug(
+                       "ISIS-LFA: computing repair path(s) of %s %s w.r.t %s",
+                       vtype2string(vertex->type),
+                       vid2string(vertex, buf, sizeof(buf)),
+                       lfa_protected_resource2str(
+                               &spftree_pc->lfa.protected_resource));
+
+       /* Find PQ node. */
+       rtr_id_pq = rlfa_find_pq_node(spftree_pc, vertex, vertex, NULL);
+       if (!rtr_id_pq) {
+               if (IS_DEBUG_LFA)
+                       zlog_debug("ISIS-LFA: no acceptable PQ node found");
+               return;
+       }
+
+       /* Store valid RLFA and store LDP label for the PQ node. */
+       rlfa = rlfa_add(spftree_old, vertex, *rtr_id_pq);
+
+       /* Register RLFA with LDP. */
+       if (isis_zebra_rlfa_register(spftree_old, rlfa) != 0)
+               rlfa_delete(spftree_old, rlfa);
+}
+
+/**
+ * Compute the Remote LFA backup paths for a given protected interface.
+ *
+ * @param area           IS-IS area
+ * @param spftree        IS-IS SPF tree
+ * @param spftree_reverse IS-IS Reverse SPF tree
+ * @param max_metric     Remote LFA maximum metric
+ * @param resource       Protected resource
+ *
+ * @return               Pointer to the post-convergence SPF tree
+ */
+struct isis_spftree *isis_rlfa_compute(struct isis_area *area,
+                                      struct isis_spftree *spftree,
+                                      struct isis_spftree *spftree_reverse,
+                                      uint32_t max_metric,
+                                      struct lfa_protected_resource *resource)
+{
+       struct isis_spftree *spftree_pc;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: computing remote LFAs for %s",
+                          lfa_protected_resource2str(resource));
+
+       /* Create post-convergence SPF tree. */
+       spftree_pc = isis_spftree_new(area, spftree->lspdb, spftree->sysid,
+                                     spftree->level, spftree->tree_id,
+                                     SPF_TYPE_RLFA, spftree->flags);
+       spftree_pc->lfa.old.spftree = spftree;
+       spftree_pc->lfa.old.spftree_reverse = spftree_reverse;
+       spftree_pc->lfa.remote.max_metric = max_metric;
+       spftree_pc->lfa.protected_resource = *resource;
+
+       /* Compute the extended P-space and Q-space. */
+       lfa_calc_pq_spaces(spftree_pc, resource);
+
+       if (IS_DEBUG_LFA)
+               zlog_debug(
+                       "ISIS-LFA: computing the post convergence SPT w.r.t. %s",
+                       lfa_protected_resource2str(resource));
+
+       /* Re-run SPF in the local node to find the post-convergence paths. */
+       isis_run_spf(spftree_pc);
+
+       return spftree_pc;
+}
+
 /* Calculate the distance from the root node to the given IP destination. */
 static int lfa_calc_dist_destination(struct isis_spftree *spftree,
                                     const struct isis_vertex *vertex_N,
@@ -1451,8 +1941,7 @@ static bool clfa_node_protecting_check(struct isis_spftree *spftree,
 }
 
 static struct list *
-isis_lfa_tiebreakers(struct isis_area *area, struct isis_circuit *circuit,
-                    struct isis_spftree *spftree,
+isis_lfa_tiebreakers(struct isis_area *area, struct isis_spftree *spftree,
                     struct lfa_protected_resource *resource,
                     struct isis_vertex *vertex,
                     struct isis_spf_adj *sadj_primary, struct list *lfa_list)
@@ -1572,6 +2061,10 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
 
        resource->type = LFA_LINK_PROTECTION;
 
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: computing local LFAs for %s",
+                          lfa_protected_resource2str(resource));
+
        for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, vnode, vertex)) {
                struct list *lfa_list;
                struct list *filtered_lfa_list;
@@ -1591,7 +2084,8 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
                                                  resource)) {
                        if (IS_DEBUG_LFA)
                                zlog_debug(
-                                       "ISIS-LFA: route unaffected by %s",
+                                       "ISIS-LFA: %s %s unaffected by %s",
+                                       vtype2string(vertex->type), buf,
                                        lfa_protected_resource2str(resource));
                        continue;
                }
@@ -1697,15 +2191,18 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
 
                if (list_isempty(lfa_list)) {
                        if (IS_DEBUG_LFA)
-                               zlog_debug("ISIS-LFA: no valid LFAs found");
+                               zlog_debug(
+                                       "ISIS-LFA: no valid local LFAs found");
                        list_delete(&lfa_list);
                        continue;
                }
 
+               SET_FLAG(vertex->flags, F_ISIS_VERTEX_LFA_PROTECTED);
+
                /* Check tie-breakers. */
                filtered_lfa_list =
-                       isis_lfa_tiebreakers(area, circuit, spftree, resource,
-                                            vertex, sadj_primary, lfa_list);
+                       isis_lfa_tiebreakers(area, spftree, resource, vertex,
+                                            sadj_primary, lfa_list);
 
                /* Create backup route using the best LFAs. */
                allow_ecmp = area->lfa_load_sharing[level - 1];
@@ -1746,7 +2243,7 @@ static void isis_spf_run_tilfa(struct isis_area *area,
 }
 
 /**
- * Run the LFA/TI-LFA algorithms for all protected interfaces.
+ * Run the LFA/RLFA/TI-LFA algorithms for all protected interfaces.
  *
  * @param area         IS-IS area
  * @param spftree      IS-IS SPF tree
@@ -1756,13 +2253,11 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
        struct isis_spftree *spftree_reverse = NULL;
        struct isis_circuit *circuit;
        struct listnode *node;
-       bool tilfa_configured;
        int level = spftree->level;
 
-       tilfa_configured = (area->tilfa_protected_links[level - 1] > 0);
-
        /* Run reverse SPF locally. */
-       if (tilfa_configured)
+       if (area->rlfa_protected_links[level - 1] > 0
+           || area->tilfa_protected_links[level - 1] > 0)
                spftree_reverse = isis_spf_reverse_run(spftree);
 
        /* Run forward SPF on all adjacent routers. */
@@ -1808,15 +2303,32 @@ void isis_spf_run_lfa(struct isis_area *area, struct isis_spftree *spftree)
                        continue;
                }
 
-               if (circuit->lfa_protection[level - 1])
+               if (circuit->lfa_protection[level - 1]) {
+                       /* Run local LFA. */
                        isis_lfa_compute(area, circuit, spftree, &resource);
-               else if (circuit->tilfa_protection[level - 1]) {
+
+                       if (circuit->rlfa_protection[level - 1]) {
+                               struct isis_spftree *spftree_pc;
+                               uint32_t max_metric;
+
+                               /* Run remote LFA. */
+                               assert(spftree_reverse);
+                               max_metric =
+                                       circuit->rlfa_max_metric[level - 1];
+                               spftree_pc = isis_rlfa_compute(
+                                       area, spftree, spftree_reverse,
+                                       max_metric, &resource);
+                               listnode_add(spftree->lfa.remote.pc_spftrees,
+                                            spftree_pc);
+                       }
+               } else if (circuit->tilfa_protection[level - 1]) {
+                       /* Run TI-LFA. */
                        assert(spftree_reverse);
                        isis_spf_run_tilfa(area, circuit, spftree,
                                           spftree_reverse, &resource);
                }
        }
 
-       if (tilfa_configured)
+       if (spftree_reverse)
                isis_spftree_del(spftree_reverse);
 }
index f09fc663a45a4d2e34e684ab391ed79ff51843ae..65891cae44313e81ed0f56fe1651facb6ca62d55 100644 (file)
 #define _FRR_ISIS_LFA_H
 
 #include "lib/typesafe.h"
+#include "lib/zclient.h"
 
 PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree)
+PREDECL_RBTREE_UNIQ(rlfa_tree)
 
 enum lfa_tiebreaker_type {
        LFA_TIEBREAKER_DOWNSTREAM = 0,
@@ -41,6 +43,15 @@ int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a,
 DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry,
                    lfa_tiebreaker_cmp)
 
+struct rlfa {
+       struct rlfa_tree_item entry;
+       struct prefix prefix;
+       struct isis_vertex *vertex;
+       struct in_addr pq_address;
+};
+int rlfa_cmp(const struct rlfa *a, const struct rlfa *b);
+DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp)
+
 enum isis_tilfa_sid_type {
        TILFA_SID_PREFIX = 1,
        TILFA_SID_ADJ,
@@ -145,6 +156,19 @@ bool isis_lfa_excise_node_check(const struct isis_spftree *spftree,
                                const uint8_t *id);
 struct isis_spftree *isis_spf_reverse_run(const struct isis_spftree *spftree);
 int isis_spf_run_neighbors(struct isis_spftree *spftree);
+int isis_rlfa_activate(struct isis_spftree *spftree, struct rlfa *rlfa,
+                      struct zapi_rlfa_response *response);
+void isis_rlfa_deactivate(struct isis_spftree *spftree, struct rlfa *rlfa);
+void isis_rlfa_list_init(struct isis_spftree *spftree);
+void isis_rlfa_list_clear(struct isis_spftree *spftree);
+void isis_rlfa_process_ldp_response(struct zapi_rlfa_response *response);
+void isis_ldp_rlfa_handle_client_close(struct zapi_client_close_info *info);
+void isis_rlfa_check(struct isis_spftree *spftree, struct isis_vertex *vertex);
+struct isis_spftree *isis_rlfa_compute(struct isis_area *area,
+                                      struct isis_spftree *spftree,
+                                      struct isis_spftree *spftree_reverse,
+                                      uint32_t max_metric,
+                                      struct lfa_protected_resource *resource);
 void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
                      struct isis_spftree *spftree,
                      struct lfa_protected_resource *resource);
index 4576a4a95c9a8f63aabbb4695a96b7d8d017d246..1b04f4f7a0938112ac0e08ee361fdb4f81001c32 100644 (file)
@@ -246,6 +246,8 @@ int main(int argc, char **argv, char **envp)
        access_list_delete_hook(isis_filter_update);
        isis_vrf_init();
        prefix_list_init();
+       prefix_list_add_hook(isis_prefix_list_update);
+       prefix_list_delete_hook(isis_prefix_list_update);
        isis_init();
        isis_circuit_init();
 #ifdef FABRICD
index b63a82f4048e2c3b6299b60a82823f088aae42a8..f716e060cd59828c0185148a54e23e96ef5391cc 100644 (file)
@@ -46,3 +46,4 @@ DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")
 DEFINE_MTYPE(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info")
 DEFINE_MTYPE(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters")
 DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name")
+DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name")
index 3ef1c5bf0bbd23b4f92783284df59979b590d71c..5bcd2a3983528b98e7ae2af8b187fc9103ab5574 100644 (file)
@@ -45,5 +45,6 @@ DECLARE_MTYPE(ISIS_EXT_ROUTE)
 DECLARE_MTYPE(ISIS_EXT_INFO)
 DECLARE_MTYPE(ISIS_MPLS_TE)
 DECLARE_MTYPE(ISIS_ACL_NAME)
+DECLARE_MTYPE(ISIS_PLIST_NAME)
 
 #endif /* _QUAGGA_ISIS_MEMORY_H */
index c3d2f238dd913721d12fe149299fc0854e961916..a02e6a45b183139440a2d1baed04e70b589a2a44 100644 (file)
@@ -484,6 +484,14 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify,
                        }
                },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_remote_lfa_plist,
+                               .modify = isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify,
+                               .destroy = isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing",
                        .cbs = {
@@ -513,6 +521,14 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify,
                        }
                },
+               {
+                       .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list",
+                       .cbs = {
+                               .cli_show = cli_show_isis_frr_remote_lfa_plist,
+                               .modify = isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify,
+                               .destroy = isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-isisd:isis/instance/log-adjacency-changes",
                        .cbs = {
@@ -926,6 +942,20 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .destroy = lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable",
+                       .cbs = {
+                               .modify = lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric",
+                       .cbs = {
+                               .cli_show = cli_show_frr_remote_lfa_max_metric,
+                               .modify = lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify,
+                               .destroy = lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/enable",
                        .cbs = {
@@ -952,6 +982,20 @@ const struct frr_yang_module_info frr_isisd_info = {
                                .destroy = lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable",
+                       .cbs = {
+                               .modify = lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric",
+                       .cbs = {
+                               .cli_show = cli_show_frr_remote_lfa_max_metric,
+                               .modify = lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify,
+                               .destroy = lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable",
                        .cbs = {
index f529f20861d106959555dabe290b5f936650407c..679bc6345dd79b9c267713a11dc39c261564e2ab 100644 (file)
@@ -183,6 +183,10 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy(
        struct nb_cb_destroy_args *args);
 int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
        struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
 int isis_instance_fast_reroute_level_2_lfa_load_sharing_modify(
        struct nb_cb_modify_args *args);
 int isis_instance_fast_reroute_level_2_lfa_priority_limit_modify(
@@ -195,6 +199,10 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy(
        struct nb_cb_destroy_args *args);
 int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
        struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args);
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_destroy(
+       struct nb_cb_destroy_args *args);
 int isis_instance_log_adjacency_changes_modify(struct nb_cb_modify_args *args);
 int isis_instance_mpls_te_create(struct nb_cb_create_args *args);
 int isis_instance_mpls_te_destroy(struct nb_cb_destroy_args *args);
@@ -300,6 +308,12 @@ int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_create(
        struct nb_cb_create_args *args);
 int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy(
        struct nb_cb_destroy_args *args);
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_interface_isis_fast_reroute_level_1_ti_lfa_enable_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_isis_fast_reroute_level_1_ti_lfa_node_protection_modify(
@@ -310,6 +324,12 @@ int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_create(
        struct nb_cb_create_args *args);
 int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy(
        struct nb_cb_destroy_args *args);
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args);
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_interface_isis_fast_reroute_level_2_ti_lfa_enable_modify(
        struct nb_cb_modify_args *args);
 int lib_interface_isis_fast_reroute_level_2_ti_lfa_node_protection_modify(
@@ -467,6 +487,8 @@ void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode,
                                      bool show_defaults);
 void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode,
                                        bool show_defaults);
+void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
 void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode,
                              bool show_defaults);
 void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode,
@@ -503,6 +525,8 @@ void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode,
                          bool show_defaults);
 void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode,
                                        bool show_defaults);
+void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode,
+                                       bool show_defaults);
 void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
                                bool show_defaults);
 void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode,
index 2f7469b1b1a146b0f4c7ca7c5e9bb484fe00aa45..ed0fea88249c846ec03ca87ceb23fa9abc1ff09b 100644 (file)
@@ -28,6 +28,7 @@
 #include "log.h"
 #include "bfd.h"
 #include "filter.h"
+#include "plist.h"
 #include "spf_backoff.h"
 #include "lib_errors.h"
 #include "vrf.h"
@@ -1551,6 +1552,45 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify(
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list
+ */
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *plist_name;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       plist_name = yang_dnode_get_string(args->dnode, NULL);
+
+       area->rlfa_plist_name[0] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name);
+       area->rlfa_plist[0] = prefix_list_lookup(AFI_IP, plist_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_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);
+
+       XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[0]);
+       area->rlfa_plist[0] = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/load-sharing
  */
@@ -1661,6 +1701,45 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify(
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list
+ */
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       const char *plist_name;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       area = nb_running_get_entry(args->dnode, NULL, true);
+       plist_name = yang_dnode_get_string(args->dnode, NULL);
+
+       area->rlfa_plist_name[1] = XSTRDUP(MTYPE_ISIS_PLIST_NAME, plist_name);
+       area->rlfa_plist[1] = prefix_list_lookup(AFI_IP, plist_name);
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_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);
+
+       XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[1]);
+       area->rlfa_plist[1] = NULL;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath: /frr-isisd:isis/instance/log-adjacency-changes
  */
@@ -3446,6 +3525,74 @@ int lib_interface_isis_fast_reroute_level_1_lfa_exclude_interface_destroy(
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/enable
+ */
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_protection[0] = yang_dnode_get_bool(args->dnode, NULL);
+       if (circuit->rlfa_protection[0])
+               circuit->area->rlfa_protected_links[0]++;
+       else {
+               assert(circuit->area->rlfa_protected_links[0] > 0);
+               circuit->area->rlfa_protected_links[0]--;
+       }
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/remote-lfa/maximum-metric
+ */
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[0] = yang_dnode_get_uint32(args->dnode, NULL);
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int lib_interface_isis_fast_reroute_level_1_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[0] = 0;
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-1/ti-lfa/enable
@@ -3569,6 +3716,74 @@ int lib_interface_isis_fast_reroute_level_2_lfa_exclude_interface_destroy(
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/enable
+ */
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_enable_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_protection[1] = yang_dnode_get_bool(args->dnode, NULL);
+       if (circuit->rlfa_protection[1])
+               circuit->area->rlfa_protected_links[1]++;
+       else {
+               assert(circuit->area->rlfa_protected_links[1] > 0);
+               circuit->area->rlfa_protected_links[1]--;
+       }
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/remote-lfa/maximum-metric
+ */
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[1] = yang_dnode_get_uint32(args->dnode, NULL);
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
+int lib_interface_isis_fast_reroute_level_2_remote_lfa_maximum_metric_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       circuit = nb_running_get_entry(args->dnode, NULL, true);
+       circuit->rlfa_max_metric[1] = 0;
+
+       area = circuit->area;
+       lsp_regenerate_schedule(area, area->is_type, 0);
+
+       return NB_OK;
+}
+
 /*
  * XPath:
  * /frr-interface:lib/interface/frr-isisd:isis/fast-reroute/level-2/ti-lfa/enable
index d32f219e98b2d740d19d5f9fa3f12a061c70f0f6..e1baf351f49952a22bad9fb68624c59a91e4784b 100644 (file)
@@ -279,6 +279,22 @@ static bool isis_sr_psid_info_same(struct isis_sr_psid_info *new,
        return true;
 }
 
+static bool isis_label_stack_same(struct mpls_label_stack *new,
+                                 struct mpls_label_stack *old)
+{
+       if (!new && !old)
+               return true;
+       if (!new || !old)
+               return false;
+       if (new->num_labels != old->num_labels)
+               return false;
+       if (memcmp(&new->label, &old->label,
+                  sizeof(mpls_label_t) * new->num_labels))
+               return false;
+
+       return true;
+}
+
 static int isis_route_info_same(struct isis_route_info *new,
                                struct isis_route_info *old, char *buf,
                                size_t buf_size)
@@ -327,6 +343,12 @@ static int isis_route_info_same(struct isis_route_info *new,
                                snprintf(buf, buf_size, "nhop SR label");
                        return 0;
                }
+               if (!isis_label_stack_same(new_nh->label_stack,
+                                          old_nh->label_stack)) {
+                       if (buf)
+                               snprintf(buf, buf_size, "nhop label stack");
+                       return 0;
+               }
        }
 
        /* only the resync flag needs to be checked */
@@ -400,8 +422,8 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
        return route_info;
 }
 
-static void isis_route_delete(struct isis_area *area, struct route_node *rode,
-                             struct route_table *table)
+void isis_route_delete(struct isis_area *area, struct route_node *rode,
+                      struct route_table *table)
 {
        struct isis_route_info *rinfo;
        char buff[SRCDEST2STR_BUFFER];
@@ -466,9 +488,6 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix,
                SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
                UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
        } else {
-               if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
-                       return;
-
                /* Uninstall Prefix-SID label. */
                if (route_info->sr.present)
                        isis_zebra_prefix_sid_uninstall(
@@ -516,6 +535,10 @@ static void _isis_route_verify_table(struct isis_area *area,
                                rinfo->backup = rnode_bck->info;
                                UNSET_FLAG(rinfo->flag,
                                           ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+                       } else if (rinfo->backup) {
+                               rinfo->backup = NULL;
+                               UNSET_FLAG(rinfo->flag,
+                                          ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
                        }
                }
 
@@ -629,6 +652,10 @@ void isis_route_verify_merge(struct isis_area *area,
                                rinfo->backup = rnode_bck->info;
                                UNSET_FLAG(rinfo->flag,
                                           ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+                       } else if (rinfo->backup) {
+                               rinfo->backup = NULL;
+                               UNSET_FLAG(rinfo->flag,
+                                          ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
                        }
 
                        mrnode = srcdest_rnode_get(merge, prefix, src_p);
index 0d4f8849590fd08a5a95d0b2e626640481030a6f..d6763ec76c10e267ac3494aed32930eeae7b9e31 100644 (file)
@@ -63,6 +63,8 @@ isis_route_create(struct prefix *prefix, struct prefix_ipv6 *src_p,
                  uint32_t cost, uint32_t depth, struct isis_sr_psid_info *sr,
                  struct list *adjacencies, bool allow_ecmp,
                  struct isis_area *area, struct route_table *table);
+void isis_route_delete(struct isis_area *area, struct route_node *rode,
+                      struct route_table *table);
 
 /* Walk the given table and install new routes to zebra and remove old ones.
  * route status is tracked using ISIS_ROUTE_FLAG_ACTIVE */
index 57b1d66c226b28624d2106b06010b1fcdb5322ca..dee082fce1e9df4fb13c8bb8031092aef2f82ce0 100644 (file)
@@ -56,6 +56,7 @@
 #include "isis_csm.h"
 #include "isis_mt.h"
 #include "isis_tlvs.h"
+#include "isis_zebra.h"
 #include "fabricd.h"
 #include "isis_spf_private.h"
 
@@ -354,7 +355,10 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area,
        tree->tree_id = tree_id;
        tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6;
        tree->flags = flags;
-       if (tree->type == SPF_TYPE_TI_LFA) {
+       isis_rlfa_list_init(tree);
+       tree->lfa.remote.pc_spftrees = list_new();
+       tree->lfa.remote.pc_spftrees->del = (void (*)(void *))isis_spftree_del;
+       if (tree->type == SPF_TYPE_RLFA || tree->type == SPF_TYPE_TI_LFA) {
                isis_spf_node_list_init(&tree->lfa.p_space);
                isis_spf_node_list_init(&tree->lfa.q_space);
        }
@@ -366,7 +370,11 @@ void isis_spftree_del(struct isis_spftree *spftree)
 {
        hash_clean(spftree->prefix_sids, NULL);
        hash_free(spftree->prefix_sids);
-       if (spftree->type == SPF_TYPE_TI_LFA) {
+       isis_zebra_rlfa_unregister_all(spftree);
+       isis_rlfa_list_clear(spftree);
+       list_delete(&spftree->lfa.remote.pc_spftrees);
+       if (spftree->type == SPF_TYPE_RLFA
+           || spftree->type == SPF_TYPE_TI_LFA) {
                isis_spf_node_list_clear(&spftree->lfa.q_space);
                isis_spf_node_list_clear(&spftree->lfa.p_space);
        }
@@ -820,7 +828,8 @@ lspfragloop:
 #endif /* EXTREME_DEBUG */
 
        if (no_overload) {
-               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
+               if ((pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                   && spftree->area->oldmetric) {
                        struct isis_oldstyle_reach *r;
                        for (r = (struct isis_oldstyle_reach *)
                                         lsp->tlvs->oldstyle_reach.head;
@@ -848,42 +857,47 @@ lspfragloop:
                        }
                }
 
-               struct isis_item_list *te_neighs = NULL;
-               if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
-                       te_neighs = &lsp->tlvs->extended_reach;
-               else
-                       te_neighs = isis_lookup_mt_items(&lsp->tlvs->mt_reach,
-                                                        spftree->mtid);
-
-               struct isis_extended_reach *er;
-               for (er = te_neighs
-                                 ? (struct isis_extended_reach *)
-                                           te_neighs->head
-                                 : NULL;
-                    er; er = er->next) {
-                       /* C.2.6 a) */
-                       /* Two way connectivity */
-                       if (!LSP_PSEUDO_ID(er->id)
-                           && !memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
-                               continue;
-                       if (!pseudo_lsp
-                           && !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
-                               continue;
-                       dist = cost
-                              + (CHECK_FLAG(spftree->flags,
-                                            F_SPFTREE_HOPCOUNT_METRIC)
-                                         ? 1
-                                         : er->metric);
-                       process_N(spftree,
-                                 LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
-                                                       : VTYPE_NONPSEUDO_TE_IS,
-                                 (void *)er->id, dist, depth + 1, NULL,
-                                 parent);
+               if (spftree->area->newmetric) {
+                       struct isis_item_list *te_neighs = NULL;
+                       if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+                               te_neighs = &lsp->tlvs->extended_reach;
+                       else
+                               te_neighs = isis_lookup_mt_items(
+                                       &lsp->tlvs->mt_reach, spftree->mtid);
+
+                       struct isis_extended_reach *er;
+                       for (er = te_neighs ? (struct isis_extended_reach *)
+                                                     te_neighs->head
+                                           : NULL;
+                            er; er = er->next) {
+                               /* C.2.6 a) */
+                               /* Two way connectivity */
+                               if (!LSP_PSEUDO_ID(er->id)
+                                   && !memcmp(er->id, root_sysid,
+                                              ISIS_SYS_ID_LEN))
+                                       continue;
+                               if (!pseudo_lsp
+                                   && !memcmp(er->id, null_sysid,
+                                              ISIS_SYS_ID_LEN))
+                                       continue;
+                               dist = cost
+                                      + (CHECK_FLAG(spftree->flags,
+                                                    F_SPFTREE_HOPCOUNT_METRIC)
+                                                 ? 1
+                                                 : er->metric);
+                               process_N(spftree,
+                                         LSP_PSEUDO_ID(er->id)
+                                                 ? VTYPE_PSEUDO_TE_IS
+                                                 : VTYPE_NONPSEUDO_TE_IS,
+                                         (void *)er->id, dist, depth + 1, NULL,
+                                         parent);
+                       }
                }
        }
 
        if (!fabricd && !pseudo_lsp && spftree->family == AF_INET
-           && spftree->mtid == ISIS_MT_IPV4_UNICAST) {
+           && spftree->mtid == ISIS_MT_IPV4_UNICAST
+           && spftree->area->oldmetric) {
                struct isis_item_list *reachs[] = {
                        &lsp->tlvs->oldstyle_ip_reach,
                        &lsp->tlvs->oldstyle_ip_reach_ext};
@@ -908,6 +922,10 @@ lspfragloop:
                }
        }
 
+       /* we can skip all the rest if we're using metric style narrow */
+       if (!spftree->area->newmetric)
+               goto end;
+
        if (!pseudo_lsp && spftree->family == AF_INET) {
                struct isis_item_list *ipv4_reachs;
                if (spftree->mtid == ISIS_MT_IPV4_UNICAST)
@@ -1027,6 +1045,7 @@ lspfragloop:
                }
        }
 
+end:
        if (fragnode == NULL)
                fragnode = listhead(lsp->lspu.frags);
        else
@@ -1429,6 +1448,9 @@ static void init_spt(struct isis_spftree *spftree, int mtid)
        list_delete_all_node(spftree->sadj_list);
        isis_vertex_queue_clear(&spftree->tents);
        isis_vertex_queue_clear(&spftree->paths);
+       isis_zebra_rlfa_unregister_all(spftree);
+       isis_rlfa_list_clear(spftree);
+       list_delete_all_node(spftree->lfa.remote.pc_spftrees);
        memset(&spftree->lfa.protection_counters, 0,
               sizeof(spftree->lfa.protection_counters));
 
@@ -1502,12 +1524,13 @@ static void spf_path_process(struct isis_spftree *spftree,
                priority = spf_prefix_priority(spftree, vertex);
                vertex->N.ip.priority = priority;
                if (vertex->depth == 1 || listcount(vertex->Adj_N) > 0) {
+                       struct isis_spftree *pre_spftree;
                        struct route_table *route_table;
                        bool allow_ecmp;
 
-                       if (spftree->type == SPF_TYPE_TI_LFA) {
-                               struct isis_spftree *pre_spftree;
-
+                       switch (spftree->type) {
+                       case SPF_TYPE_RLFA:
+                       case SPF_TYPE_TI_LFA:
                                if (priority
                                    > area->lfa_priority_limit[level - 1]) {
                                        if (IS_DEBUG_LFA)
@@ -1520,7 +1543,16 @@ static void spf_path_process(struct isis_spftree *spftree,
                                                                sizeof(buff)));
                                        return;
                                }
+                               break;
+                       default:
+                               break;
+                       }
 
+                       switch (spftree->type) {
+                       case SPF_TYPE_RLFA:
+                               isis_rlfa_check(spftree, vertex);
+                               return;
+                       case SPF_TYPE_TI_LFA:
                                if (isis_tilfa_check(spftree, vertex) != 0)
                                        return;
 
@@ -1529,7 +1561,8 @@ static void spf_path_process(struct isis_spftree *spftree,
                                allow_ecmp = area->lfa_load_sharing[level - 1];
                                pre_spftree->lfa.protection_counters
                                        .tilfa[vertex->N.ip.priority] += 1;
-                       } else {
+                               break;
+                       default:
                                route_table = spftree->route_table;
                                allow_ecmp = true;
 
@@ -1544,6 +1577,7 @@ static void spf_path_process(struct isis_spftree *spftree,
                                                spftree->lfa.protection_counters
                                                        .ecmp[priority] += 1;
                                }
+                               break;
                        }
 
                        isis_route_create(
@@ -1834,6 +1868,7 @@ int _isis_spf_schedule(struct isis_area *area, int level,
                        area->area_tag, level, diff, func, file, line);
        }
 
+       thread_cancel(&area->t_rlfa_rib_update);
        if (area->spf_delay_ietf[level - 1]) {
                /* Need to call schedule function also if spf delay is running
                 * to
index 5b6fcdaf6875ebb55630d8600a2b41ee21959d06..5b3aa593799bf347d609dd471bf96d82fc681f73 100644 (file)
@@ -31,6 +31,7 @@ struct isis_spftree;
 enum spf_type {
        SPF_TYPE_FORWARD = 1,
        SPF_TYPE_REVERSE,
+       SPF_TYPE_RLFA,
        SPF_TYPE_TI_LFA,
 };
 
index b7f326ca864692cf8477f2d5d09b73a25ebb3aa0..79dfa3e164be09412598d9bb86a1423d096f7267 100644 (file)
@@ -76,7 +76,9 @@ struct isis_vertex {
        struct list *parents;  /* list of parents for ECMP */
        struct hash *firsthops; /* first two hops to neighbor */
        uint64_t insert_counter;
+       uint8_t flags;
 };
+#define F_ISIS_VERTEX_LFA_PROTECTED    0x01
 
 /* Vertex Queue and associated functions */
 
@@ -349,6 +351,21 @@ struct isis_spftree {
                struct isis_spf_nodes p_space;
                struct isis_spf_nodes q_space;
 
+               /* Remote LFA related information. */
+               struct {
+                       /* List of RLFAs eligible to be installed. */
+                       struct rlfa_tree_head rlfas;
+
+                       /*
+                        * RLFA post-convergence SPTs (needed to activate RLFAs
+                        * once label information is received from LDP).
+                        */
+                       struct list *pc_spftrees;
+
+                       /* RLFA maximum metric (or zero if absent). */
+                       uint32_t max_metric;
+               } remote;
+
                /* Protection counters. */
                struct {
                        uint32_t lfa[SPF_PREFIX_PRIO_MAX];
index f08737c2c1a0b5b7fcae74add9435be4fc26b624..703532234ab55a0ffc1a7da93347e1a484b144d9 100644 (file)
@@ -47,6 +47,8 @@
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_lsp.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_spf_private.h"
 #include "isisd/isis_route.h"
 #include "isisd/isis_zebra.h"
 #include "isisd/isis_adjacency.h"
@@ -540,6 +542,72 @@ void isis_zebra_redistribute_unset(afi_t afi, int type)
                                     type, 0, VRF_DEFAULT);
 }
 
+/**
+ * Register RLFA with LDP.
+ */
+int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa)
+{
+       struct isis_area *area = spftree->area;
+       struct zapi_rlfa_request zr = {};
+       int ret;
+
+       if (!zclient)
+               return 0;
+
+       zr.igp.vrf_id = area->isis->vrf_id;
+       zr.igp.protocol = ZEBRA_ROUTE_ISIS;
+       strlcpy(zr.igp.isis.area_tag, area->area_tag,
+               sizeof(zr.igp.isis.area_tag));
+       zr.igp.isis.spf.tree_id = spftree->tree_id;
+       zr.igp.isis.spf.level = spftree->level;
+       zr.igp.isis.spf.run_id = spftree->runcount;
+       zr.destination = rlfa->prefix;
+       zr.pq_address = rlfa->pq_address;
+
+       zlog_debug("ISIS-LFA: registering RLFA %pFX@%pI4 with LDP",
+                  &rlfa->prefix, &rlfa->pq_address);
+
+       ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_REGISTER,
+                                         ZEBRA_ROUTE_LDP, 0, 0,
+                                         (const uint8_t *)&zr, sizeof(zr));
+       if (ret == ZCLIENT_SEND_FAILURE) {
+               zlog_warn("ISIS-LFA: failed to register RLFA with LDP");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * Unregister all RLFAs from the given SPF tree with LDP.
+ */
+void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree)
+{
+       struct isis_area *area = spftree->area;
+       struct zapi_rlfa_igp igp = {};
+       int ret;
+
+       if (!zclient || spftree->type != SPF_TYPE_FORWARD
+           || CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+               return;
+
+       if (IS_DEBUG_LFA)
+               zlog_debug("ISIS-LFA: unregistering all RLFAs with LDP");
+
+       igp.vrf_id = area->isis->vrf_id;
+       igp.protocol = ZEBRA_ROUTE_ISIS;
+       strlcpy(igp.isis.area_tag, area->area_tag, sizeof(igp.isis.area_tag));
+       igp.isis.spf.tree_id = spftree->tree_id;
+       igp.isis.spf.level = spftree->level;
+       igp.isis.spf.run_id = spftree->runcount;
+
+       ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_UNREGISTER_ALL,
+                                         ZEBRA_ROUTE_LDP, 0, 0,
+                                         (const uint8_t *)&igp, sizeof(igp));
+       if (ret == ZCLIENT_SEND_FAILURE)
+               zlog_warn("ISIS-LFA: failed to unregister RLFA with LDP");
+}
+
 /* Label Manager Functions */
 
 /**
@@ -659,6 +727,7 @@ void isis_zebra_vrf_register(struct isis *isis)
 static void isis_zebra_connected(struct zclient *zclient)
 {
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
+       zclient_register_opaque(zclient, LDP_RLFA_LABELS);
 }
 
 /*
@@ -670,6 +739,7 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
        struct zapi_opaque_msg info;
        struct ldp_igp_sync_if_state state;
        struct ldp_igp_sync_announce announce;
+       struct zapi_rlfa_response rlfa;
        int ret = 0;
 
        s = zclient->ibuf;
@@ -685,6 +755,10 @@ static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
                STREAM_GET(&announce, s, sizeof(announce));
                ret = isis_ldp_sync_announce_update(announce);
                break;
+       case LDP_RLFA_LABELS:
+               STREAM_GET(&rlfa, s, sizeof(rlfa));
+               isis_rlfa_process_ldp_response(&rlfa);
+               break;
        default:
                break;
        }
@@ -704,6 +778,7 @@ static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
                return -1;
 
        isis_ldp_sync_handle_client_close(&info);
+       isis_ldp_rlfa_handle_client_close(&info);
 
        return ret;
 }
@@ -742,6 +817,7 @@ void isis_zebra_init(struct thread_master *master, int instance)
 
 void isis_zebra_stop(void)
 {
+       zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
        zclient_stop(zclient_sync);
        zclient_free(zclient_sync);
        zclient_stop(zclient);
index c5c52a6bc6bd262deca9944cd3108d0e86bef968..b44ec4f085484708d00ff670c29ee507237efd9a 100644 (file)
@@ -59,6 +59,8 @@ void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
 int isis_distribute_list_update(int routetype);
 void isis_zebra_redistribute_set(afi_t afi, int type);
 void isis_zebra_redistribute_unset(afi_t afi, int type);
+int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa);
+void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree);
 bool isis_zebra_label_manager_ready(void);
 int isis_zebra_label_manager_connect(void);
 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
index 827e022bafd063ac547a6c2ee08d687449ef9ab0..eabebab4e000c3bc2b4bf5611ce88a6b987bc0b8 100644 (file)
@@ -32,6 +32,7 @@
 #include "if.h"
 #include "hash.h"
 #include "filter.h"
+#include "plist.h"
 #include "stream.h"
 #include "prefix.h"
 #include "table.h"
@@ -485,6 +486,7 @@ void isis_area_destroy(struct isis_area *area)
        thread_cancel(&area->t_tick);
        thread_cancel(&area->t_lsp_refresh[0]);
        thread_cancel(&area->t_lsp_refresh[1]);
+       thread_cancel(&area->t_rlfa_rib_update);
 
        thread_cancel_event(master, area);
 
@@ -649,6 +651,34 @@ void isis_filter_update(struct access_list *access)
        }
 }
 
+void isis_prefix_list_update(struct prefix_list *plist)
+{
+       struct isis *isis;
+       struct isis_area *area;
+       struct listnode *node, *anode;
+
+       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+               for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+                       for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+                            level++) {
+                               const char *plist_name =
+                                       prefix_list_name(plist);
+
+                               if (!area->rlfa_plist_name[level - 1])
+                                       continue;
+
+                               if (!strmatch(area->rlfa_plist_name[level - 1],
+                                             plist_name))
+                                       continue;
+
+                               area->rlfa_plist[level - 1] =
+                                       prefix_list_lookup(AFI_IP, plist_name);
+                               lsp_regenerate_schedule(area, area->is_type, 0);
+                       }
+               }
+       }
+}
+
 #ifdef FABRICD
 static void area_set_mt_enabled(struct isis_area *area, uint16_t mtid,
                                bool enabled)
index 4618d14af3db0580189fdf1eb7df8f9ffa5ac06c..9b903eed48098be08b8d638fbfa855fee46420c6 100644 (file)
@@ -131,6 +131,7 @@ struct isis_area {
        struct thread *t_tick; /* LSP walker */
        struct thread *t_lsp_refresh[ISIS_LEVELS];
        struct timeval last_lsp_refresh_event[ISIS_LEVELS];
+       struct thread *t_rlfa_rib_update;
        /* t_lsp_refresh is used in two ways:
         * a) regular refresh of LSPs
         * b) (possibly throttled) updates to LSPs
@@ -197,6 +198,9 @@ struct isis_area {
        size_t lfa_load_sharing[ISIS_LEVELS];
        enum spf_prefix_priority lfa_priority_limit[ISIS_LEVELS];
        struct lfa_tiebreaker_tree_head lfa_tiebreakers[ISIS_LEVELS];
+       char *rlfa_plist_name[ISIS_LEVELS];
+       struct prefix_list *rlfa_plist[ISIS_LEVELS];
+       size_t rlfa_protected_links[ISIS_LEVELS];
        size_t tilfa_protected_links[ISIS_LEVELS];
        /* Counters */
        uint32_t circuit_state_changes;
@@ -240,6 +244,7 @@ struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
 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);
+void isis_prefix_list_update(struct prefix_list *plist);
 void print_debug(struct vty *, int, int);
 struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
                             struct isis *isis);
index 795a41491cd4fe9ade5f0093f46695104e6d4538..d390e70ad0d0cd8b9d794e683557173d41633444 100644 (file)
@@ -183,7 +183,8 @@ adj_itimer(struct thread *thread)
 
        if (adj->source.type == HELLO_TARGETED) {
                if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
-                   adj->source.target->pw_count == 0) {
+                   adj->source.target->pw_count == 0 &&
+                   adj->source.target->rlfa_count == 0) {
                        /* remove dynamic targeted neighbor */
                        tnbr_del(leconf, adj->source.target);
                        return (0);
@@ -259,7 +260,7 @@ struct tnbr *
 tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
 {
        if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
-           tnbr->pw_count == 0) {
+           tnbr->pw_count == 0 && tnbr->rlfa_count == 0) {
                tnbr_del(xconf, tnbr);
                return (NULL);
        }
index 327cb32434afb0578a7999babf341ba3ed7d92a9..5aa14ed067f9b0d1a0e8009e59651767f5265ade 100644 (file)
@@ -67,7 +67,8 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
                af = tnbr->af;
                holdtime = tnbr_get_hello_holdtime(tnbr);
                flags = F_HELLO_TARGETED;
-               if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
+               if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count
+                   || tnbr->rlfa_count)
                        flags |= F_HELLO_REQ_TARG;
                fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
 
index 5ed0ed4520dc668d0660b732d3396b847e02c1e7..69338b8bad6a407d93ce19b428c0bdc1dc3de010 100644 (file)
@@ -27,6 +27,7 @@
 #include "log.h"
 #include "lde.h"
 #include "ldp_debug.h"
+#include "rlfa.h"
 
 #include <lib/log.h>
 #include "memory.h"
@@ -444,6 +445,10 @@ lde_dispatch_parent(struct thread *thread)
        int                      shut = 0;
        struct fec               fec;
        struct ldp_access       *laccess;
+       struct ldp_rlfa_node     *rnode, *rntmp;
+       struct ldp_rlfa_client   *rclient;
+       struct zapi_rlfa_request *rlfa_req;
+       struct zapi_rlfa_igp     *rlfa_igp;
 
        iev->ev_read = NULL;
 
@@ -650,6 +655,42 @@ lde_dispatch_parent(struct thread *thread)
                        lde_check_filter_af(AF_INET6, &ldeconf->ipv6,
                                laccess->name);
                        break;
+               case IMSG_RLFA_REG:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_request)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_req = imsg.data;
+                       rnode = rlfa_node_find(&rlfa_req->destination,
+                                              rlfa_req->pq_address);
+                       if (!rnode)
+                               rnode = rlfa_node_new(&rlfa_req->destination,
+                                                     rlfa_req->pq_address);
+                       rclient = rlfa_client_find(rnode, &rlfa_req->igp);
+                       if (rclient)
+                               /* RLFA already registered - do nothing */
+                               break;
+                       rclient = rlfa_client_new(rnode, &rlfa_req->igp);
+                       lde_rlfa_check(rclient);
+                       break;
+               case IMSG_RLFA_UNREG_ALL:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_igp)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_igp = imsg.data;
+
+                       RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
+                                        &rlfa_node_tree, rntmp) {
+                               rclient = rlfa_client_find(rnode, rlfa_igp);
+                               if (!rclient)
+                                       continue;
+
+                               rlfa_client_del(rclient);
+                       }
+                       break;
                default:
                        log_debug("%s: unexpected imsg %d", __func__,
                            imsg.hdr.type);
@@ -875,6 +916,48 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh)
        }
 }
 
+void
+lde_fec2prefix(const struct fec *fec, struct prefix *prefix)
+{
+       memset(prefix, 0, sizeof(*prefix));
+       switch (fec->type) {
+       case FEC_TYPE_IPV4:
+               prefix->family = AF_INET;
+               prefix->u.prefix4 = fec->u.ipv4.prefix;
+               prefix->prefixlen = fec->u.ipv4.prefixlen;
+               break;
+       case FEC_TYPE_IPV6:
+               prefix->family = AF_INET6;
+               prefix->u.prefix6 = fec->u.ipv6.prefix;
+               prefix->prefixlen = fec->u.ipv6.prefixlen;
+               break;
+       default:
+               prefix->family = AF_UNSPEC;
+               break;
+       }
+}
+
+void
+lde_prefix2fec(const struct prefix *prefix, struct fec *fec)
+{
+       memset(fec, 0, sizeof(*fec));
+       switch (prefix->family) {
+       case AF_INET:
+               fec->type = FEC_TYPE_IPV4;
+               fec->u.ipv4.prefix = prefix->u.prefix4;
+               fec->u.ipv4.prefixlen = prefix->prefixlen;
+               break;
+       case AF_INET6:
+               fec->type = FEC_TYPE_IPV6;
+               fec->u.ipv6.prefix = prefix->u.prefix6;
+               fec->u.ipv6.prefixlen = prefix->prefixlen;
+               break;
+       default:
+               fatalx("lde_prefix2fec: unknown af");
+               break;
+       }
+}
+
 void
 lde_fec2map(struct fec *fec, struct map *map)
 {
@@ -1388,6 +1471,9 @@ lde_nbr_del(struct lde_nbr *ln)
        RB_FOREACH(f, fec_tree, &ft) {
                fn = (struct fec_node *)f;
 
+               /* Update RLFA clients. */
+               lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
+
                LIST_FOREACH(fnh, &fn->nexthops, entry) {
                        switch (f->type) {
                        case FEC_TYPE_IPV4:
index 660aeafb34bf309f5a851252dd9252275c3144d2..28468931ec625d9129e8a82f01728bcc10ad9dd7 100644 (file)
@@ -129,7 +129,9 @@ struct fec_node {
        uint32_t                 pw_remote_status;
 
        void                    *data;          /* fec specific data */
+       uint8_t                  flags;
 };
+#define F_FEC_NHS_CHANGED      0x01
 
 #define CHUNK_SIZE             64
 struct label_chunk {
@@ -156,6 +158,8 @@ uint32_t     lde_update_label(struct fec_node *);
 void            lde_free_label(uint32_t label);
 void            lde_send_change_klabel(struct fec_node *, struct fec_nh *);
 void            lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
+void            lde_fec2prefix(const struct fec *fec, struct prefix *prefix);
+void            lde_prefix2fec(const struct prefix *prefix, struct fec *fec);
 void            lde_fec2map(struct fec *, struct map *);
 void            lde_map2fec(struct map *, struct in_addr, struct fec *);
 void            lde_send_labelmapping(struct lde_nbr *, struct fec_node *,
index 9db931677dc38072639150dc7dc4919d436cfbe4..68b721e2133e449ffbf9fee976e3e15508066450 100644 (file)
@@ -23,6 +23,7 @@
 #include "ldpe.h"
 #include "lde.h"
 #include "log.h"
+#include "rlfa.h"
 
 #include "mpls.h"
 
@@ -339,6 +340,8 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
 
        fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
        if (fnh == NULL) {
+               fn->flags |= F_FEC_NHS_CHANGED;
+
                fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
                    route_instance);
                /*
@@ -415,11 +418,17 @@ lde_kernel_update(struct fec *fec)
                        } else
                                fnh->flags |= F_FEC_NH_NO_LDP;
                } else {
+                       fn->flags |= F_FEC_NHS_CHANGED;
                        lde_send_delete_klabel(fn, fnh);
                        fec_nh_del(fnh);
                }
        }
 
+       if (!(fn->flags & F_FEC_NHS_CHANGED))
+               /* return earlier if nothing has changed */
+               return;
+       fn->flags &= ~F_FEC_NHS_CHANGED;
+
        if (LIST_EMPTY(&fn->nexthops)) {
                RB_FOREACH(ln, nbr_tree, &lde_nbrs)
                        lde_send_labelwithdraw(ln, fn, NULL, NULL);
@@ -601,6 +610,10 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
                        break;
                }
        }
+
+       /* Update RLFA clients. */
+       lde_rlfa_update_clients(&fec, ln, map->label);
+
        /* LMp.13 & LMp.16: Record the mapping from this peer */
        if (me == NULL)
                me = lde_map_add(ln, fn, 0);
@@ -858,6 +871,9 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln)
                fnh->remote_label = NO_LABEL;
        }
 
+       /* Update RLFA clients. */
+       lde_rlfa_update_clients(&fec, ln, MPLS_INVALID_LABEL);
+
        /* LWd.2: send label release */
        lde_send_labelrelease(ln, fn, NULL, map->label);
 
@@ -940,6 +956,9 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
                        fnh->remote_label = NO_LABEL;
                }
 
+               /* Update RLFA clients. */
+               lde_rlfa_update_clients(f, ln, MPLS_INVALID_LABEL);
+
                /* LWd.3: check previously received label mapping */
                if (me && (map->label == NO_LABEL ||
                    map->label == me->map.label))
index a53854fa56d4b304d7dc8e5d682bcc889d5b8ed8..ea86c2dc039c40fbc474718066d7689e6dc7b8c8 100644 (file)
@@ -114,12 +114,16 @@ static void
 ldp_zebra_opaque_register(void)
 {
        zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+       zclient_register_opaque(zclient, LDP_RLFA_REGISTER);
+       zclient_register_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
 }
 
 static void
 ldp_zebra_opaque_unregister(void)
 {
        zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+       zclient_unregister_opaque(zclient, LDP_RLFA_REGISTER);
+       zclient_unregister_opaque(zclient, LDP_RLFA_UNREGISTER_ALL);
 }
 
 int
@@ -147,12 +151,29 @@ ldp_sync_zebra_send_announce(void)
                return 0;
 }
 
+int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *rlfa_labels)
+{
+       int ret;
+
+       ret = zclient_send_opaque(zclient, LDP_RLFA_LABELS,
+                                 (const uint8_t *)rlfa_labels,
+                                 sizeof(*rlfa_labels));
+       if (ret == ZCLIENT_SEND_FAILURE) {
+               log_warn("failed to send RLFA labels to IGP");
+               return -1;
+       }
+
+       return 0;
+}
+
 static int
 ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
 {
        struct stream *s;
        struct zapi_opaque_msg info;
        struct ldp_igp_sync_if_state_req state_req;
+       struct zapi_rlfa_igp igp;
+       struct zapi_rlfa_request rlfa;
 
         s = zclient->ibuf;
 
@@ -165,6 +186,14 @@ ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
                main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req,
                            sizeof(state_req));
                break;
+       case LDP_RLFA_REGISTER:
+               STREAM_GET(&rlfa, s, sizeof(rlfa));
+               main_imsg_compose_both(IMSG_RLFA_REG, &rlfa, sizeof(rlfa));
+               break;
+       case LDP_RLFA_UNREGISTER_ALL:
+               STREAM_GET(&igp, s, sizeof(igp));
+               main_imsg_compose_both(IMSG_RLFA_UNREG_ALL, &igp, sizeof(igp));
+               break;
        default:
                break;
        }
index d6da45c8624ab9b71ae7ea2a819b1353fc2ad717..83e93ebbbc52715295bfd53700088f0a28d44d36 100644 (file)
@@ -625,6 +625,7 @@ main_dispatch_lde(struct thread *thread)
        struct imsg      imsg;
        ssize_t          n;
        int              shut = 0;
+       struct zapi_rlfa_response *rlfa_labels;
 
        iev->ev_read = NULL;
 
@@ -691,6 +692,15 @@ main_dispatch_lde(struct thread *thread)
                                fatalx("IMSG_ACL_CHECK imsg with wrong len");
                        ldp_acl_reply(iev, (struct acl_check *)imsg.data);
                        break;
+               case IMSG_RLFA_LABELS:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_response)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_labels = imsg.data;
+                       ldp_zebra_send_rlfa_labels(rlfa_labels);
+                       break;
                default:
                        log_debug("%s: error handling imsg %d", __func__,
                            imsg.hdr.type);
index f8a94b4e2a50d08d651a6210966ab0109149d8f7..beb625d8a26bf08133c8ea573e8d9479afb1b7ec 100644 (file)
@@ -157,7 +157,10 @@ enum imsg_type {
        IMSG_FILTER_UPDATE,
        IMSG_NBR_SHUTDOWN,
        IMSG_LDP_SYNC_IF_STATE_REQUEST,
-       IMSG_LDP_SYNC_IF_STATE_UPDATE
+       IMSG_LDP_SYNC_IF_STATE_UPDATE,
+       IMSG_RLFA_REG,
+       IMSG_RLFA_UNREG_ALL,
+       IMSG_RLFA_LABELS,
 };
 
 struct ldpd_init {
@@ -373,6 +376,7 @@ struct tnbr {
        union ldpd_addr          addr;
        int                      state;
        uint16_t                 pw_count;
+       uint32_t                 rlfa_count;
        uint8_t                  flags;
        QOBJ_FIELDS
 };
@@ -875,6 +879,8 @@ extern char                  ctl_sock_path[MAXPATHLEN];
 void            ldp_zebra_init(struct thread_master *);
 void            ldp_zebra_destroy(void);
 int             ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *);
+int             ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *
+                   rlfa_labels);
 
 /* compatibility */
 #ifndef __OpenBSD__
index f3f8b8510257bad73365ad83c2dec713c35ba3ca..6a5a0750bd007f2cc281ea33c4ca80f44b064ae2 100644 (file)
@@ -27,6 +27,7 @@
 #include "control.h"
 #include "log.h"
 #include "ldp_debug.h"
+#include "rlfa.h"
 
 #include <lib/log.h>
 #include "memory.h"
@@ -298,7 +299,11 @@ ldpe_dispatch_main(struct thread *thread)
        int                      n, shut = 0;
        struct ldp_access       *laccess;
        struct ldp_igp_sync_if_state_req *ldp_sync_if_state_req;
-       
+       struct ldp_rlfa_node     *rnode, *rntmp;
+       struct ldp_rlfa_client   *rclient;
+       struct zapi_rlfa_request *rlfa_req;
+       struct zapi_rlfa_igp     *rlfa_igp;
+
        iev->ev_read = NULL;
 
        if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
@@ -569,6 +574,44 @@ ldpe_dispatch_main(struct thread *thread)
                        ldp_sync_if_state_req = imsg.data;
                        ldp_sync_fsm_state_req(ldp_sync_if_state_req);
                        break;
+               case IMSG_RLFA_REG:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_request)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_req = imsg.data;
+
+                       rnode = rlfa_node_find(&rlfa_req->destination,
+                                              rlfa_req->pq_address);
+                       if (!rnode)
+                               rnode = rlfa_node_new(&rlfa_req->destination,
+                                                     rlfa_req->pq_address);
+                       rclient = rlfa_client_find(rnode, &rlfa_req->igp);
+                       if (rclient)
+                               /* RLFA already registered - do nothing */
+                               break;
+                       rclient = rlfa_client_new(rnode, &rlfa_req->igp);
+                       ldpe_rlfa_init(rclient);
+                       break;
+               case IMSG_RLFA_UNREG_ALL:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE +
+                           sizeof(struct zapi_rlfa_igp)) {
+                               log_warnx("%s: wrong imsg len", __func__);
+                               break;
+                       }
+                       rlfa_igp = imsg.data;
+
+                       RB_FOREACH_SAFE (rnode, ldp_rlfa_node_head,
+                                        &rlfa_node_tree, rntmp) {
+                               rclient = rlfa_client_find(rnode, rlfa_igp);
+                               if (!rclient)
+                                       continue;
+
+                               ldpe_rlfa_exit(rclient);
+                               rlfa_client_del(rclient);
+                       }
+                       break;
                default:
                        log_debug("ldpe_dispatch_main: error handling imsg %d",
                            imsg.hdr.type);
diff --git a/ldpd/rlfa.c b/ldpd/rlfa.c
new file mode 100644 (file)
index 0000000..697ec08
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2020  NetDEF, Inc.
+ *                     Renato Westphal
+ *
+ * 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 <zebra.h>
+
+#include "ldpd.h"
+#include "lde.h"
+#include "ldpe.h"
+#include "log.h"
+#include "ldp_debug.h"
+#include "rlfa.h"
+
+#include <lib/log.h>
+
+struct ldp_rlfa_node_head rlfa_node_tree;
+
+static int ldp_rlfa_client_compare(const struct ldp_rlfa_client *a,
+                                  const struct ldp_rlfa_client *b)
+{
+       if (a->igp.vrf_id < b->igp.vrf_id)
+               return -1;
+       if (a->igp.vrf_id > b->igp.vrf_id)
+               return 1;
+
+       if (a->igp.protocol < b->igp.protocol)
+               return -1;
+       if (a->igp.protocol > b->igp.protocol)
+               return 1;
+
+       if (a->igp.isis.spf.tree_id < b->igp.isis.spf.tree_id)
+               return -1;
+       if (a->igp.isis.spf.tree_id > b->igp.isis.spf.tree_id)
+               return 1;
+
+       if (a->igp.isis.spf.level < b->igp.isis.spf.level)
+               return -1;
+       if (a->igp.isis.spf.level > b->igp.isis.spf.level)
+               return 1;
+
+       return 0;
+}
+RB_GENERATE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
+           ldp_rlfa_client_compare)
+
+static int ldp_rlfa_node_compare(const struct ldp_rlfa_node *a,
+                                const struct ldp_rlfa_node *b)
+{
+       if (ntohl(a->pq_address.s_addr) < ntohl(b->pq_address.s_addr))
+               return -1;
+       if (ntohl(a->pq_address.s_addr) > ntohl(b->pq_address.s_addr))
+               return 1;
+
+       return prefix_cmp(&a->destination, &b->destination);
+}
+RB_GENERATE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare)
+
+struct ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
+                                       struct zapi_rlfa_igp *igp)
+{
+       struct ldp_rlfa_client *rclient;
+
+       if ((rclient = calloc(1, sizeof(*rclient))) == NULL)
+               fatal(__func__);
+
+       rclient->igp = *igp;
+       rclient->node = rnode;
+       RB_INSERT(ldp_rlfa_client_head, &rnode->clients, rclient);
+
+       return rclient;
+}
+
+void rlfa_client_del(struct ldp_rlfa_client *rclient)
+{
+       struct ldp_rlfa_node *rnode = rclient->node;
+
+       RB_REMOVE(ldp_rlfa_client_head, &rnode->clients, rclient);
+       free(rclient);
+
+       /* Delete RLFA node if it's empty. */
+       if (RB_EMPTY(ldp_rlfa_client_head, &rnode->clients))
+               rlfa_node_del(rnode);
+}
+
+struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
+                                        struct zapi_rlfa_igp *igp)
+{
+       struct ldp_rlfa_client rclient;
+
+       rclient.igp = *igp;
+       return RB_FIND(ldp_rlfa_client_head, &rnode->clients, &rclient);
+}
+
+struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
+                                   struct in_addr pq_address)
+{
+       struct ldp_rlfa_node *rnode;
+
+       if ((rnode = calloc(1, sizeof(*rnode))) == NULL)
+               fatal(__func__);
+
+       rnode->destination = *destination;
+       rnode->pq_address = pq_address;
+       rnode->pq_label = MPLS_INVALID_LABEL;
+       RB_INIT(ldp_rlfa_client_head, &rnode->clients);
+       RB_INSERT(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
+
+       return rnode;
+}
+
+void rlfa_node_del(struct ldp_rlfa_node *rnode)
+{
+       /* Delete RLFA clients. */
+       while (!RB_EMPTY(ldp_rlfa_client_head, &rnode->clients)) {
+               struct ldp_rlfa_client *rclient;
+
+               rclient = RB_ROOT(ldp_rlfa_client_head, &rnode->clients);
+               rlfa_client_del(rclient);
+       }
+
+       RB_REMOVE(ldp_rlfa_node_head, &rlfa_node_tree, rnode);
+       free(rnode);
+}
+
+struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
+                                    struct in_addr pq_address)
+{
+       struct ldp_rlfa_node rnode = {};
+
+       rnode.destination = *destination;
+       rnode.pq_address = pq_address;
+       return RB_FIND(ldp_rlfa_node_head, &rlfa_node_tree, &rnode);
+}
+
+void lde_rlfa_client_send(struct ldp_rlfa_client *rclient)
+{
+       struct ldp_rlfa_node            *rnode = rclient->node;
+       struct zapi_rlfa_response        rlfa_labels = {};
+       struct fec                       fec;
+       struct fec_node                 *fn;
+       struct fec_nh                   *fnh;
+       int                              i = 0;
+
+       /* Fill in inner label (allocated by PQ node). */
+       rlfa_labels.igp = rclient->igp;
+       rlfa_labels.destination = rnode->destination;
+       rlfa_labels.pq_label = rnode->pq_label;
+
+       /* Fill in outer label(s) (allocated by the nexthop routers). */
+       fec.type = FEC_TYPE_IPV4;
+       fec.u.ipv4.prefix = rnode->pq_address;
+       fec.u.ipv4.prefixlen = IPV4_MAX_BITLEN;
+       fn = (struct fec_node *)fec_find(&ft, &fec);
+       if (!fn)
+               return;
+       LIST_FOREACH(fnh, &fn->nexthops, entry) {
+               if (fnh->remote_label == NO_LABEL)
+                       continue;
+
+               rlfa_labels.nexthops[i].family = fnh->af;
+               switch (fnh->af) {
+               case AF_INET:
+                       rlfa_labels.nexthops[i].gate.ipv4 = fnh->nexthop.v4;
+                       break;
+               case AF_INET6:
+                       rlfa_labels.nexthops[i].gate.ipv6 = fnh->nexthop.v6;
+                       break;
+               default:
+                       continue;
+               }
+               rlfa_labels.nexthops[i].label = fnh->remote_label;
+               i++;
+       }
+       rlfa_labels.nexthop_num = i;
+
+       lde_imsg_compose_parent(IMSG_RLFA_LABELS, 0, &rlfa_labels,
+                               sizeof(rlfa_labels));
+}
+
+void lde_rlfa_label_update(const struct fec *fec)
+{
+       struct ldp_rlfa_node *rnode;
+
+       if (fec->type != FEC_TYPE_IPV4
+           || fec->u.ipv4.prefixlen != IPV4_MAX_BITLEN)
+               return;
+
+       /*
+        * TODO: use an rb-tree lookup to restrict the iteration to the RLFAs
+        * that were effectivelly affected by the label update.
+        */
+       RB_FOREACH (rnode, ldp_rlfa_node_head, &rlfa_node_tree) {
+               struct ldp_rlfa_client *rclient;
+
+               if (!IPV4_ADDR_SAME(&rnode->pq_address, &fec->u.ipv4.prefix))
+                       continue;
+
+               RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
+                       lde_rlfa_client_send(rclient);
+       }
+}
+
+void lde_rlfa_check(struct ldp_rlfa_client *rclient)
+{
+       struct lde_nbr *ln;
+       struct lde_map *me;
+       struct fec fec;
+       union ldpd_addr pq_address = {};
+
+       pq_address.v4 = rclient->node->pq_address;
+       ln = lde_nbr_find_by_addr(AF_INET, &pq_address);
+       if (!ln)
+               return;
+
+       lde_prefix2fec(&rclient->node->destination, &fec);
+       me = (struct lde_map *)fec_find(&ln->recv_map, &fec);
+       if (!me)
+               return;
+
+       rclient->node->pq_label = me->map.label;
+       lde_rlfa_client_send(rclient);
+}
+
+/*
+ * Check if there's any registered RLFA client for this prefix/neighbor (PQ
+ * node) and notify about the updated label.
+ */
+void lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
+                            uint32_t label)
+{
+       struct prefix            rlfa_dest;
+       struct ldp_rlfa_node    *rnode;
+
+       lde_fec2prefix(fec, &rlfa_dest);
+       rnode = rlfa_node_find(&rlfa_dest, ln->id);
+       if (rnode) {
+               struct ldp_rlfa_client *rclient;
+
+               rnode->pq_label = label;
+               RB_FOREACH (rclient, ldp_rlfa_client_head, &rnode->clients)
+                       lde_rlfa_client_send(rclient);
+       } else
+               lde_rlfa_label_update(fec);
+}
+
+void ldpe_rlfa_init(struct ldp_rlfa_client *rclient)
+{
+       struct tnbr *tnbr;
+       union ldpd_addr pq_address = {};
+
+       pq_address.v4 = rclient->node->pq_address;
+       tnbr = tnbr_find(leconf, AF_INET, &pq_address);
+       if (tnbr == NULL) {
+               tnbr = tnbr_new(AF_INET, &pq_address);
+               tnbr_update(tnbr);
+               RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
+       }
+
+       tnbr->rlfa_count++;
+}
+
+void ldpe_rlfa_exit(struct ldp_rlfa_client *rclient)
+{
+       struct tnbr *tnbr;
+       union ldpd_addr pq_address = {};
+
+       pq_address.v4 = rclient->node->pq_address;
+       tnbr = tnbr_find(leconf, AF_INET, &pq_address);
+       if (tnbr) {
+               tnbr->rlfa_count--;
+               tnbr_check(leconf, tnbr);
+       }
+}
diff --git a/ldpd/rlfa.h b/ldpd/rlfa.h
new file mode 100644 (file)
index 0000000..fe67917
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020  NetDEF, Inc.
+ *                     Renato Westphal
+ *
+ * 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
+ */
+
+#ifndef _LDPD_RLFA_H_
+#define _LDPD_RLFA_H_
+
+#include "openbsd-tree.h"
+#include "zclient.h"
+
+struct ldp_rlfa_client {
+       RB_ENTRY(ldp_rlfa_client) entry;
+
+       /* IGP instance data. */
+       struct zapi_rlfa_igp igp;
+
+       /* Backpointer to RLFA node. */
+       struct ldp_rlfa_node *node;
+};
+RB_HEAD(ldp_rlfa_client_head, ldp_rlfa_client);
+RB_PROTOTYPE(ldp_rlfa_client_head, ldp_rlfa_client, entry,
+            ldp_rlfa_client_compare);
+
+struct ldp_rlfa_node {
+       RB_ENTRY(ldp_rlfa_node) entry;
+
+       /* Destination prefix. */
+       struct prefix destination;
+
+       /* PQ node address. */
+       struct in_addr pq_address;
+
+       /* RLFA clients. */
+       struct ldp_rlfa_client_head clients;
+
+       /* Label allocated by the PQ node to the RLFA destination. */
+       mpls_label_t pq_label;
+};
+RB_HEAD(ldp_rlfa_node_head, ldp_rlfa_node);
+RB_PROTOTYPE(ldp_rlfa_node_head, ldp_rlfa_node, entry, ldp_rlfa_node_compare);
+
+extern struct ldp_rlfa_node_head rlfa_node_tree;
+
+/* prototypes */
+struct          ldp_rlfa_client *rlfa_client_new(struct ldp_rlfa_node *rnode,
+                   struct zapi_rlfa_igp *igp);
+void            rlfa_client_del(struct ldp_rlfa_client *rclient);
+struct ldp_rlfa_client *rlfa_client_find(struct ldp_rlfa_node *rnode,
+                   struct zapi_rlfa_igp *igp);
+struct ldp_rlfa_node *rlfa_node_new(const struct prefix *destination,
+                   struct in_addr pq_address);
+void rlfa_node_del(struct ldp_rlfa_node *rnode);
+struct ldp_rlfa_node *rlfa_node_find(const struct prefix *destination,
+                   struct in_addr pq_address);
+void            lde_rlfa_check(struct ldp_rlfa_client *rclient);
+void            lde_rlfa_client_send(struct ldp_rlfa_client *rclient);
+void            lde_rlfa_label_update(const struct fec *fec);
+void            lde_rlfa_update_clients(struct fec *fec, struct lde_nbr *ln,
+                   uint32_t label);
+void            ldpe_rlfa_init(struct ldp_rlfa_client *rclient);
+void            ldpe_rlfa_exit(struct ldp_rlfa_client *rclient);
+
+#endif /* _LDPD_RLFA_H_ */
index 2058d2596a6d7e992eca01817bf4bb86948bd2dc..d89d18341d0a315c67bf9e11cef4887970a44478 100644 (file)
@@ -36,6 +36,7 @@ ldpd_libldp_a_SOURCES = \
        ldpd/notification.c \
        ldpd/packet.c \
        ldpd/pfkey.c \
+       ldpd/rlfa.c \
        ldpd/socket.c \
        ldpd/util.c \
        # end
@@ -53,6 +54,7 @@ noinst_HEADERS += \
        ldpd/ldpd.h \
        ldpd/ldpe.h \
        ldpd/log.h \
+       ldpd/rlfa.h \
        # end
 
 ldpd_ldpd_SOURCES = ldpd/ldpd.c
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index cb4555650d2e48d680e765f41e2adc463e7d27dd..f16c94369b65c86cd882ac66ed976d7363c119cc 100644 (file)
@@ -40,6 +40,7 @@
 #include "nexthop_group.h"
 #include "lib_errors.h"
 #include "srte.h"
+#include "printfrr.h"
 
 DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
 DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -4121,3 +4122,51 @@ uint32_t zclient_get_nhg_start(uint32_t proto)
 
        return ZEBRA_NHG_PROTO_SPACING * proto;
 }
+
+char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len)
+{
+       if (flags == 0) {
+               snprintfrr(buf, len, "None ");
+               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 "
+                                                            : "");
+       return buf;
+}
+
+char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len)
+{
+       if (flags == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       snprintfrr(
+               buf, len, "%s%s%s%s%s%s%s",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "Sticky MAC " : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? "Gateway MAC " : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? "Router "
+                                                               : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_OVERRIDE_FLAG) ? "Override "
+                                                                 : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP) ? "SVI MAC " : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT) ? "Proxy "
+                                                                : "",
+               CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH) ? "Sync " : "");
+
+       return buf;
+}
index 2af448a20c9943e94fde993142ff5a47fd7b03ee..57bad7c2e6cdcef53c8cf310d2393e23f5d77e11 100644 (file)
@@ -479,6 +479,7 @@ struct zapi_route {
        uint8_t type;
        unsigned short instance;
 
+       /* If you add flags, update zclient_dump_route_flags */
        uint32_t flags;
 /*
  * Cause Zebra to consider this routes nexthops recursively
@@ -580,6 +581,8 @@ struct zapi_route {
        } opaque;
 };
 
+extern char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len);
+
 struct zapi_labels {
        uint8_t message;
 #define ZAPI_LABELS_FTN           0x01
@@ -634,6 +637,52 @@ struct zapi_pw_status {
        uint32_t status;
 };
 
+/* IGP instance data associated to a RLFA. */
+struct zapi_rlfa_igp {
+       vrf_id_t vrf_id;
+       int protocol;
+       union {
+               struct {
+                       char area_tag[32];
+                       struct {
+                               int tree_id;
+                               int level;
+                               unsigned int run_id;
+                       } spf;
+               } isis;
+       };
+};
+
+/* IGP -> LDP RLFA (un)registration message. */
+struct zapi_rlfa_request {
+       /* IGP instance data. */
+       struct zapi_rlfa_igp igp;
+
+       /* Destination prefix. */
+       struct prefix destination;
+
+       /* PQ node address. */
+       struct in_addr pq_address;
+};
+
+/* LDP -> IGP RLFA label update. */
+struct zapi_rlfa_response {
+       /* IGP instance data. */
+       struct zapi_rlfa_igp igp;
+
+       /* Destination prefix. */
+       struct prefix destination;
+
+       /* Resolved LDP labels. */
+       mpls_label_t pq_label;
+       uint16_t nexthop_num;
+       struct {
+               int family;
+               union g_addr gate;
+               mpls_label_t label;
+       } nexthops[MULTIPATH_NUM];
+};
+
 enum zapi_route_notify_owner {
        ZAPI_ROUTE_FAIL_INSTALL,
        ZAPI_ROUTE_BETTER_ADMIN_WON,
@@ -722,8 +771,11 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
 #define ZEBRA_MACIP_TYPE_PROXY_ADVERT          0x20 /* Not locally active */
 #define ZEBRA_MACIP_TYPE_SYNC_PATH             0x40 /* sync path */
 /* XXX - flags is an u8; that needs to be changed to u32 if you need
- * to allocate past 0x80
+ * to allocate past 0x80.  Additionally touch zclient_evpn_dump_macip_flags
  */
+#define MACIP_BUF_SIZE 128
+extern char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf,
+                                          size_t len);
 
 /* Zebra ES VTEP flags (ZEBRA_REMOTE_ES_VTEP_ADD) */
 /* ESR has been rxed from the VTEP. Only VTEPs that have advertised the
@@ -1091,6 +1143,12 @@ enum zapi_opaque_registry {
        LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
        /* Announce that LDP is up  */
        LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
+       /* Register RLFA with LDP */
+       LDP_RLFA_REGISTER = 7,
+       /* Unregister all RLFAs with LDP */
+       LDP_RLFA_UNREGISTER_ALL = 8,
+       /* Announce LDP labels associated to a previously registered RLFA */
+       LDP_RLFA_LABELS = 9,
 };
 
 /* Send the hello message.
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 6052d48e83d131ce0b51a99f96ed669cda4a28a2..c58073c52152378b6fcd34aae3236cb703b3cdbd 100644 (file)
@@ -3365,6 +3365,54 @@ DEFUN (show_ip_ospf_instance,
        return ret;
 }
 
+static void ospf_interface_auth_show(struct vty *vty, struct ospf_interface *oi,
+                                    json_object *json, bool use_json)
+{
+       int auth_type;
+
+       auth_type = OSPF_IF_PARAM(oi, auth_type);
+
+       switch (auth_type) {
+       case OSPF_AUTH_NULL:
+               if (use_json)
+                       json_object_string_add(json, "authentication",
+                                              "authenticationNone");
+               else
+                       vty_out(vty, "  Authentication NULL is enabled\n");
+               break;
+       case OSPF_AUTH_SIMPLE: {
+               if (use_json)
+                       json_object_string_add(json, "authentication",
+                                              "authenticationSimplePassword");
+               else
+                       vty_out(vty,
+                               "  Simple password authentication enabled\n");
+               break;
+       }
+       case OSPF_AUTH_CRYPTOGRAPHIC: {
+               struct crypt_key *ckey;
+
+               if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
+                       return;
+
+               ckey = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+               if (ckey) {
+                       if (use_json) {
+                               json_object_string_add(json, "authentication",
+                                                      "authenticationMessageDigest");
+                       } else {
+                               vty_out(vty,
+                                       "  Cryptographic authentication enabled\n");
+                               vty_out(vty, "  Algorithm:MD5\n");
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+}
+
 static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                                       struct interface *ifp,
                                       json_object *json_interface_sub,
@@ -3686,6 +3734,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                                ospf_nbr_count(oi, 0),
                                ospf_nbr_count(oi, NSM_Full));
                ospf_bfd_interface_show(vty, ifp, json_interface_sub, use_json);
+
+               /* OSPF Authentication information */
+               ospf_interface_auth_show(vty, oi, json_interface_sub, use_json);
        }
 }
 
index 439891b559da5935b1199d9ab18d8e08e94ca1d0..936ffaaad58d4ec96605e4955d147e51a0a74767 100644 (file)
@@ -1265,7 +1265,8 @@ int main(void)
 {
        int i = 0;
        qobj_init();
-       bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(thread_master_create(NULL), BGP_SOCKET_SNDBUF_SIZE,
+                       list_new());
        master = bm->master;
        bgp_option_set(BGP_OPT_NO_LISTEN);
        bgp_attr_init();
index 1b3f90434bd56735df74df7a550b91dce3b24d96..153b83897d988b3ed11a76656e43b356a1e8959c 100644 (file)
@@ -912,7 +912,7 @@ int main(void)
 
        qobj_init();
        master = thread_master_create(NULL);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
index 7fabaad7fa659a9c0f146c4ef3f5d3e2055b718a..f51076091357f83cd4083a658d6a14959ff0eab3 100644 (file)
@@ -1086,7 +1086,7 @@ int main(void)
        cmd_init(0);
        bgp_vty_init();
        master = thread_master_create("test mp attr");
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
        bgp_attr_init();
index 520c460f159096d71e1e43c268827300b9549c38..92efd4c3d612b3a0e9d61ff7526cf005303eb0be 100644 (file)
@@ -393,7 +393,7 @@ static int global_test_init(void)
        qobj_init();
        master = thread_master_create(NULL);
        zclient = zclient_new(master, &zclient_options_default);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
index d2c093fbea2487eb600904825db89ddf4767180a..db5918745d6d8943aa40e5542c8e066492d0fc21 100644 (file)
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
        qobj_init();
        bgp_attr_init();
        master = thread_master_create(NULL);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
index 0a15886c108858faf35d8bf1328c363e2bc59a8b..123d97bc9700eeadd8a195e3be0468e5a106dd66 100644 (file)
@@ -1399,7 +1399,7 @@ static void bgp_startup(void)
        master = thread_master_create(NULL);
        yang_init(true);
        nb_init(master, bgpd_yang_modules, array_size(bgpd_yang_modules), false);
-       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE);
+       bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new());
        bgp_option_set(BGP_OPT_NO_LISTEN);
        vrf_init(NULL, NULL, NULL, NULL, NULL);
        frr_pthread_init();
index 5fa604c7499c2be8ff90f8d6d23d1fffc32a2212..5b2028ffd409600a284f97bbf8f5e5060a808190 100644 (file)
@@ -69,6 +69,24 @@ test_find_adjacency(const struct isis_test_node *tnode, const char *hostname)
        return NULL;
 }
 
+mpls_label_t test_topology_node_ldp_label(const struct isis_topology *topology,
+                                         struct in_addr router_id)
+{
+       for (size_t i = 0; topology->nodes[i].hostname[0]; i++) {
+               const struct isis_test_node *tnode = &topology->nodes[i];
+               struct in_addr node_router_id;
+
+               if (!tnode->router_id)
+                       continue;
+
+               (void)inet_pton(AF_INET, tnode->router_id, &node_router_id);
+               if (IPV4_ADDR_SAME(&router_id, &node_router_id))
+                       return (50000 + (i + 1) * 100);
+       }
+
+       return MPLS_INVALID_LABEL;
+}
+
 static struct isis_lsp *lsp_add(struct lspdb_head *lspdb,
                                struct isis_area *area, int level,
                                const uint8_t *sysid, uint8_t pseudonode_id)
index 6fd0d3813e5ad4b26b2ce68ba854f3c3c9c3b166..3359a893acf3e9be6b019fad27c9913f535d74b1 100644 (file)
@@ -70,6 +70,9 @@ test_topology_find_node(const struct isis_topology *topology,
                        const char *hostname, uint8_t pseudonode_id);
 extern const struct isis_topology *
 test_topology_find(struct isis_topology *test_topologies, uint16_t number);
+extern mpls_label_t
+test_topology_node_ldp_label(const struct isis_topology *topology,
+                            struct in_addr router_id);
 extern int test_topology_load(const struct isis_topology *topology,
                              struct isis_area *area,
                              struct lspdb_head lspdb[]);
index 36ef93669bc5f0a575cd9fe78e24e4f456a8549d..e06944a037e2ec267e5a358f277b25034acb9c64 100644 (file)
@@ -31,6 +31,7 @@
 #include "isisd/isisd.h"
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_misc.h"
+#include "isisd/isis_route.h"
 #include "isisd/isis_spf.h"
 #include "isisd/isis_spf_private.h"
 
@@ -40,6 +41,7 @@ enum test_type {
        TEST_SPF = 1,
        TEST_REVERSE_SPF,
        TEST_LFA,
+       TEST_RLFA,
        TEST_TI_LFA,
 };
 
@@ -105,6 +107,86 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology,
        isis_spftree_del(spftree_self);
 }
 
+static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology,
+                         const struct isis_test_node *root,
+                         struct isis_area *area, struct lspdb_head *lspdb,
+                         int level, int tree,
+                         struct lfa_protected_resource *protected_resource)
+{
+       struct isis_spftree *spftree_self;
+       struct isis_spftree *spftree_reverse;
+       struct isis_spftree *spftree_pc;
+       struct isis_spf_node *spf_node, *node;
+       struct rlfa *rlfa;
+       uint8_t flags;
+
+       /* Run forward SPF in the root node. */
+       flags = F_SPFTREE_NO_ADJACENCIES;
+       spftree_self = isis_spftree_new(area, lspdb, root->sysid, level, tree,
+                                       SPF_TYPE_FORWARD, flags);
+       isis_run_spf(spftree_self);
+
+       /* Run reverse SPF in the root node. */
+       spftree_reverse = isis_spf_reverse_run(spftree_self);
+
+       /* Run forward SPF on all adjacent routers. */
+       isis_spf_run_neighbors(spftree_self);
+
+       /* Compute the local LFA repair paths. */
+       isis_lfa_compute(area, NULL, spftree_self, protected_resource);
+
+       /* Compute the remote LFA repair paths. */
+       spftree_pc = isis_rlfa_compute(area, spftree_self, spftree_reverse, 0,
+                                      protected_resource);
+
+       /* Print the extended P-space and Q-space. */
+       vty_out(vty, "P-space (self):\n");
+       RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.p_space)
+               vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
+       vty_out(vty, "\n");
+       RB_FOREACH (spf_node, isis_spf_nodes, &spftree_self->adj_nodes) {
+               if (RB_EMPTY(isis_spf_nodes, &spf_node->lfa.p_space))
+                       continue;
+               vty_out(vty, "P-space (%s):\n",
+                       print_sys_hostname(spf_node->sysid));
+               RB_FOREACH (node, isis_spf_nodes, &spf_node->lfa.p_space)
+                       vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
+               vty_out(vty, "\n");
+       }
+       vty_out(vty, "Q-space:\n");
+       RB_FOREACH (node, isis_spf_nodes, &spftree_pc->lfa.q_space)
+               vty_out(vty, " %s\n", print_sys_hostname(node->sysid));
+       vty_out(vty, "\n");
+
+       /* Print the post-convergence SPT. */
+       isis_print_spftree(vty, spftree_pc);
+
+       /*
+        * Activate the computed RLFAs (if any) using artificial LDP labels for
+        * the PQ nodes.
+        */
+       frr_each_safe (rlfa_tree, &spftree_self->lfa.remote.rlfas, rlfa) {
+               struct zapi_rlfa_response response = {};
+
+               response.pq_label = test_topology_node_ldp_label(
+                       topology, rlfa->pq_address);
+               assert(response.pq_label != MPLS_INVALID_LABEL);
+               isis_rlfa_activate(spftree_self, rlfa, &response);
+       }
+
+       /* Print the SPT and the corresponding main/backup routing tables. */
+       isis_print_spftree(vty, spftree_self);
+       vty_out(vty, "Main:\n");
+       isis_print_routes(vty, spftree_self, false, false);
+       vty_out(vty, "Backup:\n");
+       isis_print_routes(vty, spftree_self, false, true);
+
+       /* Cleanup everything. */
+       isis_spftree_del(spftree_self);
+       isis_spftree_del(spftree_reverse);
+       isis_spftree_del(spftree_pc);
+}
+
 static void test_run_ti_lfa(struct vty *vty,
                            const struct isis_topology *topology,
                            const struct isis_test_node *root,
@@ -242,6 +324,11 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
                                             &area->lspdb[level - 1], level,
                                             tree, &protected_resource);
                                break;
+                       case TEST_RLFA:
+                               test_run_rlfa(vty, topology, root, area,
+                                             &area->lspdb[level - 1], level,
+                                             tree, &protected_resource);
+                               break;
                        case TEST_TI_LFA:
                                test_run_ti_lfa(vty, topology, root, area,
                                                &area->lspdb[level - 1], level,
@@ -266,6 +353,7 @@ DEFUN(test_isis, test_isis_cmd,
           spf\
           |reverse-spf\
           |lfa system-id WORD [pseudonode-id <1-255>]\
+          |remote-lfa system-id WORD [pseudonode-id <1-255>]\
           |ti-lfa system-id WORD [pseudonode-id <1-255>] [node-protection]\
         >\
         [display-lspdb] [<ipv4-only|ipv6-only>] [<level-1-only|level-2-only>]",
@@ -282,6 +370,11 @@ DEFUN(test_isis, test_isis_cmd,
       "System ID\n"
       "Pseudonode-ID\n"
       "Pseudonode-ID\n"
+      "Remote LFA\n"
+      "System ID\n"
+      "System ID\n"
+      "Pseudonode-ID\n"
+      "Pseudonode-ID\n"
       "Topology Independent LFA\n"
       "System ID\n"
       "System ID\n"
@@ -330,6 +423,14 @@ DEFUN(test_isis, test_isis_cmd,
        else if (argv_find(argv, argc, "lfa", &idx)) {
                test_type = TEST_LFA;
 
+               fail_sysid_str = argv[idx + 2]->arg;
+               if (argv_find(argv, argc, "pseudonode-id", &idx))
+                       fail_pseudonode_id =
+                               strtoul(argv[idx + 1]->arg, NULL, 10);
+               protection_type = LFA_LINK_PROTECTION;
+       } else if (argv_find(argv, argc, "remote-lfa", &idx)) {
+               test_type = TEST_RLFA;
+
                fail_sysid_str = argv[idx + 2]->arg;
                if (argv_find(argv, argc, "pseudonode-id", &idx))
                        fail_pseudonode_id =
index 93e18124e6b6155e24bb1f86bcc93e439564fe10..f8f65ffdf795eaf8ebe83298de7105f6c3648a3b 100644 (file)
@@ -31,6 +31,18 @@ test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1
 test isis topology 14 root rt1 lfa system-id rt2
 test isis topology 14 root rt5 lfa system-id rt4
 
+test isis topology 1 root rt1 remote-lfa system-id rt2
+test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1
+test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only
+test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only
+test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only
+test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only
+test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only
+test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only
+test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only
+test isis topology 11 root rt2 remote-lfa system-id rt4
+test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only
+
 test isis topology 1 root rt1 ti-lfa system-id rt2
 test isis topology 2 root rt1 ti-lfa system-id rt3
 test isis topology 2 root rt1 ti-lfa system-id rt1 pseudonode-id 1
index dced6fb1037bf03fb1ee6febf55abc66a0a57154..024f7256e0bd61df7daa32337d5625a08d7b629e 100644 (file)
@@ -1806,6 +1806,1227 @@ IS-IS L1 IPv6 routing table:
  2001:db8::3/128  50      -          rt3      -         \r
  2001:db8::4/128  60      -          rt3      -         \r
 \r
+test# \r
+test# test isis topology 1 root rt1 remote-lfa system-id rt2\r
+P-space (self):\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt2\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt4                  TE-IS        40     rt3                  -         rt6(4)\r
+10.0.255.6/32        IP TE        40     rt3                  -         rt6(4)\r
+rt2                  TE-IS        50     rt3                  -         rt4(4)\r
+10.0.255.4/32        IP TE        50     rt3                  -         rt4(4)\r
+10.0.255.2/32        IP TE        60     rt3                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+                        -          rt3      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.2/32  60      -          rt3      50600/16020  \r
+ 10.0.255.4/32  50      -          rt3      50600/16040  \r
+\r
+P-space (self):\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt2\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt3                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 30     rt3                  -         rt5(4)\r
+rt4                  TE-IS        40     rt3                  -         rt6(4)\r
+2001:db8::6/128      IP6 internal 40     rt3                  -         rt6(4)\r
+rt2                  TE-IS        50     rt3                  -         rt4(4)\r
+2001:db8::4/128      IP6 internal 50     rt3                  -         rt4(4)\r
+2001:db8::2/128      IP6 internal 60     rt3                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+2001:db8::1/128      IP6 internal 0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 20     rt2                  -         rt2(4)\r
+2001:db8::3/128      IP6 internal 20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         rt5(4)\r
+2001:db8::4/128      IP6 internal 30     rt2                  -         rt4(4)\r
+2001:db8::5/128      IP6 internal 30     rt3                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 40     rt2                  -         rt6(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  0       -          -        -              \r
+ 2001:db8::2/128  20      -          rt2      implicit-null  \r
+ 2001:db8::3/128  20      -          rt3      implicit-null  \r
+ 2001:db8::4/128  30      -          rt2      16041          \r
+ 2001:db8::5/128  30      -          rt3      16051          \r
+ 2001:db8::6/128  40      -          rt2      16061          \r
+                          -          rt3      16061          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)     \r
+ ----------------------------------------------------------\r
+ 2001:db8::2/128  60      -          rt3      50600/16021  \r
+ 2001:db8::4/128  50      -          rt3      50600/16041  \r
+\r
+test# test isis topology 2 root rt5 remote-lfa system-id rt1 pseudonode-id 1\r
+P-space (self):\r
+ rt6\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+\r
+P-space (rt6):\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt4                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt1                  pseudo_TE-IS 30     rt6                  -         rt4(4)\r
+rt1                  TE-IS        30     rt6                  -         rt1(2)\r
+10.0.255.4/32        IP TE        30     rt6                  -         rt4(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+10.0.255.1/32        IP TE        40     rt6                  -         rt1(4)\r
+rt2                  TE-IS        45     rt6                  -         rt1(4)\r
+10.0.255.3/32        IP TE        50     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        55     rt6                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt1                  TE-IS        10     rt1                  -         rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt4                  -         rt4(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+10.0.255.2/32        IP TE        35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+                                         rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        50     rt3                  -         rt3(4)\r
+                                         rt1                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  20      -          rt1      implicit-null  \r
+ 10.0.255.2/32  35      -          rt1      16020          \r
+ 10.0.255.3/32  50      -          rt3      implicit-null  \r
+                        -          rt1      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  0       -          -        -              \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt6      50400/16010  \r
+ 10.0.255.2/32  55      -          rt6      50400/16020  \r
+ 10.0.255.4/32  30      -          rt6      50400/16040  \r
+\r
+P-space (self):\r
+ rt6\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+\r
+P-space (rt6):\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+2001:db8::5/128      IP6 internal 0                                     rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt4                  TE-IS        20     rt6                  -         rt6(4)\r
+2001:db8::6/128      IP6 internal 20     rt6                  -         rt6(4)\r
+rt1                  pseudo_TE-IS 30     rt6                  -         rt4(4)\r
+rt1                  TE-IS        30     rt6                  -         rt1(2)\r
+2001:db8::4/128      IP6 internal 30     rt6                  -         rt4(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+2001:db8::1/128      IP6 internal 40     rt6                  -         rt1(4)\r
+rt2                  TE-IS        45     rt6                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 50     rt3                  -         rt3(4)\r
+2001:db8::2/128      IP6 internal 55     rt6                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+2001:db8::5/128      IP6 internal 0                                     rt5(4)\r
+rt1                  TE-IS        10     rt1                  -         rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt1                  pseudo_TE-IS 20     rt1                  -         rt1(4)\r
+                                         rt4                  -         rt4(4)\r
+2001:db8::1/128      IP6 internal 20     rt1                  -         rt1(4)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+2001:db8::6/128      IP6 internal 20     rt6                  -         rt6(4)\r
+rt2                  TE-IS        25     rt1                  -         rt1(4)\r
+2001:db8::2/128      IP6 internal 35     rt1                  -         rt2(4)\r
+rt3                  TE-IS        40     rt3                  -         rt5(4)\r
+                                         rt1                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 50     rt3                  -         rt3(4)\r
+                                         rt1                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  20      -          rt1      implicit-null  \r
+ 2001:db8::2/128  35      -          rt1      16021          \r
+ 2001:db8::3/128  50      -          rt3      implicit-null  \r
+                          -          rt1      implicit-null  \r
+ 2001:db8::4/128  20      -          rt4      implicit-null  \r
+ 2001:db8::5/128  0       -          -        -              \r
+ 2001:db8::6/128  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)     \r
+ ----------------------------------------------------------\r
+ 2001:db8::1/128  40      -          rt6      50400/16011  \r
+ 2001:db8::2/128  55      -          rt6      50400/16021  \r
+ 2001:db8::4/128  30      -          rt6      50400/16041  \r
+\r
+test# test isis topology 3 root rt5 remote-lfa system-id rt4 ipv4-only\r
+P-space (self):\r
+ rt6\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+P-space (rt6):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt4                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt3                  -         rt5(4)\r
+rt2                  TE-IS        30     rt6                  -         rt4(4)\r
+10.0.255.4/32        IP TE        30     rt6                  -         rt4(4)\r
+rt1                  TE-IS        40     rt3                  -         rt3(4)\r
+                                         rt6                  -         rt2(4)\r
+10.0.255.3/32        IP TE        40     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        40     rt6                  -         rt2(4)\r
+10.0.255.1/32        IP TE        50     rt3                  -         rt1(4)\r
+                                         rt6                  -         \r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt2                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt3                  -         rt5(4)\r
+                                         rt4                  -         rt2(4)\r
+rt1                  TE-IS        30     rt4                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt4                  -         rt2(4)\r
+10.0.255.3/32        IP TE        40     rt3                  -         rt3(4)\r
+                                         rt4                  -         \r
+10.0.255.1/32        IP TE        40     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt4      16010          \r
+ 10.0.255.2/32  30      -          rt4      16020          \r
+ 10.0.255.3/32  40      -          rt3      implicit-null  \r
+                        -          rt4      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  0       -          -        -              \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)  \r
+ -----------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt3      16010     \r
+                        -          rt6      16010     \r
+ 10.0.255.2/32  30      -          rt3      16020     \r
+                        -          rt6      16020     \r
+ 10.0.255.4/32  20      -          rt3      16040     \r
+                        -          rt6      16040     \r
+\r
+test# test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only\r
+P-space (self):\r
+ rt1\r
+ rt2\r
+ rt4\r
+ rt6\r
+\r
+P-space (rt4):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+P-space (rt6):\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt2                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt1                  TE-IS        30     rt4                  -         rt2(4)\r
+rt3                  TE-IS        30     rt4                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt4                  -         rt2(4)\r
+10.0.255.1/32        IP TE        40     rt4                  -         rt1(4)\r
+10.0.255.3/32        IP TE        40     rt4                  -         rt3(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt5                                                                   \r
+10.0.255.5/32        IP internal  0                                     rt5(4)\r
+rt4                  TE-IS        10     rt4                  -         rt5(4)\r
+rt6                  TE-IS        10     rt6                  -         rt5(4)\r
+rt2                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt3                  -         rt5(4)\r
+                                         rt4                  -         rt2(4)\r
+rt1                  TE-IS        30     rt4                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt4                  -         rt2(4)\r
+10.0.255.3/32        IP TE        40     rt3                  -         rt3(4)\r
+                                         rt4                  -         \r
+10.0.255.1/32        IP TE        40     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  40      -          rt4      16010          \r
+ 10.0.255.2/32  30      -          rt4      16020          \r
+ 10.0.255.3/32  40      -          rt3      implicit-null  \r
+                        -          rt4      implicit-null  \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  0       -          -        -              \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+test# test isis topology 5 root rt1 remote-lfa system-id rt2 ipv4-only\r
+P-space (self):\r
+ rt3\r
+ rt5\r
+ rt7\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt5\r
+ rt7\r
+ rt8\r
+\r
+Q-space:\r
+ rt2\r
+ rt4\r
+ rt6\r
+ rt8\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt8                  TE-IS        40     rt3                  -         rt7(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+rt6                  TE-IS        50     rt3                  -         rt8(4)\r
+10.0.255.8/32        IP TE        50     rt3                  -         rt8(4)\r
+rt4                  TE-IS        60     rt3                  -         rt6(4)\r
+10.0.255.6/32        IP TE        60     rt3                  -         rt6(4)\r
+rt2                  TE-IS        70     rt3                  -         rt4(4)\r
+10.0.255.4/32        IP TE        70     rt3                  -         rt4(4)\r
+10.0.255.2/32        IP TE        80     rt3                  -         rt2(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        30     rt2                  -         rt4(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+rt8                  TE-IS        40     rt2                  -         rt6(4)\r
+                                         rt3                  -         rt7(4)\r
+10.0.255.6/32        IP TE        40     rt2                  -         rt6(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+10.0.255.8/32        IP TE        50     rt2                  -         rt8(4)\r
+                                         rt3                  -         \r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  40      -          rt2      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+ 10.0.255.8/32  50      -          rt2      16080          \r
+                        -          rt3      16080          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.2/32  80      -          rt3      50800/16020  \r
+ 10.0.255.4/32  70      -          rt3      50800/16040  \r
+ 10.0.255.6/32  60      -          rt3      50800/16060  \r
+\r
+test# test isis topology 6 root rt4 remote-lfa system-id rt3 ipv4-only\r
+P-space (self):\r
+ rt2\r
+ rt5\r
+ rt6\r
+ rt7\r
+ rt8\r
+\r
+P-space (rt2):\r
+ rt1\r
+ rt2\r
+\r
+P-space (rt6):\r
+ rt5\r
+ rt6\r
+ rt7\r
+ rt8\r
+\r
+Q-space:\r
+ rt1\r
+ rt3\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt2                  TE-IS        10     rt2                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  TE-IS        20     rt2                  -         rt2(4)\r
+rt5                  TE-IS        20     rt6                  -         rt6(4)\r
+rt8                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt3                  TE-IS        30     rt2                  -         rt1(4)\r
+rt7                  TE-IS        30     rt6                  -         rt5(4)\r
+                                                                        rt8(4)\r
+10.0.255.1/32        IP TE        30     rt2                  -         rt1(4)\r
+10.0.255.5/32        IP TE        30     rt6                  -         rt5(4)\r
+10.0.255.8/32        IP TE        30     rt6                  -         rt8(4)\r
+10.0.255.3/32        IP TE        40     rt2                  -         rt3(4)\r
+10.0.255.7/32        IP TE        40     rt6                  -         rt7(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt4                                                                   \r
+10.0.255.4/32        IP internal  0                                     rt4(4)\r
+rt2                  TE-IS        10     rt2                  -         rt4(4)\r
+rt3                  TE-IS        10     rt3                  -         rt4(4)\r
+rt6                  TE-IS        10     rt6                  -         rt4(4)\r
+rt1                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt3                  -         rt3(4)\r
+rt5                  TE-IS        20     rt6                  -         rt6(4)\r
+rt8                  TE-IS        20     rt6                  -         rt6(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.6/32        IP TE        20     rt6                  -         rt6(4)\r
+rt7                  TE-IS        30     rt6                  -         rt5(4)\r
+                                                                        rt8(4)\r
+10.0.255.1/32        IP TE        30     rt2                  -         rt1(4)\r
+                                         rt3                  -         \r
+10.0.255.5/32        IP TE        30     rt6                  -         rt5(4)\r
+10.0.255.8/32        IP TE        30     rt6                  -         rt8(4)\r
+10.0.255.7/32        IP TE        40     rt6                  -         rt7(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  30      -          rt2      16010          \r
+                        -          rt3      16010          \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  0       -          -        -              \r
+ 10.0.255.5/32  30      -          rt6      16050          \r
+ 10.0.255.6/32  20      -          rt6      implicit-null  \r
+ 10.0.255.7/32  40      -          rt6      16070          \r
+ 10.0.255.8/32  30      -          rt6      16080          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.3/32  40      -          rt2      50100/16030  \r
+\r
+test# test isis topology 7 root rt11 remote-lfa system-id rt8 ipv4-only\r
+P-space (self):\r
+ rt10\r
+ rt12\r
+\r
+P-space (rt10):\r
+ rt1\r
+ rt4\r
+ rt7\r
+ rt10\r
+\r
+P-space (rt12):\r
+ rt9\r
+ rt12\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+ rt7\r
+ rt8\r
+ rt9\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt11                                                                  \r
+10.0.255.11/32       IP internal  0                                     rt11(4)\r
+rt10                 TE-IS        10     rt10                 -         rt11(4)\r
+rt12                 TE-IS        10     rt12                 -         rt11(4)\r
+rt9                  TE-IS        20     rt12                 -         rt12(4)\r
+10.0.255.10/32       IP TE        20     rt10                 -         rt10(4)\r
+10.0.255.12/32       IP TE        20     rt12                 -         rt12(4)\r
+rt7                  TE-IS        30     rt10                 -         rt10(4)\r
+rt8                  TE-IS        30     rt12                 -         rt9(4)\r
+10.0.255.9/32        IP TE        30     rt12                 -         rt9(4)\r
+rt4                  TE-IS        40     rt10                 -         rt7(4)\r
+rt5                  TE-IS        40     rt12                 -         rt8(4)\r
+10.0.255.7/32        IP TE        40     rt10                 -         rt7(4)\r
+10.0.255.8/32        IP TE        40     rt12                 -         rt8(4)\r
+rt6                  TE-IS        50     rt12                 -         rt9(4)\r
+                                                                        rt5(4)\r
+rt1                  TE-IS        50     rt10                 -         rt4(4)\r
+rt2                  TE-IS        50     rt12                 -         rt5(4)\r
+10.0.255.4/32        IP TE        50     rt10                 -         rt4(4)\r
+10.0.255.5/32        IP TE        50     rt12                 -         rt5(4)\r
+rt3                  TE-IS        60     rt12                 -         rt6(4)\r
+                                                                        rt2(4)\r
+10.0.255.6/32        IP TE        60     rt12                 -         rt6(4)\r
+10.0.255.1/32        IP TE        60     rt10                 -         rt1(4)\r
+10.0.255.2/32        IP TE        60     rt12                 -         rt2(4)\r
+10.0.255.3/32        IP TE        70     rt12                 -         rt3(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt11                                                                  \r
+10.0.255.11/32       IP internal  0                                     rt11(4)\r
+rt8                  TE-IS        10     rt8                  -         rt11(4)\r
+rt10                 TE-IS        10     rt10                 -         rt11(4)\r
+rt12                 TE-IS        10     rt12                 -         rt11(4)\r
+rt5                  TE-IS        20     rt8                  -         rt8(4)\r
+rt7                  TE-IS        20     rt8                  -         rt8(4)\r
+rt9                  TE-IS        20     rt8                  -         rt8(4)\r
+                                         rt12                 -         rt12(4)\r
+10.0.255.8/32        IP TE        20     rt8                  -         rt8(4)\r
+10.0.255.10/32       IP TE        20     rt10                 -         rt10(4)\r
+10.0.255.12/32       IP TE        20     rt12                 -         rt12(4)\r
+rt2                  TE-IS        30     rt8                  -         rt5(4)\r
+rt4                  TE-IS        30     rt8                  -         rt5(4)\r
+                                                                        rt7(4)\r
+rt6                  TE-IS        30     rt8                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt8                  -         rt5(4)\r
+10.0.255.7/32        IP TE        30     rt8                  -         rt7(4)\r
+10.0.255.9/32        IP TE        30     rt8                  -         rt9(4)\r
+                                         rt12                 -         \r
+rt3                  TE-IS        40     rt8                  -         rt2(4)\r
+                                                                        rt6(4)\r
+rt1                  TE-IS        40     rt8                  -         rt4(4)\r
+10.0.255.2/32        IP TE        40     rt8                  -         rt2(4)\r
+10.0.255.4/32        IP TE        40     rt8                  -         rt4(4)\r
+10.0.255.6/32        IP TE        40     rt8                  -         rt6(4)\r
+10.0.255.3/32        IP TE        50     rt8                  -         rt3(4)\r
+10.0.255.1/32        IP TE        50     rt8                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   50      -          rt8      16010          \r
+ 10.0.255.2/32   40      -          rt8      16020          \r
+ 10.0.255.3/32   50      -          rt8      16030          \r
+ 10.0.255.4/32   40      -          rt8      16040          \r
+ 10.0.255.5/32   30      -          rt8      16050          \r
+ 10.0.255.6/32   40      -          rt8      16060          \r
+ 10.0.255.7/32   30      -          rt8      16070          \r
+ 10.0.255.8/32   20      -          rt8      implicit-null  \r
+ 10.0.255.9/32   30      -          rt8      16090          \r
+                         -          rt12     16090          \r
+ 10.0.255.10/32  20      -          rt10     implicit-null  \r
+ 10.0.255.11/32  0       -          -        -              \r
+ 10.0.255.12/32  20      -          rt12     implicit-null  \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.1/32  50      -          rt10     16010        \r
+ 10.0.255.2/32  60      -          rt12     50900/16020  \r
+ 10.0.255.3/32  70      -          rt12     50900/16030  \r
+ 10.0.255.4/32  40      -          rt10     16040        \r
+ 10.0.255.5/32  50      -          rt12     50900/16050  \r
+ 10.0.255.6/32  60      -          rt12     50900/16060  \r
+ 10.0.255.7/32  30      -          rt10     16070        \r
+ 10.0.255.8/32  40      -          rt12     50900/16080  \r
+\r
+test# test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only\r
+P-space (self):\r
+ rt3\r
+\r
+P-space (rt3):\r
+ rt2\r
+ rt3\r
+\r
+P-space (rt9):\r
+ rt1\r
+ rt2\r
+ rt4\r
+ rt5\r
+ rt7\r
+ rt8\r
+ rt9\r
+ rt10\r
+ rt11\r
+ rt12\r
+\r
+Q-space:\r
+ rt1\r
+ rt2\r
+ rt4\r
+ rt5\r
+ rt7\r
+ rt8\r
+ rt9\r
+ rt10\r
+ rt11\r
+ rt12\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt6                                                                   \r
+10.0.255.6/32        IP internal  0                                     rt6(4)\r
+rt3                  TE-IS        10     rt3                  -         rt6(4)\r
+rt2                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt9                  TE-IS        30     rt9                  -         rt6(4)\r
+rt5                  TE-IS        30     rt3                  -         rt2(4)\r
+10.0.255.2/32        IP TE        30     rt3                  -         rt2(4)\r
+rt8                  TE-IS        40     rt9                  -         rt9(4)\r
+                                         rt3                  -         rt5(4)\r
+rt12                 TE-IS        40     rt9                  -         rt9(4)\r
+rt4                  TE-IS        40     rt3                  -         rt5(4)\r
+10.0.255.9/32        IP TE        40     rt9                  -         rt9(4)\r
+10.0.255.5/32        IP TE        40     rt3                  -         rt5(4)\r
+rt7                  TE-IS        50     rt9                  -         rt8(4)\r
+                                         rt3                  -         rt4(4)\r
+rt11                 TE-IS        50     rt9                  -         rt8(4)\r
+                                         rt3                  -         rt12(4)\r
+rt1                  TE-IS        50     rt3                  -         rt4(4)\r
+10.0.255.8/32        IP TE        50     rt9                  -         rt8(4)\r
+                                         rt3                  -         \r
+10.0.255.12/32       IP TE        50     rt9                  -         rt12(4)\r
+10.0.255.4/32        IP TE        50     rt3                  -         rt4(4)\r
+rt10                 TE-IS        60     rt9                  -         rt11(4)\r
+                                         rt3                  -         \r
+10.0.255.7/32        IP TE        60     rt9                  -         rt7(4)\r
+                                         rt3                  -         \r
+10.0.255.11/32       IP TE        60     rt9                  -         rt11(4)\r
+                                         rt3                  -         \r
+10.0.255.1/32        IP TE        60     rt3                  -         rt1(4)\r
+10.0.255.10/32       IP TE        70     rt9                  -         rt10(4)\r
+                                         rt3                  -         \r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt6                                                                   \r
+10.0.255.6/32        IP internal  0                                     rt6(4)\r
+rt3                  TE-IS        10     rt3                  -         rt6(4)\r
+rt5                  TE-IS        10     rt5                  -         rt6(4)\r
+rt2                  TE-IS        20     rt3                  -         rt3(4)\r
+                                         rt5                  -         rt5(4)\r
+rt4                  TE-IS        20     rt5                  -         rt5(4)\r
+rt8                  TE-IS        20     rt5                  -         rt5(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+rt9                  TE-IS        30     rt9                  -         rt6(4)\r
+                                         rt5                  -         rt8(4)\r
+rt1                  TE-IS        30     rt5                  -         rt4(4)\r
+rt7                  TE-IS        30     rt5                  -         rt4(4)\r
+                                                                        rt8(4)\r
+rt11                 TE-IS        30     rt5                  -         rt8(4)\r
+10.0.255.2/32        IP TE        30     rt3                  -         rt2(4)\r
+                                         rt5                  -         \r
+10.0.255.4/32        IP TE        30     rt5                  -         rt4(4)\r
+10.0.255.8/32        IP TE        30     rt5                  -         rt8(4)\r
+rt12                 TE-IS        40     rt9                  -         rt9(4)\r
+                                         rt5                  -         rt11(4)\r
+rt10                 TE-IS        40     rt5                  -         rt11(4)\r
+10.0.255.9/32        IP TE        40     rt9                  -         rt9(4)\r
+                                         rt5                  -         \r
+10.0.255.1/32        IP TE        40     rt5                  -         rt1(4)\r
+10.0.255.7/32        IP TE        40     rt5                  -         rt7(4)\r
+10.0.255.11/32       IP TE        40     rt5                  -         rt11(4)\r
+10.0.255.12/32       IP TE        50     rt9                  -         rt12(4)\r
+                                         rt5                  -         \r
+10.0.255.10/32       IP TE        50     rt5                  -         rt10(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   40      -          rt5      16010          \r
+ 10.0.255.2/32   30      -          rt3      16020          \r
+                         -          rt5      16020          \r
+ 10.0.255.3/32   20      -          rt3      implicit-null  \r
+ 10.0.255.4/32   30      -          rt5      16040          \r
+ 10.0.255.5/32   20      -          rt5      implicit-null  \r
+ 10.0.255.6/32   0       -          -        -              \r
+ 10.0.255.7/32   40      -          rt5      16070          \r
+ 10.0.255.8/32   30      -          rt5      16080          \r
+ 10.0.255.9/32   40      -          rt9      implicit-null  \r
+                         -          rt5      implicit-null  \r
+ 10.0.255.10/32  50      -          rt5      16100          \r
+ 10.0.255.11/32  40      -          rt5      16110          \r
+ 10.0.255.12/32  50      -          rt9      16120          \r
+                         -          rt5      16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)  \r
+ ------------------------------------------------------\r
+ 10.0.255.1/32   70      -          rt9      16010     \r
+ 10.0.255.4/32   60      -          rt9      16040     \r
+ 10.0.255.5/32   50      -          rt9      16050     \r
+ 10.0.255.7/32   50      -          rt9      16070     \r
+ 10.0.255.8/32   40      -          rt9      16080     \r
+ 10.0.255.10/32  60      -          rt9      16100     \r
+ 10.0.255.11/32  50      -          rt9      16110     \r
+\r
+test# test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only\r
+P-space (self):\r
+ rt1\r
+ rt3\r
+ rt4\r
+ rt7\r
+ rt10\r
+\r
+P-space (rt1):\r
+ rt1\r
+ rt4\r
+ rt7\r
+ rt10\r
+\r
+P-space (rt3):\r
+ rt3\r
+ rt6\r
+\r
+Q-space:\r
+ rt5\r
+ rt6\r
+ rt8\r
+ rt9\r
+ rt11\r
+ rt12\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt1                  TE-IS        10     rt1                  -         rt2(4)\r
+rt3                  TE-IS        10     rt3                  -         rt2(4)\r
+rt4                  TE-IS        20     rt1                  -         rt1(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt1                  -         rt4(4)\r
+rt5                  TE-IS        30     rt3                  -         rt6(4)\r
+10.0.255.4/32        IP TE        30     rt1                  -         rt4(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+rt10                 TE-IS        40     rt1                  -         rt7(4)\r
+rt8                  TE-IS        40     rt3                  -         rt5(4)\r
+10.0.255.7/32        IP TE        40     rt1                  -         rt7(4)\r
+10.0.255.5/32        IP TE        40     rt3                  -         rt5(4)\r
+rt9                  TE-IS        50     rt3                  -         rt8(4)\r
+rt11                 TE-IS        50     rt3                  -         rt8(4)\r
+10.0.255.10/32       IP TE        50     rt1                  -         rt10(4)\r
+10.0.255.8/32        IP TE        50     rt3                  -         rt8(4)\r
+rt12                 TE-IS        60     rt3                  -         rt9(4)\r
+                                                                        rt11(4)\r
+10.0.255.9/32        IP TE        60     rt3                  -         rt9(4)\r
+10.0.255.11/32       IP TE        60     rt3                  -         rt11(4)\r
+10.0.255.12/32       IP TE        70     rt3                  -         rt12(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt1                  TE-IS        10     rt1                  -         rt2(4)\r
+rt3                  TE-IS        10     rt3                  -         rt2(4)\r
+rt5                  TE-IS        10     rt5                  -         rt2(4)\r
+rt4                  TE-IS        20     rt1                  -         rt1(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+                                         rt5                  -         rt5(4)\r
+rt8                  TE-IS        20     rt5                  -         rt5(4)\r
+10.0.255.1/32        IP TE        20     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+10.0.255.5/32        IP TE        20     rt5                  -         rt5(4)\r
+rt7                  TE-IS        30     rt1                  -         rt4(4)\r
+rt9                  TE-IS        30     rt5                  -         rt8(4)\r
+rt11                 TE-IS        30     rt5                  -         rt8(4)\r
+10.0.255.4/32        IP TE        30     rt1                  -         rt4(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+                                         rt5                  -         \r
+10.0.255.8/32        IP TE        30     rt5                  -         rt8(4)\r
+rt10                 TE-IS        40     rt1                  -         rt7(4)\r
+rt12                 TE-IS        40     rt5                  -         rt9(4)\r
+                                                                        rt11(4)\r
+10.0.255.7/32        IP TE        40     rt1                  -         rt7(4)\r
+10.0.255.9/32        IP TE        40     rt5                  -         rt9(4)\r
+10.0.255.11/32       IP TE        40     rt5                  -         rt11(4)\r
+10.0.255.10/32       IP TE        50     rt1                  -         rt10(4)\r
+10.0.255.12/32       IP TE        50     rt5                  -         rt12(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)       \r
+ -----------------------------------------------------------\r
+ 10.0.255.1/32   20      -          rt1      implicit-null  \r
+ 10.0.255.2/32   0       -          -        -              \r
+ 10.0.255.3/32   20      -          rt3      implicit-null  \r
+ 10.0.255.4/32   30      -          rt1      16040          \r
+ 10.0.255.5/32   20      -          rt5      implicit-null  \r
+ 10.0.255.6/32   30      -          rt3      16060          \r
+                         -          rt5      16060          \r
+ 10.0.255.7/32   40      -          rt1      16070          \r
+ 10.0.255.8/32   30      -          rt5      16080          \r
+ 10.0.255.9/32   40      -          rt5      16090          \r
+ 10.0.255.10/32  50      -          rt1      16100          \r
+ 10.0.255.11/32  40      -          rt5      16110          \r
+ 10.0.255.12/32  50      -          rt5      16120          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix          Metric  Interface  Nexthop  Label(s)     \r
+ ---------------------------------------------------------\r
+ 10.0.255.5/32   40      -          rt3      50600/16050  \r
+ 10.0.255.8/32   50      -          rt3      50600/16080  \r
+ 10.0.255.9/32   60      -          rt3      50600/16090  \r
+ 10.0.255.11/32  60      -          rt3      50600/16110  \r
+ 10.0.255.12/32  70      -          rt3      50600/16120  \r
+\r
+test# test isis topology 11 root rt2 remote-lfa system-id rt4\r
+P-space (self):\r
+\r
+P-space (rt1):\r
+ rt1\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt1                  TE-IS        50     rt1                  -         rt2(4)\r
+rt3                  TE-IS        50     rt3                  -         rt2(4)\r
+rt2                                                                   \r
+rt5                  TE-IS        60     rt3                  -         rt3(4)\r
+10.0.255.1/32        IP TE        60     rt1                  -         rt1(4)\r
+10.0.255.3/32        IP TE        60     rt3                  -         rt3(4)\r
+rt4                  TE-IS        70     rt3                  -         rt5(4)\r
+rt6                  TE-IS        70     rt3                  -         rt5(4)\r
+10.0.255.5/32        IP TE        70     rt3                  -         rt5(4)\r
+10.0.255.4/32        IP TE        80     rt3                  -         rt4(4)\r
+10.0.255.6/32        IP TE        80     rt3                  -         rt6(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+10.0.255.2/32        IP internal  0                                     rt2(4)\r
+rt4                  TE-IS        10     rt4                  -         rt2(4)\r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+rt6                  TE-IS        20     rt4                  -         rt4(4)\r
+10.0.255.4/32        IP TE        20     rt4                  -         rt4(4)\r
+rt3                  TE-IS        30     rt4                  -         rt5(4)\r
+10.0.255.5/32        IP TE        30     rt4                  -         rt5(4)\r
+10.0.255.6/32        IP TE        30     rt4                  -         rt6(4)\r
+rt2                                                                   \r
+rt1                  TE-IS        40     rt4                  -         rt2(2)\r
+10.0.255.3/32        IP TE        40     rt4                  -         rt3(4)\r
+10.0.255.1/32        IP TE        50     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  50      -          rt4      16010          \r
+ 10.0.255.2/32  0       -          -        -              \r
+ 10.0.255.3/32  40      -          rt4      16030          \r
+ 10.0.255.4/32  20      -          rt4      implicit-null  \r
+ 10.0.255.5/32  30      -          rt4      16050          \r
+ 10.0.255.6/32  30      -          rt4      16060          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  50      -          rt1      implicit-null  \r
+                        -          rt3      16010          \r
+ 10.0.255.3/32  50      -          rt1      16030          \r
+                        -          rt3      implicit-null  \r
+ 10.0.255.4/32  80      -          rt3      50500/16040    \r
+ 10.0.255.5/32  60      -          rt1      16050          \r
+                        -          rt3      16050          \r
+ 10.0.255.6/32  70      -          rt3      16060          \r
+\r
+P-space (self):\r
+\r
+P-space (rt1):\r
+ rt1\r
+ rt3\r
+ rt5\r
+\r
+P-space (rt3):\r
+ rt1\r
+ rt3\r
+ rt5\r
+ rt6\r
+\r
+Q-space:\r
+ rt1\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+2001:db8::2/128      IP6 internal 0                                     rt2(4)\r
+rt1                  TE-IS        50     rt1                  -         rt2(4)\r
+rt3                  TE-IS        50     rt3                  -         rt2(4)\r
+rt2                                                                   \r
+rt5                  TE-IS        60     rt3                  -         rt3(4)\r
+2001:db8::1/128      IP6 internal 60     rt1                  -         rt1(4)\r
+2001:db8::3/128      IP6 internal 60     rt3                  -         rt3(4)\r
+rt4                  TE-IS        70     rt3                  -         rt5(4)\r
+rt6                  TE-IS        70     rt3                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 70     rt3                  -         rt5(4)\r
+2001:db8::4/128      IP6 internal 80     rt3                  -         rt4(4)\r
+2001:db8::6/128      IP6 internal 80     rt3                  -         rt6(4)\r
+\r
+IS-IS paths to level-1 routers that speak IPv6\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt2                                                                   \r
+2001:db8::2/128      IP6 internal 0                                     rt2(4)\r
+rt4                  TE-IS        10     rt4                  -         rt2(4)\r
+rt5                  TE-IS        20     rt4                  -         rt4(4)\r
+rt6                  TE-IS        20     rt4                  -         rt4(4)\r
+2001:db8::4/128      IP6 internal 20     rt4                  -         rt4(4)\r
+rt3                  TE-IS        30     rt4                  -         rt5(4)\r
+2001:db8::5/128      IP6 internal 30     rt4                  -         rt5(4)\r
+2001:db8::6/128      IP6 internal 30     rt4                  -         rt6(4)\r
+rt2                                                                   \r
+rt1                  TE-IS        40     rt4                  -         rt2(2)\r
+2001:db8::3/128      IP6 internal 40     rt4                  -         rt3(4)\r
+2001:db8::1/128      IP6 internal 50     rt4                  -         rt1(4)\r
+\r
+Main:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  50      -          rt4      16011          \r
+ 2001:db8::2/128  0       -          -        -              \r
+ 2001:db8::3/128  40      -          rt4      16031          \r
+ 2001:db8::4/128  20      -          rt4      implicit-null  \r
+ 2001:db8::5/128  30      -          rt4      16051          \r
+ 2001:db8::6/128  30      -          rt4      16061          \r
+\r
+Backup:\r
+IS-IS L1 IPv6 routing table:\r
+\r
+ Prefix           Metric  Interface  Nexthop  Label(s)       \r
+ ------------------------------------------------------------\r
+ 2001:db8::1/128  50      -          rt1      implicit-null  \r
+                          -          rt3      16011          \r
+ 2001:db8::3/128  50      -          rt1      16031          \r
+                          -          rt3      implicit-null  \r
+ 2001:db8::4/128  80      -          rt3      50500/16041    \r
+ 2001:db8::5/128  60      -          rt1      16051          \r
+                          -          rt3      16051          \r
+ 2001:db8::6/128  70      -          rt3      16061          \r
+\r
+test# test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only\r
+P-space (self):\r
+ rt2\r
+\r
+P-space (rt2):\r
+ rt2\r
+ rt4\r
+\r
+Q-space:\r
+ rt3\r
+ rt4\r
+ rt5\r
+ rt6\r
+ rt7\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+rt3                  TE-IS        30     rt2                  -         rt4(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+rt5                  TE-IS        40     rt2                  -         rt3(4)\r
+rt6                  TE-IS        40     rt2                  -         rt3(4)\r
+10.0.255.3/32        IP TE        40     rt2                  -         rt3(4)\r
+rt7                  TE-IS        50     rt2                  -         rt5(4)\r
+                                                                        rt6(4)\r
+10.0.255.5/32        IP TE        50     rt2                  -         rt5(4)\r
+10.0.255.6/32        IP TE        50     rt2                  -         rt6(4)\r
+10.0.255.7/32        IP TE        60     rt2                  -         rt7(4)\r
+\r
+IS-IS paths to level-1 routers that speak IP\r
+Vertex               Type         Metric Next-Hop             Interface Parent\r
+rt1                                                                   \r
+10.0.255.1/32        IP internal  0                                     rt1(4)\r
+rt2                  TE-IS        10     rt2                  -         rt1(4)\r
+rt3                  TE-IS        10     rt3                  -         rt1(4)\r
+rt4                  TE-IS        20     rt2                  -         rt2(4)\r
+                                         rt3                  -         rt3(4)\r
+rt5                  TE-IS        20     rt3                  -         rt3(4)\r
+rt6                  TE-IS        20     rt3                  -         rt3(4)\r
+10.0.255.2/32        IP TE        20     rt2                  -         rt2(4)\r
+10.0.255.3/32        IP TE        20     rt3                  -         rt3(4)\r
+rt7                  TE-IS        30     rt3                  -         rt5(4)\r
+                                                                        rt6(4)\r
+10.0.255.4/32        IP TE        30     rt2                  -         rt4(4)\r
+                                         rt3                  -         \r
+10.0.255.5/32        IP TE        30     rt3                  -         rt5(4)\r
+10.0.255.6/32        IP TE        30     rt3                  -         rt6(4)\r
+10.0.255.7/32        IP TE        40     rt3                  -         rt7(4)\r
+\r
+Main:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)       \r
+ ----------------------------------------------------------\r
+ 10.0.255.1/32  0       -          -        -              \r
+ 10.0.255.2/32  20      -          rt2      implicit-null  \r
+ 10.0.255.3/32  20      -          rt3      implicit-null  \r
+ 10.0.255.4/32  30      -          rt2      16040          \r
+                        -          rt3      16040          \r
+ 10.0.255.5/32  30      -          rt3      16050          \r
+ 10.0.255.6/32  30      -          rt3      16060          \r
+ 10.0.255.7/32  40      -          rt3      16070          \r
+\r
+Backup:\r
+IS-IS L1 IPv4 routing table:\r
+\r
+ Prefix         Metric  Interface  Nexthop  Label(s)     \r
+ --------------------------------------------------------\r
+ 10.0.255.3/32  40      -          rt2      50400/16030  \r
+ 10.0.255.5/32  50      -          rt2      50400/16050  \r
+ 10.0.255.6/32  50      -          rt2      50400/16060  \r
+ 10.0.255.7/32  60      -          rt2      50400/16070  \r
+\r
 test# \r
 test# test isis topology 1 root rt1 ti-lfa system-id rt2\r
 P-space (self):\r
diff --git a/tests/topotests/bgp_features/exabgp.env b/tests/topotests/bgp_features/exabgp.env
new file mode 100644 (file)
index 0000000..6c554f5
--- /dev/null
@@ -0,0 +1,53 @@
+
+[exabgp.api]
+encoder = text
+highres = false
+respawn = false
+socket = ''
+
+[exabgp.bgp]
+openwait = 60
+
+[exabgp.cache]
+attributes = true
+nexthops = true
+
+[exabgp.daemon]
+daemonize = true
+pid = '/var/run/exabgp/exabgp.pid'
+user = 'exabgp'
+
+[exabgp.log]
+all = false
+configuration = true
+daemon = true
+destination = '/var/log/exabgp.log'
+enable = true
+level = INFO
+message = false
+network = true
+packets = false
+parser = false
+processes = true
+reactor = true
+rib = false
+routes = false
+short = false
+timers = false
+
+[exabgp.pdb]
+enable = false
+
+[exabgp.profile]
+enable = false
+file = ''
+
+[exabgp.reactor]
+speed = 1.0
+
+[exabgp.tcp]
+acl = false
+bind = ''
+delay = 0
+once = false
+port = 179
diff --git a/tests/topotests/bgp_features/peer1/exa_readpipe.py b/tests/topotests/bgp_features/peer1/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer1/exabgp.cfg b/tests/topotests/bgp_features/peer1/exabgp.cfg
new file mode 100644 (file)
index 0000000..2e95252
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.3;
+                local-address 192.168.101.3;
+                local-as 65403;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/peer2/exa_readpipe.py b/tests/topotests/bgp_features/peer2/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer2/exabgp.cfg b/tests/topotests/bgp_features/peer2/exabgp.cfg
new file mode 100644 (file)
index 0000000..1f65547
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.4;
+                local-address 192.168.101.4;
+                local-as 65404;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/peer3/exa_readpipe.py b/tests/topotests/bgp_features/peer3/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer3/exabgp.cfg b/tests/topotests/bgp_features/peer3/exabgp.cfg
new file mode 100644 (file)
index 0000000..8632cc8
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.5;
+                local-address 192.168.101.5;
+                local-as 65405;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/peer4/exa_readpipe.py b/tests/topotests/bgp_features/peer4/exa_readpipe.py
new file mode 100644 (file)
index 0000000..dba1536
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+"Helper script to read api commands from a pipe and feed them to ExaBGP"
+
+import sys
+
+if len(sys.argv) != 2:
+    sys.exit(1)
+fifo = sys.argv[1]
+
+while True:
+    pipe = open(fifo, 'r')
+    with pipe:
+        line = pipe.readline().strip()
+        if line != "":
+            sys.stdout.write("{}\n".format(line))
+            sys.stdout.flush()
+        pipe.close()
+
+sys.exit(0)
diff --git a/tests/topotests/bgp_features/peer4/exabgp.cfg b/tests/topotests/bgp_features/peer4/exabgp.cfg
new file mode 100644 (file)
index 0000000..06bc0d6
--- /dev/null
@@ -0,0 +1,12 @@
+group exabgp {
+        process announce-routes {
+                run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in";
+                encoder text;
+        }
+        neighbor 192.168.101.1 {
+                router-id 192.168.101.6;
+                local-address 192.168.101.6;
+                local-as 65406;
+                peer-as 65000;
+        }
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_damp_announced.json b/tests/topotests/bgp_features/r1/bgp_damp_announced.json
new file mode 100644 (file)
index 0000000..cb4a2c9
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "localAS":65000,
+  "routes":{
+    "192.168.31.0/24": [ { "valid":true, "network":"192.168.31.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.32.0/24": [ { "valid":true, "network":"192.168.32.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.33.0/24": [ { "valid":true, "network":"192.168.33.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.34.0/24": [ { "valid":true, "network":"192.168.34.0\/24", "peerId":"192.168.101.3" } ],
+    "192.168.41.0/24": [ { "valid":true, "network":"192.168.41.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.42.0/24": [ { "valid":true, "network":"192.168.42.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.43.0/24": [ { "valid":true, "network":"192.168.43.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.44.0/24": [ { "valid":true, "network":"192.168.44.0\/24", "peerId":"192.168.101.4" } ],
+    "192.168.51.0/24": [ { "valid":true, "network":"192.168.51.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.52.0/24": [ { "valid":true, "network":"192.168.52.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.53.0/24": [ { "valid":true, "network":"192.168.53.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.54.0/24": [ { "valid":true, "network":"192.168.54.0\/24", "peerId":"192.168.101.5" } ],
+    "192.168.61.0/24": [ { "valid":true, "network":"192.168.61.0\/24", "peerId":"192.168.101.6" } ],
+    "192.168.62.0/24": [ { "valid":true, "network":"192.168.62.0\/24", "peerId":"192.168.101.6" } ],
+    "192.168.63.0/24": [ { "valid":true, "network":"192.168.63.0\/24", "peerId":"192.168.101.6" } ],
+    "192.168.64.0/24": [ { "valid":true, "network":"192.168.64.0\/24", "peerId":"192.168.101.6" } ]
+  }
+}
diff --git a/tests/topotests/bgp_features/r1/bgp_damp_setup.json b/tests/topotests/bgp_features/r1/bgp_damp_setup.json
new file mode 100644 (file)
index 0000000..f9f89db
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "ipv4Unicast":{
+    "peers":{
+      "192.168.101.3":{"remoteAs":65403, "state":"Established"},
+      "192.168.101.4":{"remoteAs":65404, "state":"Established"},
+      "192.168.101.5":{"remoteAs":65405, "state":"Established"},
+      "192.168.101.6":{"remoteAs":65406, "state":"Established"}
+    }
+  }
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_damp_announced.json b/tests/topotests/bgp_features/r2/bgp_damp_announced.json
new file mode 100644 (file)
index 0000000..9394358
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "localAS":65000,
+  "routes":{
+    "192.168.31.0/24": [ { "network":"192.168.31.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.32.0/24": [ { "network":"192.168.32.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.33.0/24": [ { "network":"192.168.33.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.34.0/24": [ { "network":"192.168.34.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.41.0/24": [ { "network":"192.168.41.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.42.0/24": [ { "network":"192.168.42.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.43.0/24": [ { "network":"192.168.43.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.44.0/24": [ { "network":"192.168.44.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.51.0/24": [ { "network":"192.168.51.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.52.0/24": [ { "network":"192.168.52.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.53.0/24": [ { "network":"192.168.53.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.54.0/24": [ { "network":"192.168.54.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.61.0/24": [ { "network":"192.168.61.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.62.0/24": [ { "network":"192.168.62.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.63.0/24": [ { "network":"192.168.63.0\/24", "peerId":"192.168.0.1" } ],
+    "192.168.64.0/24": [ { "network":"192.168.64.0\/24", "peerId":"192.168.0.1" } ]
+  }
+}
diff --git a/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json b/tests/topotests/bgp_features/r2/bgp_damp_withdrawn.json
new file mode 100644 (file)
index 0000000..f3c54a7
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "192.168.31.0/24": null,
+  "192.168.32.0/24": null,
+  "192.168.33.0/24": null,
+  "192.168.34.0/24": null,
+  "192.168.41.0/24": null,
+  "192.168.42.0/24": null,
+  "192.168.43.0/24": null,
+  "192.168.44.0/24": null,
+  "192.168.51.0/24": null,
+  "192.168.52.0/24": null,
+  "192.168.53.0/24": null,
+  "192.168.54.0/24": null,
+  "192.168.61.0/24": null,
+  "192.168.62.0/24": null,
+  "192.168.63.0/24": null,
+  "192.168.64.0/24": null
+}
index 5f3809c2b3e02a290a41de199f2108e33925b323..3d963b4cf65b53291454de680025110d37659f70 100644 (file)
@@ -33,6 +33,7 @@ import sys
 import pytest
 import re
 import time
+from time import sleep
 
 # Save the Current Working Directory to find configuration files.
 CWD = os.path.dirname(os.path.realpath(__file__))
@@ -64,6 +65,14 @@ class BGPFeaturesTopo1(Topo):
         for rtrNum in range(1, 6):
             tgen.add_router("r{}".format(rtrNum))
 
+        # create ExaBGP peers
+        for peer_num in range(1, 5):
+            tgen.add_exabgp_peer(
+                "peer{}".format(peer_num),
+                ip="192.168.101.{}".format(peer_num + 2),
+                defaultRoute="via 192.168.101.1",
+            )
+
         # Setup Switches and connections
         for swNum in range(1, 11):
             tgen.add_switch("sw{}".format(swNum))
@@ -89,6 +98,12 @@ class BGPFeaturesTopo1(Topo):
         tgen.gears["r2"].add_link(tgen.gears["sw5"])
         tgen.gears["r5"].add_link(tgen.gears["sw5"])
 
+        # Add ExaBGP peers to sw4
+        tgen.gears["peer1"].add_link(tgen.gears["sw4"])
+        tgen.gears["peer2"].add_link(tgen.gears["sw4"])
+        tgen.gears["peer3"].add_link(tgen.gears["sw4"])
+        tgen.gears["peer4"].add_link(tgen.gears["sw4"])
+
 
 #####################################################
 #
@@ -1093,6 +1108,662 @@ def test_bgp_delayopen_dual():
     # end test_bgp_delayopen_dual
 
 
+def test_bgp_dampening_setup():
+    "BGP route-flap dampening test setup"
+
+    # This test starts four ExaBGP peers, adds them as neighbors to the
+    # configuration of router r1 and checks if connections get established.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting BGP route-flap dampening test setup")
+
+    # Start ExaBGP peers connected to r1 via switch 4
+    logger.info("Starting ExaBGP peers")
+    for peer_num in range(1, 5):
+        logger.info("Creating named pipe for ExaBGP peer peer{}".format(peer_num))
+        fifo_in = "/var/run/exabgp_peer{}.in".format(peer_num)
+        if os.path.exists(fifo_in):
+            os.remove(fifo_in)
+        os.mkfifo(fifo_in, 0o777)
+        logger.info("Starting ExaBGP on peer peer{}".format(peer_num))
+        peer = tgen.gears["peer{}".format(peer_num)]
+        peer_dir = os.path.join(CWD, "peer{}".format(peer_num))
+        env_file = os.path.join(CWD, "exabgp.env")
+        peer.start(peer_dir, env_file)
+
+    # Add ExaBGP peers to configuration of router r2
+    logger.info("Adding ExaBGP peers as neighbors to configuration of router r2")
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.3 remote-as 65403"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 route-map testmap-out"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.4 remote-as 65404"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.4 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.4 route-map testmap-out"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.5 remote-as 65405"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 route-map testmap-out"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.6 remote-as 65406"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.6 route-map testmap-in"'
+    )
+    tgen.net["r1"].cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.6 route-map testmap-out"'
+    )
+
+    # Check if exabgp peers are up and running
+    logger.info("Checking for established connections to ExaBGP peers on router r1")
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_damp_setup.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp summary json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = (
+        "BGP session on r1 did not establish connections with one ore more ExaBGP peers"
+    )
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_setup
+
+
+def test_bgp_dampening_route_announce():
+    "Test of BGP route-flap dampening route announcement"
+
+    # This test checks if the four ExaBGP peers can announce routes to router
+    # r1 and if these routes get forwarded to router r2.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening route announcement")
+
+    # Announce routes on exabgp peers to r2
+    logger.info("Announcing routes on ExaBGP peers to r1")
+    for prefix_iter in range(1, 5):
+        for peer_num in range(1, 5):
+            pipe = open("/run/exabgp_peer{}.in".format(peer_num), "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.{}{}.0/24 next-hop 192.168.101.{}\n".format(
+                        (peer_num + 2), prefix_iter, (peer_num + 2)
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check if routes announced by ExaBGP peers are present in RIB of router r1
+    logger.info(
+        "Checking if routes announced by ExaBGP peers are present in RIB of router r1"
+    )
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_damp_announced.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = (
+        "BGP session on router r1 did not receive routes announced by ExaBGP peers"
+    )
+    assert res is None, assertmsg
+
+    # Check if routes announced by ExaBGP peers to router r1 have been forwarded
+    # and are now present in RIB of router r2
+    logger.info(
+        "Checking if forwarded routes announced by ExaBGP peers are present in RIB of router r2"
+    )
+    router = tgen.gears["r2"]
+    reffile = os.path.join(CWD, "r2/bgp_damp_announced.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = "BGP session on router r2 did not receive routes announced by ExaBGP peers forwarded by router r1"
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_route_announce
+
+
+def test_bgp_dampening_disabled():
+    "Test of BGP route-flapping with dampening disabled"
+
+    # This test verifies that flapped routes do not get withdrawn from the RIB
+    # of router r1 if dampening is disabled.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flapping with dampening disabled")
+
+    # Flapping routes on ExaBGP peer peer1
+    logger.info(
+        "Flapping routes on ExaBGP peer peer1 with route-flap dampening disabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Verify flapped routes are still present in RIB of router r1
+    logger.info(
+        "Verifying that the flapped routes are still present in RIB of router r1"
+    )
+    router = tgen.gears["r1"]
+    reffile = os.path.join(CWD, "r1/bgp_damp_announced.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, router, "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=10, wait=1)
+    assertmsg = "BGP session on router r1 removed flapped routes despite route-flap dampening being disabled"
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_disabled
+
+
+def test_bgp_dampening_config():
+    "Test of BGP route-flap dampening configuration"
+
+    # This test adds peer-group group1 with peers peer1 and peer2 to the
+    # configuration of router r1, sets up dampening configurations with
+    # different profiles and verifies the configured dampening parameters.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening configuration")
+
+    # Add peer-group group1 with peers peer1 and peer2
+    logger.info(
+        "Creating peer-group group1 and adding ExaBGP peers peer1 and peer2 to it"
+    )
+    r_1.cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor group1 peer-group"')
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.3 peer-group group1"'
+    )  # peer1
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.4 peer-group group1"'
+    )  # peer2
+
+    # Enable different dampening profiles for peer1, peer3, group1 and global
+    # configuration
+    logger.info(
+        "Enabling different dampening profiles for peer1, peer3, group1 and global configuration"
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "bgp dampening 30 300 900 90"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor group1 dampening 20 200 600 60"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.3 dampening 10 100 300 30"'
+    )  # peer1
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "neighbor 192.168.101.5 dampening 10 100 300 30"'
+    )  # peer3
+
+    # Verify route-flap dampening configuration
+    logger.info("Verifying route-flap dampening configuration on router r1")
+    vtyout = r_1.cmd('vtysh -c "show running-config"')
+    assertmsg = "BGP Session on r1 does not show enabled global route-flap dampening in running configuration"
+    assert re.search("bgp dampening 30 300 900 90", vtyout), assertmsg
+    assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer-group group1 in running configuration"
+    assert re.search("neighbor group1 dampening 20 200 600 60", vtyout), assertmsg
+    assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer peer1 in running configuration"
+    assert re.search(
+        "neighbor 192.168.101.3 dampening 10 100 300 30", vtyout
+    ), assertmsg
+    assertmsg = "BGP Session on r1 does not show route-flap dampening enabled for peer peer3 in running configuration"
+    assert re.search(
+        "neighbor 192.168.101.5 dampening 10 100 300 30", vtyout
+    ), assertmsg
+
+    # end test_bgp_dampening_config
+
+
+def test_bgp_dampening_profile_peer_over_group():
+    "Test of BGP route-flap dampening profile preferences: peer over group"
+
+    # This test verifies that the dampening profile of a peer takes precedence
+    # over the dampening profile of its peer-group by flapping the peers routes
+    # until dampened and comparing the reuse times to the one specified in the
+    # dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Starting test of BGP route-flap dampening profile preferences: peer over group"
+    )
+
+    # Flapping routes on ExaBGP peer peer1
+    logger.info(
+        "Flapping routes on ExaBGP peer peer1 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer1.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.3{}.0/24 next-hop 192.168.101.3\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer1 witn peer profile
+    logger.info(
+        "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer1"
+    )
+    sleep(5)  # Wait 5 seconds for paths to show up in dampened-paths list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.3\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer1"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer1"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 0) and (  # hours of reuse time
+            35 > int(route.split()[3].split(":")[1]) > 25
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_peer_over_group
+
+
+def test_bgp_dampening_profile_group_over_global():
+    "Test of BGP route-flap dampening profile preferences: group over global"
+
+    # This test verifies that the dampening profile of a peer-group takes
+    # precedence over the global dampening profile by flapping the routes of a
+    # peer-group member until dampened and comparing the reuse times to the one
+    # specified in the dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Starting test of BGP route-flap dampening profile preferences: group over global"
+    )
+
+    # Flapping routes on ExaBGP peer peer2
+    logger.info(
+        "Flapping routes on ExaBGP peer peer2 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer2.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.4{}.0/24 next-hop 192.168.101.4\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer2.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.4{}.0/24 next-hop 192.168.101.4\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer2 witn group profile
+    logger.info(
+        "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer2"
+    )
+    sleep(5)  # wait 5 seconds for paths to shop up in damp list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.4\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer2"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer2"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 0) and (  # hours of reuse time
+            65 > int(route.split()[3].split(":")[1]) > 55
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_group_over_global
+
+
+def test_bgp_dampening_profile_peer_over_global():
+    "Test of BGP route-flap dampening profile preferences: peer over global"
+
+    # This test verifies that the dampening profile of a peer takes precedence
+    # over the global dampening profile by flapping the routes of the peer until
+    # dampened and comparing the reuse times to the one specified in the
+    # dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info(
+        "Starting test of BGP route-flap dampening profile preferences: peer over global"
+    )
+
+    # Flapping routes on ExaBGP peer peer3
+    logger.info(
+        "Flapping routes on ExaBGP peer peer3 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer3.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.5{}.0/24 next-hop 192.168.101.5\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer3.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.5{}.0/24 next-hop 192.168.101.5\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer3 witn peer profile
+    logger.info(
+        "Checking if router r1 used the correct dampening profile on routes flapped by ExaBGP peer peer3"
+    )
+    sleep(5)  # wait 5 seconds for paths to shop up in damp list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.5\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer3"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 used wrong dampening profile for a route flapped by ExaBGP peer peer3"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 0) and (  # hours of reuse time
+            35 > int(route.split()[3].split(":")[1]) > 25
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_peer_over_global
+
+
+def test_bgp_dampening_profile_global():
+    "Test of BGP route-flap dampening global profile"
+
+    # This test verifies the application of the global dampening profile by
+    # flapping the routes of a peer until dampened and comparing the reuse times
+    # to the one specified in the dampening configuration.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening global profile")
+
+    # Flapping routes on ExaBGP peer peer4
+    logger.info(
+        "Flapping routes on ExaBGP peer peer4 with route-flap dampening enabled"
+    )
+    for _ in range(1, 5):
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer4.in", "w")
+            with pipe:
+                pipe.write(
+                    "withdraw route 192.168.6{}.0/24 next-hop 192.168.101.6\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+        sleep(1)  # Give the BGP session on router r1 time to process routes
+        for prefix_iter in range(1, 5):
+            pipe = open("/run/exabgp_peer4.in", "w")
+            with pipe:
+                pipe.write(
+                    "announce route 192.168.6{}.0/24 next-hop 192.168.101.6\n".format(
+                        prefix_iter
+                    )
+                )
+                pipe.close()
+                sleep(0.1)  # ExaBGP API command processing delay
+
+    # Check damped paths on r1 for routes of peer4 witn global profile
+    logger.info(
+        "Checking if router r1 used the global dampening profile on routes flapped by ExaBGP peer peer4"
+    )
+    sleep(5)  # wait 5 seconds for paths to shop up in damp list
+    vtyout = r_1.cmd('vtysh -c "show ip bgp dampening dampened-paths"')
+    routes = re.findall(r"\*d 192\.168\.6\d\.0\/24.*", vtyout)
+    assertmsg = (
+        "BGP session on router r1 did not dampen routes flapped by ExaBGP peer peer4"
+    )
+    assert len(routes) == 4, assertmsg
+    assertmsg = "BGP session on router r1 did not use the global dampening profile for a route flapped by ExaBGP peer peer4"
+    for route in routes:
+        assert (int(route.split()[3].split(":")[0]) == 1) and (  # hours of reuse time
+            35 > int(route.split()[3].split(":")[1]) > 25
+        ), assertmsg  # minutes of reuse time
+
+    # end test_bgp_dampening_profile_global
+
+
+def test_bgp_dampening_withdaw():
+    "Test BGP route-flap dampening route withdraw"
+
+    # This test verifies that the withrawl of dampened routes from the RIB of
+    # router r1 was propagated to router r2.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting test of BGP route-flap dampening route withdraw")
+
+    # Check if routes dampened on router r1 have been withdrawn from the RIB on
+    # router r2
+    logger.info(
+        "Checking if routes dampened on router r1 have been withdrawn of RIB on router r2"
+    )
+    reffile = os.path.join(CWD, "r2/bgp_damp_withdrawn.json")
+    expected = json.loads(open(reffile).read())
+    test_func = functools.partial(
+        topotest.router_json_cmp, tgen.gears["r2"], "show ip bgp json", expected
+    )
+    _, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
+    assertmsg = "BGP session on router r2 did not receive withdraw of routes dampened on router r1"
+    assert res is None, assertmsg
+
+    # end test_bgp_dampening_withdaw
+
+
+def test_bgp_dampening_cleanup():
+    "BGP route-flap dampening test cleanup"
+
+    # This test cleans up after other tests associated with route-flap dampening
+    # by disabling all dampening configurations, removing added peers and
+    # peer-groups from the configuration on router r1, and shutting down ExaBGP
+    # peers peer1, peer2 and peer3.
+
+    tgen = get_topogen()
+    r_1 = tgen.net["r1"]
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("Starting BGP route-flap dampening test cleanup")
+
+    # Disable all dampening configurations
+    logger.info("Disabling all dampening configurations")
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no bgp dampening"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor group1 dampening"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor 192.168.101.3 dampening"'
+    )
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "address-family ipv4 unicast" -c "no neighbor 192.168.101.5 dampening"'
+    )
+
+    # Remove ExaBGP peers from configuration of router r1
+    logger.info("Removing ExaBGP peers from configuration of router r1")
+    for router_num in range(3, 7):
+        r_1.cmd(
+            'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.{}"'.format(
+                router_num
+            )
+        )
+
+    # Remove peer-group group1 from configuration of router r1
+    logger.info("Removing peer-group group1 peers from configuration of router r1")
+    r_1.cmd(
+        'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor group1 peer-group"'
+    )
+
+    # Stop ExaBGP peers and remove associated named pipes
+    logger.info("Stopping ExaBGP peers and removing associated named pipes")
+    for peer_num in range(1, 5):
+        logger.info("Terminating ExaBGP on peer peer{}".format(peer_num))
+        peer = tgen.gears["peer{}".format(peer_num)]
+        logger.info("Removing named pipe of ExaBGP peer peer{}".format(peer_num))
+        fifo_in = "/var/run/exabgp_peer{}.in".format(peer_num)
+        peer.stop()
+        if os.path.exists(fifo_in):
+            os.remove(fifo_in)
+
+    # end test_bgp_dampening_cleanup
+
+
+def test_bgp_dampening_aftermath():
+    "BGP route-flap dampening aftermath test"
+
+    # This test verifies routers r1 and r2 not being affected by the route-flap
+    # dampening test series.
+
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    # Check BGP Summary on routers r1 and r2
+    for rtr_num in [1, 2]:
+        logger.info(
+            "Checking if BGP router on r{} remains unaffected by route-flap dampening tests".format(
+                rtr_num
+            )
+        )
+        router = tgen.gears["r{}".format(rtr_num)]
+        reffile = os.path.join(CWD, "r{}/show_bgp.json".format(rtr_num))
+        expected = json.loads(open(reffile).read())
+        test_func = functools.partial(
+            topotest.router_json_cmp, router, "show ip bgp json", expected
+        )
+        _, res = topotest.run_and_expect(test_func, None, count=10, wait=2)
+        assertmsg = "BGP routes on router r{} are wrong after route-flap dampening tests".format(
+            rtr_num
+        )
+        assert res is None, assertmsg
+
+    # end test_bgp_dampening_aftermath
+
+
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
     sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json b/tests/topotests/bgp_listen_on_multiple_addresses/bgp_listen_on_multiple_addresses.json
new file mode 100644 (file)
index 0000000..95de8cc
--- /dev/null
@@ -0,0 +1,154 @@
+{
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 24,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 24,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:DB8:F::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                       "local_as": "1000",
+                       "address_family": {
+                           "ipv4": {
+                               "unicast": {
+                                   "neighbor": {
+                                       "r2": {
+                                           "dest_link": {
+                                               "r1": {}
+                                           }
+                                       }
+                                   }
+                               }
+                           }
+                       }
+                   }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "2000",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r1": {
+                                    "dest_link": {
+                                        "r2": {}
+                                    }
+                                },
+                                "r3": {
+                                    "dest_link": {
+                                        "r2": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+           },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "2000",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3": {}
+                                    }
+                                },
+                                "r4": {
+                                    "dest_link": {
+                                        "r3": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r4": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "3000",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r4": {}
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py b/tests/topotests/bgp_listen_on_multiple_addresses/test_bgp_listen_on_multiple_addresses.py
new file mode 100755 (executable)
index 0000000..d773e87
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_listen_on_multiple_addresses.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by Boeing Defence Australia
+# Adriano Marto Reis
+#
+# 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 NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+"""
+test_bgp_listen_on_multiple_addresses.py: Test BGP daemon listening for
+connections on multiple addresses.
+
+    +------+        +------+        +------+        +------+
+    |      |        |      |        |      |        |      |
+    |  r1  |--------|  r2  |--------|  r3  |--------|  r4  |
+    |      |        |      |        |      |        |      |
+    +------+        +------+        +------+        +------+
+
+  |            |                                |             |
+  |  AS 1000   |            AS 2000             |   AS 3000   |
+  |            |                                |             |
+  +------------+--------------------------------+-------------+
+"""
+
+import os
+import sys
+import json
+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, "../"))
+
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.common_config import start_topology
+from lib.topotest import router_json_cmp, run_and_expect
+from mininet.topo import Topo
+from functools import partial
+
+
+LISTEN_ADDRESSES = {
+    "r1": ["10.0.0.1"],
+    "r2": ["10.0.0.2", "10.0.1.1"],
+    "r3": ["10.0.1.2", "10.0.2.1"],
+    "r4": ["10.0.2.2"],
+}
+
+
+# Reads data from JSON File for topology and configuration creation.
+jsonFile = "{}/bgp_listen_on_multiple_addresses.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+
+class TemplateTopo(Topo):
+    "Topology builder."
+
+    def build(self, *_args, **_opts):
+        "Defines the allocation and relationship between routers and switches."
+        tgen = get_topogen(self)
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    "Sets up the test environment."
+    tgen = Topogen(TemplateTopo, mod.__name__)
+
+    # Adds extra parameters to bgpd so they listen for connections on specific
+    # multiple addresses.
+    for router_name in tgen.routers().keys():
+        tgen.net[router_name].daemons_options["bgpd"] = "-l " + " -l ".join(
+            LISTEN_ADDRESSES[router_name]
+        )
+
+    start_topology(tgen)
+    build_config_from_json(tgen, topo)
+
+
+def teardown_module(_mod):
+    "Tears-down the test environment."
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_peering():
+    "Checks if the routers peer-up."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    _bgp_converge_initial("r1", "10.0.0.2")
+    _bgp_converge_initial("r2", "10.0.0.1")
+    _bgp_converge_initial("r2", "10.0.1.2")
+    _bgp_converge_initial("r3", "10.0.1.1")
+    _bgp_converge_initial("r3", "10.0.2.2")
+    _bgp_converge_initial("r4", "10.0.2.1")
+
+
+def test_listening_address():
+    """
+    Checks if bgpd is only listening on the specified IP addresses.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for router in tgen.routers().values():
+        # bgpd must not be listening on the default address.
+        output = router.run("netstat -nlt4 | grep 0.0.0.0:179")
+        assert output == "", "{}: bpgd is listening on 0.0.0.0:179".format(router.name)
+
+        # bgpd must be listening on the specified addresses.
+        for address in LISTEN_ADDRESSES[router.name]:
+            output = router.run("netstat -nlt4 | grep {}:179".format(address))
+            assert output != "", "{}: bpgd is not listening on {}:179".format(
+                router.name, address
+            )
+
+
+def _bgp_converge_initial(router_name, peer_address, timeout=180):
+    """
+    Waits for the BGP connection between a given router and a given peer
+    (specified by its IP address) to be established. If the connection is
+    not established within a given timeout, then an exception is raised. 
+    """
+    tgen = get_topogen()
+    router = tgen.routers()[router_name]
+    expected = {"ipv4Unicast": {"peers": {peer_address: {"state": "Established"}}}}
+
+    test_func = partial(router_json_cmp, router, "show ip bgp summary json", expected)
+    _, result = run_and_expect(test_func, None, count=timeout, wait=1)
+    assert result is None, "{}: Failed to establish connection with {}".format(
+        router_name, peer_address
+    )
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis-rlfa-topo1/__init__.py b/tests/topotests/isis-rlfa-topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt1/isisd.conf
new file mode 100644 (file)
index 0000000..a80f30d
--- /dev/null
@@ -0,0 +1,39 @@
+password 1
+hostname rt1
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+ isis fast-reroute lfa
+ isis fast-reroute remote-lfa tunnel mpls-ldp
+!
+interface eth-rt3
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+ isis fast-reroute lfa
+ isis fast-reroute remote-lfa tunnel mpls-ldp
+!
+ip prefix-list PLIST seq 5 permit 10.0.255.8/32
+!
+router isis 1
+ net 49.0000.0000.0000.0001.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+ fast-reroute remote-lfa prefix-list PLIST
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt1/ldpd.conf
new file mode 100644 (file)
index 0000000..f60fdb9
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt1
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.1
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.1
+  !
+  interface eth-rt2
+  interface eth-rt3
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::1
+  !
+  interface eth-rt2
+  interface eth-rt3
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ip_route.ref
new file mode 100644 (file)
index 0000000..680b31e
--- /dev/null
@@ -0,0 +1,235 @@
+{
+  "10.0.255.2\/32":[
+    {
+      "prefix":"10.0.255.2\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.3\/32":[
+    {
+      "prefix":"10.0.255.3\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.4\/32":[
+    {
+      "prefix":"10.0.255.4\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.5\/32":[
+    {
+      "prefix":"10.0.255.5\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.6\/32":[
+    {
+      "prefix":"10.0.255.6\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.7\/32":[
+    {
+      "prefix":"10.0.255.7\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "10.0.255.8\/32":[
+    {
+      "prefix":"10.0.255.8\/32",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "ip":"10.0.255.2",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "onLink":true
+        },
+        {
+          "fib":true,
+          "ip":"10.0.255.3",
+          "afi":"ipv4",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "onLink":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644 (file)
index 0000000..c487d27
--- /dev/null
@@ -0,0 +1,207 @@
+{
+  "2001:db8::2\/128":[
+    {
+      "prefix":"2001:db8::2\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::3\/128":[
+    {
+      "prefix":"2001:db8::3\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::4\/128":[
+    {
+      "prefix":"2001:db8::4\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::5\/128":[
+    {
+      "prefix":"2001:db8::5\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::6\/128":[
+    {
+      "prefix":"2001:db8::6\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::7\/128":[
+    {
+      "prefix":"2001:db8::7\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true,
+          "backupIndex":[
+            0
+          ]
+        }
+      ],
+      "backupNexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true,
+          "labels":"*"
+        }
+      ]
+    }
+  ],
+  "2001:db8::8\/128":[
+    {
+      "prefix":"2001:db8::8\/128",
+      "protocol":"isis",
+      "selected":true,
+      "destSelected":true,
+      "distance":115,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        },
+        {
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-rlfa-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644 (file)
index 0000000..3fe2b79
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "frr-interface:lib": {
+    "interface": [
+      {
+        "name": "eth-rt2",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1-2",
+                  "neighbor-sysid": "0000.0000.0002",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      },
+      {
+        "name": "eth-rt3",
+        "vrf": "default",
+        "state": {
+          "frr-isisd:isis": {
+            "adjacencies": {
+              "adjacency": [
+                {
+                  "neighbor-sys-type": "level-1-2",
+                  "neighbor-sysid": "0000.0000.0003",
+                  "hold-timer": 9,
+                  "neighbor-priority": 0,
+                  "state": "up"
+                }
+              ]
+            }
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..ef5707f
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step9/show_ip_route.ref
++++ b/rt1/step10/show_ip_route.ref
+@@ -15,7 +15,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -70,7 +83,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -125,7 +151,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step10/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..acd2ce0
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step9/show_ipv6_route.ref
++++ b/rt1/step10/show_ipv6_route.ref
+@@ -13,7 +13,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -62,7 +73,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -111,7 +133,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..f7f31ac
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/rt1/step1/show_ip_route.ref
++++ b/rt1/step2/show_ip_route.ref
+@@ -15,20 +15,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -49,20 +36,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -83,20 +57,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -117,20 +78,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -151,20 +99,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -185,20 +120,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step2/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..e980031
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/rt1/step1/show_ipv6_route.ref
++++ b/rt1/step2/show_ipv6_route.ref
+@@ -13,18 +13,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -43,18 +32,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -73,18 +51,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -103,18 +70,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -133,18 +89,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -163,18 +108,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..f3ed764
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/rt1/step2/show_ip_route.ref
++++ b/rt1/step3/show_ip_route.ref
+@@ -15,7 +15,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -36,7 +49,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -57,7 +83,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -78,7 +117,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -99,7 +151,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -120,7 +185,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step3/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..57b0b1d
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/rt1/step2/show_ipv6_route.ref
++++ b/rt1/step3/show_ipv6_route.ref
+@@ -13,7 +13,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -32,7 +43,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -51,7 +73,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -70,7 +103,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -89,7 +133,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -108,7 +163,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..107a0ba
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step3/show_ip_route.ref
++++ b/rt1/step4/show_ip_route.ref
+@@ -15,20 +15,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -83,20 +70,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -151,20 +125,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step4/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..9cf2408
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step3/show_ipv6_route.ref
++++ b/rt1/step4/show_ipv6_route.ref
+@@ -13,18 +13,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -73,18 +62,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -133,18 +111,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..0946950
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step4/show_ip_route.ref
++++ b/rt1/step5/show_ip_route.ref
+@@ -36,20 +36,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -91,20 +78,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -146,20 +120,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.2",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step5/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..70fb1a6
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step4/show_ipv6_route.ref
++++ b/rt1/step5/show_ipv6_route.ref
+@@ -32,18 +32,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -81,18 +70,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -130,18 +108,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt2",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..4e4a569
--- /dev/null
@@ -0,0 +1,134 @@
+--- a/rt1/step5/show_ip_route.ref
++++ b/rt1/step6/show_ip_route.ref
+@@ -15,7 +15,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -36,7 +49,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -57,7 +83,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -78,7 +117,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -99,7 +151,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.3",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -120,7 +185,20 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt3",
+           "active":true,
+-          "onLink":true
++          "onLink":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "ip":"10.0.255.2",
++          "afi":"ipv4",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "onLink":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step6/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..c9ebb1e
--- /dev/null
@@ -0,0 +1,122 @@
+--- a/rt1/step5/show_ipv6_route.ref
++++ b/rt1/step6/show_ipv6_route.ref
+@@ -13,7 +13,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -32,7 +43,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -51,7 +73,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -70,7 +103,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -89,7 +133,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt3",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
+@@ -108,7 +163,18 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt3",
+-          "active":true
++          "active":true,
++          "backupIndex":[
++            0
++          ]
++        }
++      ],
++      "backupNexthops":[
++        {
++          "afi":"ipv6",
++          "interfaceName":"eth-rt2",
++          "active":true,
++          "labels":"*"
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step7/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step8/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ip_route.ref.diff
new file mode 100644 (file)
index 0000000..33eb657
--- /dev/null
@@ -0,0 +1,68 @@
+--- a/rt1/step8/show_ip_route.ref
++++ b/rt1/step9/show_ip_route.ref
+@@ -15,20 +15,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -83,20 +70,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
+@@ -151,20 +125,7 @@
+           "afi":"ipv4",
+           "interfaceName":"eth-rt2",
+           "active":true,
+-          "onLink":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "ip":"10.0.255.3",
+-          "afi":"ipv4",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "onLink":true,
+-          "labels":"*"
++          "onLink":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff b/tests/topotests/isis-rlfa-topo1/rt1/step9/show_ipv6_route.ref.diff
new file mode 100644 (file)
index 0000000..7aaca33
--- /dev/null
@@ -0,0 +1,62 @@
+--- a/rt1/step8/show_ipv6_route.ref
++++ b/rt1/step9/show_ipv6_route.ref
+@@ -13,18 +13,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -73,18 +62,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
+@@ -133,18 +111,7 @@
+           "fib":true,
+           "afi":"ipv6",
+           "interfaceName":"eth-rt2",
+-          "active":true,
+-          "backupIndex":[
+-            0
+-          ]
+-        }
+-      ],
+-      "backupNexthops":[
+-        {
+-          "afi":"ipv6",
+-          "interfaceName":"eth-rt3",
+-          "active":true,
+-          "labels":"*"
++          "active":true
+         }
+       ]
+     }
diff --git a/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt1/zebra.conf
new file mode 100644 (file)
index 0000000..741fc2d
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.1/32
+ ipv6 address 2001:db8::1/128
+!
+interface eth-rt2
+ ip address 10.0.255.1/32
+!
+interface eth-rt3
+ ip address 10.0.255.1/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt2/isisd.conf
new file mode 100644 (file)
index 0000000..7b4c6c5
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt2
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0002.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt2/ldpd.conf
new file mode 100644 (file)
index 0000000..0a815ef
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt2
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.2
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.2
+  !
+  interface eth-rt1
+  interface eth-rt4
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::2
+  !
+  interface eth-rt1
+  interface eth-rt4
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt2/zebra.conf
new file mode 100644 (file)
index 0000000..657c69b
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.2/32
+ ipv6 address 2001:db8::2/128
+!
+interface eth-rt1
+ ip address 10.0.255.2/32
+!
+interface eth-rt4
+ ip address 10.0.255.2/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt3/isisd.conf
new file mode 100644 (file)
index 0000000..17d58a9
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt3
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0003.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt3/ldpd.conf
new file mode 100644 (file)
index 0000000..40f1f55
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt3
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.3
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.3
+  !
+  interface eth-rt1
+  interface eth-rt5
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::3
+  !
+  interface eth-rt1
+  interface eth-rt5
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt3/zebra.conf
new file mode 100644 (file)
index 0000000..86f5d28
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.3/32
+ ipv6 address 2001:db8::3/128
+!
+interface eth-rt1
+ ip address 10.0.255.3/32
+!
+interface eth-rt5
+ ip address 10.0.255.3/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt4/isisd.conf
new file mode 100644 (file)
index 0000000..1519fd4
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt4
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0004.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt4/ldpd.conf
new file mode 100644 (file)
index 0000000..569ecf7
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt4
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.4
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.4
+  !
+  interface eth-rt2
+  interface eth-rt6
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::4
+  !
+  interface eth-rt2
+  interface eth-rt6
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt4/zebra.conf
new file mode 100644 (file)
index 0000000..1dd09bf
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.4/32
+ ipv6 address 2001:db8::4/128
+!
+interface eth-rt2
+ ip address 10.0.255.4/32
+!
+interface eth-rt6
+ ip address 10.0.255.4/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt5/isisd.conf
new file mode 100644 (file)
index 0000000..caf7477
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt5
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt3
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt7
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0005.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt5/ldpd.conf
new file mode 100644 (file)
index 0000000..519c3d3
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt5
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.5
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.5
+  !
+  interface eth-rt3
+  interface eth-rt7
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::5
+  !
+  interface eth-rt3
+  interface eth-rt7
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt5/zebra.conf
new file mode 100644 (file)
index 0000000..7117a2a
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.5/32
+ ipv6 address 2001:db8::5/128
+!
+interface eth-rt3
+ ip address 10.0.255.5/32
+!
+interface eth-rt7
+ ip address 10.0.255.5/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt6/isisd.conf
new file mode 100644 (file)
index 0000000..cdf6267
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt6
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt8
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0006.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt6/ldpd.conf
new file mode 100644 (file)
index 0000000..a5b7062
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt6
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.6
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.6
+  !
+  interface eth-rt4
+  interface eth-rt8
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::6
+  !
+  interface eth-rt4
+  interface eth-rt8
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt6/zebra.conf
new file mode 100644 (file)
index 0000000..c634487
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt6
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.6/32
+ ipv6 address 2001:db8::6/128
+!
+interface eth-rt4
+ ip address 10.0.255.6/32
+!
+interface eth-rt8
+ ip address 10.0.255.6/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt7/isisd.conf
new file mode 100644 (file)
index 0000000..8ab8fcb
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt7
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt8
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0007.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt7/ldpd.conf
new file mode 100644 (file)
index 0000000..26d428c
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt7
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.7
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.7
+  !
+  interface eth-rt5
+  interface eth-rt8
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::7
+  !
+  interface eth-rt5
+  interface eth-rt8
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt7/zebra.conf
new file mode 100644 (file)
index 0000000..4c5e0f1
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt7
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.7/32
+ ipv6 address 2001:db8::7/128
+!
+interface eth-rt5
+ ip address 10.0.255.7/32
+!
+interface eth-rt8
+ ip address 10.0.255.7/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf b/tests/topotests/isis-rlfa-topo1/rt8/isisd.conf
new file mode 100644 (file)
index 0000000..abdc6a5
--- /dev/null
@@ -0,0 +1,32 @@
+password 1
+hostname rt8
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+interface eth-rt7
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+ isis network point-to-point
+!
+router isis 1
+ net 49.0000.0000.0000.0008.00
+ is-type level-1-2
+ lsp-gen-interval 2
+ topology ipv6-unicast
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf b/tests/topotests/isis-rlfa-topo1/rt8/ldpd.conf
new file mode 100644 (file)
index 0000000..1629f82
--- /dev/null
@@ -0,0 +1,30 @@
+log file ldpd.log
+!
+hostname rt8
+!
+debug mpls ldp messages recv
+debug mpls ldp messages sent
+debug mpls ldp zebra
+!
+mpls ldp
+ router-id 10.0.255.8
+ dual-stack transport-connection prefer ipv4
+ !
+ address-family ipv4
+  label local allocate host-routes
+  discovery targeted-hello accept
+  discovery transport-address 10.0.255.8
+  !
+  interface eth-rt6
+  interface eth-rt7
+  !
+ !
+ address-family ipv6
+  label local allocate host-routes
+  discovery transport-address 2001:db8::8
+  !
+  interface eth-rt6
+  interface eth-rt7
+  !
+ !
+!
diff --git a/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf b/tests/topotests/isis-rlfa-topo1/rt8/zebra.conf
new file mode 100644 (file)
index 0000000..f3f10f6
--- /dev/null
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt8
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 10.0.255.8/32
+ ipv6 address 2001:db8::8/128
+!
+interface eth-rt6
+ ip address 10.0.255.8/32
+!
+interface eth-rt7
+ ip address 10.0.255.8/32
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
new file mode 100755 (executable)
index 0000000..872fef8
--- /dev/null
@@ -0,0 +1,662 @@
+#!/usr/bin/env python
+
+#
+# test_isis_rlfa_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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 NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+"""
+test_isis_rlfa_topo1.py:
+
+ +---------+                     +---------+
+ |         |                     |         |
+ |   RT1   |                     |   RT2   |
+ |         +---------------------+         |
+ |         |                     |         |
+ +---+-----+                     +------+--+
+     |                                  |
+     |                                  |
+     |                                  |
+ +---+-----+                     +------+--+
+ |         |                     |         |
+ |   RT3   |                     |   RT4   |
+ |         |                     |         |
+ |         |                     |         |
+ +---+-----+                     +------+--+
+     |                                  |
+     |                                  |
+     |                                  |
+ +---+-----+                     +------+--+
+ |         |                     |         |
+ |   RT5   |                     |   RT6   |
+ |         |                     |         |
+ |         |                     |         |
+ +---+-----+                     +------+--+
+     |                                  |
+     |                                  |
+     |                                  |
+ +---+-----+                     +------+--+
+ |         |                     |         |
+ |   RT7   |                     |   RT8   |
+ |         +---------------------+         |
+ |         |                     |         |
+ +---------+                     +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+import tempfile
+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__))
+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.
+from mininet.topo import Topo
+
+# Global multi-dimensional dictionary containing all expected outputs
+outputs = {}
+
+
+class TemplateTopo(Topo):
+    "Test topology builder"
+
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        #
+        # Define FRR Routers
+        #
+        for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7", "rt8"]:
+            tgen.add_router(router)
+
+        #
+        # Define connections
+        #
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s2")
+        switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2")
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3")
+        switch = tgen.add_switch("s5")
+        switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4")
+        switch = tgen.add_switch("s6")
+        switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5")
+        switch = tgen.add_switch("s7")
+        switch.add_link(tgen.gears["rt6"], nodeif="eth-rt8")
+        switch.add_link(tgen.gears["rt8"], nodeif="eth-rt6")
+        switch = tgen.add_switch("s8")
+        switch.add_link(tgen.gears["rt7"], nodeif="eth-rt8")
+        switch.add_link(tgen.gears["rt8"], nodeif="eth-rt7")
+
+        #
+        # Populate multi-dimensional dictionary containing all expected outputs
+        #
+        files = [
+            "show_ip_route.ref",
+            "show_ipv6_route.ref",
+            "show_yang_interface_isis_adjacencies.ref",
+        ]
+        for rname in ["rt1"]:
+            outputs[rname] = {}
+            for step in range(1, 10 + 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()
+                        f_in.write(outputs[rname][step - 1][file])
+                        f_in.flush()
+                        f_out = tempfile.NamedTemporaryFile()
+                        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"
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in router_list.iteritems():
+        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_LDP, os.path.join(CWD, "{}/ldpd.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 router_compare_json_output(rname, command, reference):
+    "Compare router JSON output"
+
+    logger.info('Comparing router "%s" "%s" output', rname, command)
+
+    tgen = get_topogen()
+    expected = json.loads(reference)
+
+    # Run test function until we get an result. Wait at most 60 seconds.
+    test_func = 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
+
+
+#
+# Step 1
+#
+# Test initial network convergence
+#
+def test_isis_adjacencies_step1():
+    logger.info("Test (step 1): check IS-IS adjacencies")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname,
+            "show yang operational-data /frr-interface:lib isisd",
+            outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
+        )
+
+
+def test_rib_ipv4_step1():
+    logger.info("Test (step 1): verify IPv4 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"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step1():
+    logger.info("Test (step 1): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 2
+#
+# Action(s):
+# -Configure rt8 (rt1's PQ router) to not accept targeted hello messages
+#
+# Expected changes:
+# -All rt1 backup routes should be uninstalled
+#
+def test_rib_ipv4_step2():
+    logger.info("Test (step 2): 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("Configuring rt8 to not accept targeted hello messages")
+    tgen.net["rt8"].cmd(
+        'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "no discovery targeted-hello accept"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step2():
+    logger.info("Test (step 2): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 3
+#
+# Action(s):
+# -Configure rt8 (rt1's PQ router) to accept targeted hello messages
+#
+# Expected changes:
+# -All rt1 previously uninstalled backup routes should be reinstalled
+#
+def test_rib_ipv4_step3():
+    logger.info("Test (step 3): 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("Configuring rt8 to accept targeted hello messages")
+    tgen.net["rt8"].cmd(
+        'vtysh -c "conf t" -c "mpls ldp" -c "address-family ipv4" -c "discovery targeted-hello accept"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step3():
+    logger.info("Test (step 3): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 4
+#
+# Action(s):
+# -Disable RLFA on rt1's eth-rt2 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops
+#
+def test_rib_ipv4_step4():
+    logger.info("Test (step 4): 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("Disabling RLFA on rt1's eth-rt2 interface")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step4():
+    logger.info("Test (step 4): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 5
+#
+# Action(s):
+# -Disable RLFA on rt1's eth-rt3 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt3 should lose their backup nexthops
+#
+def test_rib_ipv4_step5():
+    logger.info("Test (step 5): 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("Disabling RLFA on rt1's eth-rt3 interface")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step5():
+    logger.info("Test (step 5): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 6
+#
+# Action(s):
+# -Re-enable RLFA on rt1's eth-rt2 and eth-rt3 interfaces
+#
+# Expected changes:
+# -Revert changes from the previous two steps (reinstall all backup routes)
+#
+def test_rib_ipv4_step6():
+    logger.info("Test (step 6): 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("Re-enabling RLFA on rt1's eth-rt2 and eth-rt3 interfaces")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute remote-lfa tunnel mpls-ldp"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step6():
+    logger.info("Test (step 6): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 7
+#
+# Action(s):
+# -Configure a PQ node prefix-list filter
+#
+# Expected changes:
+# -All backup routes should be uninstalled
+#
+def test_rib_ipv4_step7():
+    logger.info("Test (step 7): 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("Configuring a PQ node prefix-list filter")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute remote-lfa prefix-list PLIST"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step7():
+    logger.info("Test (step 7): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 8
+#
+# Action(s):
+# -Configure a prefix-list allowing rt8 as a PQ node
+#
+# Expected changes:
+# -All backup routes should be installed again
+#
+def test_rib_ipv4_step8():
+    logger.info("Test (step 8): 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("Configuring a prefix-list allowing rt8 as a PQ node")
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "ip prefix-list PLIST seq 5 permit 10.0.255.8/32"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step8():
+    logger.info("Test (step 8): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 9
+#
+# Action(s):
+# -Change the maximum metric up to the PQ node to 30 on the eth-rt2 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt2 should lose their backup nexthops
+#
+def test_rib_ipv4_step9():
+    logger.info("Test (step 9): 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(
+        "Changing the maximum metric up to the PQ node to 30 on the eth-rt2 interface"
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 30"'
+    )
+
+    for rname in ["rt1"]:
+        router_compare_json_output(
+            rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"]
+        )
+
+
+def test_rib_ipv6_step9():
+    logger.info("Test (step 9): 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"]:
+        router_compare_json_output(
+            rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
+        )
+
+
+#
+# Step 10
+#
+# Action(s):
+# -Change the maximum metric up to the PQ node to 40 on the eth-rt2 interface
+#
+# Expected changes:
+# -All non-ECMP routes whose primary nexthop is eth-rt2 should recover their backup nexthops
+#
+def test_rib_ipv4_step10():
+    logger.info("Test (step 10): 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(
+        "Changing the maximum metric up to the PQ node to 40 on the eth-rt2 interface"
+    )
+    tgen.net["rt1"].cmd(
+        'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute remote-lfa maximum-metric 40"'
+    )
+
+    for rname in ["rt1"]:
+        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"]:
+        router_compare_json_output(
+            rname,
+            "show ipv6 route isis json",
+            outputs[rname][10]["show_ipv6_route.ref"],
+        )
+
+
+# Memory leak test template
+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))
index 27efecb7621ef3e07577bbaf0f2f413be3fd0722..175d660d1e1a990ca0c541165e5899604295caae 100644 (file)
@@ -1659,7 +1659,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
                             interface_data.append("no ip ospf " " hello-interval")
                         else:
                             interface_data.append(
-                                "ip ospf " " hello-interval {}".format(intf_ospf_hello)
+                                "ip ospf" " hello-interval {}".format(intf_ospf_hello)
                             )
 
                     if "dead_interval" in ospf_data:
@@ -1670,7 +1670,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
                             interface_data.append("no ip ospf" " dead-interval")
                         else:
                             interface_data.append(
-                                "ip ospf " " dead-interval {}".format(intf_ospf_dead)
+                                "ip ospf" " dead-interval {}".format(intf_ospf_dead)
                             )
 
                     if "network" in ospf_data:
@@ -3065,7 +3065,11 @@ def verify_rib(
                                     errormsg = (
                                         "[DUT: {}]: tag value {}"
                                         " is not matched for"
-                                        " route {} in RIB \n".format(dut, _tag, st_rt,)
+                                        " route {} in RIB \n".format(
+                                            dut,
+                                            _tag,
+                                            st_rt,
+                                        )
                                     )
                                     return errormsg
 
@@ -3082,7 +3086,11 @@ def verify_rib(
                                     errormsg = (
                                         "[DUT: {}]: metric value "
                                         "{} is not matched for "
-                                        "route {} in RIB \n".format(dut, metric, st_rt,)
+                                        "route {} in RIB \n".format(
+                                            dut,
+                                            metric,
+                                            st_rt,
+                                        )
                                     )
                                     return errormsg
 
@@ -4333,3 +4341,58 @@ def kill_iperf(tgen, dut=None, action=None):
                 rnode.run(cmd)
 
     logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+
+def verify_ip_nht(tgen, input_dict):
+    """
+    Running "show ip nht" command and verifying given nexthop resolution
+    Parameters
+    ----------
+    * `tgen` : topogen object
+    * `input_dict`: data to verify nexthop
+    Usage
+    -----
+    input_dict_4 = {
+            "r1": {
+                nh: {
+                    "Address": nh,
+                    "resolvedVia": "connected",
+                    "nexthops": {
+                        "nexthop1": {
+                            "Interface": intf
+                        }
+                    }
+                }
+            }
+        }
+    result = verify_ip_nht(tgen, input_dict_4)
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: verify_ip_nht()")
+
+    for router in input_dict.keys():
+        if router not in tgen.routers():
+            continue
+
+        rnode = tgen.routers()[router]
+        nh_list = input_dict[router]
+
+        if validate_ip_address(nh_list.keys()[0]) is "ipv6":
+            show_ip_nht = run_frr_cmd(rnode, "show ipv6 nht")
+        else:
+            show_ip_nht = run_frr_cmd(rnode, "show ip nht")
+
+        for nh in nh_list:
+            if nh in show_ip_nht:
+                logger.info("Nexthop %s is resolved on %s", nh, router)
+                return True
+            else:
+                errormsg = "Nexthop {} is resolved on {}".format(nh, router)
+                return errormsg
+
+    logger.debug("Exiting lib API: verify_ip_nht()")
+    return False
+
index 23b647d0941394418796f2c1036762d89cc4b070..3e368cd7d3de3c1865d28c598cc4353adb9714b1 100644 (file)
@@ -62,7 +62,7 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru
         "r1": {
             "ospf": {
                 "router_id": "22.22.22.22",
-                "area": [{ "id":0.0.0.0, "type": "nssa"}]
+                "area": [{ "id": "0.0.0.0", "type": "nssa"}]
         }
     }
 
@@ -327,7 +327,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
                         "links": {
                             "r2": {
                                 "ospf": {
-                                    "authentication": 'message-digest',
+                                    "authentication": "message-digest",
                                     "authentication-key": "ospf",
                                     "message-digest-key": "10"
                                 }
@@ -376,6 +376,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
             if data_ospf_area:
                 cmd = "ip ospf area {}".format(data_ospf_area)
                 config_data.append(cmd)
+
             # interface ospf auth
             if data_ospf_auth:
                 if data_ospf_auth == "null":
@@ -461,6 +462,32 @@ def clear_ospf(tgen, router):
     logger.debug("Exiting lib API: clear_ospf()")
 
 
+def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
+    """
+    Redstribution of routes inside ospf.
+
+    Parameters
+    ----------
+    * `tgen`: Topogen object
+    * `topo` : json file data
+    * `dut`: device under test
+    * `route_type`: "static" or "connected" or ....
+    * `kwargs`: pass extra information (see below)
+
+    Usage
+    -----
+    redistribute_ospf(tgen, topo, "r0", "static", delete=True)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
+    """
+
+    ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}}
+    for k, v in kwargs.items():
+        ospf_red[dut]["ospf"]["redistribute"][0][k] = v
+
+    result = create_router_ospf(tgen, topo, ospf_red)
+    assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
 ################################
 # Verification procs
 ################################
@@ -522,7 +549,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
 
             logger.info("Verifying OSPF neighborship on router %s:", router)
             show_ospf_json = run_frr_cmd(
-                rnode, "show ip ospf neighbor  all json", isjson=True
+                rnode, "show ip ospf neighbor all json", isjson=True
             )
 
             # Verifying output dictionary show_ospf_json is empty or not
@@ -844,19 +871,23 @@ def verify_ospf_rib(
                                 if "routeType" not in ospf_rib_json[st_rt]:
                                     errormsg = (
                                         "[DUT: {}]: routeType missing"
-                                        "for route {} in OSPF RIB \n".format(dut, st_rt)
+                                        " for route {} in OSPF RIB \n".format(
+                                            dut, st_rt
+                                        )
                                     )
                                     return errormsg
                                 elif _rtype != ospf_rib_json[st_rt]["routeType"]:
                                     errormsg = (
                                         "[DUT: {}]: routeType mismatch"
-                                        "for route {} in OSPF RIB \n".format(dut, st_rt)
+                                        " for route {} in OSPF RIB \n".format(
+                                            dut, st_rt
+                                        )
                                     )
                                     return errormsg
                                 else:
                                     logger.info(
-                                        "DUT: {}]: Found routeType {}"
-                                        "for route {}".format(dut, _rtype, st_rt)
+                                        "[DUT: {}]: Found routeType {}"
+                                        " for route {}".format(dut, _rtype, st_rt)
                                     )
                             if tag:
                                 if "tag" not in ospf_rib_json[st_rt]:
diff --git a/tests/topotests/ospf_basic_functionality/ospf_p2mp.json b/tests/topotests/ospf_basic_functionality/ospf_p2mp.json
new file mode 100644 (file)
index 0000000..40815f3
--- /dev/null
@@ -0,0 +1,198 @@
+{
+
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 24,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 24
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32
+    },
+    "routers": {
+        "r0": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.0",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "description": "DummyIntftoR3"
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.1",
+                "neighbors": {
+                    "r0": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r3": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.2",
+                "neighbors": {
+                    "r1": {},
+                    "r0": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r1": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r2": {
+                    "ipv4": "auto",
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-multipoint"
+                    }
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "description": "DummyIntftoR1",
+                    "ospf": {
+                        "area": "0.0.0.0"
+                    }
+                }
+            },
+            "ospf": {
+                "router_id": "100.1.1.3",
+                "neighbors": {
+                    "r0": {},
+                    "r1": {},
+                    "r2": {}
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
index 5ef6b9b0bed0d2d9d1e0bad0ca1ec8c906d6d807..441368e8fa040aa952b2e7aa0e924923b0347580 100644 (file)
@@ -65,6 +65,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_interface,
+    redistribute_ospf,
 )
 
 topo = None
@@ -184,38 +185,6 @@ def teardown_module(mod):
     logger.info("=" * 40)
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -264,7 +233,7 @@ def test_ospf_ecmp_tc16_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Verify that route in R2 in stalled with 8 next hops.")
     nh = []
@@ -345,7 +314,7 @@ def test_ospf_ecmp_tc16_p0(request):
     step(" Un configure static route on R0")
 
     dut = "r0"
-    red_static(dut, config=False)
+    redistribute_ospf(tgen, topo, dut, "static", delete=True)
 
     # Wait for R0 to flush external LSAs.
     sleep(10)
@@ -376,7 +345,7 @@ def test_ospf_ecmp_tc16_p0(request):
 
     step("Re configure the static route in R0.")
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     dut = "r1"
     result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
@@ -431,7 +400,7 @@ def test_ospf_ecmp_tc17_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Verify that route in R2 in stalled with 2 next hops.")
 
@@ -450,7 +419,7 @@ def test_ospf_ecmp_tc17_p0(request):
     step(" Un configure static route on R0")
 
     dut = "r0"
-    red_static(dut, config=False)
+    redistribute_ospf(tgen, topo, dut, "static", delete=True)
     # sleep till the route gets withdrawn
     sleep(10)
 
@@ -480,7 +449,7 @@ def test_ospf_ecmp_tc17_p0(request):
 
     step("Reconfigure the static route in R0.Change ECMP value to 2.")
     dut = "r0"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Configure cost on R0 as 100")
     r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}}
index 967bc448790d3402df35d26a0ec885acd21cf538..2da1dcd21ab53a0a0abd14c824b02c263bb37b84 100644 (file)
@@ -66,6 +66,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_interface,
+    redistribute_ospf,
 )
 from ipaddress import IPv4Address
 
@@ -187,42 +188,6 @@ def teardown_module():
         pass
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "static", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -275,7 +240,7 @@ def test_ospf_lan_ecmp_tc18_p0(request):
         )
 
         dut = rtr
-        red_static(dut)
+        redistribute_ospf(tgen, topo, dut, "static")
 
     step(
         "Verify that route in R0 in stalled with 8 hops. "
index 0f1115f81576aa379945752fe19aa8cd1685f3f8..dac32090bcc7136c39d9a642d1d50928631d91d2 100644 (file)
@@ -183,42 +183,6 @@ def teardown_module():
         pass
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "static", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
index 82a34d046cdd72f384f80ee8209426c62cd23492..3644bff3dcaeff9839aec7acb8e9ec6aa2980716 100644 (file)
@@ -30,6 +30,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_interface,
+    redistribute_ospf,
 )
 from lib.topojson import build_topo_from_json, build_config_from_json
 from lib.topolog import logger
@@ -181,38 +182,6 @@ def teardown_module(mod):
     logger.info("=" * 40)
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -268,7 +237,7 @@ def test_ospf_learning_tc15_p0(request):
 
     step("Redistribute static route in R2 ospf.")
     dut = "r2"
-    red_static(dut)
+    redistribute_ospf(tgen, topo, dut, "static")
 
     step("Verify that Type 5 LSA is originated by R2.")
     dut = "r0"
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
new file mode 100644 (file)
index 0000000..c90275e
--- /dev/null
@@ -0,0 +1,416 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from copy import deepcopy
+from ipaddress import IPv4Address
+
+# 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/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+import ipaddress
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    step,
+    create_route_maps,
+    shutdown_bringup_interface,
+    create_interfaces_cfg,
+    topo_daemons,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+    verify_ospf_neighbor,
+    config_ospf_interface,
+    clear_ospf,
+    verify_ospf_rib,
+    create_router_ospf,
+    verify_ospf_interface,
+    verify_ospf_database,
+)
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_p2mp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+"""
+TOPOOLOGY =
+      Please view in a fixed-width font such as Courier.
+      +---+  A1       +---+
+      +R1 +------------+R2 |
+      +-+-+-           +--++
+        |  --        --  |
+        |    -- A0 --    |
+      A0|      ----      |
+        |      ----      | A2
+        |    --    --    |
+        |  --        --  |
+      +-+-+-            +-+-+
+      +R0 +-------------+R3 |
+      +---+     A3     +---+
+
+TESTCASES =
+1. OSPF P2MP -Verify state change events on p2mp network.
+ """
+
+
+class CreateTopo(Topo):
+    """
+    Test topology builder.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+    Sets up the pytest environment
+
+    * `mod`: module name
+    """
+    global topo
+    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")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    # get list of daemons needs to be started for this suite.
+    daemons = topo_daemons(tgen, topo)
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    start_topology(tgen, daemons)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+
+    logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+    """
+    Teardown the pytest environment.
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_p2mp_tc1_p0(request):
+    """OSPF IFSM -Verify state change events on p2mp network."""
+    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)
+
+    global topo
+    step("Bring up the base config as per the topology")
+    reset_config_on_routers(tgen)
+    step(
+        "Verify that OSPF is subscribed to multi cast services "
+        "(All SPF, all DR Routers)."
+    )
+    step("Verify that interface is enabled in ospf.")
+    step("Verify that config is successful.")
+    dut = "r0"
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {"ospf": {"mcastMemberOspfAllRouters": True, "ospfEnabled": True}}
+            }
+        }
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Delete the ip address")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Change the ip on the R0 interface")
+
+    topo_modify_change_ip = deepcopy(topo)
+    intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
+        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+    ) + "/{}".format(intf_ip.split("/")[1])
+
+    build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+    step("Verify that interface is enabled in ospf.")
+    dut = "r0"
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ospf": {
+                        "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+                            "r3"
+                        ]["ipv4"].split("/")[0],
+                        "ipAddressPrefixlen": int(
+                            topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                                "ipv4"
+                            ].split("/")[1]
+                        ),
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Modify the mask on the R0 interface")
+    ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    step("Delete the ip address")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv4": ip_addr,
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("Change the ip on the R0 interface")
+
+    topo_modify_change_ip = deepcopy(topo)
+    intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+    topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
+        IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+    ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
+
+    build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+    step("Verify that interface is enabled in ospf.")
+    dut = "r0"
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ospf": {
+                        "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+                            "r3"
+                        ]["ipv4"].split("/")[0],
+                        "ipAddressPrefixlen": int(
+                            topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                                "ipv4"
+                            ].split("/")[1]
+                        ),
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv4": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                        "ipv4"
+                    ],
+                    "interface": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                        "interface"
+                    ],
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, topo1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    build_config_from_json(tgen, topo, save_bkup=False)
+
+    step("Change the area id on the interface")
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.0"},
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.1"},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+    step("Verify that interface is enabled in ospf.")
+    dut = "r0"
+    input_dict = {
+        "r0": {"links": {"r3": {"ospf": {"area": "0.0.0.1", "ospfEnabled": True}}}}
+    }
+    result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.1"},
+                    "delete": True,
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {"area": "0.0.0.0"},
+                }
+            }
+        }
+    }
+
+    result = create_interfaces_cfg(tgen, input_dict)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step("Verify if interface is enabled with network type P2MP")
+    input_dict = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+                    "ospf": {
+                        "area": "0.0.0.0",
+                        "networkType":"POINTOMULTIPOINT"
+                    },
+                }
+            }
+        }
+    }
+    result = create_interfaces_cfg(tgen, input_dict)
+    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))
index 88667a6ac8e322a3a482d519a65dc6a23586a302..ceadb3975b0895d945de2a186d32bef096e5cb6c 100644 (file)
@@ -62,6 +62,7 @@ from lib.ospf import (
     verify_ospf_rib,
     create_router_ospf,
     verify_ospf_database,
+    redistribute_ospf,
 )
 
 # Global variables
@@ -226,9 +227,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
     result = create_static_routes(tgen, input_dict)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
-    ospf_red_r1 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    result = create_router_ospf(tgen, topo, ospf_red_r1)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static")
 
     dut = "r1"
     lsid = NETWORK["ipv4"][0].split("/")[0]
@@ -240,13 +239,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
     result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
-    ospf_red_r1 = {
-        "r0": {
-            "ospf": {"redistribute": [{"redist_type": "static", "del_action": True}]}
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r1)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", delete=True)
 
     step(
         "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32"
@@ -293,15 +286,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
         " ospf using route map rmap1"
     )
 
-    ospf_red_r1 = {
-        "r0": {
-            "ospf": {
-                "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
-            }
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r1)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
 
     step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1")
     # Create ip prefix list
@@ -495,15 +480,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     step("Redistribute to ospf using route map ( non existent route map)")
-    ospf_red_r1 = {
-        "r0": {
-            "ospf": {
-                "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
-            }
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r1)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
 
     step(
         "Verify that routes are not allowed in OSPF even tough no "
@@ -633,15 +610,7 @@ def test_ospf_routemaps_functionality_tc21_p0(request):
     result = create_static_routes(tgen, input_dict)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
-    ospf_red_r0 = {
-        "r0": {
-            "ospf": {
-                "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
-            }
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r0)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
 
     # Create route map
     routemaps = {
@@ -877,15 +846,7 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
     result = create_static_routes(tgen, input_dict)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
-    ospf_red_r0 = {
-        "r0": {
-            "ospf": {
-                "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
-            }
-        }
-    }
-    result = create_router_ospf(tgen, topo, ospf_red_r0)
-    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
 
     # Create ip prefix list
     pfx_list = {
index 434d7f8ef5cd7a971687a0ef69253b84e2f7a777..5aa2779aee5a8e99adcea8bec9d92a9940c57699 100644 (file)
@@ -61,6 +61,7 @@ from lib.ospf import (
     clear_ospf,
     verify_ospf_rib,
     create_router_ospf,
+    redistribute_ospf,
 )
 
 # Global variables
@@ -183,42 +184,6 @@ def teardown_module(mod):
     logger.info("=" * 40)
 
 
-def red_static(dut, config=True):
-    """Local def for Redstribute static routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "static", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
-    """Local def for Redstribute connected routes inside ospf."""
-    global topo
-    tgen = get_topogen()
-    if config:
-        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
-    else:
-        ospf_red = {
-            dut: {
-                "ospf": {
-                    "redistribute": [{"redist_type": "connected", "del_action": True}]
-                }
-            }
-        }
-    result = create_router_ospf(tgen, topo, ospf_red)
-    assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
 # ##################################
 # Test cases start here.
 # ##################################
@@ -486,8 +451,8 @@ def test_ospf_redistribution_tc8_p1(request):
         "advertised/exchaged via ospf"
     )
     for rtr in topo["routers"]:
-        red_static(rtr)
-        red_connected(rtr)
+        redistribute_ospf(tgen, topo, rtr, "static")
+        redistribute_ospf(tgen, topo, rtr, "connected")
     for node in topo["routers"]:
         input_dict = {
             "r0": {
@@ -544,13 +509,7 @@ def test_ospf_redistribution_tc8_p1(request):
     )
 
     for rtr in topo["routers"]:
-        ospf_red = {
-            rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
-        }
-        result = create_router_ospf(tgen, topo, ospf_red)
-        assert result is True, "Testcase {} : Failed \n Error: {}".format(
-            tc_name, result
-        )
+        redistribute_ospf(tgen, topo, rtr, "static", delete=True)
 
     input_dict = {
         "r0": {
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo3_ebgp.json
new file mode 100644 (file)
index 0000000..5246a31
--- /dev/null
@@ -0,0 +1,189 @@
+{
+    "address_types": [
+        "ipv4",
+        "ipv6"
+    ],
+    "ipv4base": "10.0.0.0",
+    "ipv4mask": 30,
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv4": "10.0.0.0",
+        "v4mask": 29,
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv4": "1.0.",
+        "v4mask": 32,
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r2-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link1": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link2": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link3": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link4": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link5": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link6": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r1-link7": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "100",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r3": {
+                                    "dest_link": {
+                                        "r2-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv4": "auto",
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r2-link0": {
+                    "ipv4": "auto",
+                    "ipv6": "auto"
+                }
+            },
+            "bgp": {
+                "local_as": "200",
+                "address_family": {
+                    "ipv4": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    "ipv6": {
+                        "unicast": {
+                            "neighbor": {
+                                "r2": {
+                                    "dest_link": {
+                                        "r3-link0": {
+                                            "keepalivetimer": 1,
+                                            "holddowntimer": 4
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
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
new file mode 100644 (file)
index 0000000..255bb07
--- /dev/null
@@ -0,0 +1,1333 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+"""
+    -Verify static route ECMP functionality with 8 next hop
+
+    -Verify static route functionality with 8 next hop different AD value
+
+    -Verify static route with tag option
+
+    -Verify BGP did not install the static route when it receive route
+    with local next hop
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import random
+import platform
+from lib.topotest import version_cmp
+
+# 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/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    write_test_footer,
+    reset_config_on_routers,
+    verify_rib,
+    create_static_routes,
+    check_address_types,
+    step,
+    create_interfaces_cfg,
+    shutdown_bringup_interface,
+    stop_router,
+    start_router,
+    create_route_maps,
+    verify_ip_nht,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo3_ebgp.json".format(CWD)
+try:
+    with open(jsonFile, "r") as topoJson:
+        topo = json.load(topoJson)
+except IOError:
+    assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+    "ipv4": [
+        "11.0.20.1/32",
+        "11.0.20.2/32",
+        "11.0.20.3/32",
+        "11.0.20.4/32",
+        "11.0.20.5/32",
+        "11.0.20.6/32",
+        "11.0.20.7/32",
+        "11.0.20.8/32",
+    ],
+    "ipv6": [
+        "2::1/128",
+        "2::2/128",
+        "2::3/128",
+        "2::4/128",
+        "2::5/128",
+        "2::6/128",
+        "2::7/128",
+        "2::8/128",
+    ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]}
+NEXT_HOP_IP = []
+
+
+class CreateTopo(Topo):
+    """
+    Test CreateTopo - topology 1.
+
+    * `Topo`: Topology object
+    """
+
+    def build(self, *_args, **_opts):
+        """Build function."""
+        tgen = get_topogen(self)
+
+        # Building topology from json file
+        build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+    """
+
+    Set up the pytest environment.
+
+    * `mod`: module name
+    """
+    global topo
+    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")
+
+    # This function initiates the topology build with Topogen...
+    tgen = Topogen(CreateTopo, mod.__name__)
+    # ... 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)
+
+    # Creating configuration from JSON
+    build_config_from_json(tgen, topo)
+
+    if version_cmp(platform.release(), "4.19") < 0:
+        error_msg = (
+            'These tests will not run. (have kernel "{}", '
+            "requires kernel >= 4.19)".format(platform.release())
+        )
+        pytest.skip(error_msg)
+
+    # Checking BGP convergence
+    global BGP_CONVERGENCE
+    global ADDR_TYPES
+
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+    # Api call verify whether BGP is converged
+    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(mod):
+    """
+    Teardown the pytest environment
+
+    * `mod`: module name
+    """
+
+    logger.info("Running teardown_module to delete topology")
+
+    tgen = get_topogen()
+
+    # Stop toplogy and Remove tmp files
+    tgen.stop_topology()
+
+    logger.info(
+        "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+    )
+    logger.info("=" * 40)
+
+
+def populate_nh():
+    NEXT_HOP_IP = {
+        "nh1": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+        },
+        "nh2": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+        },
+        "nh3": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+        },
+        "nh4": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+        },
+        "nh5": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+        },
+        "nh6": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+        },
+        "nh7": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+        },
+        "nh8": {
+            "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+            "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+        },
+    }
+    return NEXT_HOP_IP
+
+
+#####################################################
+#
+#   Tests starting
+#
+#####################################################
+
+
+def test_staticroute_with_ecmp_p0_tc3_ebgp(request):
+    """
+    Verify static route ECMP functionality with 8 next hop'
+
+    """
+    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)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2,")
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2),"
+        "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static"
+        "route next-hop present on R1"
+    )
+
+    step("Configure IBGP IPv4 peering between R2 and R3 router.")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+        nh = [
+            NEXT_HOP_IP["nh1"][addr_type],
+            NEXT_HOP_IP["nh2"][addr_type],
+            NEXT_HOP_IP["nh3"][addr_type],
+            NEXT_HOP_IP["nh4"][addr_type],
+            NEXT_HOP_IP["nh5"][addr_type],
+            NEXT_HOP_IP["nh6"][addr_type],
+            NEXT_HOP_IP["nh7"][addr_type],
+            NEXT_HOP_IP["nh8"][addr_type],
+        ]
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes are"
+        " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by" "one")
+
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    result = verify_rib(
+        tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    result = verify_rib(
+        tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+    )
+    assert result is True, "Testcase {} : Failed \nError: Routes are"
+    " missing in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ebgp(request):
+    """
+    Verify static route ECMP functionality with 8 next hop
+
+    """
+    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)
+    NEXT_HOP_IP = populate_nh()
+
+    step("Configure 8 interfaces / links between R1 and R2,")
+    step("Configure IBGP IPv4 peering between R2 and R3 router.")
+    reset_config_on_routers(tgen)
+    NEXT_HOP_IP = populate_nh()
+    nh_all = {}
+    for addr_type in ADDR_TYPES:
+        nh_all[addr_type] = []
+        for nhp in range(1, 9):
+            nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+    step(
+        "Configure IPv4 static route in R2 with 8 next hop"
+        "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+        "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+        "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+        "present on R1"
+    )
+    for addr_type in ADDR_TYPES:
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+            logger.info("Configure static routes")
+            result = create_static_routes(tgen, input_dict_4)
+            assert result is True, "Testcase {} : Failed \n Error: {}".format(
+                tc_name, result
+            )
+        logger.info("Verifying %s routes on r2", addr_type)
+
+        step(
+            "On R2, static route installed in RIB using "
+            "show ip route with 8 next hop, lowest AD nexthop is active"
+        )
+        step("On R2, static route with lowest AD nexthop installed in FIB")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Configure redistribute static in BGP on R2 router")
+    for addr_type in ADDR_TYPES:
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+
+        logger.info("Configuring redistribute static")
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "After configuring them, route is always active with lowest AD"
+            "value and all the nexthop populated in RIB and FIB again "
+        )
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+    step(
+        "Remove the static route configured with nexthop N1 to N8, one"
+        "by one from running config"
+    )
+
+    for addr_type in ADDR_TYPES:
+        # delete static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                            "delete": True,
+                        }
+                    ]
+                }
+            }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+    step(
+        "After removing the static route with N1 to N8 one by one, "
+        "route become active with next preferred nexthop and nexthop which "
+        "got removed is not shown in RIB and FIB"
+    )
+    result = verify_rib(
+        tgen,
+        addr_type,
+        dut,
+        input_dict_4,
+        next_hop=nh_all[addr_type],
+        protocol=protocol,
+        expected=False,
+    )
+    assert result is not True, "Testcase {} : Failed \nError: Routes are"
+    " still present in RIB".format(tc_name)
+
+    step("Configure the static route with nexthop N1 to N8, one by" "one")
+    for addr_type in ADDR_TYPES:
+        # add static routes
+        for nhp in range(1, 9):
+            input_dict_4 = {
+                "r2": {
+                    "static_routes": [
+                        {
+                            "network": PREFIX1[addr_type],
+                            "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+                            "admin_distance": 10 * nhp,
+                        }
+                    ]
+                }
+            }
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("On R2, static route with lowest AD nexthop installed in FIB")
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    step("Random shut of the nexthop interfaces")
+    randnum = random.randint(0, 7)
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        input_dict_5 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+                    }
+                ]
+            }
+        }
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_5,
+            next_hop=nhip,
+            protocol=protocol,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \n"
+        "Error: Routes are still present in RIB".format(tc_name)
+
+    step("Random no shut of the nexthop interfaces")
+    for addr_type in ADDR_TYPES:
+        intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+        nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \n"
+        "Error: Routes are missing in RIB".format(tc_name)
+
+    step("Reload the FRR router")
+    # stop/start -> restart FRR router and verify
+    stop_router(tgen, "r2")
+    start_router(tgen, "r2")
+
+    step(
+        "After reload of FRR router, static route installed "
+        "in RIB and FIB properly ."
+    )
+    for addr_type in ADDR_TYPES:
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": PREFIX1[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "admin_distance": 10,
+                    }
+                ]
+            }
+        }
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        " lowest AD is missing in RIB".format(tc_name)
+
+        nh = []
+        for nhp in range(2, 9):
+            nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            next_hop=nh,
+            protocol=protocol,
+            fib=True,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes "
+        " with high AD are active in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_bgp_local_nexthop_p1_tc14_ebgp(request):
+    """
+    Verify BGP did not install the static route when it receive route
+    with local next hop
+
+    """
+    tc_name = request.node.name
+    write_test_header(tc_name)
+    tgen = get_topogen()
+
+    step("Configure BGP IPv4 session between R2 and R3")
+    step("Configure IPv4 static route on R2")
+    reset_config_on_routers(tgen)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][
+                            addr_type
+                        ].split("/")[0],
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Configure redistribute static in the BGP")
+
+        input_dict_2 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {"redistribute": [{"redist_type": "static"}]}
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_2)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("Verify R2 BGP table has IPv4 route")
+        dut = "r2"
+        result = verify_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB of R2".format(tc_name)
+
+        step(" Verify route did not install in the R3 BGP table, RIB/FIB")
+        dut = "r3"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in BGP RIB of R2".format(tc_name)
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " still present in RIB of R2".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_frr_intf_name_as_gw_gap_tc4_ebgp_p0(request):
+    """
+    Verify static route configure with interface name as gateway'
+        'address'
+    """
+    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)
+
+    dut = "r1"
+    intf = topo["routers"]["r1"]["links"]["r2-link0"]["interface"]
+    nh = topo["routers"]["r1"]["links"]["r2-link0"]
+    ip_list = {
+        "ipv4": [(dut, intf, ["1.1.1.1/32"], nh["ipv4"].split("/")[0])],
+        "ipv6": [(dut, intf, ["4001::32/128"], nh["ipv6"].split("/")[0])],
+    }
+
+    step(
+        "Configure IPv4 and IPv6 static route in FRR with different next"
+        "hop (ens224 as nexthop))"
+    )
+    step("ip route 2.2.2.0/24 20.1.1.1 ens224 ----from FRR cli")
+    step("ipv6 route 2000::1/120 5000::1 ens224 ----from FRR cli")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        nh = topo["routers"]["r2"]["links"]["r1-link0"][addr_type].split("/")[0]
+        input_dict_4 = {
+            "r1": {
+                "static_routes": [
+                    {"network": ip_list[addr_type][0][2][0], "next_hop": nh}
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "IPv4 and IPv6 Static route added in FRR verify using "
+            "show ip route , nexthop is resolved using show nht"
+        )
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, next_hop=nh
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        input_dict_nh = {
+            "r1": {
+                nh: {
+                    "Address": nh,
+                    "resolvedVia": "connected",
+                    "nexthops": {"nexthop1": {"Interfcae": intf}},
+                }
+            }
+        }
+        result = verify_ip_nht(tgen, input_dict_nh)
+        assert result is True, "Testcase {} : Failed \nError: Nexthop is"
+        " missing in RIB".format(tc_name)
+
+        step(
+            "Shut / no shut IPv4 and IPv6 static next hop interface from"
+            "kernel and FRR CLI"
+        )
+
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step(
+            "After shut of nexthop interface, IPv4 and IPv6 route got removed "
+            "from RIB verify using show ip route show nht"
+        )
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            protocol=protocol,
+            next_hop=nh,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes is"
+        " missing in RIB".format(tc_name)
+
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step(
+            "After no shut route got added again in RIB /FIB using "
+            "show ip route nexthop is resolved using show nht"
+        )
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+        assert result is True, "Testcase {} : Failed".format(tc_name)
+
+    for addr_type in ADDR_TYPES:
+        nh = topo["routers"]["r2"]["links"]["r1-link0"][addr_type].split("/")[0]
+        input_dict_4 = {
+            "r1": {
+                "static_routes": [
+                    {
+                        "network": ip_list[addr_type][0][2][0],
+                        "next_hop": nh,
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Removing FRR configured static route verify FRR route also "
+            "removed from FRR"
+        )
+        result = verify_rib(
+            tgen,
+            addr_type,
+            dut,
+            input_dict_4,
+            protocol=protocol,
+            next_hop=nh,
+            expected=False,
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Routes"
+        " still present in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_static_route_with_tag_p0_tc_13_ebgp(request):
+    """
+    Verify static route with tag option
+
+    """
+    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)
+
+    step("Configure 8 links between R1 and R2")
+    step("Configure 1 links between R2 and R3")
+    NEXT_HOP_IP = populate_nh()
+
+    step(
+        "Configure 2 IPv4 static route (S1 and S2) in R2 with same"
+        "next hop N1 28.1.1.2"
+    )
+    step("Configure static route S1 with tag 1 and static route S2 with" "tag2")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1")
+    step("S2= ip route 20.1.1.1/24 28.1.1.2 tag 2")
+    step("Enable redistribute static in BGP with route-map")
+    reset_config_on_routers(tgen)
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4001,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4002,
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+        step("verify routes are present in RIB")
+        dut = "r2"
+        protocol = "static"
+        nh = NEXT_HOP_IP["nh1"][addr_type]
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+        step("Configure route-map on R2 with allow tag1 and deny tag2")
+
+        # Create route map
+        input_dict_3 = {
+            "r2": {
+                "route_maps": {
+                    "rmap_match_tag_1_{}".format(addr_type): [
+                        {
+                            "action": "permit",
+                            "seq_id": 10,
+                            "match": {addr_type: {"tag": "4001"}},
+                        },
+                        {
+                            "action": "deny",
+                            "seq_id": 20,
+                            "match": {addr_type: {"tag": "4002"}},
+                        },
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, input_dict_3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        # Configure neighbor for route map
+        input_dict_4 = {
+            "r2": {
+                "bgp": {
+                    "address_family": {
+                        addr_type: {
+                            "unicast": {
+                                "neighbor": {
+                                    "r3": {
+                                        "dest_link": {
+                                            "r2-link0": {
+                                                "route_maps": [
+                                                    {
+                                                        "name": "rmap_match_tag_1_ipv4",
+                                                        "direction": "out",
+                                                    }
+                                                ]
+                                            }
+                                        }
+                                    }
+                                },
+                                "redistribute": [{"redist_type": "static"}],
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        result = create_router_bgp(tgen, topo, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify static route S1 advetised in BGP table when tag1 permit"
+            "in route-map else it is denied"
+        )
+        dut = "r3"
+        input_dict_0 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4002,
+                    }
+                ]
+            }
+        }
+
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_0, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route with "
+        "tag 4002 is still present in RIB".format(tc_name)
+
+        dut = "r2"
+        input_dict_1 = {
+            "r2": {"static_routes": [{"network": NETWORK[addr_type], "tag": 4001}]}
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_0, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        "tag 4001 is missing in RIB".format(tc_name)
+
+        step("Modify the route-map to allow tag2 and deny tag1")
+        # Create route map
+        input_dict_3 = {
+            "r2": {
+                "route_maps": {
+                    "rmap_match_tag_1_{}".format(addr_type): [
+                        {
+                            "action": "deny",
+                            "seq_id": 10,
+                            "match": {addr_type: {"tag": "4001"}},
+                        },
+                        {
+                            "action": "permit",
+                            "seq_id": 20,
+                            "match": {addr_type: {"tag": "4002"}},
+                        },
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, input_dict_3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r3"
+        step(
+            "Verify static route S2 advertised in BGP table when tag2"
+            "permit in route-map else it is denied"
+        )
+        protocol = "bgp"
+        input_dict_0 = {
+            "r2": {"static_routes": [{"network": NETWORK2[addr_type], "tag": 4002}]}
+        }
+
+        result = verify_rib(tgen, addr_type, dut, input_dict_0, protocol=protocol)
+        assert result is True, "Testcase {} : Failed \nError: Route with "
+        "tag 4002 is missing in RIB".format(tc_name)
+
+        input_dict_1 = {
+            "r2": {"static_routes": [{"network": NETWORK[addr_type], "tag": 4001}]}
+        }
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_1, protocol=protocol, expected=False
+        )
+        assert result is not True, "Testcase {} : Failed \nError: Route with "
+        "tag 4001 is still present in RIB".format(tc_name, result)
+
+    step("Configure one static route with 2 ECMP nexthop N1 and N2")
+    step("For N1 configure tag 1 and for N2 configure tag 2")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1")
+    step("S1= ip route 10.1.1.1/24 29.1.1.2 tag 2")
+    step("configure the route-map to allow tag1 and deny tag 2")
+    step("Modify the route-map to allow tag2 and deny tag1")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4001,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "tag": 4002,
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(
+            tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True
+        )
+        assert result is True, "Testcase {} : Failed \nError: Routes are"
+        " missing in RIB".format(tc_name)
+
+    step("shut/no shut of tag1 and tag2 nexthop")
+
+    intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+    shutdown_bringup_interface(tgen, dut, intf, False)
+
+    shutdown_bringup_interface(tgen, dut, intf, True)
+
+    step("configure one static route with 3 next-hop")
+    step("N1-tag1, N2-tag2, N3-tag3")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 1")
+    step("S1= ip route 10.1.1.1/24 29.1.1.2 tag 2")
+    step("S1= ip route 10.1.1.1/24 28.1.1.2 tag 3")
+
+    for addr_type in ADDR_TYPES:
+        # Enable static routes
+        input_dict_4 = {
+            "r2": {
+                "static_routes": [
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+                        "tag": 4001,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+                        "tag": 4002,
+                    },
+                    {
+                        "network": NETWORK2[addr_type],
+                        "next_hop": NEXT_HOP_IP["nh3"][addr_type],
+                        "tag": 4003,
+                    },
+                ]
+            }
+        }
+
+        logger.info("Configure static routes")
+        result = create_static_routes(tgen, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        dut = "r2"
+        protocol = "static"
+        result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+
+        step("configure the route-map to allow tag2 & tag3 and deny tag1")
+        # Create route map
+        input_dict_3 = {
+            "r2": {
+                "route_maps": {
+                    "rmap_match_tag_1_{}".format(addr_type): [
+                        {
+                            "action": "deny",
+                            "seq_id": 10,
+                            "match": {addr_type: {"tag": "4001"}},
+                        },
+                        {
+                            "action": "permit",
+                            "seq_id": 20,
+                            "match": {addr_type: {"tag": "4002"}},
+                        },
+                        {
+                            "action": "permit",
+                            "seq_id": 30,
+                            "match": {addr_type: {"tag": "4003"}},
+                        },
+                    ]
+                }
+            }
+        }
+        result = create_route_maps(tgen, input_dict_3)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step(
+            "Verify static route advertised in BGP table with tag3"
+            " nexthop if tag2 is down"
+        )
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        assert result is True, "Testcase {} : Failed \n Error: {}".format(
+            tc_name, result
+        )
+
+        step("shut / no shut of tag2 and tag3 next-hop")
+
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        intf = topo["routers"]["r2"]["links"]["r1-link2"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, False)
+
+        step("shut/no shut of tag2 and tag3 nexthop")
+        intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        intf = topo["routers"]["r2"]["links"]["r1-link2"]["interface"]
+        shutdown_bringup_interface(tgen, dut, intf, True)
+
+        step("Verify after shut/noshut of nexthop BGP table updated correctly")
+        dut = "r3"
+        protocol = "bgp"
+        result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+        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))
index d5fa8ab6a3d5294b855cc8134a9c3ea384615775..0aa5f1e51668f90ab46a282e9e21f042d978cf63 100755 (executable)
@@ -221,6 +221,7 @@ ip forwarding
         for ligne in lines:
             self.dlines[ligne] = True
 
+
 def get_normalized_es_id(line):
     """
     The es-id or es-sys-mac need to be converted to lower case
@@ -233,6 +234,7 @@ def get_normalized_es_id(line):
             break
     return line
 
+
 def get_normalized_mac_ip_line(line):
     if line.startswith("evpn mh es"):
         return get_normalized_es_id(line)
@@ -242,6 +244,7 @@ def get_normalized_mac_ip_line(line):
 
     return line
 
+
 class Config(object):
 
     """
@@ -640,7 +643,7 @@ end
                 log.debug(
                     "LINE %-50s: popping segment routing sub-context to ctx%-50s",
                     line,
-                    ctx_keys
+                    ctx_keys,
                 )
 
             elif line in ["exit-address-family", "exit", "exit-vnc"]:
@@ -654,7 +657,7 @@ end
                     log.debug(
                         "LINE %-50s: popping from subcontext to ctx%-50s",
                         line,
-                        ctx_keys
+                        ctx_keys,
                     )
 
             elif line in ["exit-vni", "exit-ldp-if"]:
@@ -755,7 +758,8 @@ end
                 self.save_contexts(ctx_keys, current_context_lines)
                 current_context_lines = []
                 log.debug(
-                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
+                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+                    line,
                 )
                 ctx_keys.append(line)
 
@@ -770,7 +774,8 @@ end
                 self.save_contexts(ctx_keys, current_context_lines)
                 current_context_lines = []
                 log.debug(
-                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
+                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+                    line,
                 )
                 ctx_keys.append(line)
 
@@ -785,7 +790,8 @@ end
                 self.save_contexts(ctx_keys, current_context_lines)
                 current_context_lines = []
                 log.debug(
-                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
+                    "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+                    line,
                 )
                 ctx_keys.append(line)
 
@@ -803,7 +809,8 @@ end
                 current_context_lines = []
                 main_ctx_key = copy.deepcopy(ctx_keys)
                 log.debug(
-                    "LINE %-50s: entering candidate-path sub-context, append to ctx_keys", line
+                    "LINE %-50s: entering candidate-path sub-context, append to ctx_keys",
+                    line,
                 )
                 ctx_keys.append(line)
 
@@ -836,7 +843,8 @@ end
                 current_context_lines = []
                 main_ctx_key = copy.deepcopy(ctx_keys)
                 log.debug(
-                    "LINE %-50s: entering pce-config sub-context, append to ctx_keys", line
+                    "LINE %-50s: entering pce-config sub-context, append to ctx_keys",
+                    line,
                 )
                 ctx_keys.append(line)
 
@@ -1230,30 +1238,44 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
                     lines_to_add_to_del.append((ctx[0], None))
 
         """
-        ip/ipv6 prefix-list can be specified without a seq number. However,
-        the running config always adds 'seq x', where x is a number incremented
-        by 5 for every element, to the prefix list. So, ignore such lines as
-        well. Sample prefix-list lines:
+        ip/ipv6 prefix-lists and access-lists can be specified without a seq number.
+        However, the running config always adds 'seq x', where x is a number
+        incremented by 5 for every element of the prefix/access list.
+        So, ignore such lines as well. Sample prefix-list and acces-list lines:
              ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32
              ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32
              ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64
+             access-list FOO seq 5 permit 2.2.2.2/32
+             ipv6 access-list BAR seq 5 permit 2:2:2::2/128
         """
-        re_ip_pfxlst = re.search(
-            "^(ip|ipv6)(\s+prefix-list\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+        re_acl_pfxlst = re.search(
+            "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
             ctx_keys[0],
         )
-        if re_ip_pfxlst:
+        if re_acl_pfxlst:
+            found = False
             tmpline = (
-                re_ip_pfxlst.group(1)
-                + re_ip_pfxlst.group(2)
-                + re_ip_pfxlst.group(3)
-                + re_ip_pfxlst.group(5)
-                + re_ip_pfxlst.group(6)
+                re_acl_pfxlst.group(1)
+                + re_acl_pfxlst.group(2)
+                + re_acl_pfxlst.group(3)
+                + re_acl_pfxlst.group(5)
+                + re_acl_pfxlst.group(6)
             )
             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 prefix-lists or access-lists are being deleted and
+            not added (see comment above), add command with 'no' to
+            lines_to_add and remove from lines_to_del to improve
+            scaling performance.
+            """
+            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
@@ -1451,14 +1473,9 @@ def compare_context_objects(newconf, running):
             # doing vtysh -c inefficient (and can time out.)  For
             # these commands, instead of adding them to lines_to_del,
             # add the "no " version to lines_to_add.
-            elif (
-                running_ctx_keys[0].startswith("ip route")
-                or running_ctx_keys[0].startswith("ipv6 route")
-                or running_ctx_keys[0].startswith("access-list")
-                or running_ctx_keys[0].startswith("ipv6 access-list")
-                or running_ctx_keys[0].startswith("ip prefix-list")
-                or running_ctx_keys[0].startswith("ipv6 prefix-list")
-            ):
+            elif running_ctx_keys[0].startswith("ip route") or running_ctx_keys[
+                0
+            ].startswith("ipv6 route"):
                 add_cmd = ("no " + running_ctx_keys[0],)
                 lines_to_add.append((add_cmd, None))
 
@@ -1473,14 +1490,17 @@ def compare_context_objects(newconf, running):
                 continue
 
             # same thing for a pseudowire sub-context inside an l2vpn context
-            elif (len(running_ctx_keys) > 1 and running_ctx_keys[0].startswith('l2vpn') and
-                  running_ctx_keys[1].startswith('member pseudowire') and
-                  (running_ctx_keys[:1], None) in lines_to_del):
+            elif (
+                len(running_ctx_keys) > 1
+                and running_ctx_keys[0].startswith("l2vpn")
+                and running_ctx_keys[1].startswith("member pseudowire")
+                and (running_ctx_keys[:1], None) in lines_to_del
+            ):
                 continue
 
             # Segment routing and traffic engineering never need to be deleted
             elif (
-                running_ctx_keys[0].startswith('segment-routing')
+                running_ctx_keys[0].startswith("segment-routing")
                 and len(running_ctx_keys) < 3
             ):
                 continue
@@ -1488,8 +1508,8 @@ def compare_context_objects(newconf, running):
             # Neither the pcep command
             elif (
                 len(running_ctx_keys) == 3
-                and running_ctx_keys[0].startswith('segment-routing')
-                and running_ctx_keys[2].startswith('pcep')
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[2].startswith("pcep")
             ):
                 continue
 
@@ -1497,8 +1517,8 @@ def compare_context_objects(newconf, running):
             # use them, so add them to a separate array that is going to be appended at the end
             elif (
                 len(running_ctx_keys) == 3
-                and running_ctx_keys[0].startswith('segment-routing')
-                and running_ctx_keys[2].startswith('segment-list')
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[2].startswith("segment-list")
             ):
                 seglist_to_del.append((running_ctx_keys, None))
 
@@ -1506,8 +1526,8 @@ def compare_context_objects(newconf, running):
             # we add them to a separate array that is going to be appended at the end
             elif (
                 len(running_ctx_keys) == 3
-                and running_ctx_keys[0].startswith('segment-routing')
-                and running_ctx_keys[2].startswith('policy')
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[2].startswith("policy")
             ):
                 pollist_to_del.append((running_ctx_keys, None))
 
@@ -1515,16 +1535,16 @@ def compare_context_objects(newconf, running):
             # to a separate array that is going to be appended at the end
             elif (
                 len(running_ctx_keys) >= 4
-                and running_ctx_keys[0].startswith('segment-routing')
-                and running_ctx_keys[3].startswith('pce-config')
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[3].startswith("pce-config")
             ):
                 pceconf_to_del.append((running_ctx_keys, None))
 
             # pcc must be deleted after the pce and pce-config too
             elif (
                 len(running_ctx_keys) >= 4
-                and running_ctx_keys[0].startswith('segment-routing')
-                and running_ctx_keys[3].startswith('pcc')
+                and running_ctx_keys[0].startswith("segment-routing")
+                and running_ctx_keys[3].startswith("pcc")
             ):
                 pcclist_to_del.append((running_ctx_keys, None))
 
@@ -1572,9 +1592,9 @@ def compare_context_objects(newconf, running):
                     # so add them to a separate array that is going to be appended at the end
                     if (
                         len(newconf_ctx_keys) == 3
-                        and newconf_ctx_keys[0].startswith('segment-routing')
-                        and newconf_ctx_keys[2].startswith('policy ')
-                        and line.startswith('candidate-path ')
+                        and newconf_ctx_keys[0].startswith("segment-routing")
+                        and newconf_ctx_keys[2].startswith("policy ")
+                        and line.startswith("candidate-path ")
                     ):
                         candidates_to_add.append((newconf_ctx_keys, line))
 
@@ -1593,8 +1613,8 @@ def compare_context_objects(newconf, running):
             # so add them to a separate array that is going to be appended at the end
             if (
                 len(newconf_ctx_keys) == 4
-                and newconf_ctx_keys[0].startswith('segment-routing')
-                and newconf_ctx_keys[3].startswith('candidate-path')
+                and newconf_ctx_keys[0].startswith("segment-routing")
+                and newconf_ctx_keys[3].startswith("candidate-path")
             ):
                 candidates_to_add.append((newconf_ctx_keys, None))
                 for line in newconf_ctx.lines:
@@ -1823,8 +1843,6 @@ if __name__ == "__main__":
         else:
             running.load_from_show_running(args.daemon)
 
-
-
         (lines_to_add, lines_to_del) = compare_context_objects(newconf, running)
         lines_to_configure = []
 
index d751a19f0772347e6c02751c5876204456dc4b6d..812dd4159d7b49814b57f9f96900bac5e8feea5d 100644 (file)
@@ -248,6 +248,10 @@ module frr-isisd {
     type string;
   }
 
+  typedef prefix-list-ref {
+    type string;
+  }
+
   grouping redistribute-attributes {
     description
       "Common optional attributes of any redistribute entry.";
@@ -410,6 +414,19 @@ module frr-isisd {
     }
   }
 
+  grouping global-config-remote-lfa {
+    container remote-lfa {
+      description
+        "Remote LFA configuration.";
+
+      leaf prefix-list {
+        type prefix-list-ref;
+        description
+          "Filter PQ node router ID based on prefix list.";
+      }
+    }
+  }
+
   grouping interface-config-lfa {
     container lfa {
       description
@@ -428,6 +445,32 @@ module frr-isisd {
     }
   }
 
+  grouping interface-config-remote-lfa {
+    container remote-lfa {
+      description
+        "Remote LFA configuration.";
+
+      leaf enable {
+        type boolean;
+        default false;
+        description
+          "Enables remote LFA computation using LDP tunnels.";
+        must ". = 'false' or ../../lfa/enable = 'true'" {
+          error-message
+            "Remote LFA depends on classic LFA being configured in the interface.";
+        }
+
+      }
+      leaf maximum-metric {
+        type uint32 {
+          range "1..16777215";
+        }
+        description
+          "Limit remote LFA node selection within the metric.";
+      }
+    }
+  }
+
   grouping interface-config-ti-lfa {
     container ti-lfa {
       description
@@ -761,6 +804,7 @@ module frr-isisd {
             "Can't enable both classic LFA and TI-LFA in the same interface.";
         }
         uses interface-config-lfa;
+        uses interface-config-remote-lfa;
         uses interface-config-ti-lfa;
       }
       container level-2 {
@@ -771,6 +815,7 @@ module frr-isisd {
             "Can't enable both classic LFA and TI-LFA in the same interface.";
         }
         uses interface-config-lfa;
+        uses interface-config-remote-lfa;
         uses interface-config-ti-lfa;
       }
     }
@@ -1394,11 +1439,13 @@ module frr-isisd {
           description
             "Level-1 IP Fast-reroute configuration.";
           uses global-config-lfa;
+          uses global-config-remote-lfa;
         }
         container level-2 {
           description
             "Level-2 IP Fast-reroute configuration.";
           uses global-config-lfa;
+          uses global-config-remote-lfa;
         }
       }
 
index c96a86cc7319db77bc01f27a840bffd6996bed15..464205f2f364aa77969f90e3eadad63415d6446d 100644 (file)
@@ -92,7 +92,6 @@ static int sample_process(struct zebra_dplane_provider *prov)
 static int init_sample_plugin(struct thread_master *tm)
 {
        int ret;
-       struct zebra_dplane_provider *prov = NULL;
 
        /* Note that we don't use or store the thread_master 'tm'. We
         * don't use the zebra main pthread: our plugin code will run in
index cdacabc102895ba42dc75b30ed09cb0b01efaf06..f842a8c0f33e674567bc9cf3ab1a64b50afc3935 100644 (file)
@@ -40,6 +40,11 @@ if LINUX
 module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la
 endif
 
+# Dataplane sample plugin
+if DEV_BUILD
+module_LTLIBRARIES += zebra/dplane_sample_plugin.la
+endif
+
 man8 += $(MANBUILD)/frr-zebra.8
 ## endif ZEBRA
 endif
@@ -206,6 +211,12 @@ zebra/zebra_fpm_dt.lo: fpm/fpm.pb-c.h qpb/qpb.pb-c.h
 endif
 endif
 
+# Sample dataplane plugin
+if DEV_BUILD
+zebra_dplane_sample_plugin_la_SOURCES = zebra/sample_plugin.c
+zebra_dplane_sample_plugin_la_LDFLAGS = -module -shared -avoid-version -export-dynamic
+endif
+
 nodist_zebra_zebra_SOURCES = \
        yang/frr-zebra.yang.c \
        # end
index da7f4cf64e94a7c216cd401e66cb47671ecd48c2..db2b9e002eca6465d28f316f63e353e3ace01fc7 100644 (file)
@@ -3684,7 +3684,7 @@ int dplane_show_helper(struct vty *vty, bool detailed)
 int dplane_show_provs_helper(struct vty *vty, bool detailed)
 {
        struct zebra_dplane_provider *prov;
-       uint64_t in, in_max, out, out_max;
+       uint64_t in, in_q, in_max, out, out_q, out_max;
 
        vty_out(vty, "Zebra dataplane providers:\n");
 
@@ -3697,17 +3697,20 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
 
                in = atomic_load_explicit(&prov->dp_in_counter,
                                          memory_order_relaxed);
+               in_q = atomic_load_explicit(&prov->dp_in_queued,
+                                           memory_order_relaxed);
                in_max = atomic_load_explicit(&prov->dp_in_max,
                                              memory_order_relaxed);
                out = atomic_load_explicit(&prov->dp_out_counter,
                                           memory_order_relaxed);
+               out_q = atomic_load_explicit(&prov->dp_out_queued,
+                                            memory_order_relaxed);
                out_max = atomic_load_explicit(&prov->dp_out_max,
                                               memory_order_relaxed);
 
-               vty_out(vty,
-                       "%s (%u): in: %" PRIu64 ", q_max: %" PRIu64
-                       ", out: %" PRIu64 ", q_max: %" PRIu64 "\n",
-                       prov->dp_name, prov->dp_id, in, in_max, out, out_max);
+               vty_out(vty, "%s (%u): in: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64", out: %"PRIu64", q: %"PRIu64", q_max: %"PRIu64"\n",
+                       prov->dp_name, prov->dp_id, in, in_q, in_max,
+                       out, out_q, out_max);
 
                DPLANE_LOCK();
                prov = TAILQ_NEXT(prov, dp_prov_link);
@@ -3912,11 +3915,24 @@ uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov)
 void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
                                     struct zebra_dplane_ctx *ctx)
 {
+       uint64_t curr, high;
+
        dplane_provider_lock(prov);
 
        TAILQ_INSERT_TAIL(&(prov->dp_ctx_out_q), ctx,
                          zd_q_entries);
 
+       /* Maintain out-queue counters */
+       atomic_fetch_add_explicit(&(prov->dp_out_queued), 1,
+                                 memory_order_relaxed);
+       curr = atomic_load_explicit(&prov->dp_out_queued,
+                                   memory_order_relaxed);
+       high = atomic_load_explicit(&prov->dp_out_max,
+                                   memory_order_relaxed);
+       if (curr > high)
+               atomic_store_explicit(&prov->dp_out_max, curr,
+                                     memory_order_relaxed);
+
        dplane_provider_unlock(prov);
 
        atomic_fetch_add_explicit(&(prov->dp_out_counter), 1,
index 376721f83ad589bfbddbc00e3742f668eaa85da8..6753bf520c2b9116d339ff81fa99c91854516899 100644 (file)
@@ -29,6 +29,7 @@
 #include "prefix.h"
 #include "vlan.h"
 #include "json.h"
+#include "printfrr.h"
 
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
@@ -254,6 +255,37 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
        }
 }
 
+#define MAC_BUF_SIZE 256
+static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac_t_ *mac, char *buf,
+                                           size_t len)
+{
+       if (mac->flags == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       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_DEF_GW) ? "Default 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) ? "LOC Active "
+                                                                : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
+               CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
+                       ? "LOC Inactive "
+                       : "");
+       return buf;
+}
+
 static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
 {
        struct zebra_vrf *zvrf = NULL;
@@ -278,12 +310,17 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
        if (!mac)
                return 0;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
+       if (IS_ZEBRA_DEBUG_VXLAN) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired",
+                       "%s: duplicate addr mac %s flags %slearn count %u host count %u auto recovery expired",
                        __func__,
                        prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                       mac->flags, mac->dad_count, listcount(mac->neigh_list));
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)),
+                       mac->dad_count, listcount(mac->neigh_list));
+       }
 
        /* Remove all IPs as duplicate associcated with this MAC */
        for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
@@ -350,14 +387,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
         * Remote MAC event -> hold on installing it.
         */
        if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
-               if (IS_ZEBRA_DEBUG_VXLAN)
+               if (IS_ZEBRA_DEBUG_VXLAN) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u",
+                               "%s: duplicate addr MAC %s flags %sskip update to client, learn count %u recover time %u",
                                __func__,
                                prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                               mac->flags, mac->dad_count,
-                               zvrf->dad_freeze_time);
-
+                               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
                 * client but update neigh due to
                 * this MAC update.
@@ -385,12 +425,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
        }
 
        if (reset_params) {
-               if (IS_ZEBRA_DEBUG_VXLAN)
+               if (IS_ZEBRA_DEBUG_VXLAN) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
+                               "%s: duplicate addr MAC %s flags %sdetection time passed, reset learn count %u",
                                __func__,
                                prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                               mac->flags, mac->dad_count);
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
+                               mac->dad_count);
+               }
 
                mac->dad_count = 0;
                /* Start dup. addr detection (DAD) start time,
@@ -452,13 +497,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
                /* Start auto recovery timer for this MAC */
                THREAD_OFF(mac->dad_mac_auto_recovery_timer);
                if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
-                       if (IS_ZEBRA_DEBUG_VXLAN)
+                       if (IS_ZEBRA_DEBUG_VXLAN) {
+                               char mac_buf[MAC_BUF_SIZE];
+
                                zlog_debug(
-                                       "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start",
+                                       "%s: duplicate addr MAC %s flags %sauto recovery time %u start",
                                        __func__,
                                        prefix_mac2str(&mac->macaddr, buf,
                                                       sizeof(buf)),
-                                       mac->flags, zvrf->dad_freeze_time);
+                                       zebra_evpn_zebra_mac_flag_dump(
+                                               mac, mac_buf, sizeof(mac_buf)),
+                                       zvrf->dad_freeze_time);
+                       }
 
                        thread_add_timer(zrouter.master,
                                         zebra_evpn_dad_mac_auto_recovery_exp,
@@ -694,7 +744,7 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
 }
 
 static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
-       uint32_t flags_buf_sz)
+                                       size_t flags_buf_sz)
 {
        snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
                        mac->sync_neigh_cnt ?
@@ -903,14 +953,19 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
+       if (IS_ZEBRA_DEBUG_VXLAN) {
+               char flag_buf[MACIP_BUF_SIZE];
+
                zlog_debug(
-                       "Send MACIP %s f 0x%x MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
-                       (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
+                       "Send MACIP %s f %s MAC %s IP %s 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)),
                        prefix_mac2str(macaddr, buf, sizeof(buf)),
                        ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
                        es ? es->esi_str : "-",
                        zebra_route_string(client->proto));
+       }
 
        if (cmd == ZEBRA_MACIP_ADD)
                client->macipadd_cnt++;
@@ -982,10 +1037,12 @@ zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr)
        mac->uptime = monotime(NULL);
        if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
                char buf[ETHER_ADDR_STRLEN];
+               char mac_buf[MAC_BUF_SIZE];
 
-               zlog_debug("%s: MAC %s flags 0x%x", __func__,
+               zlog_debug("%s: MAC %s flags %s", __func__,
                           prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                          mac->flags);
+                          zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                         sizeof(mac_buf)));
        }
        return mac;
 }
@@ -999,10 +1056,12 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
 
        if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
                char buf[ETHER_ADDR_STRLEN];
+               char mac_buf[MAC_BUF_SIZE];
 
-               zlog_debug("%s: MAC %s flags 0x%x", __func__,
+               zlog_debug("%s: MAC %s flags %s", __func__,
                           prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                          mac->flags);
+                          zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                         sizeof(mac_buf)));
        }
 
        /* If the MAC is freed before the neigh we will end up
@@ -1047,11 +1106,13 @@ static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
                 && !listcount(mac->neigh_list)) {
                if (IS_ZEBRA_DEBUG_VXLAN) {
                        char buf[ETHER_ADDR_STRLEN];
+                       char mac_buf[MAC_BUF_SIZE];
 
                        zlog_debug(
-                               "%s: Del MAC %s flags 0x%x", __func__,
+                               "%s: Del MAC %s flags %s", __func__,
                                prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
-                               mac->flags);
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
                }
                wctx->uninstall = 0;
 
@@ -1204,24 +1265,34 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
        zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
 
        if (!ifp) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no access-port",
+                               "%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 : "-", mac->flags,
+                               mac->es ? mac->es->esi_str : "-",
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
                                set_inactive ? "inactive " : "");
+               }
                return -1;
        }
 
        zif = ifp->info;
        br_ifp = zif->brslave_info.br_if;
        if (!br_ifp) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no br",
+                               "%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 : "-", mac->flags,
+                               mac->es ? mac->es->esi_str : "-",
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
                                set_inactive ? "inactive " : "");
+               }
                return -1;
        }
 
@@ -1236,13 +1307,18 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
         * supported and if the local ES is oper-down.
         */
        if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "dp-%s sync-nw-mac vni %u mac %pEA es %s 0x%x %s",
+                               "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
                                set_static ? "install" : "uninstall",
                                zevpn->vni, &mac->macaddr,
-                               mac->es ? mac->es->esi_str : "-", mac->flags,
+                               mac->es ? mac->es->esi_str : "-",
+                               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
@@ -1256,13 +1332,17 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
                return 0;
        }
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
-               zlog_debug(
-                       "dp-install sync-mac vni %u mac %pEA es %s 0x%x %s%s",
-                       zevpn->vni, &mac->macaddr,
-                       mac->es ? mac->es->esi_str : "-", mac->flags,
-                       set_static ? "static " : "",
-                       set_inactive ? "inactive " : "");
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
+               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)),
+                          set_static ? "static " : "",
+                          set_inactive ? "inactive " : "");
+       }
 
        dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
                             set_static, set_inactive);
@@ -1310,12 +1390,17 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t)
        new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
        new_static = zebra_evpn_mac_is_static(mac);
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac vni %u mac %s es %s 0x%x hold expired",
+                       "sync-mac vni %u mac %s es %s %shold expired",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags);
+                       mac->es ? mac->es->esi_str : "-",
+                       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
         * longer static
@@ -1340,12 +1425,17 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac)
        if (mac->hold_timer)
                return;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac vni %u mac %s es %s 0x%x hold started",
+                       "sync-mac vni %u mac %s es %s %shold started",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags);
+                       mac->es ? mac->es->esi_str : "-",
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
        thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
                         zmh_info->mac_hold_time, &mac->hold_timer);
 }
@@ -1357,12 +1447,18 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac)
        if (!mac->hold_timer)
                return;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac vni %u mac %s es %s 0x%x hold stopped",
+                       "sync-mac vni %u mac %s es %s %shold stopped",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
-                       mac->es ? mac->es->esi_str : "-", mac->flags);
+                       mac->es ? mac->es->esi_str : "-",
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
+
        THREAD_OFF(mac->hold_timer);
 }
 
@@ -1372,13 +1468,18 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
        bool old_static;
        bool new_static;
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "sync-mac del vni %u mac %s es %s seq %d f 0x%x",
+                       "sync-mac del vni %u mac %s es %s seq %d f %s",
                        mac->zevpn->vni,
                        prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
                        mac->es ? mac->es->esi_str : "-", mac->loc_seq,
-                       mac->flags);
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)));
+       }
+
        old_static = zebra_evpn_mac_is_static(mac);
        UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
        if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
@@ -1418,9 +1519,12 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
                 */
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
                    && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
-                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
+                           || IS_ZEBRA_DEBUG_VXLAN) {
+                               char mac_buf[MAC_BUF_SIZE];
+
                                zlog_debug(
-                                       "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f 0x%x",
+                                       "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f %s",
                                        sync ? "sync" : "rem", zevpn->vni,
                                        n_type,
                                        prefix_mac2str(&mac->macaddr, macbuf,
@@ -1429,13 +1533,19 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
                                        ipa_len ? ipaddr2str(ipaddr, ipbuf,
                                                             sizeof(ipbuf))
                                                : "",
-                                       tmp_seq, mac->flags);
+                                       tmp_seq,
+                                       zebra_evpn_zebra_mac_flag_dump(
+                                               mac, mac_buf, sizeof(mac_buf)));
+                       }
+
                        return true;
                }
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f 0x%x",
+                               "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f %s",
                                sync ? "sync" : "rem", zevpn->vni, n_type,
                                prefix_mac2str(&mac->macaddr, macbuf,
                                               sizeof(macbuf)),
@@ -1443,7 +1553,10 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
                                ipa_len ? ipaddr2str(ipaddr, ipbuf,
                                                     sizeof(ipbuf))
                                        : "",
-                               tmp_seq, mac->flags);
+                               tmp_seq,
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
+               }
                return false;
        }
 
@@ -1574,12 +1687,20 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
                mac->flags = new_flags;
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags))
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
+                       char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
+                       struct zebra_mac_t_ omac;
+
+                       omac.flags = old_flags;
                        zlog_debug(
-                               "sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
+                               "sync-mac vni %u mac %s old_f %snew_f %s",
                                zevpn->vni,
                                prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
-                               old_flags, mac->flags);
+                               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 */
                es_change = zebra_evpn_es_mac_ref(mac, esi);
@@ -1613,13 +1734,18 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                inform_bgp = true;
        }
 
-       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
-               zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f 0x%x%s%s",
+       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+               char mac_buf[MAC_BUF_SIZE];
+
+               zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f %s%s%s",
                           ctx->mac_created ? "created" : "updated", zevpn->vni,
                           prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
                           mac->es ? mac->es->esi_str : "-", mac->loc_seq,
-                          mac->flags, inform_bgp ? " inform_bgp" : "",
+                          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,
@@ -1869,14 +1995,20 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
                        /* force drop the sync flags */
                        old_static = zebra_evpn_mac_is_static(mac);
-                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+                       if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                               char mac_buf[MAC_BUF_SIZE];
+
                                zlog_debug(
-                                       "sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
+                                       "sync-mac->remote vni %u mac %s es %s seq %d f %s",
                                        zevpn->vni,
                                        prefix_mac2str(macaddr, buf,
                                                       sizeof(buf)),
                                        mac->es ? mac->es->esi_str : "-",
-                                       mac->loc_seq, mac->flags);
+                                       mac->loc_seq,
+                                       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,
@@ -1970,14 +2102,18 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
                        SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
                inform_client = true;
        } else {
-               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
+                               "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags %s",
                                sticky ? "sticky " : "",
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                ifp->name, ifp->ifindex, vid, zevpn->vni,
                                local_inactive ? "local-inactive " : "",
-                               mac->flags);
+                               zebra_evpn_zebra_mac_flag_dump(
+                                       mac, mac_buf, sizeof(mac_buf)));
+               }
 
                if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
                        struct interface *old_ifp;
@@ -2125,14 +2261,19 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
         */
        if ((old_local_inactive != local_inactive)
            || (new_bgp_ready != old_bgp_ready)) {
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "local mac vni %u mac %s es %s seq %d f 0x%x%s",
+                               "local mac vni %u mac %s es %s seq %d f %s%s",
                                zevpn->vni,
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                mac->es ? mac->es->esi_str : "", mac->loc_seq,
-                               mac->flags,
-                               local_inactive ? " local-inactive" : "");
+                               zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                              sizeof(mac_buf)),
+                               local_inactive ? "local-inactive" : "");
+               }
+
                if (!is_dup_detect)
                        inform_client = true;
        }
@@ -2177,12 +2318,18 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
        if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
                return 0;
 
-       if (IS_ZEBRA_DEBUG_VXLAN)
+       if (IS_ZEBRA_DEBUG_VXLAN) {
+               char mac_buf[MAC_BUF_SIZE];
+
                zlog_debug(
-                       "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u",
+                       "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags %snbr count %u",
                        prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
                        ifp->ifindex, mac->fwd_info.local.vid, zevpn->vni,
-                       mac->loc_seq, mac->flags, listcount(mac->neigh_list));
+                       mac->loc_seq,
+                       zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+                                                      sizeof(mac_buf)),
+                       listcount(mac->neigh_list));
+       }
 
        old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
        if (zebra_evpn_mac_is_static(mac)) {
@@ -2191,13 +2338,17 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
                 */
                memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
 
-               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+               if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+                       char mac_buf[MAC_BUF_SIZE];
+
                        zlog_debug(
-                               "re-add sync-mac vni %u mac %s es %s seq %d f 0x%x",
+                               "re-add sync-mac vni %u mac %s es %s seq %d f %s",
                                zevpn->vni,
                                prefix_mac2str(macaddr, buf, sizeof(buf)),
                                mac->es ? mac->es->esi_str : "-", mac->loc_seq,
-                               mac->flags);
+                               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)) {
index 1730991f1e7ad8dc423b609bbfebd204323c1a26..e21b61050137522988986754aa1939479f189744 100644 (file)
@@ -56,6 +56,7 @@ struct zebra_mac_t_ {
        /* MAC address. */
        struct ethaddr macaddr;
 
+       /* When modifying flags please fixup zebra_evpn_zebra_mac_flag_dump */
        uint32_t flags;
 #define ZEBRA_MAC_LOCAL 0x01
 #define ZEBRA_MAC_REMOTE 0x02
index 375be45df0909fe846fd2456048d1d89f648fe02..0a692feb35baa7d0852df70895c21b083e529f74 100644 (file)
@@ -2120,7 +2120,6 @@ static unsigned nexthop_active_check(struct route_node *rn,
        struct interface *ifp;
        route_map_result_t ret = RMAP_PERMITMATCH;
        int family;
-       char buf[SRCDEST2STR_BUFFER];
        const struct prefix *p, *src_p;
        struct zebra_vrf *zvrf;
 
@@ -2230,10 +2229,9 @@ static unsigned nexthop_active_check(struct route_node *rn,
                                    zvrf, re->tag);
        if (ret == RMAP_DENYMATCH) {
                if (IS_ZEBRA_DEBUG_RIB) {
-                       srcdest_rnode2str(rn, buf, sizeof(buf));
                        zlog_debug(
-                               "%u:%s: Filtering out with NH out %s due to route map",
-                               re->vrf_id, buf,
+                               "%u:%pRN: Filtering out with NH out %s due to route map",
+                               re->vrf_id, rn,
                                ifindex2ifname(nexthop->ifindex,
                                               nexthop->vrf_id));
                }
index 1f92c43a69257da28fb90232a86468c757a3f105..7c867355457406debc4211ba89262fde0c4c9bbf 100644 (file)
@@ -38,6 +38,7 @@
 #include "workqueue.h"
 #include "nexthop_group_private.h"
 #include "frr_pthread.h"
+#include "printfrr.h"
 
 #include "zebra/zebra_router.h"
 #include "zebra/connected.h"
@@ -148,6 +149,30 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
        zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf);
 }
 
+static char *_dump_re_status(const struct route_entry *re, char *buf,
+                            size_t len)
+{
+       if (re->status == 0) {
+               snprintfrr(buf, len, "None ");
+               return buf;
+       }
+
+       snprintfrr(
+               buf, len, "%s%s%s%s%s%s%s",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)
+                       ? "Label Changed "
+                       : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
+                                                             : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "",
+               CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG) ? "Fib NHG "
+                                                               : "");
+       return buf;
+}
+
 #define rnode_debug(node, vrf_id, ...)                                         \
        _rnode_zlog(__func__, vrf_id, node, LOG_DEBUG, __VA_ARGS__)
 #define rnode_info(node, ...)                                                  \
@@ -1080,12 +1105,20 @@ static void rib_process(struct route_node *rn)
        }
 
        RNODE_FOREACH_RE_SAFE (rn, re, next) {
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+                       char flags_buf[128];
+                       char status_buf[128];
+
                        zlog_debug(
-                               "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
+                               "%s(%u:%u):%s: Examine re %p (%s) status: %sflags: %sdist %d metric %d",
                                VRF_LOGNAME(vrf), vrf_id, re->table, buf, re,
-                               zebra_route_string(re->type), re->status,
-                               re->flags, re->distance, re->metric);
+                               zebra_route_string(re->type),
+                               _dump_re_status(re, status_buf,
+                                               sizeof(status_buf)),
+                               zclient_dump_route_flags(re->flags, flags_buf,
+                                                        sizeof(flags_buf)),
+                               re->distance, re->metric);
+               }
 
                /* Currently selected re. */
                if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@ -1107,6 +1140,9 @@ static void rib_process(struct route_node *rn)
                 */
                if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) {
                        if (!nexthop_active_update(rn, re)) {
+                               const struct prefix *p;
+                               struct rib_table_info *info;
+
                                if (re->type == ZEBRA_ROUTE_TABLE) {
                                        /* XXX: HERE BE DRAGONS!!!!!
                                         * In all honesty, I have not yet
@@ -1136,6 +1172,11 @@ static void rib_process(struct route_node *rn)
                                                         ROUTE_ENTRY_REMOVED);
                                }
 
+                               info = srcdest_rnode_table_info(rn);
+                               srcdest_rnode_prefixes(rn, &p, NULL);
+                               zsend_route_notify_owner(re, p,
+                                                        ZAPI_ROUTE_FAIL_INSTALL,
+                                                        info->afi, info->safi);
                                continue;
                        }
                } else {
@@ -2791,6 +2832,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
        bool is_srcdst = src_p && src_p->prefixlen;
        char straddr[PREFIX_STRLEN];
        char srcaddr[PREFIX_STRLEN];
+       char flags_buf[128];
+       char status_buf[128];
        struct nexthop *nexthop;
        struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
        struct nexthop_group *nhg;
@@ -2804,9 +2847,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
        zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d",
                   straddr, (unsigned long)re->uptime, re->type, re->instance,
                   re->table);
-       zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
-                  straddr, re->metric, re->mtu, re->distance, re->flags,
-                  re->status);
+       zlog_debug(
+               "%s: metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s",
+               straddr, re->metric, re->mtu, re->distance,
+               zclient_dump_route_flags(re->flags, flags_buf,
+                                        sizeof(flags_buf)),
+               _dump_re_status(re, status_buf, sizeof(status_buf)));
        zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
                   nexthop_group_nexthop_num(&(re->nhe->nhg)),
                   nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
@@ -2941,8 +2987,10 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
        struct nhg_hash_entry *nhe = NULL;
        struct route_table *table;
        struct route_node *rn;
-       struct route_entry *same = NULL;
+       struct route_entry *same = NULL, *first_same = NULL;
        int ret = 0;
+       int same_count = 0;
+       rib_dest_t *dest;
 
        if (!re || !re_nhe)
                return -1;
@@ -3010,14 +3058,22 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
         * for the install don't do a route replace.
         */
        RNODE_FOREACH_RE (rn, same) {
-               if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED))
+               if (CHECK_FLAG(same->status, ROUTE_ENTRY_REMOVED)) {
+                       same_count++;
                        continue;
+               }
 
                /* Compare various route_entry properties */
-               if (rib_compare_routes(re, same))
-                       break;
+               if (rib_compare_routes(re, same)) {
+                       same_count++;
+
+                       if (first_same == NULL)
+                               first_same = same;
+               }
        }
 
+       same = first_same;
+
        /* If this route is kernel/connected route, notify the dataplane. */
        if (RIB_SYSTEM_ROUTE(re)) {
                /* Notify dataplane */
@@ -3027,8 +3083,9 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
        /* Link new re to node.*/
        if (IS_ZEBRA_DEBUG_RIB) {
                rnode_debug(rn, re->vrf_id,
-                           "Inserting route rn %p, re %p (%s) existing %p",
-                           rn, re, zebra_route_string(re->type), same);
+                           "Inserting route rn %p, re %p (%s) existing %p, same_count %d",
+                           rn, re, zebra_route_string(re->type), same,
+                           same_count);
 
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        route_entry_dump(p, src_p, re);
@@ -3042,6 +3099,24 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
        if (same)
                rib_delnode(rn, same);
 
+       /* 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. */
+                       if (dest && re == dest->selected_fib)
+                               continue;
+
+                       if (IS_ZEBRA_DEBUG_RIB)
+                               rnode_debug(rn, re->vrf_id, "rn %p, removing unneeded re %p",
+                                           rn, re);
+
+                       rib_unlink(rn, re);
+               }
+       }
+
        route_unlock_node(rn);
        return ret;
 }