summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c13
-rw-r--r--bgpd/bgp_attr.h4
-rw-r--r--bgpd/bgp_fsm.c33
-rw-r--r--bgpd/bgp_mplsvpn.c103
-rw-r--r--bgpd/bgp_network.c37
-rw-r--r--bgpd/bgp_network.h5
-rw-r--r--bgpd/bgp_nexthop.c121
-rw-r--r--bgpd/bgp_nexthop.h33
-rw-r--r--bgpd/bgp_nht.c299
-rw-r--r--bgpd/bgp_open.c3
-rw-r--r--bgpd/bgp_packet.c21
-rw-r--r--bgpd/bgp_route.c12
-rw-r--r--bgpd/bgp_routemap.c43
-rw-r--r--bgpd/bgp_vty.c223
-rw-r--r--bgpd/bgp_zebra.c8
-rw-r--r--bgpd/bgpd.c27
-rw-r--r--bgpd/bgpd.h320
-rwxr-xr-xconfigure.ac4
-rw-r--r--debian/control2
-rw-r--r--doc/developer/building-libyang.rst15
-rw-r--r--doc/developer/lists.rst61
-rw-r--r--doc/figures/nodes.dot2
-rw-r--r--doc/user/bgp.rst64
-rw-r--r--doc/user/isisd.rst27
-rw-r--r--doc/user/routemap.rst6
-rw-r--r--isisd/isis_circuit.c39
-rw-r--r--isisd/isis_cli.c160
-rw-r--r--isisd/isis_main.c5
-rw-r--r--isisd/isis_nb.c7
-rw-r--r--isisd/isis_nb.h1
-rw-r--r--isisd/isis_nb_config.c69
-rw-r--r--isisd/isis_zebra.c14
-rw-r--r--isisd/isis_zebra.h1
-rw-r--r--isisd/isisd.c136
-rw-r--r--isisd/isisd.h9
-rw-r--r--ldpd/lde.c158
-rw-r--r--ldpd/lde.h3
-rw-r--r--ldpd/lde_lib.c20
-rw-r--r--ldpd/ldp_vty_cmds.c2
-rw-r--r--ldpd/ldpd.c43
-rw-r--r--ldpd/ldpe.c8
-rw-r--r--lib/filter.h10
-rw-r--r--lib/filter_cli.c97
-rw-r--r--lib/filter_nb.c96
-rw-r--r--lib/hash.c15
-rw-r--r--lib/mpls.h3
-rw-r--r--lib/privs.c6
-rw-r--r--lib/stream.c24
-rw-r--r--lib/stream.h9
-rw-r--r--ospf6d/ospf6_abr.c2
-rw-r--r--ospf6d/ospf6_asbr.c52
-rw-r--r--ospf6d/ospf6_asbr.h2
-rw-r--r--ospf6d/ospf6_bfd.c6
-rw-r--r--ospf6d/ospf6_interface.c14
-rw-r--r--ospf6d/ospf6_interface.h3
-rw-r--r--ospf6d/ospf6_intra.c7
-rw-r--r--ospf6d/ospf6_main.c6
-rw-r--r--ospf6d/ospf6_message.c2
-rw-r--r--ospf6d/ospf6_route.c18
-rw-r--r--ospf6d/ospf6_snmp.c24
-rw-r--r--ospf6d/ospf6_spf.c2
-rw-r--r--ospf6d/ospf6_top.c2
-rw-r--r--ospf6d/ospf6_zebra.c22
-rw-r--r--ospf6d/ospf6_zebra.h8
-rw-r--r--ospfd/ospf_abr.c1
-rw-r--r--ospfd/ospf_asbr.c24
-rw-r--r--ospfd/ospf_asbr.h1
-rw-r--r--ospfd/ospf_zebra.c17
-rw-r--r--pbrd/pbr_map.c18
-rw-r--r--pbrd/pbr_nht.c30
-rw-r--r--pbrd/pbr_nht.h1
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--tests/isisd/test_isis_spf.c2
-rw-r--r--tests/topotests/bfd-profiles-topo1/r1/ospfd.conf2
-rw-r--r--tests/topotests/bfd-profiles-topo1/r6/ospfd.conf2
-rw-r--r--tests/topotests/bfd-topo2/r2/ospf6d.conf2
-rw-r--r--tests/topotests/bfd-topo2/r2/ospfd.conf2
-rw-r--r--tests/topotests/bfd-topo2/r3/ospfd.conf2
-rw-r--r--tests/topotests/bfd-topo2/r4/ospf6d.conf2
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd.conf18
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf40
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf37
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_vrf.conf21
-rw-r--r--tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R1/ospfd.conf4
-rw-r--r--tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf9
-rw-r--r--tests/topotests/bgp-auth/R1/ospfd_vrf.conf4
-rw-r--r--tests/topotests/bgp-auth/R1/zebra.conf21
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf37
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf37
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_vrf.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R2/ospfd.conf4
-rw-r--r--tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf9
-rw-r--r--tests/topotests/bgp-auth/R2/ospfd_vrf.conf4
-rw-r--r--tests/topotests/bgp-auth/R2/zebra.conf21
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf37
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf37
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_vrf.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf18
-rw-r--r--tests/topotests/bgp-auth/R3/ospfd.conf4
-rw-r--r--tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf9
-rw-r--r--tests/topotests/bgp-auth/R3/ospfd_vrf.conf4
-rw-r--r--tests/topotests/bgp-auth/R3/zebra.conf21
-rwxr-xr-xtests/topotests/bgp-auth/test_bgp_auth.py747
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf9
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf1
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf5
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf1
-rw-r--r--tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf5
-rw-r--r--tests/topotests/bgp_features/r1/bgpd.conf4
-rw-r--r--tests/topotests/bgp_features/r1/ospfd.conf11
-rw-r--r--tests/topotests/bgp_features/r2/bgpd.conf4
-rw-r--r--tests/topotests/bgp_features/r2/ospfd.conf11
-rw-r--r--tests/topotests/bgp_features/r3/ospfd.conf11
-rw-r--r--tests/topotests/bgp_features/r4/bgpd.conf3
-rw-r--r--tests/topotests/bgp_features/r5/bgpd.conf3
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf4
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf12
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf8
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf4
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf1
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf4
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf12
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf8
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf3
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf4
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf4
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf12
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf8
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf4
-rw-r--r--tests/topotests/bgp_update_delay/__init__.py0
-rw-r--r--tests/topotests/bgp_update_delay/r1/bgpd.conf10
-rw-r--r--tests/topotests/bgp_update_delay/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/r2/bgpd.conf18
-rw-r--r--tests/topotests/bgp_update_delay/r2/zebra.conf20
-rw-r--r--tests/topotests/bgp_update_delay/r3/bgpd.conf10
-rw-r--r--tests/topotests/bgp_update_delay/r3/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/r4/bgpd.conf11
-rw-r--r--tests/topotests/bgp_update_delay/r4/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/r5/bgpd.conf11
-rw-r--r--tests/topotests/bgp_update_delay/r5/zebra.conf9
-rwxr-xr-xtests/topotests/bgp_update_delay/test_bgp_update_delay.py295
-rw-r--r--tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json563
-rw-r--r--tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json563
-rwxr-xr-xtests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py1848
-rwxr-xr-xtests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py962
-rw-r--r--tests/topotests/isis-topo1-vrf/__init__.py0
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/isisd.conf15
-rw-r--r--tests/topotests/isis-topo1-vrf/r1/r1_route.json57
-rw-r--r--tests/topotests/isis-topo1-vrf/r1/r1_route6.json40
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json14
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/r1_route_linux.json13
-rw-r--r--tests/topotests/isis-topo1-vrf/r1/r1_topology.json80
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r1/zebra.conf9
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/isisd.conf15
-rw-r--r--tests/topotests/isis-topo1-vrf/r2/r2_route.json57
-rw-r--r--tests/topotests/isis-topo1-vrf/r2/r2_route6.json40
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json14
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/r2_route_linux.json13
-rw-r--r--tests/topotests/isis-topo1-vrf/r2/r2_topology.json80
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r2/zebra.conf9
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/isisd.conf22
-rw-r--r--tests/topotests/isis-topo1-vrf/r3/r3_route.json112
-rw-r--r--tests/topotests/isis-topo1-vrf/r3/r3_route6.json78
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json26
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/r3_route_linux.json24
-rw-r--r--tests/topotests/isis-topo1-vrf/r3/r3_topology.json132
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r3/zebra.conf13
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/isisd.conf25
-rw-r--r--tests/topotests/isis-topo1-vrf/r4/r4_route.json105
-rw-r--r--tests/topotests/isis-topo1-vrf/r4/r4_route6.json78
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json26
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/r4_route_linux.json24
-rw-r--r--tests/topotests/isis-topo1-vrf/r4/r4_topology.json132
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r4/zebra.conf13
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/isisd.conf21
-rw-r--r--tests/topotests/isis-topo1-vrf/r5/r5_route.json106
-rw-r--r--tests/topotests/isis-topo1-vrf/r5/r5_route6.json78
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json26
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/r5_route_linux.json24
-rw-r--r--tests/topotests/isis-topo1-vrf/r5/r5_topology.json124
-rwxr-xr-xtests/topotests/isis-topo1-vrf/r5/zebra.conf13
-rwxr-xr-xtests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot100
-rwxr-xr-xtests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpgbin0 -> 74340 bytes
-rwxr-xr-xtests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py455
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf4
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf8
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf4
-rw-r--r--tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf4
-rw-r--r--tests/topotests/ldp-oc-topo1/r1/ospfd.conf4
-rw-r--r--tests/topotests/ldp-oc-topo1/r2/ospfd.conf8
-rw-r--r--tests/topotests/ldp-oc-topo1/r3/ospfd.conf4
-rw-r--r--tests/topotests/ldp-oc-topo1/r4/ospfd.conf4
-rw-r--r--tests/topotests/ldp-topo1/r1/ospfd.conf4
-rw-r--r--tests/topotests/ldp-topo1/r2/ospfd.conf12
-rw-r--r--tests/topotests/ldp-topo1/r3/ospfd.conf8
-rw-r--r--tests/topotests/ldp-topo1/r4/ospfd.conf4
-rw-r--r--tests/topotests/ldp-vpls-topo1/r1/ospfd.conf8
-rw-r--r--tests/topotests/ldp-vpls-topo1/r2/ospfd.conf8
-rw-r--r--tests/topotests/ldp-vpls-topo1/r3/ospfd.conf8
-rw-r--r--tests/topotests/lib/bgp.py11
-rw-r--r--tests/topotests/lib/common_config.py298
-rw-r--r--tests/topotests/lib/topotest.py84
-rw-r--r--tests/topotests/ospf-sr-topo1/r1/ospfd.conf4
-rw-r--r--tests/topotests/ospf-sr-topo1/r2/ospfd.conf8
-rw-r--r--tests/topotests/ospf-sr-topo1/r3/ospfd.conf4
-rw-r--r--tests/topotests/ospf-sr-topo1/r4/ospfd.conf4
-rw-r--r--tests/topotests/ospf-topo1/r1/ospf6d.conf4
-rw-r--r--tests/topotests/ospf-topo1/r1/ospfd.conf4
-rw-r--r--tests/topotests/ospf-topo1/r2/ospf6d.conf8
-rw-r--r--tests/topotests/ospf-topo1/r2/ospfd.conf4
-rw-r--r--tests/topotests/ospf-topo1/r3/ospf6d.conf12
-rw-r--r--tests/topotests/ospf-topo1/r3/ospfd.conf8
-rw-r--r--tests/topotests/ospf-topo1/r4/ospf6d.conf8
-rw-r--r--tests/topotests/ospf-topo1/r4/ospfd.conf4
-rw-r--r--tests/topotests/ospf-topo2/r1/ospfd.conf2
-rw-r--r--tests/topotests/ospf-topo2/r2/ospfd.conf2
-rw-r--r--vtysh/vtysh.c5
-rw-r--r--yang/frr-filter.yang39
-rw-r--r--yang/frr-interface.yang6
-rw-r--r--yang/frr-isisd.yang15
-rw-r--r--yang/frr-ripd.yang6
-rw-r--r--yang/frr-ripngd.yang2
-rw-r--r--yang/frr-route-map.yang2
-rw-r--r--yang/frr-zebra.yang20
244 files changed, 10552 insertions, 846 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index cac3ab1ca7..8817263cef 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -729,7 +729,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
&& attr1->distance == attr2->distance
&& srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
- && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn))
+ && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
+ && attr1->srte_color == attr2->srte_color)
return true;
}
@@ -1631,16 +1632,20 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
external peer, then this attribute MUST be ignored by the
receiving speaker. */
if (peer->sort == BGP_PEER_EBGP) {
- stream_forward_getp(peer->curr, length);
+ STREAM_FORWARD_GETP(peer->curr, length);
return BGP_ATTR_PARSE_PROCEED;
}
- attr->local_pref = stream_getl(peer->curr);
+ STREAM_GETL(peer->curr, attr->local_pref);
/* Set the local-pref flag. */
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
return BGP_ATTR_PARSE_PROCEED;
+
+stream_failure:
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
}
/* Atomic aggregate. */
@@ -3023,7 +3028,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
size_t lfl =
CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
/* Rewind to end of flag field */
- stream_forward_getp(BGP_INPUT(peer), -(1 + lfl));
+ stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
/* Type */
stream_get(&ndata[0], BGP_INPUT(peer), 1);
/* Length */
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index c57cf81007..e6e953364b 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -24,6 +24,7 @@
#include "mpls.h"
#include "bgp_attr_evpn.h"
#include "bgpd/bgp_encap_types.h"
+#include "srte.h"
/* Simple bit mapping. */
#define BITMAP_NBBY 8
@@ -290,6 +291,9 @@ struct attr {
/* EVPN ES */
esi_t esi;
+
+ /* SR-TE Color */
+ uint32_t srte_color;
};
/* rmap_change_flags definition */
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 28e93c4096..14dcf2b593 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1105,6 +1105,13 @@ void bgp_fsm_change_status(struct peer *peer, int status)
peer->ostatus = peer->status;
peer->status = status;
+ /* Reset received keepalives counter on every FSM change */
+ peer->rtt_keepalive_rcv = 0;
+
+ /* Fire backward transition hook if that's the case */
+ if (peer->ostatus > peer->status)
+ hook_call(peer_backward_transition, peer);
+
/* Save event that caused status change. */
peer->last_major_event = peer->cur_event;
@@ -1268,8 +1275,6 @@ int bgp_stop(struct peer *peer)
peer->host);
update_group_remove_peer_afs(peer);
- hook_call(peer_backward_transition, peer);
-
/* Reset peer synctime */
peer->synctime = 0;
}
@@ -1872,6 +1877,30 @@ static int bgp_establish(struct peer *peer)
}
}
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ if ((bgp_peer_gr_mode_get(peer) == PEER_GR)
+ || ((bgp_peer_gr_mode_get(peer) == PEER_GLOBAL_INHERIT)
+ && (bgp_global_gr_mode_get(peer->bgp) == GLOBAL_GR))) {
+ FOREACH_AFI_SAFI (afi, safi)
+ /* Send route processing complete
+ message to RIB */
+ bgp_zebra_update(
+ afi, safi, peer->bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+ }
+ } else {
+ /* Peer sends R-bit. In this case, we need to send
+ * ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV)) {
+ FOREACH_AFI_SAFI (afi, safi)
+ /* Send route processing complete
+ message to RIB */
+ bgp_zebra_update(
+ afi, safi, peer->bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+ }
+ }
+
peer->nsf_af_count = nsf_af_count;
if (nsf_af_count)
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 86fc4bc0a3..5ef3cf736d 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -101,11 +101,9 @@ void encode_label(mpls_label_t label, mpls_label_t *label_pnt)
int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
struct bgp_nlri *packet)
{
- uint8_t *pnt;
- uint8_t *lim;
struct prefix p;
- int psize = 0;
- int prefixlen;
+ uint8_t psize = 0;
+ uint8_t prefixlen;
uint16_t type;
struct rd_as rd_as;
struct rd_ip rd_ip;
@@ -115,13 +113,14 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
safi_t safi;
int addpath_encoded;
uint32_t addpath_id;
+ int ret = 0;
/* Make prefix_rd */
prd.family = AF_UNSPEC;
prd.prefixlen = 64;
- pnt = packet->nlri;
- lim = pnt + packet->length;
+ struct stream *data = stream_new(packet->length);
+ stream_put(data, packet->nlri, packet->length);
afi = packet->afi;
safi = packet->safi;
addpath_id = 0;
@@ -132,23 +131,26 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
PEER_CAP_ADDPATH_AF_TX_RCV));
#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */
- for (; pnt < lim; pnt += psize) {
+ while (STREAM_READABLE(data) > 0) {
/* Clear prefix structure. */
memset(&p, 0, sizeof(struct prefix));
if (addpath_encoded) {
-
- /* When packet overflow occurs return immediately. */
- if (pnt + BGP_ADDPATH_ID_LEN > lim)
- return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
-
- memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
+ STREAM_GET(&addpath_id, data, BGP_ADDPATH_ID_LEN);
addpath_id = ntohl(addpath_id);
- pnt += BGP_ADDPATH_ID_LEN;
+ }
+
+ if (STREAM_READABLE(data) < 1) {
+ flog_err(
+ EC_BGP_UPDATE_RCV,
+ "%s [Error] Update packet error / VPN (truncated NLRI of size %u; no prefix length)",
+ peer->host, packet->length);
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ goto done;
}
/* Fetch prefix length. */
- prefixlen = *pnt++;
+ STREAM_GETC(data, prefixlen);
p.family = afi2family(packet->afi);
psize = PSIZE(prefixlen);
@@ -157,16 +159,18 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",
peer->host, prefixlen);
- return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
+ ret = BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH;
+ goto done;
}
/* sanity check against packet data */
- if ((pnt + psize) > lim) {
+ if (STREAM_READABLE(data) < psize) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)",
- peer->host, prefixlen, (uint)(lim - pnt));
- return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
+ peer->host, prefixlen, packet->length);
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
+ goto done;
}
/* sanity check against storage for the IP address portion */
@@ -177,7 +181,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
sizeof(p.u));
- return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ goto done;
}
/* Sanity check against max bitlen of the address family */
@@ -188,30 +193,48 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
p.family, prefix_blen(&p));
- return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ goto done;
}
/* Copy label to prefix. */
- memcpy(&label, pnt, BGP_LABEL_BYTES);
+ if (STREAM_READABLE(data) < BGP_LABEL_BYTES) {
+ flog_err(
+ EC_BGP_UPDATE_RCV,
+ "%s [Error] Update packet error / VPN (truncated NLRI of size %u; no label)",
+ peer->host, packet->length);
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ goto done;
+ }
+
+ STREAM_GET(&label, data, BGP_LABEL_BYTES);
bgp_set_valid_label(&label);
/* Copy routing distinguisher to rd. */
- memcpy(&prd.val, pnt + BGP_LABEL_BYTES, 8);
+ if (STREAM_READABLE(data) < 8) {
+ flog_err(
+ EC_BGP_UPDATE_RCV,
+ "%s [Error] Update packet error / VPN (truncated NLRI of size %u; no RD)",
+ peer->host, packet->length);
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+ goto done;
+ }
+ STREAM_GET(&prd.val, data, 8);
/* Decode RD type. */
- type = decode_rd_type(pnt + BGP_LABEL_BYTES);
+ type = decode_rd_type(prd.val);
switch (type) {
case RD_TYPE_AS:
- decode_rd_as(pnt + 5, &rd_as);
+ decode_rd_as(&prd.val[2], &rd_as);
break;
case RD_TYPE_AS4:
- decode_rd_as4(pnt + 5, &rd_as);
+ decode_rd_as4(&prd.val[2], &rd_as);
break;
case RD_TYPE_IP:
- decode_rd_ip(pnt + 5, &rd_ip);
+ decode_rd_ip(&prd.val[2], &rd_ip);
break;
#ifdef ENABLE_BGP_VNC
@@ -224,11 +247,9 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
break; /* just report */
}
- p.prefixlen =
- prefixlen
- - VPN_PREFIXLEN_MIN_BYTES * 8; /* exclude label & RD */
- memcpy(p.u.val, pnt + VPN_PREFIXLEN_MIN_BYTES,
- psize - VPN_PREFIXLEN_MIN_BYTES);
+ /* exclude label & RD */
+ p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8;
+ STREAM_GET(p.u.val, data, psize - VPN_PREFIXLEN_MIN_BYTES);
if (attr) {
bgp_update(peer, &p, addpath_id, attr, packet->afi,
@@ -241,15 +262,27 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
}
}
/* Packet length consistency check. */
- if (pnt != lim) {
+ if (STREAM_READABLE(data) != 0) {
flog_err(
EC_BGP_UPDATE_RCV,
"%s [Error] Update packet error / VPN (%td data remaining after parsing)",
- peer->host, lim - pnt);
+ peer->host, STREAM_READABLE(data));
return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
}
- return 0;
+ goto done;
+
+stream_failure:
+ flog_err(
+ EC_BGP_UPDATE_RCV,
+ "%s [Error] Update packet error / VPN (NLRI of size %u - length error)",
+ peer->host, packet->length);
+ ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;
+
+done:
+ stream_free(data);
+ return ret;
+
#undef VPN_PREFIXLEN_MIN_BYTES
}
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index c324f259ba..cae11ae7bd 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -160,12 +160,26 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
*/
frr_with_privs(&bgpd_privs) {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
- if (listener->su.sa.sa_family
- == peer->su.sa.sa_family) {
+ if (listener->su.sa.sa_family ==
+ peer->su.sa.sa_family) {
uint16_t prefixlen =
peer->su.sa.sa_family == AF_INET
- ? IPV4_MAX_PREFIXLEN
- : IPV6_MAX_PREFIXLEN;
+ ? IPV4_MAX_PREFIXLEN
+ : IPV6_MAX_PREFIXLEN;
+
+ /*
+ * if we have stored a BGP vrf instance in the
+ * listener it must match the bgp instance in
+ * the peer otherwise the peer bgp instance
+ * must be the default vrf or a view instance
+ */
+ if (!listener->bgp) {
+ if (peer->bgp->vrf_id != VRF_DEFAULT
+ && peer->bgp->inst_type
+ != BGP_INSTANCE_TYPE_VIEW)
+ continue;
+ } else if (listener->bgp != peer->bgp)
+ continue;
ret = bgp_md5_set_socket(listener->fd,
&peer->su, prefixlen,
@@ -176,7 +190,7 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
return ret;
}
-int bgp_md5_set_prefix(struct prefix *p, const char *password)
+int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, const char *password)
{
int ret = 0;
union sockunion su;
@@ -186,7 +200,9 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)
/* Set or unset the password on the listen socket(s). */
frr_with_privs(&bgpd_privs) {
for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
- if (listener->su.sa.sa_family == p->family) {
+ if (listener->su.sa.sa_family == p->family
+ && ((bgp->vrf_id == VRF_DEFAULT)
+ || (listener->bgp == bgp))) {
prefix2sockunion(p, &su);
ret = bgp_md5_set_socket(listener->fd, &su,
p->prefixlen,
@@ -198,9 +214,9 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)
return ret;
}
-int bgp_md5_unset_prefix(struct prefix *p)
+int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p)
{
- return bgp_md5_set_prefix(p, NULL);
+ return bgp_md5_set_prefix(bgp, p, NULL);
}
int bgp_md5_set(struct peer *peer)
@@ -812,8 +828,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
listener->fd = sock;
listener->name = XSTRDUP(MTYPE_BGP_LISTENER, bgp->name);
- /* this socket needs a change of ns. record bgp back pointer */
- if (bgp->vrf_id != VRF_DEFAULT && vrf_is_backend_netns())
+ /* this socket is in a vrf record bgp back pointer */
+ if (bgp->vrf_id != VRF_DEFAULT
+ && bgp->inst_type != BGP_INSTANCE_TYPE_VIEW)
listener->bgp = bgp;
memcpy(&listener->su, sa, salen);
diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h
index 018efbc08e..0b5cc17523 100644
--- a/bgpd/bgp_network.h
+++ b/bgpd/bgp_network.h
@@ -31,8 +31,9 @@ extern void bgp_close(void);
extern int bgp_connect(struct peer *);
extern int bgp_getsockname(struct peer *);
-extern int bgp_md5_set_prefix(struct prefix *p, const char *password);
-extern int bgp_md5_unset_prefix(struct prefix *p);
+extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p,
+ const char *password);
+extern int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p);
extern int bgp_md5_set(struct peer *);
extern int bgp_md5_unset(struct peer *);
extern int bgp_set_socket_ttl(struct peer *, int fd);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 5cc0d60529..ed026a2fff 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -35,7 +35,6 @@
#include "filter.h"
#include "bgpd/bgpd.h"
-#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_nexthop.h"
@@ -48,10 +47,20 @@
DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
-char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
+int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
+ const struct bgp_nexthop_cache *b)
{
- prefix2str(bgp_dest_get_prefix(bnc->dest), buf, size);
- return buf;
+ if (a->srte_color < b->srte_color)
+ return -1;
+ if (a->srte_color > b->srte_color)
+ return 1;
+
+ return prefix_cmp(&a->prefix, &b->prefix);
+}
+
+const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
+{
+ return prefix2str(&bnc->prefix, buf, size);
}
void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
@@ -59,32 +68,62 @@ void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)
nexthops_free(bnc->nexthop);
}
-struct bgp_nexthop_cache *bnc_new(void)
+struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix, uint32_t srte_color)
{
struct bgp_nexthop_cache *bnc;
bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,
sizeof(struct bgp_nexthop_cache));
+ bnc->prefix = *prefix;
+ bnc->srte_color = srte_color;
+ bnc->tree = tree;
LIST_INIT(&(bnc->paths));
+ bgp_nexthop_cache_add(tree, bnc);
+
return bnc;
}
+bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc)
+{
+ struct bgp_nexthop_cache *bnc_tmp;
+
+ frr_each (bgp_nexthop_cache, bnc->tree, bnc_tmp) {
+ if (bnc_tmp == bnc)
+ continue;
+ if (prefix_cmp(&bnc->prefix, &bnc_tmp->prefix) == 0)
+ return true;
+ }
+ return false;
+}
+
void bnc_free(struct bgp_nexthop_cache *bnc)
{
bnc_nexthop_free(bnc);
+ bgp_nexthop_cache_del(bnc->tree, bnc);
XFREE(MTYPE_BGP_NEXTHOP_CACHE, bnc);
}
+struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix, uint32_t srte_color)
+{
+ struct bgp_nexthop_cache bnc = {};
+
+ if (!tree)
+ return NULL;
+
+ bnc.prefix = *prefix;
+ bnc.srte_color = srte_color;
+ return bgp_nexthop_cache_find(tree, &bnc);
+}
+
/* Reset and free all BGP nexthop cache. */
-static void bgp_nexthop_cache_reset(struct bgp_table *table)
+static void bgp_nexthop_cache_reset(struct bgp_nexthop_cache_head *tree)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
- for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
+ while (bgp_nexthop_cache_count(tree) > 0) {
+ bnc = bgp_nexthop_cache_first(tree);
while (!LIST_EMPTY(&(bnc->paths))) {
struct bgp_path_info *path = LIST_FIRST(&(bnc->paths));
@@ -93,8 +132,6 @@ static void bgp_nexthop_cache_reset(struct bgp_table *table)
}
bnc_free(bnc);
- bgp_dest_set_bgp_nexthop_info(dest, NULL);
- bgp_dest_unlock_node(dest);
}
}
@@ -773,20 +810,21 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
}
static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
- struct bgp_dest *dest,
struct bgp_nexthop_cache *bnc,
bool specific)
{
char buf[PREFIX2STR_BUFFER];
time_t tbuf;
struct peer *peer;
- const struct prefix *p = bgp_dest_get_prefix(dest);
peer = (struct peer *)bnc->nht_info;
+ if (bnc->srte_color)
+ vty_out(vty, " SR-TE color %u -", bnc->srte_color);
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
vty_out(vty, " %s valid [IGP metric %d], #paths %d",
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
bnc->metric, bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
@@ -794,7 +832,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
bgp_show_nexthops_detail(vty, bgp, bnc);
} else {
vty_out(vty, " %s invalid, #paths %d",
- inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+ buf, sizeof(buf)),
bnc->path_count);
if (peer)
vty_out(vty, ", peer %s", peer->host);
@@ -816,29 +855,21 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
bool import_table)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
afi_t afi;
- struct bgp_table **table;
+ struct bgp_nexthop_cache_head(*tree)[AFI_MAX];
if (import_table)
vty_out(vty, "Current BGP import check cache:\n");
else
vty_out(vty, "Current BGP nexthop cache:\n");
if (import_table)
- table = bgp->import_check_table;
+ tree = &bgp->import_check_table;
else
- table = bgp->nexthop_cache_table;
+ tree = &bgp->nexthop_cache_table;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!table || !table[afi])
- continue;
- for (dest = bgp_table_top(table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
- bgp_show_nexthop(vty, bgp, dest, bnc, false);
- }
+ frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc)
+ bgp_show_nexthop(vty, bgp, bnc, false);
}
}
@@ -859,27 +890,21 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
if (nhopip_str) {
struct prefix nhop;
- struct bgp_table **table;
- struct bgp_dest *dest;
+ struct bgp_nexthop_cache_head (*tree)[AFI_MAX];
struct bgp_nexthop_cache *bnc;
if (!str2prefix(nhopip_str, &nhop)) {
vty_out(vty, "nexthop address is malformed\n");
return CMD_WARNING;
}
- table = import_table ? \
- bgp->import_check_table : bgp->nexthop_cache_table;
- dest = bgp_node_lookup(table[family2afi(nhop.family)], &nhop);
- if (!dest) {
- vty_out(vty, "specified nexthop is not found\n");
- return CMD_SUCCESS;
- }
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ tree = import_table ? &bgp->import_check_table
+ : &bgp->nexthop_cache_table;
+ bnc = bnc_find(tree[family2afi(nhop.family)], &nhop, 0);
if (!bnc) {
vty_out(vty, "specified nexthop does not have entry\n");
return CMD_SUCCESS;
}
- bgp_show_nexthop(vty, bgp, dest, bnc, true);
+ bgp_show_nexthop(vty, bgp, bnc, true);
} else
bgp_show_nexthops(vty, bgp, import_table);
@@ -966,12 +991,10 @@ void bgp_scan_init(struct bgp *bgp)
afi_t afi;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- bgp->nexthop_cache_table[afi] =
- bgp_table_init(bgp, afi, SAFI_UNICAST);
+ bgp_nexthop_cache_init(&bgp->nexthop_cache_table[afi]);
+ bgp_nexthop_cache_init(&bgp->import_check_table[afi]);
bgp->connected_table[afi] = bgp_table_init(bgp, afi,
SAFI_UNICAST);
- bgp->import_check_table[afi] =
- bgp_table_init(bgp, afi, SAFI_UNICAST);
}
}
@@ -988,16 +1011,12 @@ void bgp_scan_finish(struct bgp *bgp)
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
/* Only the current one needs to be reset. */
- bgp_nexthop_cache_reset(bgp->nexthop_cache_table[afi]);
- bgp_table_unlock(bgp->nexthop_cache_table[afi]);
- bgp->nexthop_cache_table[afi] = NULL;
+ bgp_nexthop_cache_reset(&bgp->nexthop_cache_table[afi]);
+ bgp_nexthop_cache_reset(&bgp->import_check_table[afi]);
bgp->connected_table[afi]->route_table->cleanup =
bgp_connected_cleanup;
bgp_table_unlock(bgp->connected_table[afi]);
bgp->connected_table[afi] = NULL;
-
- bgp_table_unlock(bgp->import_check_table[afi]);
- bgp->import_check_table[afi] = NULL;
}
}
diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h
index 416ab2a739..c4b913faf4 100644
--- a/bgpd/bgp_nexthop.h
+++ b/bgpd/bgp_nexthop.h
@@ -24,6 +24,7 @@
#include "if.h"
#include "queue.h"
#include "prefix.h"
+#include "bgp_table.h"
#define NEXTHOP_FAMILY(nexthop_len) \
(((nexthop_len) == 4 || (nexthop_len) == 12 \
@@ -36,8 +37,13 @@
#define BGP_MP_NEXTHOP_FAMILY NEXTHOP_FAMILY
+PREDECL_RBTREE_UNIQ(bgp_nexthop_cache);
+
/* BGP nexthop cache value structure. */
struct bgp_nexthop_cache {
+ /* RB-tree entry. */
+ struct bgp_nexthop_cache_item entry;
+
/* IGP route's metric. */
uint32_t metric;
@@ -61,13 +67,22 @@ struct bgp_nexthop_cache {
#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1)
#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
- struct bgp_dest *dest;
+ /* Back pointer to the cache tree this entry belongs to. */
+ struct bgp_nexthop_cache_head *tree;
+
+ uint32_t srte_color;
+ struct prefix prefix;
void *nht_info; /* In BGP, peer session */
LIST_HEAD(path_list, bgp_path_info) paths;
unsigned int path_count;
struct bgp *bgp;
};
+extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
+ const struct bgp_nexthop_cache *b);
+DECLARE_RBTREE_UNIQ(bgp_nexthop_cache, struct bgp_nexthop_cache, entry,
+ bgp_nexthop_cache_compare);
+
/* Own tunnel-ip address structure */
struct tip_addr {
struct in_addr addr;
@@ -79,6 +94,12 @@ struct bgp_addrv6 {
struct list *ifp_name_list;
};
+/* Forward declaration(s). */
+struct peer;
+struct update_subgroup;
+struct bgp_dest;
+struct attr;
+
extern void bgp_connected_add(struct bgp *bgp, struct connected *c);
extern void bgp_connected_delete(struct bgp *bgp, struct connected *c);
extern bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
@@ -94,10 +115,16 @@ extern int bgp_config_write_scan_time(struct vty *);
extern bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
uint8_t sub_type, struct attr *attr,
struct bgp_dest *dest);
-extern struct bgp_nexthop_cache *bnc_new(void);
+extern struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix,
+ uint32_t srte_color);
+extern bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc);
extern void bnc_free(struct bgp_nexthop_cache *bnc);
+extern struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree,
+ struct prefix *prefix,
+ uint32_t srte_color);
extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc);
-extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
+extern const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);
extern void bgp_scan_init(struct bgp *bgp);
extern void bgp_scan_finish(struct bgp *bgp);
extern void bgp_scan_vty_init(void);
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index a780fb7347..9573d118e5 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -72,15 +72,14 @@ static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%s)",
+ zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%u)(%s)",
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->bgp->name_pretty);
+ bnc->srte_color, bnc->bgp->name_pretty);
}
- unregister_zebra_rnh(bnc,
- CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
- bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL);
- bgp_dest_unlock_node(bnc->dest);
- bnc->dest = NULL;
+ /* only unregister if this is the last nh for this prefix*/
+ if (!bnc_existing_for_prefix(bnc))
+ unregister_zebra_rnh(
+ bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
bnc_free(bnc);
}
}
@@ -100,16 +99,13 @@ void bgp_unlink_nexthop(struct bgp_path_info *path)
void bgp_unlink_nexthop_by_peer(struct peer *peer)
{
struct prefix p;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
afi_t afi = family2afi(peer->su.sa.sa_family);
if (!sockunion2hostprefix(&peer->su, &p))
return;
- dest = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p);
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0);
if (!bnc)
return;
@@ -127,11 +123,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
afi_t afi, struct bgp_path_info *pi,
struct peer *peer, int connected)
{
- struct bgp_dest *dest;
+ struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc;
struct prefix p;
+ uint32_t srte_color = 0;
int is_bgp_static_route = 0;
- const struct prefix *bnc_p;
if (pi) {
is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP)
@@ -155,6 +151,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
* addr */
if (make_prefix(afi, pi, &p) < 0)
return 1;
+
+ srte_color = pi->attr->srte_color;
} else if (peer) {
if (!sockunion2hostprefix(&peer->su, &p)) {
if (BGP_DEBUG(nht, NHT)) {
@@ -168,29 +166,24 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
return 0;
if (is_bgp_static_route)
- dest = bgp_node_get(bgp_nexthop->import_check_table[afi], &p);
+ tree = &bgp_nexthop->import_check_table[afi];
else
- dest = bgp_node_get(bgp_nexthop->nexthop_cache_table[afi], &p);
+ tree = &bgp_nexthop->nexthop_cache_table[afi];
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(tree, &p, srte_color);
if (!bnc) {
- bnc = bnc_new();
- bgp_dest_set_bgp_nexthop_info(dest, bnc);
- bnc->dest = dest;
+ bnc = bnc_new(tree, &p, srte_color);
bnc->bgp = bgp_nexthop;
- bgp_dest_lock_node(dest);
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- zlog_debug("Allocated bnc %s(%s) peer %p",
+ zlog_debug("Allocated bnc %s(%u)(%s) peer %p",
bnc_str(bnc, buf, PREFIX2STR_BUFFER),
- bnc->bgp->name_pretty, peer);
+ bnc->srte_color, bnc->bgp->name_pretty,
+ peer);
}
}
- bnc_p = bgp_dest_get_prefix(bnc->dest);
-
- bgp_dest_unlock_node(dest);
if (is_bgp_static_route) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
@@ -236,7 +229,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
} else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)
- && !is_default_host_route(bnc_p))
+ && !is_default_host_route(&bnc->prefix))
register_zebra_rnh(bnc, is_bgp_static_route);
if (pi && pi->nexthop != bnc) {
@@ -269,7 +262,6 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
{
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct prefix p;
@@ -279,26 +271,15 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
if (!sockunion2hostprefix(&peer->su, &p))
return;
- dest = bgp_node_lookup(
- peer->bgp->nexthop_cache_table[family2afi(p.family)], &p);
- if (!dest) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug(
- "Cannot find connected NHT node for peer %s(%s)",
- peer->host, peer->bgp->name_pretty);
- return;
- }
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)],
+ &p, 0);
if (!bnc) {
if (BGP_DEBUG(nht, NHT))
zlog_debug(
- "Cannot find connected NHT node for peer %s(%s) on route_node as expected",
+ "Cannot find connected NHT node for peer %s(%s)",
peer->host, peer->bgp->name_pretty);
- bgp_dest_unlock_node(dest);
return;
}
- bgp_dest_unlock_node(dest);
if (bnc->nht_info != peer) {
if (BGP_DEBUG(nht, NHT))
@@ -317,95 +298,40 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
"Freeing connected NHT node %p for peer %s(%s)",
bnc, peer->host, bnc->bgp->name_pretty);
unregister_zebra_rnh(bnc, 0);
- bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL);
- bgp_dest_unlock_node(bnc->dest);
bnc_free(bnc);
}
}
-void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
+static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
+ struct zapi_route *nhr)
{
- struct bgp_dest *dest = NULL;
- struct bgp_nexthop_cache *bnc;
struct nexthop *nexthop;
struct nexthop *oldnh;
struct nexthop *nhlist_head = NULL;
struct nexthop *nhlist_tail = NULL;
int i;
- struct bgp *bgp;
- struct zapi_route nhr;
-
- bgp = bgp_lookup_by_vrf_id(vrf_id);
- if (!bgp) {
- flog_err(
- EC_BGP_NH_UPD,
- "parse nexthop update: instance not found for vrf_id %u",
- vrf_id);
- return;
- }
- if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug("%s[%s]: Failure to decode nexthop update",
- __func__, bgp->name_pretty);
- return;
- }
-
- if (command == ZEBRA_NEXTHOP_UPDATE)
- dest = bgp_node_lookup(
- bgp->nexthop_cache_table[family2afi(nhr.prefix.family)],
- &nhr.prefix);
- else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
- dest = bgp_node_lookup(
- bgp->import_check_table[family2afi(nhr.prefix.family)],
- &nhr.prefix);
-
- if (!dest) {
- if (BGP_DEBUG(nht, NHT)) {
- char buf[PREFIX2STR_BUFFER];
- prefix2str(&nhr.prefix, buf, sizeof(buf));
- zlog_debug("parse nexthop update(%s(%s)): rn not found",
- buf, bgp->name_pretty);
- }
- return;
- }
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc) {
- if (BGP_DEBUG(nht, NHT)) {
- char buf[PREFIX2STR_BUFFER];
-
- prefix2str(&nhr.prefix, buf, sizeof(buf));
- zlog_debug(
- "parse nexthop update(%s(%s)): bnc node info not found",
- buf, bgp->name_pretty);
- }
- bgp_dest_unlock_node(dest);
- return;
- }
-
- bgp_dest_unlock_node(dest);
bnc->last_update = bgp_clock();
bnc->change_flags = 0;
/* debug print the input */
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
- prefix2str(&nhr.prefix, buf, sizeof(buf));
+ prefix2str(&nhr->prefix, buf, sizeof(buf));
zlog_debug(
- "%s(%u): Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
- bnc->bgp->name_pretty, vrf_id, buf, nhr.metric,
- bnc->metric, nhr.nexthop_num, bnc->nexthop_num,
- bnc->flags);
+ "%s(%u): Rcvd NH update %s(%u) - metric %d/%d #nhops %d/%d flags 0x%x",
+ bnc->bgp->name_pretty, bnc->bgp->vrf_id, buf,
+ bnc->srte_color, nhr->metric, bnc->metric,
+ nhr->nexthop_num, bnc->nexthop_num, bnc->flags);
}
- if (nhr.metric != bnc->metric)
+ if (nhr->metric != bnc->metric)
bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
- if (nhr.nexthop_num != bnc->nexthop_num)
+ if (nhr->nexthop_num != bnc->nexthop_num)
bnc->change_flags |= BGP_NEXTHOP_CHANGED;
- if (nhr.nexthop_num) {
+ if (nhr->nexthop_num) {
struct peer *peer = bnc->nht_info;
/* notify bgp fsm if nbr ip goes from invalid->valid */
@@ -413,15 +339,15 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
bnc->flags |= BGP_NEXTHOP_VALID;
- bnc->metric = nhr.metric;
- bnc->nexthop_num = nhr.nexthop_num;
+ bnc->metric = nhr->metric;
+ bnc->nexthop_num = nhr->nexthop_num;
bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */
- for (i = 0; i < nhr.nexthop_num; i++) {
+ for (i = 0; i < nhr->nexthop_num; i++) {
int num_labels = 0;
- nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]);
+ nexthop = nexthop_from_zapi_nexthop(&nhr->nexthops[i]);
/*
* Turn on RA for the v6 nexthops
@@ -431,7 +357,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
if (peer && !peer->ifp
&& CHECK_FLAG(peer->flags,
PEER_FLAG_CAPABILITY_ENHE)
- && nhr.prefix.family == AF_INET6
+ && nhr->prefix.family == AF_INET6
&& nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
struct interface *ifp;
@@ -485,7 +411,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
bnc->nexthop = nhlist_head;
} else {
bnc->flags &= ~BGP_NEXTHOP_VALID;
- bnc->nexthop_num = nhr.nexthop_num;
+ bnc->nexthop_num = nhr->nexthop_num;
/* notify bgp fsm if nbr ip goes from valid->invalid */
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
@@ -497,26 +423,88 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
evaluate_paths(bnc);
}
+void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
+{
+ struct bgp_nexthop_cache_head *tree = NULL;
+ struct bgp_nexthop_cache *bnc;
+ struct bgp *bgp;
+ struct zapi_route nhr;
+ afi_t afi;
+
+ bgp = bgp_lookup_by_vrf_id(vrf_id);
+ if (!bgp) {
+ flog_err(
+ EC_BGP_NH_UPD,
+ "parse nexthop update: instance not found for vrf_id %u",
+ vrf_id);
+ return;
+ }
+
+ if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s[%s]: Failure to decode nexthop update",
+ __PRETTY_FUNCTION__, bgp->name_pretty);
+ return;
+ }
+
+ afi = family2afi(nhr.prefix.family);
+ if (command == ZEBRA_NEXTHOP_UPDATE)
+ tree = &bgp->nexthop_cache_table[afi];
+ else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
+ tree = &bgp->import_check_table[afi];
+
+ bnc = bnc_find(tree, &nhr.prefix, nhr.srte_color);
+ if (!bnc) {
+ if (BGP_DEBUG(nht, NHT)) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&nhr.prefix, buf, sizeof(buf));
+ zlog_debug(
+ "parse nexthop update(%s(%u)(%s)): bnc info not found",
+ buf, nhr.srte_color, bgp->name_pretty);
+ }
+ return;
+ }
+
+ bgp_process_nexthop_update(bnc, &nhr);
+
+ /*
+ * HACK: if any BGP route is dependant on an SR-policy that doesn't
+ * exist, zebra will never send NH updates relative to that policy. In
+ * that case, whenever we receive an update about a colorless NH, update
+ * the corresponding colorful NHs that share the same endpoint but that
+ * are inactive. This ugly hack should work around the problem at the
+ * cost of a performance pernalty. Long term, what should be done is to
+ * make zebra's RNH subsystem aware of SR-TE colors (like bgpd is),
+ * which should provide a better infrastructure to solve this issue in
+ * a more efficient and elegant way.
+ */
+ if (nhr.srte_color == 0) {
+ struct bgp_nexthop_cache *bnc_iter;
+
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc_iter) {
+ if (!prefix_same(&bnc->prefix, &bnc_iter->prefix)
+ || bnc_iter->srte_color == 0
+ || CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID))
+ continue;
+
+ bgp_process_nexthop_update(bnc_iter, &nhr);
+ }
+ }
+}
+
/*
* Cleanup nexthop registration and status information for BGP nexthops
* pertaining to this VRF. This is invoked upon VRF deletion.
*/
void bgp_cleanup_nexthops(struct bgp *bgp)
{
- afi_t afi;
- struct bgp_dest *dest;
- struct bgp_nexthop_cache *bnc;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!bgp->nexthop_cache_table[afi])
- continue;
-
- for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
- if (!bnc)
- continue;
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
+ struct bgp_nexthop_cache *bnc;
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc) {
/* Clear relevant flags. */
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
@@ -609,7 +597,6 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
*/
static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
{
- const struct prefix *p;
bool exact_match = false;
int ret;
@@ -631,23 +618,18 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
"%s: We have not connected yet, cannot send nexthops",
__func__);
}
- p = bgp_dest_get_prefix(bnc->dest);
if ((command == ZEBRA_NEXTHOP_REGISTER
|| command == ZEBRA_IMPORT_ROUTE_REGISTER)
&& (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
exact_match = true;
- if (BGP_DEBUG(zebra, ZEBRA)) {
- char buf[PREFIX2STR_BUFFER];
-
- prefix2str(p, buf, PREFIX2STR_BUFFER);
- zlog_debug("%s: sending cmd %s for %s (vrf %s)",
- __func__, zserv_command_string(command), buf,
- bnc->bgp->name_pretty);
- }
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__,
+ zserv_command_string(command), &bnc->prefix,
+ bnc->bgp->name_pretty);
- ret = zclient_send_rnh(zclient, command, p, exact_match,
+ ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match,
bnc->bgp->vrf_id);
/* TBD: handle the failure */
if (ret < 0)
@@ -725,8 +707,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
char buf[PREFIX2STR_BUFFER];
bnc_str(bnc, buf, PREFIX2STR_BUFFER);
zlog_debug(
- "NH update for %s %s flags 0x%x chgflags 0x%x - evaluate paths",
- buf, bnc->bgp->name_pretty, bnc->flags,
+ "NH update for %s(%u)(%s) - flags 0x%x chgflags 0x%x - evaluate paths",
+ buf, bnc->srte_color, bnc->bgp->name_pretty, bnc->flags,
bnc->change_flags);
}
@@ -814,7 +796,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
path->extra->igpmetric = 0;
if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED)
- || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
+ || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)
+ || path->attr->srte_color != 0)
SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED);
path_valid = !!CHECK_FLAG(path->flags, BGP_PATH_VALID);
@@ -901,21 +884,11 @@ void path_nh_map(struct bgp_path_info *path, struct bgp_nexthop_cache *bnc,
*/
void bgp_nht_register_nexthops(struct bgp *bgp)
{
- struct bgp_dest *dest;
- struct bgp_nexthop_cache *bnc;
- afi_t afi;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++) {
- if (!bgp->nexthop_cache_table[afi])
- continue;
-
- for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest;
- dest = bgp_route_next(dest)) {
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
-
- if (!bnc)
- continue;
+ for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
+ struct bgp_nexthop_cache *bnc;
+ frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
+ bnc) {
register_zebra_rnh(bnc, 0);
}
}
@@ -924,7 +897,6 @@ void bgp_nht_register_nexthops(struct bgp *bgp)
void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
{
struct bgp *bgp;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct nexthop *nhop;
struct interface *ifp;
@@ -934,10 +906,6 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
return;
bgp = peer->bgp;
-
- if (!bgp->nexthop_cache_table[AFI_IP6])
- return;
-
if (!sockunion2hostprefix(&peer->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host);
@@ -946,11 +914,8 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
if (p.family != AF_INET6)
return;
- dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
- if (!dest)
- return;
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
if (!bnc)
return;
@@ -973,7 +938,6 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
{
struct bgp *bgp;
- struct bgp_dest *dest;
struct bgp_nexthop_cache *bnc;
struct nexthop *nhop;
struct interface *ifp;
@@ -984,9 +948,6 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
bgp = peer->bgp;
- if (!bgp->nexthop_cache_table[AFI_IP6])
- return;
-
if (!sockunion2hostprefix(&peer->su, &p)) {
zlog_warn("%s: Unable to convert sockunion to prefix for %s",
__func__, peer->host);
@@ -996,11 +957,7 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
if (p.family != AF_INET6)
return;
- dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
- if (!dest)
- return;
-
- bnc = bgp_dest_get_bgp_nexthop_info(dest);
+ bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
if (!bnc)
return;
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 732c8e6753..6cfcb9cc3d 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1102,6 +1102,9 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
zlog_debug("%s rcv OPEN w/ OPTION parameter len: %u",
peer->host, length);
+ /* Unset any previously received GR capability. */
+ UNSET_FLAG(peer->cap, PEER_CAP_RESTART_RCV);
+
while (stream_get_getp(s) < end) {
uint8_t opt_type;
uint8_t opt_length;
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 0d81403803..15dba37667 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1432,6 +1432,27 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
bgp_update_implicit_eors(peer);
+ peer->rtt = sockopt_tcp_rtt(peer->fd);
+
+ /* If the peer's RTT is higher than expected, shutdown
+ * the peer automatically.
+ */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN)
+ && peer->rtt > peer->rtt_expected) {
+
+ peer->rtt_keepalive_rcv++;
+
+ if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) {
+ zlog_warn(
+ "%s shutdown due to high round-trip-time (%dms > %dms)",
+ peer->host, peer->rtt, peer->rtt_expected);
+ peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
+ }
+ } else {
+ if (peer->rtt_keepalive_rcv)
+ peer->rtt_keepalive_rcv--;
+ }
+
return Receive_KEEPALIVE_message;
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 91acbf6c6d..8eaee36c2e 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3605,6 +3605,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
goto filtered;
}
+ /* Update Overlay Index */
+ if (afi == AFI_L2VPN) {
+ overlay_index_update(&new_attr,
+ evpn == NULL ? NULL : &evpn->gw_ip);
+ }
+
attr_new = bgp_attr_intern(&new_attr);
/* If maximum prefix count is configured and current prefix
@@ -3850,12 +3856,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
}
#endif
- /* Update Overlay Index */
- if (afi == AFI_L2VPN) {
- overlay_index_update(
- pi->attr,
- evpn == NULL ? NULL : &evpn->gw_ip);
- }
/* Update bgp route dampening information. */
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 6d81cfaab4..09cc775d47 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1668,6 +1668,45 @@ static const struct route_map_rule_cmd route_match_tag_cmd = {
route_map_rule_tag_free,
};
+static enum route_map_cmd_result_t
+route_set_srte_color(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ uint32_t *srte_color = rule;
+ struct bgp_path_info *path;
+
+ if (type != RMAP_BGP)
+ return RMAP_OKAY;
+
+ path = object;
+
+ path->attr->srte_color = *srte_color;
+ path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR);
+
+ return RMAP_OKAY;
+}
+
+/* Route map `sr-te color' compile function */
+static void *route_set_srte_color_compile(const char *arg)
+{
+ uint32_t *color;
+
+ color = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
+ *color = atoi(arg);
+
+ return color;
+}
+
+/* Free route map's compiled `sr-te color' value. */
+static void route_set_srte_color_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for sr-te color set. */
+struct route_map_rule_cmd route_set_srte_color_cmd = {
+ "sr-te color", route_set_srte_color, route_set_srte_color_compile,
+ route_set_srte_color_free};
/* Set nexthop to object. ojbect must be pointer to struct attr. */
struct rmap_ip_nexthop_set {
@@ -5686,6 +5725,9 @@ void bgp_route_map_init(void)
route_map_match_tag_hook(generic_match_add);
route_map_no_match_tag_hook(generic_match_delete);
+ route_map_set_srte_color_hook(generic_set_add);
+ route_map_no_set_srte_color_hook(generic_set_delete);
+
route_map_set_ip_nexthop_hook(generic_set_add);
route_map_no_set_ip_nexthop_hook(generic_set_delete);
@@ -5728,6 +5770,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_vrl_source_vrf_cmd);
route_map_install_set(&route_set_table_id_cmd);
+ route_map_install_set(&route_set_srte_color_cmd);
route_map_install_set(&route_set_ip_nexthop_cmd);
route_map_install_set(&route_set_local_pref_cmd);
route_map_install_set(&route_set_weight_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e94a31b685..47c5237aa6 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1642,16 +1642,91 @@ DEFUN (no_bgp_maxmed_onstartup,
return CMD_SUCCESS;
}
-static int bgp_update_delay_config_vty(struct vty *vty, const char *delay,
- const char *wait)
+static int bgp_global_update_delay_config_vty(struct vty *vty,
+ uint16_t update_delay,
+ uint16_t establish_wait)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ bool vrf_cfg = false;
+
+ /*
+ * See if update-delay is set per-vrf and warn user to delete it
+ * Note that we only need to check this if this is the first time
+ * setting the global config.
+ */
+ if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) {
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
+ vty_out(vty,
+ "%% update-delay configuration found in vrf %s\n",
+ bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ ? VRF_DEFAULT_NAME
+ : bgp->name);
+ vrf_cfg = true;
+ }
+ }
+ }
+
+ if (vrf_cfg) {
+ vty_out(vty,
+ "%%Failed: global update-delay config not permitted\n");
+ return CMD_WARNING;
+ }
+
+ if (!establish_wait) { /* update-delay <delay> */
+ bm->v_update_delay = update_delay;
+ bm->v_establish_wait = bm->v_update_delay;
+ } else {
+ /* update-delay <delay> <establish-wait> */
+ if (update_delay < establish_wait) {
+ vty_out(vty,
+ "%%Failed: update-delay less than the establish-wait!\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ bm->v_update_delay = update_delay;
+ bm->v_establish_wait = establish_wait;
+ }
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ bgp->v_update_delay = bm->v_update_delay;
+ bgp->v_establish_wait = bm->v_establish_wait;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int bgp_global_update_delay_deconfig_vty(struct vty *vty)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ bm->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bm->v_establish_wait = bm->v_update_delay;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ bgp->v_update_delay = bm->v_update_delay;
+ bgp->v_establish_wait = bm->v_establish_wait;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int bgp_update_delay_config_vty(struct vty *vty, uint16_t update_delay,
+ uint16_t establish_wait)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- uint16_t update_delay;
- uint16_t establish_wait;
- update_delay = strtoul(delay, NULL, 10);
+ /* if configured globally, per-instance config is not allowed */
+ if (bm->v_update_delay) {
+ vty_out(vty,
+ "%%Failed: per-vrf update-delay config not permitted with global update-delay\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
- if (!wait) /* update-delay <delay> */
+ if (!establish_wait) /* update-delay <delay> */
{
bgp->v_update_delay = update_delay;
bgp->v_establish_wait = bgp->v_update_delay;
@@ -1659,7 +1734,6 @@ static int bgp_update_delay_config_vty(struct vty *vty, const char *delay,
}
/* update-delay <delay> <establish-wait> */
- establish_wait = atoi(wait);
if (update_delay < establish_wait) {
vty_out(vty,
"%%Failed: update-delay less than the establish-wait!\n");
@@ -1676,6 +1750,12 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
+ /* If configured globally, cannot remove from one bgp instance */
+ if (bm->v_update_delay) {
+ vty_out(vty,
+ "%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
bgp->v_establish_wait = bgp->v_update_delay;
@@ -1684,7 +1764,8 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty)
void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
{
- if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
+ /* If configured globally, no need to display per-instance value */
+ if (bgp->v_update_delay != bm->v_update_delay) {
vty_out(vty, " update-delay %d", bgp->v_update_delay);
if (bgp->v_update_delay != bgp->v_establish_wait)
vty_out(vty, " %d", bgp->v_establish_wait);
@@ -1692,39 +1773,51 @@ void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
}
}
+/* Global update-delay configuration */
+DEFPY (bgp_global_update_delay,
+ bgp_global_update_delay_cmd,
+ "bgp update-delay (0-3600)$delay [(1-3600)$wait]",
+ BGP_STR
+ "Force initial delay for best-path and updates for all bgp instances\n"
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
+{
+ return bgp_global_update_delay_config_vty(vty, delay, wait);
+}
-/* Update-delay configuration */
-DEFUN (bgp_update_delay,
- bgp_update_delay_cmd,
- "update-delay (0-3600)",
+/* Global update-delay deconfiguration */
+DEFPY (no_bgp_global_update_delay,
+ no_bgp_global_update_delay_cmd,
+ "no bgp update-delay [(0-3600) [(1-3600)]]",
+ NO_STR
+ BGP_STR
"Force initial delay for best-path and updates\n"
- "Seconds\n")
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
{
- int idx_number = 1;
- return bgp_update_delay_config_vty(vty, argv[idx_number]->arg, NULL);
+ return bgp_global_update_delay_deconfig_vty(vty);
}
-DEFUN (bgp_update_delay_establish_wait,
- bgp_update_delay_establish_wait_cmd,
- "update-delay (0-3600) (1-3600)",
+/* Update-delay configuration */
+
+DEFPY (bgp_update_delay,
+ bgp_update_delay_cmd,
+ "update-delay (0-3600)$delay [(1-3600)$wait]",
"Force initial delay for best-path and updates\n"
- "Seconds\n"
- "Seconds\n")
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
{
- int idx_number = 1;
- int idx_number_2 = 2;
- return bgp_update_delay_config_vty(vty, argv[idx_number]->arg,
- argv[idx_number_2]->arg);
+ return bgp_update_delay_config_vty(vty, delay, wait);
}
/* Update-delay deconfiguration */
-DEFUN (no_bgp_update_delay,
+DEFPY (no_bgp_update_delay,
no_bgp_update_delay_cmd,
"no update-delay [(0-3600) [(1-3600)]]",
NO_STR
"Force initial delay for best-path and updates\n"
- "Seconds\n"
- "Seconds\n")
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
{
return bgp_update_delay_deconfig_vty(vty);
}
@@ -4480,6 +4573,64 @@ ALIAS(no_neighbor_shutdown_msg, no_neighbor_shutdown_cmd,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Administratively shut down this neighbor\n")
+DEFUN(neighbor_shutdown_rtt,
+ neighbor_shutdown_rtt_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt (1-65535) [count (1-255)]",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Administratively shut down this neighbor\n"
+ "Shutdown if round-trip-time is higher than expected\n"
+ "Round-trip-time in milliseconds\n"
+ "Specify the number of keepalives before shutdown\n"
+ "The number of keepalives with higher RTT to shutdown\n")
+{
+ int idx_peer = 1;
+ int idx_rtt = 4;
+ int idx_count = 0;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ peer->rtt_expected = strtol(argv[idx_rtt]->arg, NULL, 10);
+
+ if (argv_find(argv, argc, "count", &idx_count))
+ peer->rtt_keepalive_conf =
+ strtol(argv[idx_count + 1]->arg, NULL, 10);
+
+ return peer_flag_set_vty(vty, argv[idx_peer]->arg,
+ PEER_FLAG_RTT_SHUTDOWN);
+}
+
+DEFUN(no_neighbor_shutdown_rtt,
+ no_neighbor_shutdown_rtt_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt [(1-65535) [count (1-255)]]",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Administratively shut down this neighbor\n"
+ "Shutdown if round-trip-time is higher than expected\n"
+ "Round-trip-time in milliseconds\n"
+ "Specify the number of keepalives before shutdown\n"
+ "The number of keepalives with higher RTT to shutdown\n")
+{
+ int idx_peer = 2;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ peer->rtt_expected = 0;
+ peer->rtt_keepalive_conf = 1;
+
+ return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
+ PEER_FLAG_RTT_SHUTDOWN);
+}
+
/* neighbor capability dynamic. */
DEFUN (neighbor_capability_dynamic,
neighbor_capability_dynamic_cmd,
@@ -14829,6 +14980,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s shutdown\n", addr);
}
+ if (peergroup_flag_check(peer, PEER_FLAG_RTT_SHUTDOWN))
+ vty_out(vty, " neighbor %s shutdown rtt %u count %u\n", addr,
+ peer->rtt_expected, peer->rtt_keepalive_conf);
+
/* bfd */
if (peer->bfd_info) {
if (!peer_group_active(peer) || !g_peer->bfd_info) {
@@ -15367,6 +15522,13 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
+ if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) {
+ vty_out(vty, "bgp update-delay %d", bm->v_update_delay);
+ if (bm->v_update_delay != bm->v_establish_wait)
+ vty_out(vty, " %d", bm->v_establish_wait);
+ vty_out(vty, "\n");
+ }
+
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
@@ -15881,6 +16043,10 @@ void bgp_vty_init(void)
install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd);
install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd);
+ /* global bgp update-delay command */
+ install_element(CONFIG_NODE, &bgp_global_update_delay_cmd);
+ install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd);
+
/* Dummy commands (Currently not supported) */
install_element(BGP_NODE, &no_synchronization_cmd);
install_element(BGP_NODE, &no_auto_summary_cmd);
@@ -15921,7 +16087,6 @@ void bgp_vty_init(void)
/* bgp update-delay command */
install_element(BGP_NODE, &bgp_update_delay_cmd);
install_element(BGP_NODE, &no_bgp_update_delay_cmd);
- install_element(BGP_NODE, &bgp_update_delay_establish_wait_cmd);
install_element(BGP_NODE, &bgp_wpkt_quanta_cmd);
install_element(BGP_NODE, &bgp_rpkt_quanta_cmd);
@@ -16628,6 +16793,8 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &no_neighbor_shutdown_cmd);
install_element(BGP_NODE, &neighbor_shutdown_msg_cmd);
install_element(BGP_NODE, &no_neighbor_shutdown_msg_cmd);
+ install_element(BGP_NODE, &neighbor_shutdown_rtt_cmd);
+ install_element(BGP_NODE, &no_neighbor_shutdown_rtt_cmd);
/* "neighbor capability extended-nexthop" commands.*/
install_element(BGP_NODE, &neighbor_capability_enhe_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index dba114f86a..15bd6d33b8 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1265,6 +1265,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api.tableid = info->attr->rmap_table_id;
}
+ if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRTE);
+
/* Metric is currently based on the best-path only */
metric = info->attr->med;
@@ -1303,6 +1306,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
continue;
}
api_nh = &api.nexthops[valid_nh_count];
+
+ if (CHECK_FLAG(info->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR)))
+ api_nh->srte_color = info->attr->srte_color;
+
if (nh_family == AF_INET) {
if (bgp_debug_zebra(&api.prefix)) {
if (mpinfo->extra) {
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index aade3f0404..b654e85206 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1604,6 +1604,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
/* Default TTL set. */
peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : BGP_DEFAULT_TTL;
+ /* Default configured keepalives count for shutdown rtt command */
+ peer->rtt_keepalive_conf = 1;
+
SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
if (afi && safi) {
@@ -2284,9 +2287,9 @@ int peer_delete(struct peer *peer)
/* Password configuration */
if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)) {
XFREE(MTYPE_PEER_PASSWORD, peer->password);
-
if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer)
- && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && !CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR))
bgp_md5_unset(peer);
}
@@ -2668,7 +2671,7 @@ int peer_group_listen_range_add(struct peer_group *group, struct prefix *range)
/* Update passwords for new ranges */
if (group->conf->password)
- bgp_md5_set_prefix(prefix, group->conf->password);
+ bgp_md5_set_prefix(group->bgp, prefix, group->conf->password);
return 0;
}
@@ -2715,7 +2718,7 @@ int peer_group_listen_range_del(struct peer_group *group, struct prefix *range)
/* Remove passwords for deleted ranges */
if (group->conf->password)
- bgp_md5_unset_prefix(prefix);
+ bgp_md5_unset_prefix(group->bgp, prefix);
return 0;
}
@@ -2966,7 +2969,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->gr_info[afi][safi].route_list = list_new();
}
- bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bgp->v_update_delay = bm->v_update_delay;
+ bgp->v_establish_wait = bm->v_establish_wait;
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
bgp->default_subgroup_pkt_queue_max =
BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
@@ -3865,6 +3869,7 @@ struct peer_flag_action {
static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_PASSIVE, 0, peer_change_reset},
{PEER_FLAG_SHUTDOWN, 0, peer_change_reset},
+ {PEER_FLAG_RTT_SHUTDOWN, 0, peer_change_none},
{PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none},
{PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none},
@@ -3967,6 +3972,7 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag)
peer_nsf_stop(peer);
UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+
if (peer->t_pmax_restart) {
BGP_TIMER_OFF(peer->t_pmax_restart);
if (bgp_debug_neighbor_events(peer))
@@ -5621,9 +5627,9 @@ int peer_password_set(struct peer *peer, const char *password)
struct prefix *lr;
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr))
- bgp_md5_set_prefix(lr, password);
+ bgp_md5_set_prefix(peer->bgp, lr, password);
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr))
- bgp_md5_set_prefix(lr, password);
+ bgp_md5_set_prefix(peer->bgp, lr, password);
return ret;
}
@@ -5659,7 +5665,6 @@ int peer_password_unset(struct peer *peer)
/* Attempt to uninstall password on socket. */
if (!BGP_PEER_SU_UNSPEC(peer))
bgp_md5_unset(peer);
-
/* Skip peer-group mechanics for regular peers. */
return 0;
}
@@ -5694,9 +5699,9 @@ int peer_password_unset(struct peer *peer)
struct prefix *lr;
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr))
- bgp_md5_unset_prefix(lr);
+ bgp_md5_unset_prefix(peer->bgp, lr);
for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr))
- bgp_md5_unset_prefix(lr);
+ bgp_md5_unset_prefix(peer->bgp, lr);
return 0;
}
@@ -7001,6 +7006,8 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
bm->start_time = bgp_clock();
bm->t_rmap_update = NULL;
bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+ bm->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bm->v_establish_wait = BGP_UPDATE_DELAY_DEF;
bm->terminating = false;
bm->socket_buffer = buffer_size;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 6fc3f08836..2aa0690025 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -42,6 +42,7 @@
#include "vxlan.h"
#include "bgp_labelpool.h"
#include "bgp_addpath_types.h"
+#include "bgp_nexthop.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
@@ -168,6 +169,10 @@ struct bgp_master {
/* EVPN multihoming */
struct bgp_evpn_mh_info *mh_info;
+ /* global update-delay timer values */
+ uint16_t v_update_delay;
+ uint16_t v_establish_wait;
+
bool terminating; /* global flag that sigint terminate seen */
QOBJ_FIELDS
};
@@ -482,11 +487,11 @@ struct bgp {
/* BGP per AF peer count */
uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
- /* Route table for next-hop lookup cache. */
- struct bgp_table *nexthop_cache_table[AFI_MAX];
+ /* Tree for next-hop lookup cache. */
+ struct bgp_nexthop_cache_head nexthop_cache_table[AFI_MAX];
- /* Route table for import-check */
- struct bgp_table *import_check_table[AFI_MAX];
+ /* Tree for import-check */
+ struct bgp_nexthop_cache_head import_check_table[AFI_MAX];
struct bgp_table *connected_table[AFI_MAX];
@@ -967,6 +972,9 @@ struct peer {
int fd; /* File descriptor */
int ttl; /* TTL of TCP connection to the peer. */
int rtt; /* Estimated round-trip-time from TCP_INFO */
+ int rtt_expected; /* Expected round-trip-time for a peer */
+ uint8_t rtt_keepalive_rcv; /* Received count for RTT shutdown */
+ uint8_t rtt_keepalive_conf; /* Configured count for RTT shutdown */
int gtsm_hops; /* minimum hopcount to peer */
char *desc; /* Description of the peer. */
unsigned short port; /* Destination port for peer */
@@ -996,41 +1004,41 @@ struct peer {
/* Capability flags (reset in bgp_stop) */
uint32_t cap;
-#define PEER_CAP_REFRESH_ADV (1 << 0) /* refresh advertised */
-#define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */
-#define PEER_CAP_REFRESH_NEW_RCV (1 << 2) /* refresh rfc received */
-#define PEER_CAP_DYNAMIC_ADV (1 << 3) /* dynamic advertised */
-#define PEER_CAP_DYNAMIC_RCV (1 << 4) /* dynamic received */
-#define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */
-#define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */
-#define PEER_CAP_AS4_ADV (1 << 7) /* as4 advertised */
-#define PEER_CAP_AS4_RCV (1 << 8) /* as4 received */
-#define PEER_CAP_RESTART_BIT_ADV (1 << 9) /* sent restart state */
-#define PEER_CAP_RESTART_BIT_RCV (1 << 10) /* peer restart state */
-#define PEER_CAP_ADDPATH_ADV (1 << 11) /* addpath advertised */
-#define PEER_CAP_ADDPATH_RCV (1 << 12) /* addpath received */
-#define PEER_CAP_ENHE_ADV (1 << 13) /* Extended nexthop advertised */
-#define PEER_CAP_ENHE_RCV (1 << 14) /* Extended nexthop received */
-#define PEER_CAP_HOSTNAME_ADV (1 << 15) /* hostname advertised */
-#define PEER_CAP_HOSTNAME_RCV (1 << 16) /* hostname received */
+#define PEER_CAP_REFRESH_ADV (1U << 0) /* refresh advertised */
+#define PEER_CAP_REFRESH_OLD_RCV (1U << 1) /* refresh old received */
+#define PEER_CAP_REFRESH_NEW_RCV (1U << 2) /* refresh rfc received */
+#define PEER_CAP_DYNAMIC_ADV (1U << 3) /* dynamic advertised */
+#define PEER_CAP_DYNAMIC_RCV (1U << 4) /* dynamic received */
+#define PEER_CAP_RESTART_ADV (1U << 5) /* restart advertised */
+#define PEER_CAP_RESTART_RCV (1U << 6) /* restart received */
+#define PEER_CAP_AS4_ADV (1U << 7) /* as4 advertised */
+#define PEER_CAP_AS4_RCV (1U << 8) /* as4 received */
+#define PEER_CAP_RESTART_BIT_ADV (1U << 9) /* sent restart state */
+#define PEER_CAP_RESTART_BIT_RCV (1U << 10) /* peer restart state */
+#define PEER_CAP_ADDPATH_ADV (1U << 11) /* addpath advertised */
+#define PEER_CAP_ADDPATH_RCV (1U << 12) /* addpath received */
+#define PEER_CAP_ENHE_ADV (1U << 13) /* Extended nexthop advertised */
+#define PEER_CAP_ENHE_RCV (1U << 14) /* Extended nexthop received */
+#define PEER_CAP_HOSTNAME_ADV (1U << 15) /* hostname advertised */
+#define PEER_CAP_HOSTNAME_RCV (1U << 16) /* hostname received */
/* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX];
-#define PEER_CAP_ORF_PREFIX_SM_ADV (1 << 0) /* send-mode advertised */
-#define PEER_CAP_ORF_PREFIX_RM_ADV (1 << 1) /* receive-mode advertised */
-#define PEER_CAP_ORF_PREFIX_SM_RCV (1 << 2) /* send-mode received */
-#define PEER_CAP_ORF_PREFIX_RM_RCV (1 << 3) /* receive-mode received */
-#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1 << 4) /* send-mode received */
-#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1 << 5) /* receive-mode received */
-#define PEER_CAP_RESTART_AF_RCV (1 << 6) /* graceful restart afi/safi received */
-#define PEER_CAP_RESTART_AF_PRESERVE_RCV (1 << 7) /* graceful restart afi/safi F-bit received */
-#define PEER_CAP_ADDPATH_AF_TX_ADV (1 << 8) /* addpath tx advertised */
-#define PEER_CAP_ADDPATH_AF_TX_RCV (1 << 9) /* addpath tx received */
-#define PEER_CAP_ADDPATH_AF_RX_ADV (1 << 10) /* addpath rx advertised */
-#define PEER_CAP_ADDPATH_AF_RX_RCV (1 << 11) /* addpath rx received */
-#define PEER_CAP_ENHE_AF_ADV (1 << 12) /* Extended nexthopi afi/safi advertised */
-#define PEER_CAP_ENHE_AF_RCV (1 << 13) /* Extended nexthop afi/safi received */
-#define PEER_CAP_ENHE_AF_NEGO (1 << 14) /* Extended nexthop afi/safi negotiated */
+#define PEER_CAP_ORF_PREFIX_SM_ADV (1U << 0) /* send-mode advertised */
+#define PEER_CAP_ORF_PREFIX_RM_ADV (1U << 1) /* receive-mode advertised */
+#define PEER_CAP_ORF_PREFIX_SM_RCV (1U << 2) /* send-mode received */
+#define PEER_CAP_ORF_PREFIX_RM_RCV (1U << 3) /* receive-mode received */
+#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1U << 4) /* send-mode received */
+#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1U << 5) /* receive-mode received */
+#define PEER_CAP_RESTART_AF_RCV (1U << 6) /* graceful restart afi/safi received */
+#define PEER_CAP_RESTART_AF_PRESERVE_RCV (1U << 7) /* graceful restart afi/safi F-bit received */
+#define PEER_CAP_ADDPATH_AF_TX_ADV (1U << 8) /* addpath tx advertised */
+#define PEER_CAP_ADDPATH_AF_TX_RCV (1U << 9) /* addpath tx received */
+#define PEER_CAP_ADDPATH_AF_RX_ADV (1U << 10) /* addpath rx advertised */
+#define PEER_CAP_ADDPATH_AF_RX_RCV (1U << 11) /* addpath rx received */
+#define PEER_CAP_ENHE_AF_ADV (1U << 12) /* Extended nexthopi afi/safi advertised */
+#define PEER_CAP_ENHE_AF_RCV (1U << 13) /* Extended nexthop afi/safi received */
+#define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */
/* Global configuration flags. */
/*
@@ -1089,34 +1097,35 @@ struct peer {
* flags_invert) must be respected.
*/
uint32_t flags;
-#define PEER_FLAG_PASSIVE (1 << 0) /* passive mode */
-#define PEER_FLAG_SHUTDOWN (1 << 1) /* shutdown */
-#define PEER_FLAG_DONT_CAPABILITY (1 << 2) /* dont-capability */
-#define PEER_FLAG_OVERRIDE_CAPABILITY (1 << 3) /* override-capability */
-#define PEER_FLAG_STRICT_CAP_MATCH (1 << 4) /* strict-match */
-#define PEER_FLAG_DYNAMIC_CAPABILITY (1 << 5) /* dynamic capability */
-#define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */
-#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */
-#define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */
-#define PEER_FLAG_DELETE (1 << 9) /* mark the peer for deleting */
-#define PEER_FLAG_CONFIG_NODE (1 << 10) /* the node to update configs on */
-#define PEER_FLAG_LONESOUL (1 << 11)
-#define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 12) /* dynamic neighbor */
-#define PEER_FLAG_CAPABILITY_ENHE (1 << 13) /* Extended next-hop (rfc 5549)*/
-#define PEER_FLAG_IFPEER_V6ONLY (1 << 14) /* if-based peer is v6 only */
-#define PEER_FLAG_IS_RFAPI_HD (1 << 15) /* attached to rfapi HD */
-#define PEER_FLAG_ENFORCE_FIRST_AS (1 << 16) /* enforce-first-as */
-#define PEER_FLAG_ROUTEADV (1 << 17) /* route advertise */
-#define PEER_FLAG_TIMER (1 << 18) /* keepalive & holdtime */
-#define PEER_FLAG_TIMER_CONNECT (1 << 19) /* connect timer */
-#define PEER_FLAG_PASSWORD (1 << 20) /* password */
-#define PEER_FLAG_LOCAL_AS (1 << 21) /* local-as */
-#define PEER_FLAG_UPDATE_SOURCE (1 << 22) /* update-source */
+#define PEER_FLAG_PASSIVE (1U << 0) /* passive mode */
+#define PEER_FLAG_SHUTDOWN (1U << 1) /* shutdown */
+#define PEER_FLAG_DONT_CAPABILITY (1U << 2) /* dont-capability */
+#define PEER_FLAG_OVERRIDE_CAPABILITY (1U << 3) /* override-capability */
+#define PEER_FLAG_STRICT_CAP_MATCH (1U << 4) /* strict-match */
+#define PEER_FLAG_DYNAMIC_CAPABILITY (1U << 5) /* dynamic capability */
+#define PEER_FLAG_DISABLE_CONNECTED_CHECK (1U << 6) /* disable-connected-check */
+#define PEER_FLAG_LOCAL_AS_NO_PREPEND (1U << 7) /* local-as no-prepend */
+#define PEER_FLAG_LOCAL_AS_REPLACE_AS (1U << 8) /* local-as no-prepend replace-as */
+#define PEER_FLAG_DELETE (1U << 9) /* mark the peer for deleting */
+#define PEER_FLAG_CONFIG_NODE (1U << 10) /* the node to update configs on */
+#define PEER_FLAG_LONESOUL (1U << 11)
+#define PEER_FLAG_DYNAMIC_NEIGHBOR (1U << 12) /* dynamic neighbor */
+#define PEER_FLAG_CAPABILITY_ENHE (1U << 13) /* Extended next-hop (rfc 5549)*/
+#define PEER_FLAG_IFPEER_V6ONLY (1U << 14) /* if-based peer is v6 only */
+#define PEER_FLAG_IS_RFAPI_HD (1U << 15) /* attached to rfapi HD */
+#define PEER_FLAG_ENFORCE_FIRST_AS (1U << 16) /* enforce-first-as */
+#define PEER_FLAG_ROUTEADV (1U << 17) /* route advertise */
+#define PEER_FLAG_TIMER (1U << 18) /* keepalive & holdtime */
+#define PEER_FLAG_TIMER_CONNECT (1U << 19) /* connect timer */
+#define PEER_FLAG_PASSWORD (1U << 20) /* password */
+#define PEER_FLAG_LOCAL_AS (1U << 21) /* local-as */
+#define PEER_FLAG_UPDATE_SOURCE (1U << 22) /* update-source */
/* BGP-GR Peer related flags */
-#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1 << 23) /* Helper */
-#define PEER_FLAG_GRACEFUL_RESTART (1 << 24) /* Graceful Restart */
-#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1 << 25) /* Global-Inherit */
+#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1U << 23) /* Helper */
+#define PEER_FLAG_GRACEFUL_RESTART (1U << 24) /* Graceful Restart */
+#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */
+#define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1130,9 +1139,9 @@ struct peer {
uint8_t nsf_af_count;
uint8_t peer_gr_new_status_flag;
-#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER (1 << 0)
-#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART (1 << 1)
-#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT (1 << 2)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER (1U << 0)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART (1U << 1)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT (1U << 2)
/* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
char *tx_shutdown_message;
@@ -1154,33 +1163,33 @@ struct peer {
uint32_t af_flags_override[AFI_MAX][SAFI_MAX];
uint32_t af_flags_invert[AFI_MAX][SAFI_MAX];
uint32_t af_flags[AFI_MAX][SAFI_MAX];
-#define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */
-#define PEER_FLAG_SEND_EXT_COMMUNITY (1 << 1) /* send-community ext. */
-#define PEER_FLAG_NEXTHOP_SELF (1 << 2) /* next-hop-self */
-#define PEER_FLAG_REFLECTOR_CLIENT (1 << 3) /* reflector-client */
-#define PEER_FLAG_RSERVER_CLIENT (1 << 4) /* route-server-client */
-#define PEER_FLAG_SOFT_RECONFIG (1 << 5) /* soft-reconfiguration */
-#define PEER_FLAG_AS_PATH_UNCHANGED (1 << 6) /* transparent-as */
-#define PEER_FLAG_NEXTHOP_UNCHANGED (1 << 7) /* transparent-next-hop */
-#define PEER_FLAG_MED_UNCHANGED (1 << 8) /* transparent-next-hop */
-#define PEER_FLAG_DEFAULT_ORIGINATE (1 << 9) /* default-originate */
-#define PEER_FLAG_REMOVE_PRIVATE_AS (1 << 10) /* remove-private-as */
-#define PEER_FLAG_ALLOWAS_IN (1 << 11) /* set allowas-in */
-#define PEER_FLAG_ORF_PREFIX_SM (1 << 12) /* orf capability send-mode */
-#define PEER_FLAG_ORF_PREFIX_RM (1 << 13) /* orf capability receive-mode */
-#define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */
-#define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */
-#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */
-#define PEER_FLAG_FORCE_NEXTHOP_SELF (1 << 17) /* next-hop-self force */
-#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL (1 << 18) /* remove-private-as all */
-#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1 << 19) /* remove-private-as replace-as */
-#define PEER_FLAG_AS_OVERRIDE (1 << 20) /* as-override */
-#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1 << 21) /* remove-private-as all replace-as */
-#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
-#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
-#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
-#define PEER_FLAG_MAX_PREFIX_OUT (1 << 27) /* outgoing maximum prefix */
-#define PEER_FLAG_MAX_PREFIX_FORCE (1 << 28) /* maximum-prefix <num> force */
+#define PEER_FLAG_SEND_COMMUNITY (1U << 0) /* send-community */
+#define PEER_FLAG_SEND_EXT_COMMUNITY (1U << 1) /* send-community ext. */
+#define PEER_FLAG_NEXTHOP_SELF (1U << 2) /* next-hop-self */
+#define PEER_FLAG_REFLECTOR_CLIENT (1U << 3) /* reflector-client */
+#define PEER_FLAG_RSERVER_CLIENT (1U << 4) /* route-server-client */
+#define PEER_FLAG_SOFT_RECONFIG (1U << 5) /* soft-reconfiguration */
+#define PEER_FLAG_AS_PATH_UNCHANGED (1U << 6) /* transparent-as */
+#define PEER_FLAG_NEXTHOP_UNCHANGED (1U << 7) /* transparent-next-hop */
+#define PEER_FLAG_MED_UNCHANGED (1U << 8) /* transparent-next-hop */
+#define PEER_FLAG_DEFAULT_ORIGINATE (1U << 9) /* default-originate */
+#define PEER_FLAG_REMOVE_PRIVATE_AS (1U << 10) /* remove-private-as */
+#define PEER_FLAG_ALLOWAS_IN (1U << 11) /* set allowas-in */
+#define PEER_FLAG_ORF_PREFIX_SM (1U << 12) /* orf capability send-mode */
+#define PEER_FLAG_ORF_PREFIX_RM (1U << 13) /* orf capability receive-mode */
+#define PEER_FLAG_MAX_PREFIX (1U << 14) /* maximum prefix */
+#define PEER_FLAG_MAX_PREFIX_WARNING (1U << 15) /* maximum prefix warning-only */
+#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1U << 16) /* leave link-local nexthop unchanged */
+#define PEER_FLAG_FORCE_NEXTHOP_SELF (1U << 17) /* next-hop-self force */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL (1U << 18) /* remove-private-as all */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1U << 19) /* remove-private-as replace-as */
+#define PEER_FLAG_AS_OVERRIDE (1U << 20) /* as-override */
+#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1U << 21) /* remove-private-as all replace-as */
+#define PEER_FLAG_WEIGHT (1U << 24) /* weight */
+#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1U << 25) /* allowas-in origin */
+#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 */
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -1195,22 +1204,22 @@ struct peer {
/* Peer status flags. */
uint16_t sflags;
-#define PEER_STATUS_ACCEPT_PEER (1 << 0) /* accept peer */
-#define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */
-#define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */
-#define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */
-#define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */
-#define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */
-#define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */
+#define PEER_STATUS_ACCEPT_PEER (1U << 0) /* accept peer */
+#define PEER_STATUS_PREFIX_OVERFLOW (1U << 1) /* prefix-overflow */
+#define PEER_STATUS_CAPABILITY_OPEN (1U << 2) /* capability open send */
+#define PEER_STATUS_HAVE_ACCEPT (1U << 3) /* accept peer's parent */
+#define PEER_STATUS_GROUP (1U << 4) /* peer-group conf */
+#define PEER_STATUS_NSF_MODE (1U << 5) /* NSF aware peer */
+#define PEER_STATUS_NSF_WAIT (1U << 6) /* wait comeback peer */
/* Peer status af flags (reset in bgp_stop) */
uint16_t af_sflags[AFI_MAX][SAFI_MAX];
-#define PEER_STATUS_ORF_PREFIX_SEND (1 << 0) /* prefix-list send peer */
-#define PEER_STATUS_ORF_WAIT_REFRESH (1 << 1) /* wait refresh received peer */
-#define PEER_STATUS_PREFIX_THRESHOLD (1 << 2) /* exceed prefix-threshold */
-#define PEER_STATUS_PREFIX_LIMIT (1 << 3) /* exceed prefix-limit */
-#define PEER_STATUS_EOR_SEND (1 << 4) /* end-of-rib send to peer */
-#define PEER_STATUS_EOR_RECEIVED (1 << 5) /* end-of-rib received from peer */
+#define PEER_STATUS_ORF_PREFIX_SEND (1U << 0) /* prefix-list send peer */
+#define PEER_STATUS_ORF_WAIT_REFRESH (1U << 1) /* wait refresh received peer */
+#define PEER_STATUS_PREFIX_THRESHOLD (1U << 2) /* exceed prefix-threshold */
+#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 */
/* Configured timer values. */
_Atomic uint32_t holdtime;
@@ -1244,9 +1253,9 @@ struct peer {
/* Thread flags. */
_Atomic uint32_t thread_flags;
-#define PEER_THREAD_WRITES_ON (1 << 0)
-#define PEER_THREAD_READS_ON (1 << 1)
-#define PEER_THREAD_KEEPALIVES_ON (1 << 2)
+#define PEER_THREAD_WRITES_ON (1U << 0)
+#define PEER_THREAD_READS_ON (1U << 1)
+#define PEER_THREAD_KEEPALIVES_ON (1U << 2)
/* workqueues */
struct work_queue *clear_node_queue;
@@ -1337,11 +1346,11 @@ struct peer {
* whether the filter in filter (struct bgp_filter) is peer-specific.
*/
uint8_t filter_override[AFI_MAX][SAFI_MAX][FILTER_MAX];
-#define PEER_FT_DISTRIBUTE_LIST (1 << 0) /* distribute-list */
-#define PEER_FT_FILTER_LIST (1 << 1) /* filter-list */
-#define PEER_FT_PREFIX_LIST (1 << 2) /* prefix-list */
-#define PEER_FT_ROUTE_MAP (1 << 3) /* route-map */
-#define PEER_FT_UNSUPPRESS_MAP (1 << 4) /* unsuppress-map */
+#define PEER_FT_DISTRIBUTE_LIST (1U << 0) /* distribute-list */
+#define PEER_FT_FILTER_LIST (1U << 1) /* filter-list */
+#define PEER_FT_PREFIX_LIST (1U << 2) /* prefix-list */
+#define PEER_FT_ROUTE_MAP (1U << 3) /* route-map */
+#define PEER_FT_UNSUPPRESS_MAP (1U << 4) /* unsuppress-map */
/* ORF Prefix-list */
struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX];
@@ -1372,39 +1381,39 @@ struct peer {
/* peer reset cause */
uint8_t last_reset;
-#define PEER_DOWN_RID_CHANGE 1 /* bgp router-id command */
-#define PEER_DOWN_REMOTE_AS_CHANGE 2 /* neighbor remote-as command */
-#define PEER_DOWN_LOCAL_AS_CHANGE 3 /* neighbor local-as command */
-#define PEER_DOWN_CLID_CHANGE 4 /* bgp cluster-id command */
-#define PEER_DOWN_CONFED_ID_CHANGE 5 /* bgp confederation id command */
-#define PEER_DOWN_CONFED_PEER_CHANGE 6 /* bgp confederation peer command */
-#define PEER_DOWN_RR_CLIENT_CHANGE 7 /* neighbor rr-client command */
-#define PEER_DOWN_RS_CLIENT_CHANGE 8 /* neighbor rs-client command */
-#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9 /* neighbor update-source command */
-#define PEER_DOWN_AF_ACTIVATE 10 /* neighbor activate command */
-#define PEER_DOWN_USER_SHUTDOWN 11 /* neighbor shutdown command */
-#define PEER_DOWN_USER_RESET 12 /* clear ip bgp command */
-#define PEER_DOWN_NOTIFY_RECEIVED 13 /* notification received */
-#define PEER_DOWN_NOTIFY_SEND 14 /* notification send */
-#define PEER_DOWN_CLOSE_SESSION 15 /* tcp session close */
-#define PEER_DOWN_NEIGHBOR_DELETE 16 /* neghbor delete */
-#define PEER_DOWN_RMAP_BIND 17 /* neghbor peer-group command */
-#define PEER_DOWN_RMAP_UNBIND 18 /* no neighbor peer-group command */
-#define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */
-#define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */
-#define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */
-#define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */
-#define PEER_DOWN_V6ONLY_CHANGE 23 /* if-based peering v6only toggled */
-#define PEER_DOWN_BFD_DOWN 24 /* BFD down */
-#define PEER_DOWN_IF_DOWN 25 /* Interface down */
-#define PEER_DOWN_NBR_ADDR_DEL 26 /* Peer address lost */
-#define PEER_DOWN_WAITING_NHT 27 /* Waiting for NHT to resolve */
-#define PEER_DOWN_NBR_ADDR 28 /* Waiting for peer IPv6 IP Addr */
-#define PEER_DOWN_VRF_UNINIT 29 /* Associated VRF is not init yet */
-#define PEER_DOWN_NOAFI_ACTIVATED 30 /* No AFI/SAFI activated for peer */
-#define PEER_DOWN_AS_SETS_REJECT 31 /* Reject routes with AS_SET */
-#define PEER_DOWN_WAITING_OPEN 32 /* Waiting for open to succeed */
-#define PEER_DOWN_PFX_COUNT 33 /* Reached received prefix count */
+#define PEER_DOWN_RID_CHANGE 1U /* bgp router-id command */
+#define PEER_DOWN_REMOTE_AS_CHANGE 2U /* neighbor remote-as command */
+#define PEER_DOWN_LOCAL_AS_CHANGE 3U /* neighbor local-as command */
+#define PEER_DOWN_CLID_CHANGE 4U /* bgp cluster-id command */
+#define PEER_DOWN_CONFED_ID_CHANGE 5U /* bgp confederation id command */
+#define PEER_DOWN_CONFED_PEER_CHANGE 6U /* bgp confederation peer command */
+#define PEER_DOWN_RR_CLIENT_CHANGE 7U /* neighbor rr-client command */
+#define PEER_DOWN_RS_CLIENT_CHANGE 8U /* neighbor rs-client command */
+#define PEER_DOWN_UPDATE_SOURCE_CHANGE 9U /* neighbor update-source command */
+#define PEER_DOWN_AF_ACTIVATE 10U /* neighbor activate command */
+#define PEER_DOWN_USER_SHUTDOWN 11U /* neighbor shutdown command */
+#define PEER_DOWN_USER_RESET 12U /* clear ip bgp command */
+#define PEER_DOWN_NOTIFY_RECEIVED 13U /* notification received */
+#define PEER_DOWN_NOTIFY_SEND 14U /* notification send */
+#define PEER_DOWN_CLOSE_SESSION 15U /* tcp session close */
+#define PEER_DOWN_NEIGHBOR_DELETE 16U /* neghbor delete */
+#define PEER_DOWN_RMAP_BIND 17U /* neghbor peer-group command */
+#define PEER_DOWN_RMAP_UNBIND 18U /* no neighbor peer-group command */
+#define PEER_DOWN_CAPABILITY_CHANGE 19U /* neighbor capability command */
+#define PEER_DOWN_PASSIVE_CHANGE 20U /* neighbor passive command */
+#define PEER_DOWN_MULTIHOP_CHANGE 21U /* neighbor multihop command */
+#define PEER_DOWN_NSF_CLOSE_SESSION 22U /* NSF tcp session close */
+#define PEER_DOWN_V6ONLY_CHANGE 23U /* if-based peering v6only toggled */
+#define PEER_DOWN_BFD_DOWN 24U /* BFD down */
+#define PEER_DOWN_IF_DOWN 25U /* Interface down */
+#define PEER_DOWN_NBR_ADDR_DEL 26U /* Peer address lost */
+#define PEER_DOWN_WAITING_NHT 27U /* Waiting for NHT to resolve */
+#define PEER_DOWN_NBR_ADDR 28U /* Waiting for peer IPv6 IP Addr */
+#define PEER_DOWN_VRF_UNINIT 29U /* Associated VRF is not init yet */
+#define PEER_DOWN_NOAFI_ACTIVATED 30U /* No AFI/SAFI activated for peer */
+#define PEER_DOWN_AS_SETS_REJECT 31U /* Reject routes with AS_SET */
+#define PEER_DOWN_WAITING_OPEN 32U /* Waiting for open to succeed */
+#define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */
/*
* Remember to update peer_down_str in bgp_fsm.c when you add
* a new value to the last_reset reason
@@ -1415,15 +1424,15 @@ struct peer {
/* The kind of route-map Flags.*/
uint16_t rmap_type;
-#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */
-#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */
-#define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */
-#define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */
-#define PEER_RMAP_TYPE_DEFAULT (1 << 4) /* default-originate route-map */
-#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */
-#define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */
-#define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */
-#define PEER_RMAP_TYPE_AGGREGATE (1 << 8) /* aggregate-address route-map */
+#define PEER_RMAP_TYPE_IN (1U << 0) /* neighbor route-map in */
+#define PEER_RMAP_TYPE_OUT (1U << 1) /* neighbor route-map out */
+#define PEER_RMAP_TYPE_NETWORK (1U << 2) /* network route-map */
+#define PEER_RMAP_TYPE_REDISTRIBUTE (1U << 3) /* redistribute route-map */
+#define PEER_RMAP_TYPE_DEFAULT (1U << 4) /* default-originate route-map */
+#define PEER_RMAP_TYPE_NOSET (1U << 5) /* not allow to set commands */
+#define PEER_RMAP_TYPE_IMPORT (1U << 6) /* neighbor route-map import */
+#define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */
+#define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */
/* peer specific BFD information */
struct bfd_info *bfd_info;
@@ -1537,6 +1546,7 @@ struct bgp_nlri {
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_PREFIX_SID 40
+#define BGP_ATTR_SRTE_COLOR 51
#ifdef ENABLE_BGP_VNC_ATTR
#define BGP_ATTR_VNC 255
#endif
diff --git a/configure.ac b/configure.ac
index ae116ef754..715efbcdae 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1728,8 +1728,8 @@ AC_SUBST([SNMP_CFLAGS])
dnl ---------------
dnl libyang
dnl ---------------
-PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.105], , [
- AC_MSG_ERROR([libyang (>= 0.16.105) was not found on your system.])
+PKG_CHECK_MODULES([LIBYANG], [libyang >= 1.0.184], , [
+ AC_MSG_ERROR([libyang (>= 1.0.184) was not found on your system.])
])
ac_cflags_save="$CFLAGS"
CFLAGS="$CFLAGS $LIBYANG_CFLAGS"
diff --git a/debian/control b/debian/control
index f4275471d5..fca6956760 100644
--- a/debian/control
+++ b/debian/control
@@ -24,7 +24,7 @@ Build-Depends:
libsnmp-dev,
libssh-dev <!pkg.frr.nortrlib>,
libsystemd-dev <!pkg.frr.nosystemd>,
- libyang-dev (>= 0.16.74),
+ libyang-dev (>= 1.0.184),
pkg-config,
python3,
python3-dev,
diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst
index f50b8cf72d..56f6f4f14e 100644
--- a/doc/developer/building-libyang.rst
+++ b/doc/developer/building-libyang.rst
@@ -5,12 +5,16 @@ library.
**Option 1: Binary Install**
-The FRR project builds binary ``libyang`` packages, which we offer for download
-`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
+The FRR project builds some binary ``libyang`` packages.
+
+RPM packages are at our `RPM repository <rpm.frrouting.org>`_
+
+DEB packages are available as CI artifacts `here
+<https://ci1.netdef.org/browse/LIBYANG-LY1REL-DEB10AMD64-4/artifact>`_.
.. warning::
- ``libyang`` version 0.16.105 or newer is required to build FRR.
+ ``libyang`` version 1.0.184 or newer is required to build FRR.
.. note::
@@ -50,8 +54,3 @@ The FRR project builds binary ``libyang`` packages, which we offer for download
-D CMAKE_BUILD_TYPE:String="Release" ..
make
sudo make install
-
-When building ``libyang`` version ``0.16.x`` it's also necessary to pass the
-``-DENABLE_CACHE=OFF`` parameter to ``cmake`` to work around a
-`known bug <https://github.com/CESNET/libyang/issues/752>`_ in libyang.
-
diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst
index 9355141aa4..28b21533c0 100644
--- a/doc/developer/lists.rst
+++ b/doc/developer/lists.rst
@@ -497,6 +497,7 @@ API for hash tables
Items that compare as equal cannot be inserted. Refer to the notes
about sorted structures in the previous section.
+
.. c:function:: void Z_init_size(struct Z_head *, size_t size)
Same as :c:func:`Z_init()` but preset the minimum hash table to
@@ -506,6 +507,66 @@ Hash tables also support :c:func:`Z_add()` and :c:func:`Z_find()` with
the same semantics as noted above. :c:func:`Z_find_gteq()` and
:c:func:`Z_find_lt()` are **not** provided for hash tables.
+Hash table invariants
+^^^^^^^^^^^^^^^^^^^^^
+
+There are several ways to injure yourself using the hash table API.
+
+First, note that there are two functions related to computing uniqueness of
+objects inserted into the hash table. There is a hash function and a comparison
+function. The hash function computes the hash of the object. Our hash table
+implementation uses `chaining
+<https://en.wikipedia.org/wiki/Hash_table#Separate_chaining_with_linked_lists>`_.
+This means that your hash function does not have to be perfect; multiple
+objects having the same computed hash will be placed into a linked list
+corresponding to that key. The closer to perfect the hash function, the better
+performance, as items will be more evenly distributed and the chain length will
+not be long on any given lookup, minimizing the number of list operations
+required to find the correct item. However, the comparison function *must* be
+perfect, in the sense that any two unique items inserted into the hash table
+must compare not equal. At insertion time, if you try to insert an item that
+compares equal to an existing item the insertion will not happen and
+``hash_get()`` will return the existing item. However, this invariant *must* be
+maintained while the object is in the hash table. Suppose you insert items
+``A`` and ``B`` into the hash table which both hash to the same value ``1234``
+but do not compare equal. They will be placed in a chain like so::
+
+ 1234 : A -> B
+
+Now suppose you do something like this elsewhere in the code::
+
+ *A = *B
+
+I.e. you copy all fields of ``B`` into ``A``, such that the comparison function
+now says that they are equal based on their contents. At this point when you
+look up ``B`` in the hash table, ``hash_get()`` will search the chain for the
+first item that compares equal to ``B``, which will be ``A``. This leads to
+insidious bugs.
+
+.. warning::
+
+ Never modify the values looked at by the comparison or hash functions after
+ inserting an item into a hash table.
+
+A similar situation can occur with the hash allocation function. ``hash_get()``
+accepts a function pointer that it will call to get the item that should be
+inserted into the list if the provided item is not already present. There is a
+builtin function, ``hash_alloc_intern``, that will simply return the item you
+provided; if you always want to store the value you pass to ``hash_get`` you
+should use this one. If you choose to provide a different one, that function
+*must* return a new item that hashes and compares equal to the one you provided
+to ``hash_get()``. If it does not the behavior of the hash table is undefined.
+
+.. warning::
+
+ Always make sure your hash allocation function returns a value that hashes
+ and compares equal to the item you provided to ``hash_get()``.
+
+Finally, if you maintain pointers to items you have inserted into a hash table,
+then before deallocating them you must release them from the hash table. This
+is basic memory management but worth repeating as bugs have arisen from failure
+to do this.
+
API for heaps
-------------
diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot
index b548b5529a..4ce147b2c4 100644
--- a/doc/figures/nodes.dot
+++ b/doc/figures/nodes.dot
@@ -47,7 +47,7 @@ digraph climodes {
CONFIG_NODE -> OSPF_NODE [ label="router ospf [(1-65535)] [vrf NAME]" ];
CONFIG_NODE -> OSPF6_NODE [ label="router ospf6" ];
CONFIG_NODE -> LDP_NODE [ label="mpls ldp" ];
- CONFIG_NODE -> ISIS_NODE [ label="router isis WORD" ];
+ CONFIG_NODE -> ISIS_NODE [ label="router isis WORD [vrf NAME]" ];
CONFIG_NODE -> RMAP_NODE [ label="route-map WORD <deny|permit> (1-65535)" ];
CONFIG_NODE -> PW_NODE [ label="pseudowire IFNAME" ];
CONFIG_NODE -> VTY_NODE [ label="line vty" ];
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4a5bdc2428..63f3d05a93 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1103,6 +1103,41 @@ Redistribution
Redistribute VNC direct (not via zebra) routes to BGP process.
+.. index:: bgp update-delay MAX-DELAY
+.. clicmd:: bgp update-delay MAX-DELAY
+
+.. index:: bgp update-delay MAX-DELAY ESTABLISH-WAIT
+.. clicmd:: bgp update-delay MAX-DELAY ESTABLISH-WAIT
+
+ This feature is used to enable read-only mode on BGP process restart or when
+ a BGP process is cleared using 'clear ip bgp \*'. Note that this command is
+ configured at the global level and applies to all bgp instances/vrfs. It
+ cannot be used at the same time as the "update-delay" command described below,
+ which is entered in each bgp instance/vrf desired to delay update installation
+ and advertisements. The global and per-vrf approaches to defining update-delay
+ are mutually exclusive.
+
+ When applicable, read-only mode would begin as soon as the first peer reaches
+ Established status and a timer for max-delay seconds is started. During this
+ mode BGP doesn't run any best-path or generate any updates to its peers. This
+ mode continues until:
+
+ 1. All the configured peers, except the shutdown peers, have sent explicit EOR
+ (End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
+ Established is considered an implicit-EOR.
+ If the establish-wait optional value is given, then BGP will wait for
+ peers to reach established from the beginning of the update-delay till the
+ establish-wait period is over, i.e. the minimum set of established peers for
+ which EOR is expected would be peers established during the establish-wait
+ window, not necessarily all the configured neighbors.
+ 2. max-delay period is over.
+
+ On hitting any of the above two conditions, BGP resumes the decision process
+ and generates updates to its peers.
+
+ Default max-delay is 0, i.e. the feature is off by default.
+
+
.. index:: update-delay MAX-DELAY
.. clicmd:: update-delay MAX-DELAY
@@ -1110,12 +1145,17 @@ Redistribution
.. clicmd:: update-delay MAX-DELAY ESTABLISH-WAIT
This feature is used to enable read-only mode on BGP process restart or when
- BGP process is cleared using 'clear ip bgp \*'. When applicable, read-only
- mode would begin as soon as the first peer reaches Established status and a
- timer for max-delay seconds is started.
-
- During this mode BGP doesn't run any best-path or generate any updates to its
- peers. This mode continues until:
+ a BGP process is cleared using 'clear ip bgp \*'. Note that this command is
+ configured under the specific bgp instance/vrf that the feaure is enabled for.
+ It cannot be used at the same time as the global "bgp update-delay" described
+ above, which is entered at the global level and applies to all bgp instances.
+ The global and per-vrf approaches to defining update-delay are mutually
+ exclusive.
+
+ When applicable, read-only mode would begin as soon as the first peer reaches
+ Established status and a timer for max-delay seconds is started. During this
+ mode BGP doesn't run any best-path or generate any updates to its peers. This
+ mode continues until:
1. All the configured peers, except the shutdown peers, have sent explicit EOR
(End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
@@ -1216,14 +1256,14 @@ Defining Peers
The time in milliseconds that BGP will delay before deciding what peers
can be put into an update-group together in order to generate a single
update for them. The default time is 1000.
-
+
.. _bgp-configuring-peers:
Configuring Peers
^^^^^^^^^^^^^^^^^
-.. index:: [no] neighbor PEER shutdown [message MSG...]
-.. clicmd:: [no] neighbor PEER shutdown [message MSG...]
+.. index:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
+.. clicmd:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]
Shutdown the peer. We can delete the neighbor's configuration by
``no neighbor PEER remote-as ASN`` but all configuration of the neighbor
@@ -1232,6 +1272,12 @@ Configuring Peers
Optionally you can specify a shutdown message `MSG`.
+ Also, you can specify optionally _rtt_ in milliseconds to automatically
+ shutdown the peer if round-trip-time becomes higher than defined.
+
+ Additional _count_ parameter is the number of keepalive messages to count
+ before shutdown the peer if round-trip-time becomes higher than defined.
+
.. index:: [no] neighbor PEER disable-connected-check
.. clicmd:: [no] neighbor PEER disable-connected-check
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 1155b49eb1..8cbbe0809f 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -33,8 +33,8 @@ ISIS router
To start the ISIS process you have to specify the ISIS router. As of this
writing, *isisd* does not support multiple ISIS processes.
-.. index:: [no] router isis WORD
-.. clicmd:: [no] router isis WORD
+.. index:: [no] router isis WORD [vrf NAME]
+.. clicmd:: [no] router isis WORD [vrf NAME]
Enable or disable the ISIS process by specifying the ISIS domain with
'WORD'. *isisd* does not yet support multiple ISIS processes but you must
@@ -202,8 +202,8 @@ ISIS interface
.. _ip-router-isis-word:
-.. index:: [no] <ip|ipv6> router isis WORD
-.. clicmd:: [no] <ip|ipv6> router isis WORD
+.. index:: [no] <ip|ipv6> router isis WORD [vrf NAME]
+.. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME]
Activate ISIS adjacency on this interface. Note that the name of ISIS
instance must be the same as the one used to configure the ISIS process (see
@@ -751,3 +751,22 @@ A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration.
segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null
!
+ISIS Vrf Configuration Examples
+===============================
+
+A simple vrf example:
+
+.. code-block:: frr
+
+ !
+ interface eth0 vrf RED
+ ip router isis FOO vrf RED
+ isis network point-to-point
+ isis circuit-type level-2-only
+ !
+ router isis FOO vrf RED
+ net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00
+ metric-style wide
+ is-type level-2-only
+
+
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index f557cbe022..fa5fc248a8 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -329,6 +329,12 @@ Route Map Set Command
Set the BGP table to a given table identifier
+.. index:: set sr-te color (1-4294967295)
+.. clicmd:: set sr-te color (1-4294967295)
+
+ Set the color of a SR-TE Policy to be applied to a learned route. The SR-TE
+ Policy is uniquely determined by the color and the BGP nexthop.
+
.. _route-map-call-command:
Route Map Call Command
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 985e07820f..1214c01a12 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -1244,21 +1244,24 @@ static int isis_interface_config_write(struct vty *vty)
#else
static int isis_interface_config_write(struct vty *vty)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf = NULL;
int write = 0;
- struct interface *ifp;
- struct lyd_node *dnode;
- FOR_ALL_INTERFACES (vrf, ifp) {
- dnode = yang_dnode_get(
- running_config->dnode,
- "/frr-interface:lib/interface[name='%s'][vrf='%s']",
- ifp->name, vrf->name);
- if (dnode == NULL)
- continue;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct interface *ifp;
- write++;
- nb_cli_show_dnode_cmds(vty, dnode, false);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ struct lyd_node *dnode;
+ dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+ ifp->name, vrf->name);
+ if (dnode == NULL)
+ continue;
+
+ write++;
+ nb_cli_show_dnode_cmds(vty, dnode, false);
+ }
}
return write;
}
@@ -1268,6 +1271,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
struct interface *ifp)
{
struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
+
if (circuit && circuit->area)
return NULL;
circuit = isis_csm_state_change(ISIS_ENABLE, circuit, area);
@@ -1446,7 +1450,7 @@ int isis_if_delete_hook(struct interface *ifp)
/* Clean up the circuit data */
if (ifp && ifp->info) {
circuit = ifp->info;
- isis_csm_state_change(IF_DOWN_FROM_Z, circuit, circuit->area);
+ isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
}
return 0;
@@ -1454,10 +1458,15 @@ int isis_if_delete_hook(struct interface *ifp)
static int isis_ifp_create(struct interface *ifp)
{
- if (if_is_operative(ifp))
+ struct vrf *vrf = NULL;
+
+ if (if_is_operative(ifp)) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf)
+ isis_global_instance_create(vrf->name);
isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),
ifp);
-
+ }
hook_call(isis_if_new_hook, ifp);
return 0;
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 4d02758003..31fe41db82 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -46,16 +46,21 @@
/*
* XPath: /frr-isisd:isis/instance
*/
-DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
- ROUTER_STR
- "ISO IS-IS\n"
- "ISO Routing area tag\n")
+DEFPY_YANG_NOSH(router_isis, router_isis_cmd,
+ "router isis WORD$tag [vrf NAME$vrf_name]",
+ ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
int ret;
char base_xpath[XPATH_MAXLEN];
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
snprintf(base_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
/* default value in yang for is-type is level-1, but in FRR
* the first instance is assigned is-type level-1-2. We
@@ -77,25 +82,30 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",
return ret;
}
-DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
- NO_STR ROUTER_STR
- "ISO IS-IS\n"
- "ISO Routing area tag\n")
+DEFPY_YANG(no_router_isis, no_router_isis_cmd,
+ "no router isis WORD$tag [vrf NAME$vrf_name]",
+ NO_STR ROUTER_STR
+ "ISO IS-IS\n"
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
struct listnode *node, *nnode;
struct isis_circuit *circuit = NULL;
struct isis_area *area = NULL;
- if (!yang_dnode_exists(vty->candidate_config->dnode,
- "/frr-isisd:isis/instance[area-tag='%s']",
- tag)) {
+ if (!vrf_name)
+ vrf_name = VRF_DEFAULT_NAME;
+
+ if (!yang_dnode_exists(
+ vty->candidate_config->dnode,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name)) {
vty_out(vty, "ISIS area %s not found.\n", tag);
return CMD_ERR_NOTHING_TODO;
}
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
- area = isis_area_lookup(tag, VRF_DEFAULT);
+ area = isis_area_lookup_by_vrf(tag, vrf_name);
if (area && area->circuit_list && listcount(area->circuit_list)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
circuit)) {
@@ -114,15 +124,23 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
}
return nb_cli_apply_changes(
- vty, "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ vty, "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag,
+ vrf_name);
}
void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
+ const char *vrf = NULL;
+
+ vrf = yang_dnode_get_string(dnode, "./vrf");
+
vty_out(vty, "!\n");
- vty_out(vty, "router isis %s\n",
+ vty_out(vty, "router isis %s ",
yang_dnode_get_string(dnode, "./area-tag"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf"));
+ vty_out(vty, "\n");
}
/*
@@ -131,16 +149,18 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
* XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing
* XPath: /frr-isisd:isis/instance
*/
-DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
+ "ip router isis WORD$tag [vrf NAME$vrf_name]",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
struct isis_area *area = NULL;
struct interface *ifp;
+ struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb.
@@ -150,16 +170,26 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
return CMD_SUCCESS;
}
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp)
- area = isis_area_lookup(tag, ifp->vrf_id);
+ if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
+ vrf_name = VRF_DEFAULT_NAME;
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf && !vrf_name)
+ vrf_name = vrf->name;
+ }
+ area = isis_area_lookup_by_vrf(tag, vrf_name);
if (!area) {
+ isis_global_instance_create(vrf_name);
snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']/is-type",
- tag);
+ snprintf(
+ temp_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2"
: NULL);
@@ -167,6 +197,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(
@@ -192,6 +225,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
+
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@@ -206,16 +242,18 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
+ "ipv6 router isis WORD$tag [vrf NAME$vrf_name]",
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n" VRF_CMD_HELP_STR)
{
char temp_xpath[XPATH_MAXLEN];
const char *circ_type;
- struct isis_area *area = NULL;
struct interface *ifp;
+ struct isis_area *area;
+ struct vrf *vrf;
/* area will be created if it is not present. make sure the yang model
* is synced with FRR and call the appropriate NB cb.
@@ -225,16 +263,25 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
return CMD_SUCCESS;
ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
- if (ifp)
- area = isis_area_lookup(tag, ifp->vrf_id);
+ if (!vrf_name && ifp->vrf_id == VRF_DEFAULT)
+ vrf_name = VRF_DEFAULT_NAME;
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (vrf && !vrf_name)
+ vrf_name = vrf->name;
+ }
+ area = isis_area_lookup_by_vrf(tag, vrf_name);
if (!area) {
+ isis_global_instance_create(vrf_name);
snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']", tag);
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag);
- snprintf(temp_xpath, XPATH_MAXLEN,
- "/frr-isisd:isis/instance[area-tag='%s']/is-type",
- tag);
+ snprintf(
+ temp_xpath, XPATH_MAXLEN,
+ "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type",
+ tag, vrf_name);
nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,
listcount(im->isis) == 0 ? "level-1-2"
: NULL);
@@ -242,6 +289,9 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
+
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(
@@ -267,6 +317,8 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
NULL);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",
NB_OP_MODIFY, tag);
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY,
+ vrf_name);
nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",
NB_OP_MODIFY, "true");
nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type",
@@ -282,13 +334,13 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",
}
DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
- "no <ip|ipv6>$ip router isis [WORD]$tag",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "IP router interface commands\n"
- "IP router interface commands\n"
- "IS-IS routing protocol\n"
- "Routing process tag\n")
+ "no <ip|ipv6>$ip router isis [WORD]$tag [vrf NAME$vrf_name]",
+ NO_STR
+ "Interface Internet Protocol config commands\n"
+ "IP router interface commands\n"
+ "IP router interface commands\n"
+ "IS-IS routing protocol\n"
+ "Routing process tag\n")
{
const struct lyd_node *dnode;
@@ -324,19 +376,33 @@ DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,
void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(dnode, "../vrf");
+
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ip router isis %s\n",
+ vty_out(vty, " ip router isis %s ",
yang_dnode_get_string(dnode, "../area-tag"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, "\n");
}
void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(dnode, "../vrf");
+
if (!yang_dnode_get_bool(dnode, NULL))
vty_out(vty, " no");
- vty_out(vty, " ipv6 router isis %s\n",
+ vty_out(vty, " ipv6 router isis %s ",
yang_dnode_get_string(dnode, "../area-tag"));
+ if (!strmatch(vrf, VRF_DEFAULT_NAME))
+ vty_out(vty, "vrf %s", vrf);
+ vty_out(vty, "\n");
}
/*
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 6352303c23..26f5227aae 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -236,13 +236,12 @@ int main(int argc, char **argv, char **envp)
/* thread master */
isis_master_init(frr_init());
master = im->master;
-
/*
* initializations
*/
isis_error_init();
access_list_init();
- vrf_init(NULL, NULL, NULL, NULL, NULL);
+ isis_vrf_init();
prefix_list_init();
isis_init();
isis_circuit_init();
@@ -261,7 +260,7 @@ int main(int argc, char **argv, char **envp)
mt_init();
/* create the global 'isis' instance */
- isis_global_instance_create();
+ isis_global_instance_create(VRF_DEFAULT_NAME);
isis_zebra_init(master, instance);
isis_bfd_init();
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 2b8b02e3f1..33b0b4d02c 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -551,6 +551,13 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/vrf",
+ .cbs = {
+ .modify = lib_interface_isis_vrf_modify,
+ },
+ },
+
+ {
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",
.cbs = {
.cli_show = cli_show_ip_isis_circ_type,
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index a9401bc86a..a79cb8ff57 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -168,6 +168,7 @@ int isis_instance_mpls_te_router_address_destroy(
int lib_interface_isis_create(struct nb_cb_create_args *args);
int lib_interface_isis_destroy(struct nb_cb_destroy_args *args);
int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args);
+int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args);
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index d722868414..170fe92c28 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -53,16 +53,19 @@ int isis_instance_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
const char *area_tag;
+ const char *vrf_name;
if (args->event != NB_EV_APPLY)
return NB_OK;
-
+ vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
- area = isis_area_lookup(area_tag, VRF_DEFAULT);
+ isis_global_instance_create(vrf_name);
+ area = isis_area_lookup_by_vrf(area_tag, vrf_name);
if (area)
return NB_ERR_INCONSISTENCY;
- area = isis_area_create(area_tag, VRF_DEFAULT_NAME);
+ area = isis_area_create(area_tag, vrf_name);
+
/* save area in dnode to avoid looking it up all the time */
nb_running_set_entry(args->dnode, area);
@@ -75,7 +78,6 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
if (args->event != NB_EV_APPLY)
return NB_OK;
-
area = nb_running_unset_entry(args->dnode);
isis_area_destroy(area);
@@ -116,7 +118,6 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
if (area == NULL)
return NB_ERR_VALIDATION;
-
addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, addr.addr_len);
if (addr.area_addr[addr.addr_len - 1] != 0) {
@@ -148,6 +149,7 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
case NB_EV_APPLY:
area = nb_running_get_entry(args->dnode, NULL, true);
addrr = args->resource->ptr;
+ assert(area);
if (area->isis->sysid_set == 0) {
/*
@@ -1830,8 +1832,10 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
{
struct isis_area *area = NULL;
struct interface *ifp;
- struct isis_circuit *circuit;
+ struct isis_circuit *circuit = NULL;
+ struct vrf *vrf;
const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
+ const char *vrf_name = yang_dnode_get_string(args->dnode, "./vrf");
uint32_t min_mtu, actual_mtu;
switch (args->event) {
@@ -1846,8 +1850,17 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
/* zebra might not know yet about the MTU - nothing we can do */
if (!ifp || ifp->mtu == 0)
break;
+ vrf = vrf_lookup_by_id(ifp->vrf_id);
+ if (ifp->vrf_id != VRF_DEFAULT && vrf
+ && strcmp(vrf->name, vrf_name) != 0) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "interface %s not in vrf %s\n", ifp->name,
+ vrf_name);
+ return NB_ERR_VALIDATION;
+ }
actual_mtu =
if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
+
area = isis_area_lookup(area_tag, ifp->vrf_id);
if (area)
min_mtu = area->lsp_mtu;
@@ -1866,9 +1879,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
}
break;
case NB_EV_APPLY:
- ifp = nb_running_get_entry(args->dnode, NULL, true);
- if (ifp)
- area = isis_area_lookup(area_tag, ifp->vrf_id);
+ area = isis_area_lookup_by_vrf(area_tag, vrf_name);
/* The area should have already be created. We are
* setting the priority of the global isis area creation
* slightly lower, so it should be executed first, but I
@@ -1881,7 +1892,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)
__func__, area_tag);
abort();
}
-
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
circuit = isis_circuit_create(area, ifp);
assert(circuit
&& (circuit->state == C_STATE_CONF
@@ -1957,6 +1968,44 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)
}
/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/vrf
+ */
+int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct vrf *vrf;
+ const char *ifname, *vrfname, *vrf_name;
+ struct isis_circuit *circuit;
+
+ if (args->event == NB_EV_VALIDATE) {
+ /* libyang doesn't like relative paths across module boundaries
+ */
+ ifname = yang_dnode_get_string(args->dnode->parent->parent,
+ "./name");
+ vrfname = yang_dnode_get_string(args->dnode->parent->parent,
+ "./vrf");
+ vrf = vrf_lookup_by_name(vrfname);
+ assert(vrf);
+ ifp = if_lookup_by_name(ifname, vrf->vrf_id);
+
+ if (!ifp)
+ return NB_OK;
+
+ vrf_name = yang_dnode_get_string(args->dnode, NULL);
+ circuit = circuit_scan_by_ifp(ifp);
+ if (circuit && circuit->area && circuit->area->isis
+ && strcmp(circuit->area->isis->name, vrf_name)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "ISIS circuit is already defined on vrf %s",
+ circuit->area->isis->name);
+ return NB_ERR_VALIDATION;
+ }
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type
*/
int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args)
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 3aa21a9aed..a50eb607d9 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -577,6 +577,20 @@ int isis_zebra_label_manager_connect(void)
return 0;
}
+void isis_zebra_vrf_register(struct isis *isis)
+{
+ if (!zclient || zclient->sock < 0 || !isis)
+ return;
+
+ if (isis->vrf_id != VRF_UNKNOWN) {
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: Register VRF %s id %u", __func__,
+ isis->name, isis->vrf_id);
+ zclient_send_reg_requests(zclient, isis->vrf_id);
+ }
+}
+
+
static void isis_zebra_connected(struct zclient *zclient)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 4449b63c2e..768919ff46 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -57,5 +57,6 @@ 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);
int isis_zebra_release_label_range(uint32_t start, uint32_t end);
+void isis_zebra_vrf_register(struct isis *isis);
#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
index aca98bf651..2a2c71b1fd 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -35,6 +35,7 @@
#include "prefix.h"
#include "table.h"
#include "qobj.h"
+#include "zclient.h"
#include "vrf.h"
#include "spf_backoff.h"
#include "lib/northbound_cli.h"
@@ -167,29 +168,32 @@ void isis_master_init(struct thread_master *master)
im->master = master;
}
-void isis_global_instance_create()
+void isis_global_instance_create(const char *vrf_name)
{
struct isis *isis;
- isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+ isis = isis_lookup_by_vrfname(vrf_name);
if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(vrf_name);
isis_add(isis);
}
}
-struct isis *isis_new(vrf_id_t vrf_id)
+struct isis *isis_new(const char *vrf_name)
{
struct vrf *vrf;
struct isis *isis;
isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis));
- isis->vrf_id = vrf_id;
- vrf = vrf_lookup_by_id(vrf_id);
+ vrf = vrf_lookup_by_name(vrf_name);
if (vrf) {
+ isis->vrf_id = vrf->vrf_id;
isis_vrf_link(isis, vrf);
isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
+ } else {
+ isis->vrf_id = VRF_UNKNOWN;
+ isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);
}
if (IS_DEBUG_EVENTS)
@@ -223,15 +227,20 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
if (vrf) {
isis = isis_lookup_by_vrfid(vrf->vrf_id);
if (isis == NULL) {
- isis = isis_new(vrf->vrf_id);
+ isis = isis_new(vrf_name);
+ isis_add(isis);
+ }
+ } else {
+ isis = isis_lookup_by_vrfid(VRF_UNKNOWN);
+ if (isis == NULL) {
+ isis = isis_new(vrf_name);
isis_add(isis);
}
- } else
- return NULL;
+ }
} else {
isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL) {
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(VRF_DEFAULT_NAME);
isis_add(isis);
}
}
@@ -336,6 +345,24 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
return area;
}
+struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
+ const char *vrf_name)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis *isis = NULL;
+
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis == NULL)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
+ if (strcmp(area->area_tag, area_tag) == 0)
+ return area;
+
+ return NULL;
+}
+
struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id)
{
struct isis_area *area;
@@ -449,6 +476,95 @@ void isis_area_destroy(struct isis_area *area)
}
+/* This is hook function for vrf create called as part of vrf_init */
+static int isis_vrf_new(struct vrf *vrf)
+{
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF Created: %s(%u)", __func__, vrf->name,
+ vrf->vrf_id);
+
+ return 0;
+}
+
+/* This is hook function for vrf delete call as part of vrf_init */
+static int isis_vrf_delete(struct vrf *vrf)
+{
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF Deletion: %s(%u)", __func__, vrf->name,
+ vrf->vrf_id);
+
+ return 0;
+}
+
+static int isis_vrf_enable(struct vrf *vrf)
+{
+ struct isis *isis;
+ vrf_id_t old_vrf_id;
+
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF %s id %u enabled", __func__, vrf->name,
+ vrf->vrf_id);
+
+ isis = isis_lookup_by_vrfname(vrf->name);
+ if (isis) {
+ if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
+ XFREE(MTYPE_ISIS, isis->name);
+ isis->name = NULL;
+ }
+ old_vrf_id = isis->vrf_id;
+ /* We have instance configured, link to VRF and make it "up". */
+ isis_vrf_link(isis, vrf);
+ if (IS_DEBUG_EVENTS)
+ zlog_debug(
+ "%s: isis linked to vrf %s vrf_id %u (old id %u)",
+ __func__, vrf->name, isis->vrf_id, old_vrf_id);
+ if (old_vrf_id != isis->vrf_id) {
+ frr_with_privs (&isisd_privs) {
+ /* stop zebra redist to us for old vrf */
+ zclient_send_dereg_requests(zclient,
+ old_vrf_id);
+ /* start zebra redist to us for new vrf */
+ isis_zebra_vrf_register(isis);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int isis_vrf_disable(struct vrf *vrf)
+{
+ struct isis *isis;
+ vrf_id_t old_vrf_id = VRF_UNKNOWN;
+
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return 0;
+
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: VRF %s id %d disabled.", __func__, vrf->name,
+ vrf->vrf_id);
+ isis = isis_lookup_by_vrfname(vrf->name);
+ if (isis) {
+ old_vrf_id = isis->vrf_id;
+
+ /* We have instance configured, unlink
+ * from VRF and make it "down".
+ */
+ isis_vrf_unlink(isis, vrf);
+ if (IS_DEBUG_EVENTS)
+ zlog_debug("%s: isis old_vrf_id %d unlinked", __func__,
+ old_vrf_id);
+ }
+
+ return 0;
+}
+
+void isis_vrf_init(void)
+{
+ vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable,
+ isis_vrf_delete, isis_vrf_enable);
+}
+
void isis_finish(struct isis *isis)
{
struct vrf *vrf = NULL;
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 0c0a1eed10..c26a62dfac 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -73,7 +73,6 @@ struct isis_master {
struct list *isis;
/* ISIS thread master. */
struct thread_master *master;
- /* Various OSPF global configuration. */
uint8_t options;
};
#define F_ISIS_UNIT_TEST 0x01
@@ -213,15 +212,19 @@ void isis_finish(struct isis *isis);
void isis_master_init(struct thread_master *master);
void isis_vrf_link(struct isis *isis, struct vrf *vrf);
void isis_vrf_unlink(struct isis *isis, struct vrf *vrf);
-void isis_global_instance_create(void);
+void isis_global_instance_create(const char *vrf_name);
struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id);
struct isis *isis_lookup_by_vrfname(const char *vrfname);
struct isis *isis_lookup_by_sysid(const uint8_t *sysid);
void isis_init(void);
-struct isis *isis_new(vrf_id_t vrf_id);
+void isis_vrf_init(void);
+
+struct isis *isis_new(const char *vrf_name);
struct isis_area *isis_area_create(const char *, const char *);
struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id);
+struct isis_area *isis_area_lookup_by_vrf(const char *area_tag,
+ const char *vrf_name);
int isis_area_get(struct vty *vty, const char *area_tag);
void isis_area_destroy(struct isis_area *area);
void print_debug(struct vty *, int, int);
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 734c1ea230..df64f908ea 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -468,6 +468,10 @@ lde_dispatch_parent(struct thread *thread)
iface = if_lookup_name(ldeconf, kif->ifname);
if (iface) {
if_update_info(iface, kif);
+
+ /* if up see if any labels need to be updated */
+ if (kif->operative)
+ lde_route_update(iface, AF_UNSPEC);
break;
}
@@ -786,7 +790,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)
kr.remote_label = fnh->remote_label;
kr.route_type = fnh->route_type;
kr.route_instance = fnh->route_instance;
-
lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,
sizeof(kr));
break;
@@ -2271,3 +2274,156 @@ lde_check_filter_af(int af, struct ldpd_af_conf *af_conf,
if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0)
lde_change_expnull_for_filter(af);
}
+
+void lde_route_update(struct iface *iface, int af)
+{
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+ struct lde_nbr *ln;
+
+ /* update label of non-connected routes */
+ log_debug("update labels for interface %s", iface->name);
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+ if (IS_MPLS_UNRESERVED_LABEL(fn->local_label))
+ continue;
+
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ /* unspecified so process both address families */
+ break;
+ }
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ /*
+ * If connected leave existing label. If LDP
+ * configured on interface or a static route
+ * may need new label. If no LDP configured
+ * treat fec as a connected route
+ */
+ if (fnh->flags & F_FEC_NH_CONNECTED)
+ break;
+
+ if (fnh->ifindex != iface->ifindex)
+ continue;
+
+ fnh->flags &= ~F_FEC_NH_NO_LDP;
+ if (IS_MPLS_RESERVED_LABEL(fn->local_label)) {
+ fn->local_label = NO_LABEL;
+ fn->local_label = lde_update_label(fn);
+ if (fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(
+ ln, fn, 0);
+ }
+ break;
+ }
+ }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
+ 0, NULL, 0);
+}
+
+void lde_route_update_release(struct iface *iface, int af)
+{
+ struct lde_nbr *ln;
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+
+ /* update label of interfaces no longer running LDP */
+ log_debug("release all labels for interface %s af %s", iface->name,
+ af == AF_INET ? "ipv4" : "ipv6");
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ fatalx("lde_route_update_release: unknown af");
+ }
+
+ if (fn->local_label == NO_LABEL)
+ continue;
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ /*
+ * If connected leave existing label. If LDP
+ * removed from interface may need new label
+ * and would be treated as a connected route
+ */
+ if (fnh->flags & F_FEC_NH_CONNECTED)
+ break;
+
+ if (fnh->ifindex != iface->ifindex)
+ continue;
+
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
+ lde_free_label(fn->local_label);
+ fn->local_label = NO_LABEL;
+ fn->local_label = lde_update_label(fn);
+ if (fn->local_label != NO_LABEL)
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 0);
+ break;
+ }
+ }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid,
+ 0, NULL, 0);
+}
+
+void lde_route_update_release_all(int af)
+{
+ struct lde_nbr *ln;
+ struct fec *f;
+ struct fec_node *fn;
+ struct fec_nh *fnh;
+
+ /* remove labels from all interfaces as LDP is no longer running for
+ * this address family
+ */
+ log_debug("release all labels for address family %s",
+ af == AF_INET ? "ipv4" : "ipv6");
+ RB_FOREACH(f, fec_tree, &ft) {
+ fn = (struct fec_node *)f;
+ switch (af) {
+ case AF_INET:
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+ break;
+ case AF_INET6:
+ if (fn->fec.type != FEC_TYPE_IPV6)
+ continue;
+ break;
+ default:
+ fatalx("lde_route_update_release: unknown af");
+ }
+
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ lde_send_delete_klabel(fn, fnh);
+ }
+ }
+}
diff --git a/ldpd/lde.h b/ldpd/lde.h
index 9e6db3a90b..660aeafb34 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -193,6 +193,9 @@ void lde_change_allocate_filter(int);
void lde_change_advertise_filter(int);
void lde_change_accept_filter(int);
void lde_change_expnull_for_filter(int);
+void lde_route_update(struct iface *, int);
+void lde_route_update_release(struct iface *, int);
+void lde_route_update_release_all(int);
struct lde_addr *lde_address_find(struct lde_nbr *, int,
union ldpd_addr *);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 11d85b7449..bed276c7b1 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -404,10 +404,15 @@ lde_kernel_update(struct fec *fec)
* if LDP configured on interface or a static route
* clear flag else treat fec as a connected route
*/
- iface = if_lookup(ldeconf,fnh->ifindex);
- if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC)
- fnh->flags &=~F_FEC_NH_NO_LDP;
- else
+ if (ldeconf->flags & F_LDPD_ENABLED) {
+ iface = if_lookup(ldeconf,fnh->ifindex);
+ if (fnh->flags & F_FEC_NH_CONNECTED ||
+ iface ||
+ fnh->route_type == ZEBRA_ROUTE_STATIC)
+ fnh->flags &=~F_FEC_NH_NO_LDP;
+ else
+ fnh->flags |= F_FEC_NH_NO_LDP;
+ } else
fnh->flags |= F_FEC_NH_NO_LDP;
} else {
lde_send_delete_klabel(fn, fnh);
@@ -437,6 +442,10 @@ lde_kernel_update(struct fec *fec)
lde_send_labelmapping(ln, fn, 1);
}
+ /* if no label created yet then don't try to program labeled route */
+ if (fn->local_label == NO_LABEL)
+ return;
+
LIST_FOREACH(fnh, &fn->nexthops, entry) {
lde_send_change_klabel(fn, fnh);
@@ -567,7 +576,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)
fnh->flags &= ~F_FEC_NH_DEFER;
}
fnh->remote_label = map->label;
- lde_send_change_klabel(fn, fnh);
+ if (fn->local_label != NO_LABEL)
+ lde_send_change_klabel(fn, fnh);
break;
case FEC_TYPE_PWID:
pw = (struct l2vpn_pw *) fn->data;
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index fc84c7f76b..53a384fe55 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -616,6 +616,8 @@ DEFPY (ldp_show_mpls_ldp_binding,
"Show detailed information\n"
JSON_STR)
{
+ if (!(ldpd_conf->flags & F_LDPD_ENABLED))
+ return CMD_SUCCESS;
if (!local_label_str)
local_label = NO_LABEL;
if (!remote_label_str)
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 927c3a3c03..dca379e4eb 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -1329,6 +1329,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
int reset_nbrs_ipv4 = 0;
int reset_nbrs = 0;
int update_sockets = 0;
+ int change_ldp_disabled = 0;
/* update timers */
if (af_conf->keepalive != xa->keepalive) {
@@ -1362,6 +1363,11 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
!= (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))
change_host_label = 1;
+ /* disabling LDP for address family */
+ if ((af_conf->flags & F_LDPD_AF_ENABLED) &&
+ !(xa->flags & F_LDPD_AF_ENABLED))
+ change_ldp_disabled = 1;
+
af_conf->flags = xa->flags;
/* update the transport address */
@@ -1409,6 +1415,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
lde_change_egress_label(af);
if (change_host_label)
lde_change_allocate_filter(af);
+ if (change_ldp_disabled)
+ lde_route_update_release_all(af);
+
break;
case PROC_LDP_ENGINE:
if (stop_init_backoff)
@@ -1434,13 +1443,22 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
struct iface *iface, *itmp, *xi;
RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) {
- /* find deleted interfaces */
+ /* find deleted interfaces, which occurs when LDP is removed
+ * for all address families
+ */
if (if_lookup_name(xconf, iface->name) == NULL) {
switch (ldpd_process) {
case PROC_LDP_ENGINE:
ldpe_if_exit(iface);
break;
case PROC_LDE_ENGINE:
+ if (iface->ipv4.enabled)
+ lde_route_update_release(iface,
+ AF_INET);
+ if (iface->ipv6.enabled)
+ lde_route_update_release(iface,
+ AF_INET6);
+ break;
case PROC_MAIN:
break;
}
@@ -1468,6 +1486,29 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
continue;
}
+ /* update labels when adding or removing ldp on an
+ * interface
+ */
+ if (ldpd_process == PROC_LDE_ENGINE) {
+ /* if we are removing lpd config for an address
+ * family on an interface then advertise routes
+ * learned over this interface as if they were
+ * connected routes
+ */
+ if (iface->ipv4.enabled && !xi->ipv4.enabled)
+ lde_route_update_release(iface, AF_INET);
+ if (iface->ipv6.enabled && !xi->ipv6.enabled)
+ lde_route_update_release(iface, AF_INET6);
+
+ /* if we are adding lpd config for an address
+ * family on an interface then add proper labels
+ */
+ if (!iface->ipv4.enabled && xi->ipv4.enabled)
+ lde_route_update(iface, AF_INET);
+ if (!iface->ipv6.enabled && xi->ipv6.enabled)
+ lde_route_update(iface, AF_INET6);
+ }
+
/* update existing interfaces */
merge_iface_af(&iface->ipv4, &xi->ipv4);
merge_iface_af(&iface->ipv6, &xi->ipv6);
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 655313bf16..9078e711fb 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -614,10 +614,8 @@ ldpe_dispatch_lde(struct thread *thread)
map = imsg.data;
nbr = nbr_find_peerid(imsg.hdr.peerid);
- if (nbr == NULL) {
- log_debug("ldpe_dispatch_lde: cannot find neighbor");
+ if (nbr == NULL)
break;
- }
if (nbr->state != NBR_STA_OPER)
break;
@@ -641,10 +639,8 @@ ldpe_dispatch_lde(struct thread *thread)
case IMSG_REQUEST_ADD_END:
case IMSG_WITHDRAW_ADD_END:
nbr = nbr_find_peerid(imsg.hdr.peerid);
- if (nbr == NULL) {
- log_debug("ldpe_dispatch_lde: cannot find neighbor");
+ if (nbr == NULL)
break;
- }
if (nbr->state != NBR_STA_OPER)
break;
diff --git a/lib/filter.h b/lib/filter.h
index d41f3b65cd..623fb94527 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -32,6 +32,16 @@ extern "C" {
/* Maximum ACL name length */
#define ACL_NAMSIZ 128
+/** Cisco host wildcard mask. */
+#define CISCO_HOST_WILDCARD_MASK "0.0.0.0"
+/** Cisco host wildcard binary mask. */
+#define CISCO_BIN_HOST_WILDCARD_MASK INADDR_ANY
+
+/** Cisco any wildcard mask. */
+#define CISCO_ANY_WILDCARD_MASK "255.255.255.255"
+/** Cisco binary any wildcard mask. */
+#define CISCO_BIN_ANY_WILDCARD_MASK INADDR_NONE
+
/* Filter direction. */
#define FILTER_IN 0
#define FILTER_OUT 1
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index 8c7a515dc5..09fc3289ce 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -37,14 +37,8 @@
#define ACCESS_LIST_STR "Access list entry\n"
#define ACCESS_LIST_LEG_STR "IP standard access list\n"
-#define ACCESS_LIST_LEG_EXT_STR "IP standard access list (expanded range)\n"
#define ACCESS_LIST_ELEG_STR "IP extended access list\n"
#define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n"
-#define ACCESS_LIST_XLEG_STR \
- ACCESS_LIST_LEG_STR \
- ACCESS_LIST_LEG_EXT_STR \
- ACCESS_LIST_ELEG_STR \
- ACCESS_LIST_ELEG_EXT_STR
#define ACCESS_LIST_ZEBRA_STR "Access list entry\n"
#define ACCESS_LIST_SEQ_STR \
"Sequence number of an entry\n" \
@@ -68,7 +62,6 @@ static int64_t acl_cisco_get_seq(struct access_list *acl, const char *action,
struct filter f, *fn;
memset(&f, 0, sizeof(f));
- memset(&fc, 0, sizeof(fc));
f.cisco = 1;
if (strcmp(action, "permit") == 0)
f.type = FILTER_PERMIT;
@@ -110,7 +103,8 @@ static int64_t acl_zebra_get_seq(struct access_list *acl, const char *action,
f.type = FILTER_DENY;
fz = &f.u.zfilter;
- fz->prefix = *p;
+ if (p->family)
+ prefix_copy(&fz->prefix, p);
fz->exact = exact;
fn = filter_lookup_zebra(acl, &f);
@@ -130,6 +124,7 @@ static void concat_addr_mask_v4(const char *addr, const char *mask, char *dst,
int plen;
assert(inet_pton(AF_INET, mask, &ia) == 1);
+ ia.s_addr = ~ia.s_addr;
plen = ip_masklen(ia);
snprintf(dst, dstlen, "%s/%d", addr, plen);
}
@@ -171,17 +166,15 @@ static long acl_get_seq(struct vty *vty, const char *xpath)
*/
DEFPY_YANG(
access_list_std, access_list_std_cmd,
- "access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
+ "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
ACCESS_LIST_STR
ACCESS_LIST_LEG_STR
- ACCESS_LIST_LEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"A single host address\n"
"Address to match\n"
"Address to match\n"
- "Wildcard bits\n"
- "Any source host\n")
+ "Wildcard bits\n")
{
int64_t sseq;
char ipmask[64];
@@ -193,8 +186,7 @@ DEFPY_YANG(
* none given (backward compatibility).
*/
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (seq_str == NULL) {
/* Use XPath to find the next sequence number. */
@@ -222,18 +214,16 @@ DEFPY_YANG(
DEFPY_YANG(
no_access_list_std, no_access_list_std_cmd,
- "no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
+ "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
NO_STR
ACCESS_LIST_STR
ACCESS_LIST_LEG_STR
- ACCESS_LIST_LEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"A single host address\n"
"Address to match\n"
"Address to match\n"
- "Wildcard bits\n"
- "Any source host\n")
+ "Wildcard bits\n")
{
struct access_list *acl;
struct lyd_node *dnode;
@@ -246,15 +236,14 @@ DEFPY_YANG(
snprintf(
xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- number_str, seq_str);
+ name, seq_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
/* Otherwise, to keep compatibility, we need to figure it out. */
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
/* Access-list must exist before entries. */
if (yang_dnode_exists(running_config->dnode, xpath) == false)
@@ -263,13 +252,9 @@ DEFPY_YANG(
/* Use access-list data structure to fetch sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
- if (host_str != NULL)
- sseq = acl_cisco_get_seq(acl, action, host_str,
- mask_str ? mask_str : "0.0.0.0", NULL,
- NULL);
- else
- sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
- "255.255.255.255", NULL, NULL);
+ sseq = acl_cisco_get_seq(acl, action, host_str,
+ mask_str ? mask_str : CISCO_HOST_WILDCARD_MASK,
+ NULL, NULL);
if (sseq == -1)
return CMD_WARNING;
@@ -282,10 +267,9 @@ DEFPY_YANG(
DEFPY_YANG(
access_list_ext, access_list_ext_cmd,
- "access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
+ "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
ACCESS_LIST_STR
ACCESS_LIST_ELEG_STR
- ACCESS_LIST_ELEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"IPv4 address\n"
@@ -301,7 +285,7 @@ DEFPY_YANG(
"Any destination host\n")
{
int64_t sseq;
- char ipmask[64];
+ char ipmask[64], ipmask_dst[64];
char xpath[XPATH_MAXLEN];
char xpath_entry[XPATH_MAXLEN + 128];
@@ -310,8 +294,7 @@ DEFPY_YANG(
* none given (backward compatibility).
*/
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
if (seq_str == NULL) {
/* Use XPath to find the next sequence number. */
@@ -337,12 +320,12 @@ DEFPY_YANG(
if (dst_str != NULL && dst_mask_str == NULL) {
nb_cli_enqueue_change(vty, "./destination-host", NB_OP_MODIFY,
- src_str);
+ dst_str);
} else if (dst_str != NULL && dst_mask_str != NULL) {
- concat_addr_mask_v4(dst_str, dst_mask_str, ipmask,
- sizeof(ipmask));
+ concat_addr_mask_v4(dst_str, dst_mask_str, ipmask_dst,
+ sizeof(ipmask_dst));
nb_cli_enqueue_change(vty, "./destination-network",
- NB_OP_MODIFY, ipmask);
+ NB_OP_MODIFY, ipmask_dst);
} else {
nb_cli_enqueue_change(vty, "./destination-any", NB_OP_CREATE,
NULL);
@@ -353,11 +336,10 @@ DEFPY_YANG(
DEFPY_YANG(
no_access_list_ext, no_access_list_ext_cmd,
- "no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
+ "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
NO_STR
ACCESS_LIST_STR
ACCESS_LIST_ELEG_STR
- ACCESS_LIST_ELEG_EXT_STR
ACCESS_LIST_SEQ_STR
ACCESS_LIST_ACTION_STR
"Any Internet Protocol\n"
@@ -383,15 +365,14 @@ DEFPY_YANG(
snprintfrr(
xpath, sizeof(xpath),
"/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
- number_str, seq_str);
+ name, seq_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
/* Otherwise, to keep compatibility, we need to figure it out. */
snprintf(xpath, sizeof(xpath),
- "/frr-filter:lib/access-list[type='ipv4'][name='%s']",
- number_str);
+ "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);
/* Access-list must exist before entries. */
if (yang_dnode_exists(running_config->dnode, xpath) == false)
@@ -404,24 +385,28 @@ DEFPY_YANG(
if (dst_str != NULL)
sseq = acl_cisco_get_seq(
acl, action, src_str,
- src_mask_str ? src_mask_str : "0.0.0.0",
+ src_mask_str ? src_mask_str
+ : CISCO_HOST_WILDCARD_MASK,
dst_str,
- dst_mask_str ? dst_mask_str : "0.0.0.0");
+ dst_mask_str ? dst_mask_str
+ : CISCO_HOST_WILDCARD_MASK);
else
- sseq = acl_cisco_get_seq(acl, action, src_str,
- src_mask_str ? src_mask_str
- : "0.0.0.0",
- "0.0.0.0", "255.255.255.255");
+ sseq = acl_cisco_get_seq(
+ acl, action, src_str,
+ src_mask_str ? src_mask_str
+ : CISCO_HOST_WILDCARD_MASK,
+ "0.0.0.0", CISCO_ANY_WILDCARD_MASK);
} else {
if (dst_str != NULL)
- sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
- "255.255.255.255", dst_str,
- dst_mask_str ? dst_mask_str
- : "0.0.0.0");
+ sseq = acl_cisco_get_seq(
+ acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK,
+ dst_str,
+ dst_mask_str ? dst_mask_str
+ : CISCO_HOST_WILDCARD_MASK);
else
- sseq = acl_cisco_get_seq(acl, action, "0.0.0.0",
- "255.255.255.255", "0.0.0.0",
- "255.255.255.255");
+ sseq = acl_cisco_get_seq(
+ acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK,
+ "0.0.0.0", CISCO_ANY_WILDCARD_MASK);
}
if (sseq == -1)
return CMD_WARNING;
@@ -522,7 +507,7 @@ DEFPY_YANG(
/* Use access-list data structure to fetch sequence. */
dnode = yang_dnode_get(running_config->dnode, xpath);
acl = nb_running_get_entry(dnode, NULL, true);
- if (prefix == NULL) {
+ if (prefix_str == NULL) {
memset(&pany, 0, sizeof(pany));
pany.family = AF_INET;
sseq = acl_zebra_get_seq(acl, action, &pany, exact);
diff --git a/lib/filter_nb.c b/lib/filter_nb.c
index 91691d2f1d..8838a48abd 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -29,6 +29,7 @@
#include "lib/filter.h"
#include "lib/plist.h"
#include "lib/plist_int.h"
+#include "lib/routemap.h"
/* Helper function. */
static in_addr_t
@@ -40,6 +41,22 @@ ipv4_network_addr(in_addr_t hostaddr, int masklen)
return hostaddr & mask.s_addr;
}
+static void acl_notify_route_map(struct access_list *acl, int route_map_event)
+{
+ switch (route_map_event) {
+ case RMAP_EVENT_FILTER_ADDED:
+ if (acl->master->add_hook)
+ (*acl->master->add_hook)(acl);
+ break;
+ case RMAP_EVENT_FILTER_DELETED:
+ if (acl->master->delete_hook)
+ (*acl->master->delete_hook)(acl);
+ break;
+ }
+
+ route_map_notify_dependencies(acl->name, route_map_event);
+}
+
static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)
{
int type = yang_dnode_get_enum(args->dnode, "../../type");
@@ -112,6 +129,19 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
ple->le = 0;
}
+/**
+ * Unsets the cisco style rule for addresses so it becomes disabled (the
+ * equivalent of setting: `0.0.0.0/32`).
+ *
+ * \param addr address part.
+ * \param mask mask part.
+ */
+static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask)
+{
+ addr->s_addr = INADDR_ANY;
+ mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
+}
+
/*
* XPath: /frr-filter:lib/access-list
*/
@@ -255,6 +285,8 @@ lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
else
f->type = FILTER_DENY;
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -275,6 +307,8 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
fz = &f->u.zfilter;
yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -291,6 +325,8 @@ lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
memset(&fz->prefix, 0, sizeof(fz->prefix));
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
return NB_OK;
}
@@ -310,6 +346,8 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
fz = &f->u.zfilter;
fz->exact = yang_dnode_get_bool(args->dnode, NULL);
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -326,6 +364,8 @@ lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
fz->exact = 0;
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
return NB_OK;
}
@@ -345,7 +385,9 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
f->cisco = 1;
fc = &f->u.cfilter;
yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
- fc->addr_mask.s_addr = INADDR_ANY;
+ fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -361,8 +403,9 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -386,6 +429,9 @@ lib_access_list_entry_network_modify(struct nb_cb_modify_args *args)
yang_dnode_get_prefix(&p, args->dnode, NULL);
fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
masklen2ip(p.prefixlen, &fc->addr_mask);
+ fc->addr_mask.s_addr = ~fc->addr_mask.s_addr;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -401,8 +447,9 @@ lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -423,7 +470,9 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
f->cisco = 1;
fc = &f->u.cfilter;
fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -439,8 +488,9 @@ lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
- fc->addr.s_addr = INADDR_ANY;
- fc->addr_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -461,7 +511,9 @@ static int lib_access_list_entry_destination_host_modify(
fc = &f->u.cfilter;
fc->extended = 1;
yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
- fc->mask_mask.s_addr = INADDR_ANY;
+ fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -478,8 +530,9 @@ static int lib_access_list_entry_destination_host_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -503,6 +556,9 @@ static int lib_access_list_entry_destination_network_modify(
yang_dnode_get_prefix(&p, args->dnode, NULL);
fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
masklen2ip(p.prefixlen, &fc->mask_mask);
+ fc->mask_mask.s_addr = ~fc->mask_mask.s_addr;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -519,8 +575,9 @@ static int lib_access_list_entry_destination_network_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -541,7 +598,9 @@ static int lib_access_list_entry_destination_any_create(
fc = &f->u.cfilter;
fc->extended = 1;
fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
return NB_OK;
}
@@ -558,8 +617,9 @@ static int lib_access_list_entry_destination_any_destroy(
f = nb_running_get_entry(args->dnode, NULL, true);
fc = &f->u.cfilter;
fc->extended = 0;
- fc->mask.s_addr = INADDR_ANY;
- fc->mask_mask.s_addr = INADDR_NONE;
+ cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
+
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
return NB_OK;
}
@@ -594,6 +654,8 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
break;
}
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
+
return NB_OK;
}
@@ -609,6 +671,8 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
fz = &f->u.zfilter;
fz->prefix.family = 0;
+ acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
+
return NB_OK;
}
diff --git a/lib/hash.c b/lib/hash.c
index 7f8a237047..85982774ac 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -77,9 +77,20 @@ void *hash_alloc_intern(void *arg)
return arg;
}
+/*
+ * ssq = ssq + (new^2 - old^2)
+ * = ssq + ((new + old) * (new - old))
+ */
#define hash_update_ssq(hz, old, new) \
- atomic_fetch_add_explicit(&hz->stats.ssq, (new + old) * (new - old), \
- memory_order_relaxed);
+ do { \
+ int _adjust = (new + old) * (new - old); \
+ if (_adjust < 0) \
+ atomic_fetch_sub_explicit(&hz->stats.ssq, -_adjust, \
+ memory_order_relaxed); \
+ else \
+ atomic_fetch_add_explicit(&hz->stats.ssq, _adjust, \
+ memory_order_relaxed); \
+ } while (0)
/* Expand hash if the chain length exceeds the threshold. */
static void hash_expand(struct hash *hash)
diff --git a/lib/mpls.h b/lib/mpls.h
index 8922a36664..74bd7aae3e 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -72,8 +72,7 @@ extern "C" {
/* Maximum # labels that can be pushed. */
#define MPLS_MAX_LABELS 16
-#define IS_MPLS_RESERVED_LABEL(label) \
- (label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX)
+#define IS_MPLS_RESERVED_LABEL(label) (label <= MPLS_LABEL_RESERVED_MAX)
#define IS_MPLS_UNRESERVED_LABEL(label) \
(label >= MPLS_LABEL_UNRESERVED_MIN \
diff --git a/lib/privs.c b/lib/privs.c
index 5c7e1240e2..dc43b7279d 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -1020,11 +1020,11 @@ void zprivs_get_ids(struct zprivs_ids_t *ids)
ids->uid_priv = getuid();
(zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid)
- : (ids->uid_normal = -1);
+ : (ids->uid_normal = (uid_t)-1);
(zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid)
- : (ids->gid_normal = -1);
+ : (ids->gid_normal = (uid_t)-1);
(zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp)
- : (ids->gid_vty = -1);
+ : (ids->gid_vty = (uid_t)-1);
return;
}
diff --git a/lib/stream.c b/lib/stream.c
index 6e62e11380..dc207c16a4 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -268,6 +268,30 @@ bool stream_forward_getp2(struct stream *s, size_t size)
return true;
}
+void stream_rewind_getp(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (size > s->getp || !GETP_VALID(s, s->getp - size)) {
+ STREAM_BOUND_WARN(s, "rewind getp");
+ return;
+ }
+
+ s->getp -= size;
+}
+
+bool stream_rewind_getp2(struct stream *s, size_t size)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (size > s->getp || !GETP_VALID(s, s->getp - size))
+ return false;
+
+ s->getp -= size;
+
+ return true;
+}
+
void stream_forward_endp(struct stream *s, size_t size)
{
STREAM_VERIFY_SANE(s);
diff --git a/lib/stream.h b/lib/stream.h
index f2c16b3486..23f85d809b 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -160,7 +160,6 @@ extern size_t stream_resize_inplace(struct stream **sptr, size_t newsize);
extern size_t stream_get_getp(const struct stream *s);
extern size_t stream_get_endp(const struct stream *s);
extern size_t stream_get_size(const struct stream *s);
-extern uint8_t *stream_get_data(struct stream *s);
/**
* Create a new stream structure; copy offset bytes from s1 to the new
@@ -174,6 +173,8 @@ extern void stream_set_getp(struct stream *, size_t);
extern void stream_set_endp(struct stream *, size_t);
extern void stream_forward_getp(struct stream *, size_t);
extern bool stream_forward_getp2(struct stream *, size_t);
+extern void stream_rewind_getp(struct stream *s, size_t size);
+extern bool stream_rewind_getp2(struct stream *s, size_t size);
extern void stream_forward_endp(struct stream *, size_t);
extern bool stream_forward_endp2(struct stream *, size_t);
@@ -461,6 +462,12 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
goto stream_failure; \
} while (0)
+#define STREAM_REWIND_GETP(STR, SIZE) \
+ do { \
+ if (!stream_rewind_getp2((STR), (SIZE))) \
+ goto stream_failure; \
+ } while (0)
+
#define STREAM_FORWARD_ENDP(STR, SIZE) \
do { \
if (!stream_forward_endp2((STR), (SIZE))) \
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index b339790492..6fe3a289ce 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -72,7 +72,7 @@ static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
struct ospf6_interface *oi;
oi = ospf6_interface_lookup_by_ifindex(
- ospf6_route_get_first_nh_index(route));
+ ospf6_route_get_first_nh_index(route), area->ospf6->vrf_id);
if (oi && oi->area && oi->area == area)
return 1;
else
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 5562529ea8..71ca5afcd2 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -47,8 +47,8 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
-static void ospf6_asbr_redistribute_set(int type);
-static void ospf6_asbr_redistribute_unset(int type);
+static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id);
+static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id);
unsigned char conf_debug_ospf6_asbr = 0;
@@ -881,8 +881,8 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread)
__func__, ospf6->rmap[arg_type].name,
ZROUTE_NAME(arg_type));
- ospf6_zebra_no_redistribute(arg_type);
- ospf6_zebra_redistribute(arg_type);
+ ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id);
+ ospf6_zebra_redistribute(arg_type, ospf6->vrf_id);
}
XFREE(MTYPE_OSPF6_DIST_ARGS, arg);
@@ -948,9 +948,11 @@ static void ospf6_asbr_routemap_update(const char *mapname)
"%s: route-map %s deleted, reset redist %s",
__func__, mapname,
ZROUTE_NAME(type));
- ospf6_asbr_redistribute_unset(type);
+ ospf6_asbr_redistribute_unset(
+ type, ospf6->vrf_id);
ospf6_asbr_routemap_set(type, mapname);
- ospf6_asbr_redistribute_set(type);
+ ospf6_asbr_redistribute_set(
+ type, ospf6->vrf_id);
}
}
} else
@@ -977,17 +979,17 @@ int ospf6_asbr_is_asbr(struct ospf6 *o)
return o->external_table->count;
}
-static void ospf6_asbr_redistribute_set(int type)
+static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id)
{
- ospf6_zebra_redistribute(type);
+ ospf6_zebra_redistribute(type, vrf_id);
}
-static void ospf6_asbr_redistribute_unset(int type)
+static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id)
{
struct ospf6_route *route;
struct ospf6_external_info *info;
- ospf6_zebra_no_redistribute(type);
+ ospf6_zebra_no_redistribute(type, vrf_id);
for (route = ospf6_route_head(ospf6->external_table); route;
route = ospf6_route_next(route)) {
@@ -1031,7 +1033,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
struct listnode *lnode, *lnnode;
struct ospf6_area *oa;
- if (!ospf6_zebra_is_redistribute(type))
+ if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
return;
memset(&troute, 0, sizeof(troute));
@@ -1243,13 +1245,15 @@ DEFUN (ospf6_redistribute,
{
int type;
+ OSPF6_CMD_CHECK_RUNNING();
+
char *proto = argv[argc - 1]->text;
type = proto_redistnum(AFI_IP6, proto);
if (type < 0)
return CMD_WARNING_CONFIG_FAILED;
- ospf6_asbr_redistribute_unset(type);
- ospf6_asbr_redistribute_set(type);
+ ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);
+ ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
return CMD_SUCCESS;
}
@@ -1265,14 +1269,16 @@ DEFUN (ospf6_redistribute_routemap,
int idx_word = 3;
int type;
+ OSPF6_CMD_CHECK_RUNNING();
+
char *proto = argv[idx_protocol]->text;
type = proto_redistnum(AFI_IP6, proto);
if (type < 0)
return CMD_WARNING_CONFIG_FAILED;
- ospf6_asbr_redistribute_unset(type);
+ ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);
ospf6_asbr_routemap_set(type, argv[idx_word]->arg);
- ospf6_asbr_redistribute_set(type);
+ ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
return CMD_SUCCESS;
}
@@ -1288,12 +1294,14 @@ DEFUN (no_ospf6_redistribute,
int idx_protocol = 2;
int type;
+ OSPF6_CMD_CHECK_RUNNING();
+
char *proto = argv[idx_protocol]->text;
type = proto_redistnum(AFI_IP6, proto);
if (type < 0)
return CMD_WARNING_CONFIG_FAILED;
- ospf6_asbr_redistribute_unset(type);
+ ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);
return CMD_SUCCESS;
}
@@ -1305,7 +1313,7 @@ int ospf6_redistribute_config_write(struct vty *vty)
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
if (type == ZEBRA_ROUTE_OSPF6)
continue;
- if (!ospf6_zebra_is_redistribute(type))
+ if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
continue;
if (ospf6->rmap[type].name)
@@ -1340,7 +1348,7 @@ static void ospf6_redistribute_show_config(struct vty *vty)
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
if (type == ZEBRA_ROUTE_OSPF6)
continue;
- if (!ospf6_zebra_is_redistribute(type))
+ if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
continue;
if (ospf6->rmap[type].name)
@@ -1408,7 +1416,7 @@ ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
if (type == RMAP_OSPF6) {
ei = ((struct ospf6_route *)object)->route_option;
- ifp = if_lookup_by_name((char *)rule, VRF_DEFAULT);
+ ifp = if_lookup_by_name_all_vrf((char *)rule);
if (ifp != NULL && ei->ifindex == ifp->ifindex)
return RMAP_MATCH;
@@ -1880,15 +1888,15 @@ void ospf6_asbr_init(void)
install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
}
-void ospf6_asbr_redistribute_reset(void)
+void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id)
{
int type;
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
if (type == ZEBRA_ROUTE_OSPF6)
continue;
- if (ospf6_zebra_is_redistribute(type))
- ospf6_asbr_redistribute_unset(type);
+ if (ospf6_zebra_is_redistribute(type, vrf_id))
+ ospf6_asbr_redistribute_unset(type, vrf_id);
}
}
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 9890ef0619..41b1ac70e9 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -88,7 +88,7 @@ extern void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
extern int ospf6_redistribute_config_write(struct vty *vty);
extern void ospf6_asbr_init(void);
-extern void ospf6_asbr_redistribute_reset(void);
+extern void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id);
extern void ospf6_asbr_terminate(void);
extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 916e59baf0..1b58cd14f6 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -89,8 +89,8 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command)
cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr,
- on->ospf6_if->linklocal_addr, ifp->name, 0, 0,
- cbit, command, 0, VRF_DEFAULT);
+ on->ospf6_if->linklocal_addr, ifp->name, 0, 0, cbit,
+ command, 0, ifp->vrf_id);
if (command == ZEBRA_BFD_DEST_DEREGISTER)
bfd_info_free((struct bfd_info **)&on->bfd_info);
@@ -143,7 +143,7 @@ static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi, int command)
*/
static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
struct listnode *node;
struct interface *ifp;
struct ospf6_interface *oi;
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index d10329a93b..fabcc426ea 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -56,12 +56,13 @@ const char *const ospf6_interface_state_str[] = {
"None", "Down", "Loopback", "Waiting", "PointToPoint",
"DROther", "BDR", "DR", NULL};
-struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex)
+struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex,
+ vrf_id_t vrf_id)
{
struct ospf6_interface *oi;
struct interface *ifp;
- ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+ ifp = if_lookup_by_index(ifindex, vrf_id);
if (ifp == NULL)
return (struct ospf6_interface *)NULL;
@@ -1022,7 +1023,7 @@ DEFUN (show_ipv6_ospf6_interface,
return CMD_SUCCESS;
}
-static int ospf6_interface_show_traffic(struct vty *vty, uint32_t vrf_id,
+static int ospf6_interface_show_traffic(struct vty *vty,
struct interface *intf_ifp,
int display_once)
{
@@ -1030,7 +1031,10 @@ static int ospf6_interface_show_traffic(struct vty *vty, uint32_t vrf_id,
struct vrf *vrf = NULL;
struct ospf6_interface *oi = NULL;
- vrf = vrf_lookup_by_id(vrf_id);
+ if (intf_ifp)
+ vrf = vrf_lookup_by_id(intf_ifp->vrf_id);
+ else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
if (!display_once) {
vty_out(vty, "\n");
@@ -1105,7 +1109,7 @@ DEFUN (show_ipv6_ospf6_interface_traffic,
}
}
- ospf6_interface_show_traffic(vty, VRF_DEFAULT, ifp, display_once);
+ ospf6_interface_show_traffic(vty, ifp, display_once);
return CMD_SUCCESS;
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index 6cbfe04c44..dd7f4d1b1e 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -170,7 +170,8 @@ extern const char *const ospf6_interface_state_str[];
/* Function Prototypes */
-extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t);
+extern struct ospf6_interface *
+ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id);
extern struct ospf6_interface *ospf6_interface_create(struct interface *);
extern void ospf6_interface_delete(struct ospf6_interface *);
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index ef5d1d0583..6eda9f750c 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -1569,8 +1569,8 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
if (intra_prefix_lsa->ref_adv_router
== oa->ospf6->router_id) {
ifp = if_lookup_prefix(
- &old_route->prefix,
- VRF_DEFAULT);
+ &old_route->prefix,
+ oa->ospf6->vrf_id);
if (ifp)
ospf6_route_add_nexthop(
old_route,
@@ -1714,7 +1714,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)
memcpy(&route->path.ls_prefix, &ls_prefix,
sizeof(struct prefix));
if (direct_connect) {
- ifp = if_lookup_prefix(&route->prefix, VRF_DEFAULT);
+ ifp = if_lookup_prefix(&route->prefix,
+ oa->ospf6->vrf_id);
if (ifp)
ospf6_route_add_nexthop(route, ifp->ifindex,
NULL);
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 8ae5fdcf06..182faf0038 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -79,15 +79,17 @@ struct thread_master *master;
static void __attribute__((noreturn)) ospf6_exit(int status)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf;
struct interface *ifp;
frr_early_fini();
if (ospf6) {
+ vrf = vrf_lookup_by_id(ospf6->vrf_id);
ospf6_delete(ospf6);
ospf6 = NULL;
- }
+ } else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
bfd_gbl_exit();
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index f891f548ae..4830b38a66 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1554,7 +1554,7 @@ int ospf6_receive(struct thread *thread)
return 0;
}
- oi = ospf6_interface_lookup_by_ifindex(ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (oi == NULL || oi->area == NULL
|| CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 723746c471..a443e4c3ba 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -307,14 +307,14 @@ void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
inet_ntop(AF_INET6, &nh->address, buf,
sizeof(buf));
ifname = ifindex2ifname(nh->ifindex,
- VRF_DEFAULT);
+ ospf6->vrf_id);
zlog_debug(" nexthop: %s%%%.*s(%d)", buf,
IFNAMSIZ, ifname, nh->ifindex);
}
if (i >= entries)
return;
- nexthops[i].vrf_id = VRF_DEFAULT;
+ nexthops[i].vrf_id = ospf6->vrf_id;
nexthops[i].ifindex = nh->ifindex;
if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
nexthops[i].gate.ipv6 = nh->address;
@@ -1042,6 +1042,11 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route)
struct listnode *node;
struct ospf6_nexthop *nh;
+ if (ospf6 == NULL) {
+ vty_out(vty, "OSPFv3 is not running\n");
+ return;
+ }
+
monotime(&now);
timersub(&now, &route->changed, &res);
timerstring(&res, duration, sizeof(duration));
@@ -1060,7 +1065,7 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route)
for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
/* nexthop */
inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
- ifname = ifindex2ifname(nh->ifindex, VRF_DEFAULT);
+ ifname = ifindex2ifname(nh->ifindex, ospf6->vrf_id);
if (!i) {
vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
@@ -1086,6 +1091,11 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
struct listnode *node;
struct ospf6_nexthop *nh;
+ if (ospf6 == NULL) {
+ vty_out(vty, "OSPFv3 is not running\n");
+ return;
+ }
+
monotime(&now);
/* destination */
@@ -1160,7 +1170,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)
for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
/* nexthop */
inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
- ifname = ifindex2ifname(nh->ifindex, VRF_DEFAULT);
+ ifname = ifindex2ifname(nh->ifindex, ospf6->vrf_id);
vty_out(vty, " %s %.*s\n", nexthop, IFNAMSIZ, ifname);
}
vty_out(vty, "\n");
diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
index 9a1141f631..57cc055296 100644
--- a/ospf6d/ospf6_snmp.c
+++ b/ospf6d/ospf6_snmp.c
@@ -837,7 +837,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
int exact, size_t *var_len,
WriteMethod **write_method)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf;
struct ospf6_lsa *lsa = NULL;
ifindex_t ifindex;
uint32_t area_id, id, instid, adv_router;
@@ -861,6 +861,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
if (ospf6 == NULL)
return NULL;
+ vrf = vrf_lookup_by_id(ospf6->vrf_id);
/* Get variable length. */
offset = name + v->namelen;
offsetlen = *length - v->namelen;
@@ -926,7 +927,8 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
return NULL;
lsa = ospf6_lsdb_lookup(type, id, adv_router, oa->lsdb);
} else if (v->magic & OSPFv3WWLINKTABLE) {
- oi = ospf6_interface_lookup_by_ifindex(ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(ifindex,
+ ospf6->vrf_id);
if (!oi || oi->instance_id != instid)
return NULL;
lsa = ospf6_lsdb_lookup(type, id, adv_router, oi->lsdb);
@@ -963,7 +965,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,
if (!iif->ifindex)
continue;
oi = ospf6_interface_lookup_by_ifindex(
- iif->ifindex);
+ iif->ifindex, iif->vrf_id);
if (!oi)
continue;
if (iif->ifindex < ifindex)
@@ -1038,7 +1040,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
int exact, size_t *var_len,
WriteMethod **write_method)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf;
ifindex_t ifindex = 0;
unsigned int instid = 0;
struct ospf6_interface *oi = NULL;
@@ -1058,6 +1060,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
if (ospf6 == NULL)
return NULL;
+ vrf = vrf_lookup_by_id(ospf6->vrf_id);
/* Get variable length. */
offset = name + v->namelen;
offsetlen = *length - v->namelen;
@@ -1080,7 +1083,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
// offsetlen -= len;
if (exact) {
- oi = ospf6_interface_lookup_by_ifindex(ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (!oi || oi->instance_id != instid)
return NULL;
} else {
@@ -1095,7 +1098,8 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,
for (ALL_LIST_ELEMENTS_RO(ifslist, i, iif)) {
if (!iif->ifindex)
continue;
- oi = ospf6_interface_lookup_by_ifindex(iif->ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(iif->ifindex,
+ iif->vrf_id);
if (!oi)
continue;
if (iif->ifindex > ifindex
@@ -1191,7 +1195,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
int exact, size_t *var_len,
WriteMethod **write_method)
{
- struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct vrf *vrf;
ifindex_t ifindex = 0;
unsigned int instid, rtrid;
struct ospf6_interface *oi = NULL;
@@ -1212,6 +1216,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
if (ospf6 == NULL)
return NULL;
+ vrf = vrf_lookup_by_id(ospf6->vrf_id);
/* Get variable length. */
offset = name + v->namelen;
offsetlen = *length - v->namelen;
@@ -1241,7 +1246,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
// offsetlen -= len;
if (exact) {
- oi = ospf6_interface_lookup_by_ifindex(ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (!oi || oi->instance_id != instid)
return NULL;
on = ospf6_neighbor_lookup(rtrid, oi);
@@ -1257,7 +1262,8 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,
for (ALL_LIST_ELEMENTS_RO(ifslist, i, iif)) {
if (!iif->ifindex)
continue;
- oi = ospf6_interface_lookup_by_ifindex(iif->ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(iif->ifindex,
+ iif->vrf_id);
if (!oi)
continue;
for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) {
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index e75c132956..e5eb8d74eb 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -278,7 +278,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
return;
}
- oi = ospf6_interface_lookup_by_ifindex(ifindex);
+ oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
if (oi == NULL) {
if (IS_OSPF6_DEBUG_SPF(PROCESS))
zlog_debug("Can't find interface in SPF: ifindex %d",
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 50687a7290..6f23051dc3 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -232,7 +232,7 @@ static void ospf6_disable(struct ospf6 *o)
ospf6_area_disable(oa);
/* XXX: This also changes persistent settings */
- ospf6_asbr_redistribute_reset();
+ ospf6_asbr_redistribute_reset(o->vrf_id);
ospf6_lsdb_remove_all(o->lsdb);
ospf6_route_remove_all(o->route_table);
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 2773a666a3..62e0e149b8 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -75,25 +75,25 @@ static int ospf6_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
}
/* redistribute function */
-void ospf6_zebra_redistribute(int type)
+void ospf6_zebra_redistribute(int type, vrf_id_t vrf_id)
{
- if (vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT))
+ if (vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id))
return;
- vrf_bitmap_set(zclient->redist[AFI_IP6][type], VRF_DEFAULT);
+ vrf_bitmap_set(zclient->redist[AFI_IP6][type], vrf_id);
if (zclient->sock > 0)
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient,
- AFI_IP6, type, 0, VRF_DEFAULT);
+ AFI_IP6, type, 0, vrf_id);
}
-void ospf6_zebra_no_redistribute(int type)
+void ospf6_zebra_no_redistribute(int type, vrf_id_t vrf_id)
{
- if (!vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT))
+ if (!vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id))
return;
- vrf_bitmap_unset(zclient->redist[AFI_IP6][type], VRF_DEFAULT);
+ vrf_bitmap_unset(zclient->redist[AFI_IP6][type], vrf_id);
if (zclient->sock > 0)
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
- AFI_IP6, type, 0, VRF_DEFAULT);
+ AFI_IP6, type, 0, vrf_id);
}
static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS)
@@ -279,7 +279,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request)
dest = &request->prefix;
memset(&api, 0, sizeof(api));
- api.vrf_id = VRF_DEFAULT;
+ api.vrf_id = ospf6->vrf_id;
api.type = ZEBRA_ROUTE_OSPF6;
api.safi = SAFI_UNICAST;
api.prefix = *dest;
@@ -330,7 +330,7 @@ void ospf6_zebra_add_discard(struct ospf6_route *request)
if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
memset(&api, 0, sizeof(api));
- api.vrf_id = VRF_DEFAULT;
+ api.vrf_id = ospf6->vrf_id;
api.type = ZEBRA_ROUTE_OSPF6;
api.safi = SAFI_UNICAST;
api.prefix = *dest;
@@ -363,7 +363,7 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request)
if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
memset(&api, 0, sizeof(api));
- api.vrf_id = VRF_DEFAULT;
+ api.vrf_id = ospf6->vrf_id;
api.type = ZEBRA_ROUTE_OSPF6;
api.safi = SAFI_UNICAST;
api.prefix = *dest;
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index e2f778fa72..d23268303a 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -45,10 +45,10 @@ extern struct zclient *zclient;
extern void ospf6_zebra_route_update_add(struct ospf6_route *request);
extern void ospf6_zebra_route_update_remove(struct ospf6_route *request);
-extern void ospf6_zebra_redistribute(int);
-extern void ospf6_zebra_no_redistribute(int);
-#define ospf6_zebra_is_redistribute(type) \
- vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT)
+extern void ospf6_zebra_redistribute(int, vrf_id_t vrf_id);
+extern void ospf6_zebra_no_redistribute(int, vrf_id_t vrf_id);
+#define ospf6_zebra_is_redistribute(type, vrf_id) \
+ vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id)
extern void ospf6_zebra_init(struct thread_master *);
extern void ospf6_zebra_add_discard(struct ospf6_route *request);
extern void ospf6_zebra_delete_discard(struct ospf6_route *request);
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index 3dbc476172..f6c0504999 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -1802,6 +1802,7 @@ static int ospf_abr_task_timer(struct thread *thread)
ospf_abr_task(ospf);
ospf_abr_nssa_task(ospf); /* if nssa-abr, then scan Type-7 LSDB */
+ ospf_asbr_nssa_redist_task(ospf);
return 0;
}
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 1480b0e391..8fb6402c7e 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -275,6 +275,30 @@ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status)
ospf_router_lsa_update(ospf);
}
+/* If there's redistribution configured, we need to refresh external
+ * LSAs in order to install Type-7 and flood to all NSSA Areas
+ */
+void ospf_asbr_nssa_redist_task(struct ospf *ospf)
+{
+ int type;
+
+ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+ struct list *red_list;
+ struct listnode *node;
+ struct ospf_redist *red;
+
+ red_list = ospf->redist[type];
+ if (!red_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
+ ospf_external_lsa_refresh_type(
+ ospf, type, red->instance, LSA_REFRESH_FORCE);
+ }
+
+ ospf_external_lsa_refresh_default(ospf);
+}
+
void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type,
unsigned short instance)
{
diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h
index 1bcc32e3d8..ede6c47906 100644
--- a/ospfd/ospf_asbr.h
+++ b/ospfd/ospf_asbr.h
@@ -72,6 +72,7 @@ extern struct external_info *ospf_external_info_lookup(struct ospf *, uint8_t,
unsigned short,
struct prefix_ipv4 *);
extern void ospf_asbr_status_update(struct ospf *, uint8_t);
+extern void ospf_asbr_nssa_redist_task(struct ospf *ospf);
extern void ospf_redistribute_withdraw(struct ospf *, uint8_t, unsigned short);
extern void ospf_asbr_check(void);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index eb125394b8..8cf8430247 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1353,11 +1353,18 @@ static int ospf_distribute_list_update_timer(struct thread *thread)
default_refresh = 1;
else if (
(lsa = ospf_external_info_find_lsa(
- ospf, &ei->p)))
- ospf_external_lsa_refresh(
- ospf, lsa, ei,
- LSA_REFRESH_IF_CHANGED);
- else
+ ospf, &ei->p))) {
+ if (!CHECK_FLAG(
+ lsa->flags,
+ OSPF_LSA_IN_MAXAGE))
+ ospf_external_lsa_refresh(
+ ospf, lsa, ei,
+ LSA_REFRESH_IF_CHANGED);
+ else
+ ospf_external_lsa_refresh(
+ ospf, lsa, ei,
+ LSA_REFRESH_FORCE);
+ } else
ospf_external_lsa_originate(
ospf, ei);
}
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index cce97b5dfb..058881cbfc 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -785,8 +785,13 @@ void pbr_map_check_vrf_nh_group_change(const char *nh_group,
if (pbrms->nhgrp_name)
continue;
- if (pbrms->nhg
- && strcmp(nh_group, pbrms->internal_nhg_name))
+ if (pbrms->nhg == NULL)
+ continue;
+
+ if (strcmp(nh_group, pbrms->internal_nhg_name))
+ continue;
+
+ if (pbrms->nhg->nexthop == NULL)
continue;
if (pbrms->nhg->nexthop->vrf_id != old_vrf_id)
@@ -810,8 +815,13 @@ void pbr_map_check_interface_nh_group_change(const char *nh_group,
if (pbrms->nhgrp_name)
continue;
- if (pbrms->nhg
- && strcmp(nh_group, pbrms->internal_nhg_name))
+ if (pbrms->nhg == NULL)
+ continue;
+
+ if (strcmp(nh_group, pbrms->internal_nhg_name))
+ continue;
+
+ if (pbrms->nhg->nexthop == NULL)
continue;
if (pbrms->nhg->nexthop->ifindex != oldifindex)
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index e615818a10..3fb3759049 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -708,14 +708,14 @@ struct pbr_nht_individual {
struct pbr_nexthop_cache *pnhc;
vrf_id_t old_vrf_id;
- uint32_t valid;
+ bool valid;
bool nhr_matched;
};
static bool
pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
- const struct pbr_nht_individual *pnhi)
+ struct pbr_nht_individual *pnhi)
{
bool is_valid = pnhc->valid;
@@ -736,6 +736,7 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
break;
}
+ pnhi->nhr_matched = true;
if (!pnhi->nhr->nexthop_num) {
is_valid = false;
goto done;
@@ -767,8 +768,9 @@ done:
return pnhc->valid;
}
-static bool pbr_nht_individual_nexthop_interface_update(
- struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi)
+static bool
+pbr_nht_individual_nexthop_interface_update(struct pbr_nexthop_cache *pnhc,
+ struct pbr_nht_individual *pnhi)
{
bool is_valid = pnhc->valid;
@@ -779,6 +781,7 @@ static bool pbr_nht_individual_nexthop_interface_update(
!= pnhi->ifp->ifindex) /* Un-related interface */
goto done;
+ pnhi->nhr_matched = true;
is_valid = !!if_is_up(pnhi->ifp);
done:
@@ -793,9 +796,8 @@ done:
* If the update is un-related, the subroutines shoud just return their cached
* valid state.
*/
-static void
-pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
- const struct pbr_nht_individual *pnhi)
+static void pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc,
+ struct pbr_nht_individual *pnhi)
{
assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */
@@ -837,7 +839,7 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,
pnhc->valid);
if (pnhc->valid)
- pnhi->valid += 1;
+ pnhi->valid = true;
}
static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b,
@@ -869,10 +871,14 @@ static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
old_valid = pnhgc->valid;
pnhi.nhr = (struct zapi_route *)data;
- pnhi.valid = 0;
+ pnhi.valid = false;
+ pnhi.nhr_matched = false;
hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,
&pnhi);
+ if (!pnhi.nhr_matched)
+ return;
+
/*
* If any of the specified nexthops are valid we are valid
*/
@@ -1085,7 +1091,7 @@ pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b,
old_valid, pnhc->valid);
if (pnhc->valid)
- pnhi->valid += 1;
+ pnhi->valid = true;
}
static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
@@ -1098,14 +1104,14 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
old_valid = pnhgc->valid;
pnhi.ifp = data;
- pnhi.valid = 0;
+ pnhi.valid = false;
hash_iterate(pnhgc->nhh,
pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);
/*
* If any of the specified nexthops are valid we are valid
*/
- pnhgc->valid = !!pnhi.valid;
+ pnhgc->valid = pnhi.valid;
if (old_valid != pnhgc->valid)
pbr_map_check_nh_group_change(pnhgc->name);
diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h
index bcd770c2cf..6346795215 100644
--- a/pbrd/pbr_nht.h
+++ b/pbrd/pbr_nht.h
@@ -55,6 +55,7 @@ struct pbr_nexthop_cache {
bool looked_at;
bool valid;
+ bool nhr_matched;
};
extern void pbr_nht_write_table_range(struct vty *vty);
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 929214a142..bd0d5b27f4 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -170,7 +170,7 @@ BuildRequires: make
BuildRequires: ncurses-devel
BuildRequires: readline-devel
BuildRequires: texinfo
-BuildRequires: libyang-devel >= 0.16.74
+BuildRequires: libyang-devel >= 1.0.184
%if 0%{?rhel} && 0%{?rhel} < 7
#python27-devel is available from ius community repo for RedHat/CentOS 6
BuildRequires: python27-devel
diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c
index dae906b956..73bb531dc0 100644
--- a/tests/isisd/test_isis_spf.c
+++ b/tests/isisd/test_isis_spf.c
@@ -291,7 +291,7 @@ int main(int argc, char **argv)
/* IS-IS inits. */
yang_module_load("frr-isisd");
- isis = isis_new(VRF_DEFAULT);
+ isis = isis_new(VRF_DEFAULT_NAME);
listnode_add(im->isis, isis);
SET_FLAG(im->options, F_ISIS_UNIT_TEST);
debug_spf_events |= DEBUG_SPF_EVENTS;
diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
index c0896353ae..4798d17c40 100644
--- a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
+++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
@@ -1,5 +1,7 @@
interface r1-eth1
ip ospf area 0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf bfd
!
router ospf
diff --git a/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf
index f16844401e..d8fce344a8 100644
--- a/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf
+++ b/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf
@@ -1,5 +1,7 @@
interface r6-eth0
ip ospf area 0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf bfd
!
router ospf
diff --git a/tests/topotests/bfd-topo2/r2/ospf6d.conf b/tests/topotests/bfd-topo2/r2/ospf6d.conf
index f1cdb50285..48a729ce19 100644
--- a/tests/topotests/bfd-topo2/r2/ospf6d.conf
+++ b/tests/topotests/bfd-topo2/r2/ospf6d.conf
@@ -1,5 +1,7 @@
interface r2-eth2
ipv6 ospf6 bfd
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
!
router ospf6
ospf6 router-id 10.254.254.2
diff --git a/tests/topotests/bfd-topo2/r2/ospfd.conf b/tests/topotests/bfd-topo2/r2/ospfd.conf
index 8e0c45980d..c786f1fe43 100644
--- a/tests/topotests/bfd-topo2/r2/ospfd.conf
+++ b/tests/topotests/bfd-topo2/r2/ospfd.conf
@@ -1,5 +1,7 @@
interface r2-eth1
ip ospf area 0.0.0.1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf bfd
!
router ospf
diff --git a/tests/topotests/bfd-topo2/r3/ospfd.conf b/tests/topotests/bfd-topo2/r3/ospfd.conf
index cf2a1bdf76..932ab4da63 100644
--- a/tests/topotests/bfd-topo2/r3/ospfd.conf
+++ b/tests/topotests/bfd-topo2/r3/ospfd.conf
@@ -1,5 +1,7 @@
interface r3-eth0
ip ospf area 0.0.0.1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf bfd
!
router ospf
diff --git a/tests/topotests/bfd-topo2/r4/ospf6d.conf b/tests/topotests/bfd-topo2/r4/ospf6d.conf
index 756597d6f8..57f7f6c079 100644
--- a/tests/topotests/bfd-topo2/r4/ospf6d.conf
+++ b/tests/topotests/bfd-topo2/r4/ospf6d.conf
@@ -1,5 +1,7 @@
interface r4-eth0
ipv6 ospf6 bfd
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
!
router ospf6
ospf6 router-id 10.254.254.4
diff --git a/tests/topotests/bgp-auth/R1/bgpd.conf b/tests/topotests/bgp-auth/R1/bgpd.conf
new file mode 100644
index 0000000000..1cb26c6537
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 65001
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 password hello1
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 password hello2
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf
new file mode 100644
index 0000000000..aab35073cf
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf
@@ -0,0 +1,40 @@
+log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging
+debug bgp neighbor-events
+
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 password blue1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password blue2
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
+
+router bgp 65001 vrf red
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo2
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 password red1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo2
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password red2
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf
new file mode 100644
index 0000000000..7e15720c7e
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf
@@ -0,0 +1,37 @@
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP_blue peer-group
+ neighbor TWO_GROUP_blue remote-as 65002
+ neighbor TWO_GROUP_blue update-source 1.1.1.1
+ neighbor TWO_GROUP_blue ebgp-multihop 3
+ neighbor TWO_GROUP_blue password blue1
+ neighbor THREE_GROUP_blue peer-group
+ neighbor THREE_GROUP_blue remote-as 65003
+ neighbor THREE_GROUP_blue update-source 1.1.1.1
+ neighbor THREE_GROUP_blue ebgp-multihop 3
+ neighbor THREE_GROUP_blue password blue2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_blue
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_blue
+ address-family ipv4 unicast
+ neighbor TWO_GROUP_blue maximum-prefix 4294967295
+ neighbor THREE_GROUP_blue maximum-prefix 4294967295
+
+router bgp 65001 vrf red
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP_red peer-group
+ neighbor TWO_GROUP_red remote-as 65002
+ neighbor TWO_GROUP_red update-source 1.1.1.1
+ neighbor TWO_GROUP_red ebgp-multihop 3
+ neighbor TWO_GROUP_red password red1
+ neighbor THREE_GROUP_red peer-group
+ neighbor THREE_GROUP_red remote-as 65003
+ neighbor THREE_GROUP_red update-source 1.1.1.1
+ neighbor THREE_GROUP_red ebgp-multihop 3
+ neighbor THREE_GROUP_red password red2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_red
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_red
+ address-family ipv4 unicast
+ neighbor TWO_GROUP_red maximum-prefix 4294967295
+ neighbor THREE_GROUP_red maximum-prefix 4294967295
diff --git a/tests/topotests/bgp-auth/R1/bgpd_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_prefix.conf
new file mode 100644
index 0000000000..9200b0501d
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65001
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP peer-group
+ neighbor TWO_GROUP remote-as 65002
+ neighbor TWO_GROUP update-source 1.1.1.1
+ neighbor TWO_GROUP ebgp-multihop 3
+ neighbor TWO_GROUP password hello1
+ neighbor THREE_GROUP peer-group
+ neighbor THREE_GROUP remote-as 65003
+ neighbor THREE_GROUP update-source 1.1.1.1
+ neighbor THREE_GROUP ebgp-multihop 3
+ neighbor THREE_GROUP password hello2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP
+ address-family ipv4 unicast
+ neighbor TWO_GROUP maximum-prefix 4294967295
+ neighbor THREE_GROUP maximum-prefix 4294967295
diff --git a/tests/topotests/bgp-auth/R1/bgpd_vrf.conf b/tests/topotests/bgp-auth/R1/bgpd_vrf.conf
new file mode 100644
index 0000000000..73aa8c1a03
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_vrf.conf
@@ -0,0 +1,21 @@
+log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging
+debug bgp neighbor-events
+
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello2
+ address-family ipv4 unicast
+ neighbor 2.2.2.2 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf
new file mode 100644
index 0000000000..d68951b406
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65001 vrf blue
+ timers bgp 3 9
+ bgp router-id 1.1.1.1
+ neighbor TWO_GROUP_blue peer-group
+ neighbor TWO_GROUP_blue remote-as 65002
+ neighbor TWO_GROUP_blue update-source 1.1.1.1
+ neighbor TWO_GROUP_blue ebgp-multihop 3
+ neighbor TWO_GROUP_blue password hello1
+ neighbor THREE_GROUP_blue peer-group
+ neighbor THREE_GROUP_blue remote-as 65003
+ neighbor THREE_GROUP_blue update-source 1.1.1.1
+ neighbor THREE_GROUP_blue ebgp-multihop 3
+ neighbor THREE_GROUP_blue password hello2
+ bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_blue
+ bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_blue
+ address-family ipv4 unicast
+ neighbor TWO_GROUP_blue maximum-prefix 4294967295
+ neighbor THREE_GROUP_blue maximum-prefix 4294967295
diff --git a/tests/topotests/bgp-auth/R1/ospfd.conf b/tests/topotests/bgp-auth/R1/ospfd.conf
new file mode 100644
index 0000000000..79eb0e33da
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/ospfd.conf
@@ -0,0 +1,4 @@
+router ospf
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
diff --git a/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf
new file mode 100644
index 0000000000..e2a28000b8
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf
@@ -0,0 +1,9 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
+
+router ospf vrf red
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
diff --git a/tests/topotests/bgp-auth/R1/ospfd_vrf.conf b/tests/topotests/bgp-auth/R1/ospfd_vrf.conf
new file mode 100644
index 0000000000..0b7fbae8c4
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/ospfd_vrf.conf
@@ -0,0 +1,4 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.20.0.0/16 area 0
+ network 1.1.1.1/32 area 0
diff --git a/tests/topotests/bgp-auth/R1/zebra.conf b/tests/topotests/bgp-auth/R1/zebra.conf
new file mode 100644
index 0000000000..d39915335a
--- /dev/null
+++ b/tests/topotests/bgp-auth/R1/zebra.conf
@@ -0,0 +1,21 @@
+log file zebra.log
+!
+interface lo
+ ip address 1.1.1.1/32
+interface lo1 vrf blue
+ ip address 1.1.1.1/32
+interface lo2 vrf red
+ ip address 1.1.1.1/32
+interface R1-eth0
+ ip address 10.10.0.1/24
+interface R1-eth1
+ ip address 10.20.0.1/24
+interface R1-eth2 vrf blue
+ ip address 10.10.0.1/24
+interface R1-eth3 vrf blue
+ ip address 10.20.0.1/24
+interface R1-eth4 vrf red
+ ip address 10.10.0.1/24
+interface R1-eth5 vrf red
+ ip address 10.20.0.1/24
+! \ No newline at end of file
diff --git a/tests/topotests/bgp-auth/R2/bgpd.conf b/tests/topotests/bgp-auth/R2/bgpd.conf
new file mode 100644
index 0000000000..fa2a570ef9
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 65002
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf
new file mode 100644
index 0000000000..d5f70edf68
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf
@@ -0,0 +1,37 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
+
+router bgp 65002 vrf red
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo2
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf
new file mode 100644
index 0000000000..d5f70edf68
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf
@@ -0,0 +1,37 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
+
+router bgp 65002 vrf red
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo2
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_prefix.conf
new file mode 100644
index 0000000000..fa2a570ef9
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65002
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_vrf.conf b/tests/topotests/bgp-auth/R2/bgpd_vrf.conf
new file mode 100644
index 0000000000..d1f3847420
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_vrf.conf
@@ -0,0 +1,18 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf
new file mode 100644
index 0000000000..d1f3847420
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65002 vrf blue
+ timers bgp 3 9
+ bgp router-id 2.2.2.2
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello1
+ neighbor 3.3.3.3 remote-as 65003
+ neighbor 3.3.3.3 update-source lo1
+ neighbor 3.3.3.3 ebgp-multihop 3
+ neighbor 3.3.3.3 timers 3 10
+ neighbor 3.3.3.3 timers connect 10
+ neighbor 3.3.3.3 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp-auth/R2/ospfd.conf b/tests/topotests/bgp-auth/R2/ospfd.conf
new file mode 100644
index 0000000000..028b546a0c
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/ospfd.conf
@@ -0,0 +1,4 @@
+router ospf
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
diff --git a/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf
new file mode 100644
index 0000000000..a05dfb8e41
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf
@@ -0,0 +1,9 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
+
+router ospf vrf red
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
diff --git a/tests/topotests/bgp-auth/R2/ospfd_vrf.conf b/tests/topotests/bgp-auth/R2/ospfd_vrf.conf
new file mode 100644
index 0000000000..b198d352e2
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/ospfd_vrf.conf
@@ -0,0 +1,4 @@
+router ospf vrf blue
+ network 10.10.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 2.2.2.2/32 area 0
diff --git a/tests/topotests/bgp-auth/R2/zebra.conf b/tests/topotests/bgp-auth/R2/zebra.conf
new file mode 100644
index 0000000000..fece68472a
--- /dev/null
+++ b/tests/topotests/bgp-auth/R2/zebra.conf
@@ -0,0 +1,21 @@
+log file zebra.log
+!
+interface lo
+ ip address 2.2.2.2/32
+interface lo1 vrf blue
+ ip address 2.2.2.2/32
+interface lo2 vrf red
+ ip address 2.2.2.2/32
+interface R2-eth0
+ ip address 10.10.0.2/24
+interface R2-eth1
+ ip address 10.30.0.2/24
+interface R2-eth2 vrf blue
+ ip address 10.10.0.2/24
+interface R2-eth3 vrf blue
+ ip address 10.30.0.2/24
+interface R2-eth4 vrf red
+ ip address 10.10.0.2/24
+interface R2-eth5 vrf red
+ ip address 10.30.0.2/24
+! \ No newline at end of file
diff --git a/tests/topotests/bgp-auth/R3/bgpd.conf b/tests/topotests/bgp-auth/R3/bgpd.conf
new file mode 100644
index 0000000000..deccfd418b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd.conf
@@ -0,0 +1,18 @@
+router bgp 65003
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf
new file mode 100644
index 0000000000..fe3e64d8d5
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf
@@ -0,0 +1,37 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
+
+router bgp 65003 vrf red
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo2
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf
new file mode 100644
index 0000000000..fe3e64d8d5
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf
@@ -0,0 +1,37 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password blue2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password blue3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
+
+router bgp 65003 vrf red
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo2
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password red2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo2
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password red3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_prefix.conf
new file mode 100644
index 0000000000..deccfd418b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65003
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_vrf.conf b/tests/topotests/bgp-auth/R3/bgpd_vrf.conf
new file mode 100644
index 0000000000..c109aa801b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_vrf.conf
@@ -0,0 +1,18 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf
new file mode 100644
index 0000000000..c109aa801b
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf
@@ -0,0 +1,18 @@
+router bgp 65003 vrf blue
+ timers bgp 3 9
+ bgp router-id 3.3.3.3
+ neighbor 1.1.1.1 remote-as 65001
+ neighbor 1.1.1.1 update-source lo1
+ neighbor 1.1.1.1 ebgp-multihop 3
+ neighbor 1.1.1.1 timers 3 10
+ neighbor 1.1.1.1 timers connect 10
+ neighbor 1.1.1.1 password hello2
+ neighbor 2.2.2.2 remote-as 65002
+ neighbor 2.2.2.2 update-source lo1
+ neighbor 2.2.2.2 ebgp-multihop 3
+ neighbor 2.2.2.2 timers connect 10
+ neighbor 2.2.2.2 timers 3 10
+ neighbor 2.2.2.2 password hello3
+ address-family ipv4 unicast
+ neighbor 1.1.1.1 activate
+ neighbor 2.2.2.2 activate
diff --git a/tests/topotests/bgp-auth/R3/ospfd.conf b/tests/topotests/bgp-auth/R3/ospfd.conf
new file mode 100644
index 0000000000..0f0a2e926a
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/ospfd.conf
@@ -0,0 +1,4 @@
+router ospf
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
diff --git a/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf
new file mode 100644
index 0000000000..f32d2a8423
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf
@@ -0,0 +1,9 @@
+router ospf vrf blue
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
+!
+router ospf vrf red
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
diff --git a/tests/topotests/bgp-auth/R3/ospfd_vrf.conf b/tests/topotests/bgp-auth/R3/ospfd_vrf.conf
new file mode 100644
index 0000000000..6465b635aa
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/ospfd_vrf.conf
@@ -0,0 +1,4 @@
+router ospf vrf blue
+ network 10.20.0.0/16 area 0
+ network 10.30.0.0/16 area 0
+ network 3.3.3.3/32 area 0
diff --git a/tests/topotests/bgp-auth/R3/zebra.conf b/tests/topotests/bgp-auth/R3/zebra.conf
new file mode 100644
index 0000000000..0fe3acdfd0
--- /dev/null
+++ b/tests/topotests/bgp-auth/R3/zebra.conf
@@ -0,0 +1,21 @@
+log file zebra.log
+!
+interface lo
+ ip address 3.3.3.3/32
+interface lo1 vrf blue
+ ip address 3.3.3.3/32
+interface lo2 vrf red
+ ip address 3.3.3.3/32
+interface R3-eth0
+ ip address 10.20.0.3/24
+interface R3-eth1
+ ip address 10.30.0.3/24
+interface R3-eth2 vrf blue
+ ip address 10.20.0.3/24
+interface R3-eth3 vrf blue
+ ip address 10.30.0.3/24
+interface R3-eth4 vrf red
+ ip address 10.20.0.3/24
+interface R3-eth5 vrf red
+ ip address 10.30.0.3/24
+! \ No newline at end of file
diff --git a/tests/topotests/bgp-auth/test_bgp_auth.py b/tests/topotests/bgp-auth/test_bgp_auth.py
new file mode 100755
index 0000000000..6198997b86
--- /dev/null
+++ b/tests/topotests/bgp-auth/test_bgp_auth.py
@@ -0,0 +1,747 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_auth.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# 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_auth.py: Test BGP Md5 Authentication
+
+ +------+
+ +--------| |--------+
+ | +------| R1 |------+ |
+ | | -----| |----+ | |
+ | | | +------+ | | |
+ | | | | | |
+ +------+ +------+
+ | |------------| |
+ | R2 |------------| R3 |
+ | |------------| |
+ +------+ +------+
+
+
+setup is 3 routers with 3 links between each each link in a different vrf
+Default, blue and red respectively
+Tests check various fiddling with passwords and checking that the peer
+establishment is as expected and passwords are not leaked across sockets
+for bgp instances
+"""
+
+import os
+import sys
+import json
+import platform
+from functools import partial
+import pytest
+from time import sleep
+
+# 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
+
+from lib.common_config import apply_raw_config
+
+ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"]
+
+
+class InvalidCLIError(Exception):
+ """Raise when the CLI command is wrong"""
+
+ pass
+
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # This function only purpose is to define allocation and relationship
+ # between routers, switches and hosts.
+ #
+ #
+ # Create routers
+ tgen.add_router("R1")
+ tgen.add_router("R2")
+ tgen.add_router("R3")
+
+ # R1-R2 1
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R2"])
+
+ # R1-R3 1
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R2-R3 1
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["R2"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R1-R2 2
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R2"])
+
+ # R1-R3 2
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R2-R3 2
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["R2"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R1-R2 3
+ switch = tgen.add_switch("s7")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R2"])
+
+ # R1-R3 2
+ switch = tgen.add_switch("s8")
+ switch.add_link(tgen.gears["R1"])
+ switch.add_link(tgen.gears["R3"])
+
+ # R2-R3 2
+ switch = tgen.add_switch("s9")
+ switch.add_link(tgen.gears["R2"])
+ switch.add_link(tgen.gears["R3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+ tgen.start_topology()
+
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ # blue vrf
+ r1.run("ip link add blue type vrf table 1001")
+ r1.run("ip link set up dev blue")
+ r2.run("ip link add blue type vrf table 1001")
+ r2.run("ip link set up dev blue")
+ r3.run("ip link add blue type vrf table 1001")
+ r3.run("ip link set up dev blue")
+
+ r1.run("ip link add lo1 type dummy")
+ r1.run("ip link set lo1 master blue")
+ r1.run("ip link set up dev lo1")
+ r2.run("ip link add lo1 type dummy")
+ r2.run("ip link set up dev lo1")
+ r2.run("ip link set lo1 master blue")
+ r3.run("ip link add lo1 type dummy")
+ r3.run("ip link set up dev lo1")
+ r3.run("ip link set lo1 master blue")
+
+ r1.run("ip link set R1-eth2 master blue")
+ r1.run("ip link set R1-eth3 master blue")
+ r2.run("ip link set R2-eth2 master blue")
+ r2.run("ip link set R2-eth3 master blue")
+ r3.run("ip link set R3-eth2 master blue")
+ r3.run("ip link set R3-eth3 master blue")
+
+ r1.run("ip link set up dev R1-eth2")
+ r1.run("ip link set up dev R1-eth3")
+ r2.run("ip link set up dev R2-eth2")
+ r2.run("ip link set up dev R2-eth3")
+ r3.run("ip link set up dev R3-eth2")
+ r3.run("ip link set up dev R3-eth3")
+
+ # red vrf
+ r1.run("ip link add red type vrf table 1002")
+ r1.run("ip link set up dev red")
+ r2.run("ip link add red type vrf table 1002")
+ r2.run("ip link set up dev red")
+ r3.run("ip link add red type vrf table 1002")
+ r3.run("ip link set up dev red")
+
+ r1.run("ip link add lo2 type dummy")
+ r1.run("ip link set lo2 master red")
+ r1.run("ip link set up dev lo2")
+ r2.run("ip link add lo2 type dummy")
+ r2.run("ip link set up dev lo2")
+ r2.run("ip link set lo2 master red")
+ r3.run("ip link add lo2 type dummy")
+ r3.run("ip link set up dev lo2")
+ r3.run("ip link set lo2 master red")
+
+ r1.run("ip link set R1-eth4 master red")
+ r1.run("ip link set R1-eth5 master red")
+ r2.run("ip link set R2-eth4 master red")
+ r2.run("ip link set R2-eth5 master red")
+ r3.run("ip link set R3-eth4 master red")
+ r3.run("ip link set R3-eth5 master red")
+
+ r1.run("ip link set up dev R1-eth4")
+ r1.run("ip link set up dev R1-eth5")
+ r2.run("ip link set up dev R2-eth4")
+ r2.run("ip link set up dev R2-eth5")
+ r3.run("ip link set up dev R3-eth4")
+ r3.run("ip link set up dev R3-eth5")
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+
+ # For all registred 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_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # After loading the configurations, this function loads configured daemons.
+ 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 vrf_str(vrf):
+ if vrf == "":
+ vrf_str = ""
+ else:
+ vrf_str = "vrf {}".format(vrf)
+
+ return vrf_str
+
+
+def peer_name(rtr, prefix, vrf):
+ "generate VRF string for CLI"
+ if vrf == "":
+ vrf_str = ""
+ else:
+ vrf_str = "_" + vrf
+
+ if prefix == "yes":
+ if rtr == "R2":
+ return "TWO_GROUP" + vrf_str
+ else:
+ return "THREE_GROUP" + vrf_str
+ else:
+ if rtr == "R2":
+ return "2.2.2.2"
+ else:
+ return "3.3.3.3"
+
+
+def print_diag(vrf):
+ "print failure disagnostics"
+
+ tgen = get_topogen()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ print(rname + ":")
+ print(router.vtysh_cmd("show run"))
+ print(router.vtysh_cmd("show ip route {}".format(vrf_str(vrf))))
+ print(router.vtysh_cmd("show bgp {} neighbor".format(vrf_str(vrf))))
+
+
+def configure(conf_file):
+ "configure from a file"
+
+ tgen = get_topogen()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ with open(
+ os.path.join(CWD, "{}/{}").format(router.name, conf_file), "r+"
+ ) as cfg:
+ new_config = cfg.read()
+
+ output = router.vtysh_multicmd(new_config, pretty_output=False)
+ for out_err in ERROR_LIST:
+ if out_err.lower() in output.lower():
+ raise InvalidCLIError("%s" % output)
+
+
+def clear_bgp(vrf=""):
+ " clear bgp configuration for a vrf"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ router_list = tgen.routers()
+ if vrf == "":
+ r1.vtysh_cmd("conf t\nno router bgp 65001")
+ r2.vtysh_cmd("conf t\nno router bgp 65002")
+ r2.vtysh_cmd("conf t\nno router bgp 65003")
+ else:
+ r1.vtysh_cmd("conf t\nno router bgp 65001 vrf {}".format(vrf))
+ r2.vtysh_cmd("conf t\nno router bgp 65002 vrf {}".format(vrf))
+ r3.vtysh_cmd("conf t\nno router bgp 65003 vrf {}".format(vrf))
+
+
+def clear_ospf(vrf=""):
+ "clear ospf configuration for a vrf"
+
+ tgen = get_topogen()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ if vrf == "":
+ router.vtysh_cmd("conf t\nno router ospf")
+ else:
+ router.vtysh_cmd("conf t\nno router ospf vrf {}".format(vrf))
+
+
+def check_neigh_state(router, peer, state, vrf=""):
+ "check BGP neighbor state on a router"
+
+ count = 0
+ matched = False
+ neigh_output = ""
+ while count < 125:
+ if vrf == "":
+ neigh_output = router.vtysh_cmd("show bgp neighbors {} json".format(peer))
+ else:
+ neigh_output = router.vtysh_cmd(
+ "show bgp vrf {} neighbors {} json".format(vrf, peer)
+ )
+ neigh_output_json = json.loads(neigh_output)
+ if neigh_output_json[peer]["bgpState"] == state:
+ matched = True
+ break
+ count += 1
+ sleep(1)
+
+ assertmsg = "{} could not peer {} state expected {} got {} ".format(
+ router.name, peer, state, neigh_output_json[peer]["bgpState"]
+ )
+ if matched != True:
+ print_diag(vrf)
+ assert matched == True, assertmsg
+
+
+def check_all_peers_established(vrf=""):
+ "standard check for extablished peers per vrf"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+ # do r1 last as he might be the dynamic one
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+
+def check_vrf_peer_remove_passwords(vrf="", prefix="no"):
+ "selectively remove passwords checking state"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
+ vrf_str(vrf), peer_name("R2", prefix, vrf)
+ )
+ )
+
+ check_neigh_state(r2, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf))
+ )
+ check_all_peers_established(vrf)
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
+ vrf_str(vrf), peer_name("R3", prefix, vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "3.3.3.3", "Connect", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf))
+ )
+ check_all_peers_established(vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nno neighbor 3.3.3.3 password".format(vrf_str(vrf))
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Connect", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nno neighbor 2.2.2.2 password".format(vrf_str(vrf))
+ )
+ check_all_peers_established(vrf)
+
+
+def check_vrf_peer_change_passwords(vrf="", prefix="no"):
+ "selectively change passwords checking state"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+ check_all_peers_established(vrf)
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nneighbor {} password change1".format(
+ vrf_str(vrf), peer_name("R2", prefix, vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nneighbor 1.1.1.1 password change1".format(
+ vrf_str(vrf)
+ )
+ )
+ check_all_peers_established(vrf)
+
+ r1.vtysh_cmd(
+ "conf t\nrouter bgp 65001 {}\nneighbor {} password change2".format(
+ vrf_str(vrf), peer_name("R3", prefix, vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Established", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Connect", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ # don't check dynamic downed peers - they are removed
+ if prefix == "no":
+ check_neigh_state(r1, "3.3.3.3", "Connect", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nneighbor 1.1.1.1 password change2".format(
+ vrf_str(vrf)
+ )
+ )
+ check_all_peers_established(vrf)
+
+ r2.vtysh_cmd(
+ "conf t\nrouter bgp 65002 {}\nneighbor 3.3.3.3 password change3".format(
+ vrf_str(vrf)
+ )
+ )
+ check_neigh_state(r2, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r2, "3.3.3.3", "Connect", vrf)
+ check_neigh_state(r3, "1.1.1.1", "Established", vrf)
+ check_neigh_state(r3, "2.2.2.2", "Connect", vrf)
+ check_neigh_state(r1, "2.2.2.2", "Established", vrf)
+ check_neigh_state(r1, "3.3.3.3", "Established", vrf)
+
+ r3.vtysh_cmd(
+ "conf t\nrouter bgp 65003 {}\nneighbor 2.2.2.2 password change3".format(
+ vrf_str(vrf)
+ )
+ )
+ check_all_peers_established(vrf)
+
+
+def test_default_peer_established():
+ "default vrf 3 peers same password"
+
+ check_all_peers_established()
+ clear_bgp()
+ # tgen.mininet_cli()
+
+
+def test_default_peer_remove_passwords():
+ "selectively remove passwords checking state"
+
+ configure("bgpd.conf")
+ check_vrf_peer_remove_passwords()
+ clear_bgp()
+
+
+def test_default_peer_change_passwords():
+ "selectively change passwords checking state"
+
+ configure("bgpd.conf")
+ check_vrf_peer_change_passwords()
+ clear_bgp()
+
+
+def test_default_prefix_peer_established():
+ "default vrf 3 peers same password with prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_prefix.conf")
+ check_all_peers_established()
+ clear_bgp()
+ # tgen.mininet_cli()
+
+
+def test_prefix_peer_remove_passwords():
+ "selectively remove passwords checking state with prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+ configure("bgpd_prefix.conf")
+ check_vrf_peer_remove_passwords(prefix="yes")
+ clear_bgp()
+
+
+def test_prefix_peer_change_passwords():
+ "selecively change passwords checkig state with prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+ configure("bgpd_prefix.conf")
+ check_vrf_peer_change_passwords(prefix="yes")
+ clear_bgp()
+ clear_ospf()
+
+
+def test_vrf_peer_established():
+ "default vrf 3 peers same password with VRF config"
+
+ # clean routers and load vrf config
+ configure("bgpd_vrf.conf")
+ configure("ospfd_vrf.conf")
+
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ # tgen.mininet_cli()
+
+
+def test_vrf_peer_remove_passwords():
+ "selectively remove passwords checking state with VRF config"
+
+ configure("bgpd_vrf.conf")
+ check_vrf_peer_remove_passwords(vrf="blue")
+ clear_bgp("blue")
+
+
+def test_vrf_peer_change_passwords():
+ "selectively change passwords checking state with VRF config"
+
+ configure("bgpd_vrf.conf")
+ check_vrf_peer_change_passwords(vrf="blue")
+ clear_bgp("blue")
+
+
+def test_vrf_prefix_peer_established():
+ "default vrf 3 peers same password with VRF prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ clear_bgp("blue")
+ return
+
+ configure("bgpd_vrf_prefix.conf")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+
+
+def test_vrf_prefix_peer_remove_passwords():
+ "selectively remove passwords checking state with VRF prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_vrf_prefix.conf")
+ check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
+ clear_bgp("blue")
+
+
+def test_vrf_prefix_peer_change_passwords():
+ "selectively change passwords checking state with VRF prefix config"
+
+ tgen = get_topogen()
+ r1 = tgen.gears["R1"]
+ r2 = tgen.gears["R2"]
+ r3 = tgen.gears["R3"]
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ clear_ospf("blue")
+ return
+
+ configure("bgpd_vrf_prefix.conf")
+ check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
+ clear_bgp("blue")
+ clear_ospf("blue")
+
+
+def test_multiple_vrf_peer_established():
+ "default vrf 3 peers same password with multiple VRFs"
+
+ configure("bgpd_multi_vrf.conf")
+ configure("ospfd_multi_vrf.conf")
+ check_all_peers_established("blue")
+ check_all_peers_established("red")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_peer_remove_passwords():
+ "selectively remove passwords checking state with multiple VRFs"
+
+ configure("bgpd_multi_vrf.conf")
+ check_vrf_peer_remove_passwords("blue")
+ check_all_peers_established("red")
+ check_vrf_peer_remove_passwords("red")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_peer_change_passwords():
+ "selectively change passwords checking state with multiple VRFs"
+
+ configure("bgpd_multi_vrf.conf")
+ check_vrf_peer_change_passwords("blue")
+ check_all_peers_established("red")
+ check_vrf_peer_change_passwords("red")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_prefix_peer_established():
+ "default vrf 3 peers same password with multilpe VRFs and prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_multi_vrf.conf")
+ configure("ospfd_multi_vrf.conf")
+ check_all_peers_established("blue")
+ check_all_peers_established("red")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_prefix_peer_remove_passwords():
+ "selectively remove passwords checking state with multiple vrfs and prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ return
+
+ configure("bgpd_multi_vrf_prefix.conf")
+ tgen = get_topogen()
+ check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
+ check_all_peers_established("red")
+ check_vrf_peer_remove_passwords(vrf="red", prefix="yes")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ # tgen.mininet_cli()
+
+
+def test_multiple_vrf_prefix_peer_change_passwords():
+ "selectively change passwords checking state with multiple vrfs and prefix config"
+
+ # only supported in kernel > 5.3
+ if topotest.version_cmp(platform.release(), "5.3") < 0:
+ clear_bgp("blue")
+ clear_bgp("red")
+ clear_ospf("blue")
+ clear_ospf("red")
+ return
+
+ configure("bgpd_multi_vrf_prefix.conf")
+ check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
+ check_all_peers_established("red")
+ check_vrf_peer_change_passwords(vrf="red", prefix="yes")
+ check_all_peers_established("blue")
+ clear_bgp("blue")
+ clear_bgp("red")
+ clear_ospf("blue")
+ clear_ospf("red")
+ # tgen.mininet_cli()
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf
index 772675ddff..2db7edb806 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf
@@ -2,3 +2,12 @@
router ospf
network 10.20.0.0/16 area 0
network 10.20.20.20/32 area 0
+!
+int P1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int P1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf
index d337201f71..c7a76a98ed 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf
@@ -4,6 +4,7 @@ router bgp 65000
no bgp default ipv4-unicast
neighbor 10.30.30.30 remote-as 65000
neighbor 10.30.30.30 update-source lo
+ neighbor 10.30.30.30 timers 3 10
address-family l2vpn evpn
neighbor 10.30.30.30 activate
advertise-all-vni
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf
index 31c7fc4188..f1c2b42dc1 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf
@@ -2,3 +2,8 @@
router ospf
network 10.20.0.0/16 area 0
network 10.10.10.10/32 area 0
+!
+int PE1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf
index d99e33fc06..0a24158bb8 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf
@@ -4,6 +4,7 @@ router bgp 65000
no bgp default ipv4-unicast
neighbor 10.10.10.10 remote-as 65000
neighbor 10.10.10.10 update-source lo
+ neighbor 10.10.10.10 timers 3 10
!
address-family l2vpn evpn
neighbor 10.10.10.10 activate
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf
index c1a8308db5..065c993303 100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf
@@ -2,3 +2,8 @@
router ospf
network 10.20.0.0/16 area 0
network 10.30.30.30/32 area 0
+!
+int PE2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_features/r1/bgpd.conf b/tests/topotests/bgp_features/r1/bgpd.conf
index 48b71fc91a..7aea2dc161 100644
--- a/tests/topotests/bgp_features/r1/bgpd.conf
+++ b/tests/topotests/bgp_features/r1/bgpd.conf
@@ -3,14 +3,18 @@ hostname r1
log file bgpd.log
!
router bgp 65000
+ timers bgp 3 10
+ coalesce-time 0
bgp router-id 192.168.0.1
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.0.2 remote-as 65000
neighbor 192.168.0.2 description Router R2 (iBGP)
neighbor 192.168.0.2 update-source lo
+ neighbor 192.168.0.2 timers connect 5
neighbor 192.168.101.2 remote-as 65100
neighbor 192.168.101.2 description Router R4 (eBGP AS 65100)
+ neighbor 192.168.101.2 timers connect 5
!
address-family ipv4 unicast
network 192.168.0.0/24
diff --git a/tests/topotests/bgp_features/r1/ospfd.conf b/tests/topotests/bgp_features/r1/ospfd.conf
index 952abdec59..8f1711db7b 100644
--- a/tests/topotests/bgp_features/r1/ospfd.conf
+++ b/tests/topotests/bgp_features/r1/ospfd.conf
@@ -7,6 +7,17 @@ router ospf
ospf router-id 192.168.0.1
log-adjacency-changes
network 192.168.0.0/20 area 0.0.0.0
+ timers throttle spf 0 0 0
+ timers lsa min-arrival 10
+ timers throttle lsa all 0
+ refresh timer 10
!
line vty
+interface r1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+interface r1-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
diff --git a/tests/topotests/bgp_features/r2/bgpd.conf b/tests/topotests/bgp_features/r2/bgpd.conf
index 775733d1d3..3daf9842ce 100644
--- a/tests/topotests/bgp_features/r2/bgpd.conf
+++ b/tests/topotests/bgp_features/r2/bgpd.conf
@@ -4,13 +4,17 @@ log file bgpd.log
!
router bgp 65000
bgp router-id 192.168.0.2
+ timers bgp 3 10
+ coalesce-time 0
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.0.1 remote-as 65000
neighbor 192.168.0.1 description Router R1 (iBGP)
neighbor 192.168.0.1 update-source lo
+ neighbor 192.168.0.1 timers connect 5
neighbor 192.168.201.2 remote-as 65200
neighbor 192.168.201.2 description Router R5 (eBGP AS 65200)
+ neighbor 192.168.201.2 timers connect 5
!
address-family ipv4 unicast
network 192.168.0.0/24
diff --git a/tests/topotests/bgp_features/r2/ospfd.conf b/tests/topotests/bgp_features/r2/ospfd.conf
index c9ebfe506e..2174fddb11 100644
--- a/tests/topotests/bgp_features/r2/ospfd.conf
+++ b/tests/topotests/bgp_features/r2/ospfd.conf
@@ -7,6 +7,17 @@ router ospf
ospf router-id 192.168.0.2
log-adjacency-changes
network 192.168.0.0/20 area 0.0.0.0
+ timers throttle spf 0 0 0
+ timers lsa min-arrival 10
+ timers throttle lsa all 0
+ refresh timer 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
line vty
!
diff --git a/tests/topotests/bgp_features/r3/ospfd.conf b/tests/topotests/bgp_features/r3/ospfd.conf
index a8d66f1ed3..795344fbe6 100644
--- a/tests/topotests/bgp_features/r3/ospfd.conf
+++ b/tests/topotests/bgp_features/r3/ospfd.conf
@@ -7,6 +7,17 @@ router ospf
ospf router-id 192.168.0.3
log-adjacency-changes
network 192.168.0.0/20 area 0.0.0.0
+ timers throttle spf 0 0 0
+ timers lsa min-arrival 10
+ timers throttle lsa all 0
+ refresh timer 10
+!
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+int r3-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
line vty
!
diff --git a/tests/topotests/bgp_features/r4/bgpd.conf b/tests/topotests/bgp_features/r4/bgpd.conf
index 83b452b86d..fe1a4d4ffe 100644
--- a/tests/topotests/bgp_features/r4/bgpd.conf
+++ b/tests/topotests/bgp_features/r4/bgpd.conf
@@ -4,10 +4,13 @@ log file bgpd.log
!
router bgp 65100
bgp router-id 192.168.100.1
+ timers bgp 3 10
+ coalesce-time 0
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.101.1 remote-as 65000
neighbor 192.168.101.1 description Router R1 (eBGP AS 65000)
+ neighbor 192.168.101.1 timers connect 5
!
address-family ipv4 unicast
network 192.168.100.0/24
diff --git a/tests/topotests/bgp_features/r5/bgpd.conf b/tests/topotests/bgp_features/r5/bgpd.conf
index a6a42a007c..8504213b41 100644
--- a/tests/topotests/bgp_features/r5/bgpd.conf
+++ b/tests/topotests/bgp_features/r5/bgpd.conf
@@ -4,10 +4,13 @@ log file bgpd.log
!
router bgp 65200
bgp router-id 192.168.200.1
+ timers bgp 3 10
+ coalesce-time 0
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.201.1 remote-as 65000
neighbor 192.168.201.1 description Router R2 (eBGP AS 65000)
+ neighbor 192.168.201.1 timers connect 5
!
address-family ipv4 unicast
network 192.168.200.0/24
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf
index 2712e54f12..8b885341eb 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf
@@ -10,6 +10,7 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as 5226
neighbor 192.168.1.1 update-source 192.168.1.2
+ neighbor 192.168.1.1 timers 3 10
address-family ipv4 unicast
network 5.1.0.0/24 route-map rm-nh
network 5.1.1.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf
index 69305512cb..2accaae163 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf
@@ -10,6 +10,7 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as 5226
neighbor 192.168.1.1 update-source 192.168.1.2
+ neighbor 192.168.1.1 timers 3 10
address-family ipv4 unicast
network 5.1.0.0/24 route-map rm-nh
network 5.1.1.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf
index 3ad95c3612..42eff1b9b1 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf
@@ -10,6 +10,7 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as 5226
neighbor 192.168.1.1 update-source 192.168.1.2
+ neighbor 192.168.1.1 timers 3 10
address-family ipv4 unicast
network 5.1.2.0/24 route-map rm-nh
network 5.1.3.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf
index 502c4c8b2f..a564da9411 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf
@@ -11,8 +11,10 @@ router bgp 5226
neighbor 192.168.1.2 remote-as 5226
neighbor 192.168.1.2 update-source 192.168.1.1
neighbor 192.168.1.2 route-reflector-client
+ neighbor 192.168.1.2 timers 3 10
neighbor 2.2.2.2 remote-as 5226
neighbor 2.2.2.2 update-source 1.1.1.1
+ neighbor 2.2.2.2 timers 3 10
!
address-family ipv4 unicast
redistribute vnc-direct
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf
index c5097e214f..460a8fb016 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf
index 95890f25b9..3167306700 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf
@@ -10,10 +10,13 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 1.1.1.1 remote-as 5226
neighbor 1.1.1.1 update-source 2.2.2.2
+ neighbor 1.1.1.1 timers 3 10
neighbor 3.3.3.3 remote-as 5226
neighbor 3.3.3.3 update-source 2.2.2.2
+ neighbor 3.3.3.3 timers 3 10
neighbor 4.4.4.4 remote-as 5226
neighbor 4.4.4.4 update-source 2.2.2.2
+ neighbor 4.4.4.4 timers 3 10
address-family ipv4 unicast
no neighbor 1.1.1.1 activate
no neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf
index 8678813665..dbed6189c8 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf
@@ -5,3 +5,15 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf
index 2f7de073c3..445da08248 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf
@@ -11,8 +11,10 @@ router bgp 5226
neighbor 192.168.1.2 remote-as 5226
neighbor 192.168.1.2 update-source 192.168.1.2
neighbor 192.168.1.2 route-reflector-client
+ neighbor 192.168.1.2 timers 3 10
neighbor 2.2.2.2 remote-as 5226
neighbor 2.2.2.2 update-source 3.3.3.3
+ neighbor 2.2.2.2 timers 3 10
!
address-family ipv4 unicast
redistribute vnc-direct
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf
index c7c358f9dc..0e64ed6fc5 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf
@@ -7,3 +7,11 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf
index 720d06dbf1..1941352450 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf
@@ -11,8 +11,10 @@ router bgp 5226
neighbor 192.168.1.2 remote-as 5226
neighbor 192.168.1.2 update-source 192.168.1.1
neighbor 192.168.1.2 route-reflector-client
+ neighbor 192.168.1.2 timers 3 10
neighbor 2.2.2.2 remote-as 5226
neighbor 2.2.2.2 update-source 4.4.4.4
+ neighbor 2.2.2.2 timers 3 10
!
address-family ipv4 unicast
redistribute vnc-direct
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf
index 83d09c09a4..89e37df479 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf
index b81cd33c4f..6e6b9edde2 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf
@@ -12,6 +12,7 @@ router bgp 5227
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as 5227
neighbor 192.168.1.1 update-source 192.168.1.2
+ neighbor 192.168.1.1 timers 3 10
address-family ipv4 unicast
network 99.0.0.1/32
network 5.1.0.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf
index f18e5b852e..618acabd9f 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf
@@ -12,6 +12,7 @@ router bgp 5227
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as 5227
neighbor 192.168.1.1 update-source 192.168.1.2
+ neighbor 192.168.1.1 timers 3 10
address-family ipv4 unicast
network 99.0.0.2/32
network 5.1.0.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf
index 54a0933588..85c5973e6f 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf
@@ -12,6 +12,7 @@ router bgp 5227
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as 5227
neighbor 192.168.1.1 update-source 192.168.1.2
+ neighbor 192.168.1.1 timers 3 10
address-family ipv4 unicast
network 99.0.0.3/32
network 5.1.2.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
index 5289628480..6a5075a000 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf
@@ -12,6 +12,7 @@ router bgp 5228 vrf ce4-cust2
no bgp ebgp-requires-policy
neighbor 192.168.2.1 remote-as 5228
neighbor 192.168.2.1 update-source 192.168.2.2
+ neighbor 192.168.2.1 timers 3 10
address-family ipv4 unicast
network 99.0.0.4/32
network 5.4.2.0/24 route-map rm-nh
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
index 5da53ae1e7..8d42cfc0d8 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
@@ -18,6 +18,7 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
neighbor 2.2.2.2 update-source 1.1.1.1
+ neighbor 2.2.2.2 timers 3 10
address-family ipv4 unicast
no neighbor 2.2.2.2 activate
@@ -35,6 +36,7 @@ router bgp 5227 vrf r1-cust1
neighbor 192.168.1.2 remote-as 5227
neighbor 192.168.1.2 update-source 192.168.1.1
+ neighbor 192.168.1.2 timers 3 10
address-family ipv4 unicast
neighbor 192.168.1.2 activate
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf
index c5097e214f..460a8fb016 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf
index e4a6b8e32c..7b42b770b5 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf
@@ -12,10 +12,13 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 1.1.1.1 remote-as 5226
neighbor 1.1.1.1 update-source 2.2.2.2
+ neighbor 1.1.1.1 timers 3 10
neighbor 3.3.3.3 remote-as 5226
neighbor 3.3.3.3 update-source 2.2.2.2
+ neighbor 3.3.3.3 timers 3 10
neighbor 4.4.4.4 remote-as 5226
neighbor 4.4.4.4 update-source 2.2.2.2
+ neighbor 4.4.4.4 timers 3 10
address-family ipv4 unicast
no neighbor 1.1.1.1 activate
no neighbor 3.3.3.3 activate
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf
index 8678813665..dbed6189c8 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf
@@ -5,3 +5,15 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf
index a861469c7a..6c9640eea0 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf
@@ -13,6 +13,7 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
neighbor 2.2.2.2 update-source 3.3.3.3
+ neighbor 2.2.2.2 timers 3 10
address-family ipv4 unicast
no neighbor 2.2.2.2 activate
@@ -29,6 +30,7 @@ router bgp 5227 vrf r3-cust1
neighbor 192.168.1.2 remote-as 5227
neighbor 192.168.1.2 update-source 192.168.1.1
+ neighbor 192.168.1.2 timers 3 10
address-family ipv4 unicast
neighbor 192.168.1.2 activate
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf
index c7c358f9dc..0e64ed6fc5 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf
@@ -7,3 +7,11 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf
index 480f95954e..ca9e627172 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf
@@ -16,6 +16,7 @@ router bgp 5226
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
neighbor 2.2.2.2 update-source 4.4.4.4
+ neighbor 2.2.2.2 timers 3 10
address-family ipv4 unicast
no neighbor 2.2.2.2 activate
@@ -32,6 +33,7 @@ router bgp 5227 vrf r4-cust1
neighbor 192.168.1.2 remote-as 5227
neighbor 192.168.1.2 update-source 192.168.1.1
+ neighbor 192.168.1.2 timers 3 10
address-family ipv4 unicast
neighbor 192.168.1.2 activate
@@ -52,6 +54,7 @@ router bgp 5228 vrf r4-cust2
neighbor 192.168.2.2 remote-as 5228
neighbor 192.168.2.2 update-source 192.168.2.1
+ neighbor 192.168.2.2 timers 3 10
address-family ipv4 unicast
neighbor 192.168.2.2 activate
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf
index 83d09c09a4..89e37df479 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf
index c5097e214f..460a8fb016 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf
index 8678813665..dbed6189c8 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf
@@ -5,3 +5,15 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf
index c7c358f9dc..0e64ed6fc5 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf
@@ -7,3 +7,11 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf
index 83d09c09a4..89e37df479 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
network 0.0.0.0/4 area 0
redistribute static
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/bgp_update_delay/__init__.py b/tests/topotests/bgp_update_delay/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/__init__.py
diff --git a/tests/topotests/bgp_update_delay/r1/bgpd.conf b/tests/topotests/bgp_update_delay/r1/bgpd.conf
new file mode 100644
index 0000000000..8ebb509d6d
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r1/bgpd.conf
@@ -0,0 +1,10 @@
+! exit1
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r1/zebra.conf b/tests/topotests/bgp_update_delay/r1/zebra.conf
new file mode 100644
index 0000000000..9904bb4e16
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r1/zebra.conf
@@ -0,0 +1,9 @@
+! exit1
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r2/bgpd.conf b/tests/topotests/bgp_update_delay/r2/bgpd.conf
new file mode 100644
index 0000000000..438f9950a5
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r2/bgpd.conf
@@ -0,0 +1,18 @@
+! spine
+router bgp 65002
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.254.2 remote-as 65003
+ neighbor 192.168.253.2 remote-as 65004
+ neighbor 192.168.255.2 timers connect 10
+ neighbor 192.168.254.2 timers connect 10
+ neighbor 192.168.253.2 timers connect 10
+!
+ router bgp 65002 vrf vrf1
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.252.2 remote-as 65005
+ neighbor 192.168.252.2 timers connect 10
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r2/zebra.conf b/tests/topotests/bgp_update_delay/r2/zebra.conf
new file mode 100644
index 0000000000..420f00d974
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r2/zebra.conf
@@ -0,0 +1,20 @@
+! spine
+interface r2-eth0
+ ip address 192.168.255.1/30
+!
+interface r2-eth1
+ ip address 192.168.254.1/30
+!
+interface r2-eth2
+ ip address 192.168.253.1/30
+!
+interface r2-eth3
+ ip address 192.168.252.1/30
+ vrf vrf1
+!
+auto vrf1
+iface vrf1
+ vrf-table auto
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r3/bgpd.conf b/tests/topotests/bgp_update_delay/r3/bgpd.conf
new file mode 100644
index 0000000000..53e51788f7
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r3/bgpd.conf
@@ -0,0 +1,10 @@
+! exit2
+router bgp 65003
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.254.1 remote-as 65002
+ neighbor 192.168.254.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r3/zebra.conf b/tests/topotests/bgp_update_delay/r3/zebra.conf
new file mode 100644
index 0000000000..f490d97afe
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r3/zebra.conf
@@ -0,0 +1,9 @@
+! exit2
+interface lo
+ ip address 172.16.254.254/32
+!
+interface r3-eth0
+ ip address 192.168.254.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r4/bgpd.conf b/tests/topotests/bgp_update_delay/r4/bgpd.conf
new file mode 100644
index 0000000000..34cb429c0a
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r4/bgpd.conf
@@ -0,0 +1,11 @@
+! exit2
+router bgp 65004
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.253.1 remote-as 65002
+ neighbor 192.168.253.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r4/zebra.conf b/tests/topotests/bgp_update_delay/r4/zebra.conf
new file mode 100644
index 0000000000..baba04c160
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r4/zebra.conf
@@ -0,0 +1,9 @@
+! exit2
+interface lo
+ ip address 172.16.253.254/32
+!
+interface r4-eth0
+ ip address 192.168.253.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r5/bgpd.conf b/tests/topotests/bgp_update_delay/r5/bgpd.conf
new file mode 100644
index 0000000000..66ecc703cd
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r5/bgpd.conf
@@ -0,0 +1,11 @@
+! exit1
+router bgp 65005
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.252.1 remote-as 65002
+ neighbor 192.168.252.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r5/zebra.conf b/tests/topotests/bgp_update_delay/r5/zebra.conf
new file mode 100644
index 0000000000..8adf6f89e0
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r5/zebra.conf
@@ -0,0 +1,9 @@
+! exit1
+interface lo
+ ip address 172.16.252.254/32
+!
+interface r1-eth0
+ ip address 192.168.252.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py
new file mode 100755
index 0000000000..9d2818b965
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_update_delay.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Don Slice <dslice@nvidia.com>
+#
+# 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 the ability to define update-delay to delay bestpath, rib install
+and advertisement to peers when frr is started, restarted or "clear ip
+bgp *" is performed. Test both the vrf-specific and global configuration
+and operation.
+
+r1
+|
+r2----r3
+| \
+| \
+r5 r4
+
+
+r2 is UUT and peers with r1, r3, and r4 in default bgp instance.
+r2 peers with r5 in vrf vrf1.
+
+Check r2 initial convergence in default table
+Define update-delay with max-delay in the default bgp instance on r2
+Shutdown peering on r1 toward r2 so that delay timers can be exercised
+Clear bgp neighbors on r2 and then check for the 'in progress' indicator
+Check that r2 only installs route learned from r4 after the max-delay timer expires
+Define update-delay with max-delay and estabish-wait and check json output showing set
+Clear neighbors on r2 and check that r3 installs route from r4 after establish-wait time
+Remove update-delay timer on r2 to verify that it goes back to normal behavior
+Clear neighbors on r2 and check that route install time on r2 does not delay
+Define global bgp update-delay with max-delay and establish-wait on r2
+Check that r2 default instance and vrf1 have the max-delay and establish set
+Clear neighbors on r2 and check route-install time is after the establish-wait timer
+
+Note that the keepalive/hold times were changed to 3/9 and the connect retry timer
+to 10 to improve the odds the convergence timing in this test case is useful in the
+event of packet loss.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 6):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r5"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_update_delay():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
+ # initial convergence without update-delay defined
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
+ expected = {
+ "192.168.255.2": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {"ipv4Unicast": {"updateDelayLimit": 20}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay_in_progress(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {"ipv4Unicast": {"updateDelayInProgress":True}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_route_install(router):
+ output = json.loads(router.vtysh_cmd("show ip route 172.16.253.254/32 json"))
+ expected = {"172.16.253.254/32": [ {"protocol": "bgp"}]}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay_and_wait(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {
+ "ipv4Unicast": {
+ "updateDelayLimit": 20,
+ "updateDelayEstablishWait": 10}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {"ipv4Unicast": {"updateDelayLimit": 20}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_vrf_update_delay_and_wait(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp vrf vrf1 sum json"))
+ expected = {
+ "ipv4Unicast": {
+ "updateDelayLimit": 20,
+ "updateDelayEstablishWait": 10}}
+
+
+ return topotest.json_cmp(output, expected)
+
+
+ # Check r2 initial convergence in default table
+ test_func = functools.partial(_bgp_converge, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed bgp convergence in "{}"'.format(router2)
+
+ # Define update-delay with max-delay in the default bgp instance on r2
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ update-delay 20
+ """
+ )
+
+ # Shutdown peering on r1 toward r2 so that delay timers can be exercised
+ router1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65001
+ neighbor 192.168.255.1 shut
+ """
+ )
+
+ # Clear bgp neighbors on r2 and then check for the 'in progress' indicator
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_update_delay_in_progress, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format(router2)
+
+ # Check that r2 only installs route learned from r4 after the max-delay timer expires
+ test_func = functools.partial(_bgp_check_route_install, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to install route after update-delay "{}"'.format(router2)
+
+ # Define update-delay with max-delay and estabish-wait and check json output showing set
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ update-delay 20 10
+ """
+ )
+
+ test_func = functools.partial(_bgp_check_update_delay_and_wait, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set max-delay and establish-weight timers in "{}"'.format(router2)
+
+ # Define update-delay with max-delay and estabish-wait and check json output showing set
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_route_install, router3)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to installed advertised route after establish-wait timer espired "{}"'.format(router2)
+
+ # Remove update-delay timer on r2 to verify that it goes back to normal behavior
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ no update-delay
+ """
+ )
+
+ # Clear neighbors on r2 and check that route install time on r2 does not delay
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_route_install, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to remove update-delay delay timing "{}"'.format(router2)
+
+ # Define global bgp update-delay with max-delay and establish-wait on r2
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ bgp update-delay 20 10
+ """
+ )
+
+ # Check that r2 default instance and vrf1 have the max-delay and establish set
+ test_func = functools.partial(_bgp_check_update_delay_and_wait, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set update-delay in default instance "{}"'.format(router2)
+
+ test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2)
+
+ # Clear neighbors on r2 and check route-install time is after the establish-wait timer
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_route_install, router3)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to installed advertised route after establish-wait timer espired "{}"'.format(router2)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json
new file mode 100644
index 0000000000..b1d7d09db8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json
@@ -0,0 +1,563 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["11.11.11.1/32", "11.11.11.11/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["11:11::1/128", "11:11::11/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["10.10.10.10/32", "10.10.10.100/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["10:10::10/128", "10:10::100/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["22.22.22.2/32", "22.22.22.22/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["22:22::2/128", "22:22::22/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["20.20.20.20/32", "20.20.20.200/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["20:20::20/128", "20:20::200/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r3": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["30.30.30.3/32", "30.30.30.30/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["30:30::3/128", "30:30::30/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r4": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["40.40.40.4/32", "40.40.40.40/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["40:40::4/128", "40:40::40/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json
new file mode 100644
index 0000000000..b1d7d09db8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json
@@ -0,0 +1,563 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["11.11.11.1/32", "11.11.11.11/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["11:11::1/128", "11:11::11/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["10.10.10.10/32", "10.10.10.100/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["10:10::10/128", "10:10::100/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["22.22.22.2/32", "22.22.22.22/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["22:22::2/128", "22:22::22/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["20.20.20.20/32", "20.20.20.200/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["20:20::20/128", "20:20::200/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r3": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["30.30.30.3/32", "30.30.30.30/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["30:30::3/128", "30:30::30/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r4": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["40.40.40.4/32", "40.40.40.40/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["40:40::4/128", "40:40::40/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
new file mode 100755
index 0000000000..1947548b3e
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
@@ -0,0 +1,1848 @@
+#!/usr/bin/env 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.
+#
+
+"""
+Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking:
+
+1. Verify that dynamically imported routes are further advertised
+ to iBGP peers(peer in cluster).
+2. Verify matching a prefix based on community attribute and
+ importing it by stripping off this value
+3. Verify the route-map operation along with dynamic import command.
+4. Verifying the JSON outputs for all supported commands
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, '../lib/'))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+from mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology, write_test_header, check_address_types,
+ write_test_footer, reset_config_on_routers,
+ verify_rib, step, create_route_maps,
+ shutdown_bringup_interface, create_static_routes,
+ create_prefix_lists, create_bgp_community_lists,
+ create_interface_in_kernel,
+ check_router_status, verify_cli_json,
+ get_frr_ipv6_linklocal, verify_fib_routes
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ clear_bgp, verify_bgp_community, 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 = "{}/bgp_vrf_dynamic_route_leak_topo1.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
+NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"}
+NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"}
+NETWORK1_3 = {"ipv4": "10.10.10.10/32", "ipv6": "10:10::10/128"}
+NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"}
+
+NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"}
+NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"}
+NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"}
+NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"}
+
+NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"}
+NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"}
+NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
+NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
+
+NETWORK4_1 = {"ipv4": "40.40.40.4/32", "ipv6": "40:40::4/128"}
+NETWORK4_2 = {"ipv4": "40.40.40.40/32", "ipv6": "40:40::40/128"}
+NETWORK4_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
+NETWORK4_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
+
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+LOOPBACK_1 = {"ipv4": "10.0.0.7/24", "ipv6": "fd00:0:0:1::7/64",
+ "ipv4_mask": "255.255.255.0", "ipv6_mask": None}
+LOOPBACK_2 = {"ipv4": "10.0.0.16/24", "ipv6": "fd00:0:0:3::5/64",
+ "ipv4_mask": "255.255.255.0", "ipv6_mask": None}
+PREFERRED_NEXT_HOP = "global"
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - 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):
+ """
+ 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.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Run these tests for kernel version 4.19 or above
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('BGP vrf dynamic route leak tests will not run '
+ '(have kernel "{}", but it requires >= 4.19)'.\
+ format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ ADDR_TYPES = check_address_types()
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}". \
+ format(BGP_CONVERGENCE)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: {}".
+ format(time.asctime(time.localtime(time.time()))))
+ logger.info("=" * 40)
+
+#####################################################
+#
+# Local APIs
+#
+#####################################################
+
+def disable_route_map_to_prefer_global_next_hop(tgen, topo):
+ """
+ This API is to remove prefer global route-map applied on neighbors
+
+ Parameter:
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : Input JSON data
+
+ Returns:
+ --------
+ True/errormsg
+
+ """
+
+ logger.info("Remove prefer-global rmap applied on neighbors")
+ input_dict = {
+ "r1": {
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request):
+ """
+ TC5_FUNC_5:
+ 1.5.5. Verify that dynamically imported routes are further advertised
+ to iBGP peers(peer in cluster).
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Redistribute configured static routes into BGP process"
+ " on R1 and R3/R4")
+
+ input_dict_1={}
+ DUT = ["r1", "r3", "r4"]
+ VRFS = ["default", "default", "default"]
+ AS_NUM = [100, 300, 400]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that R1 receives BGP routes from R3 and R4 in "
+ "vrf default.")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_1[addr_type], \
+ NETWORK3_2[addr_type], \
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ input_routes_r4 = {
+ "r4": {
+ "static_routes": [{
+ "network": [
+ NETWORK4_1[addr_type], \
+ NETWORK4_2[addr_type], \
+ NETWORK4_3[addr_type], \
+ NETWORK4_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ DUT = ["r1", "r2"]
+ INPUT_DICT = [input_routes_r3, input_routes_r4]
+
+ for dut, routes in zip(DUT, INPUT_DICT):
+ result = verify_bgp_rib(tgen, addr_type, dut, routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ result = verify_fib_routes(tgen, addr_type, dut, routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Import from default vrf into vrf ISR on R1")
+
+ input_dict_isr={}
+ DUT = ["r1", "r2"]
+ VRFS = ["ISR", "ISR"]
+ AS_NUM = [100, 100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "default"
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that default vrf's imported routes are installed "
+ "in RIB/FIB of vrf ISR on R1:")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_1[addr_type], \
+ NETWORK3_2[addr_type], \
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ],
+ "vrf": "ISR"
+ }]
+ }
+ }
+
+ input_routes_r4 = {
+ "r4": {
+ "static_routes": [{
+ "network": [
+ NETWORK4_1[addr_type], \
+ NETWORK4_2[addr_type], \
+ NETWORK4_3[addr_type], \
+ NETWORK4_4[addr_type]
+ ],
+ "vrf": "ISR"
+ }]
+ }
+ }
+
+ INPUT_DICT_VRF = [input_routes_r3, input_routes_r4]
+
+ for routes in INPUT_DICT_VRF:
+ result = verify_bgp_rib(tgen, addr_type, "r1", routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ result = verify_fib_routes(tgen, addr_type, "r1", routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ intf_r2_r1 = topo["routers"]["r2"]["links"]["r1-link1"]
+ for addr_type in ADDR_TYPES:
+
+ step("Create a loopback10 interface on R1 with below IP address and "
+ "associate with vrf ISR:")
+
+ create_interface_in_kernel(tgen, "r1", "loopback2",
+ LOOPBACK_2[addr_type],
+ "ISR",
+ LOOPBACK_2["{}_mask".\
+ format(addr_type)])
+
+ for addr_type in ADDR_TYPES:
+
+ step("On router R1 Change the next-hop of static routes in vrf "
+ "ISR to LOOPBACK_1")
+
+ input_routes_r1= {
+ "r1": {
+ "static_routes":[
+ {
+ "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]],
+ "next_hop":"Null0",
+ "delete": True
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_routes_r1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_routes_r1= {
+ "r1": {
+ "static_routes":[
+ {
+ "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]],
+ "next_hop": (intf_r2_r1[addr_type]).split("/")[0]
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_routes_r1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that, though R1 originating BGP routes with next-hop"
+ " 24.1.1.2/24::1:2, which is local to R2(but in default vrf)"
+ ", R2 must receives and install all routes from R1 in vrf ISR.")
+ step("Verify on R2, that it now rejects 10.10.10.x routes originated "
+ "from R1. As next-hop IP is local to R2's vrf ISR.")
+
+ input_routes_r1= {
+ "r1": {
+ "static_routes":[
+ {
+ "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]],
+ "vrf": "ISR"
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Routes are still present \n Error {}". \
+ format(tc_name, result))
+
+ write_test_footer(tc_name)
+
+
+def test_dynamic_imported_matching_prefix_based_on_community_list_p0(request):
+ """
+ TC7_FUNC_7:
+ 1.5.7. Verify matching a prefix based on community attribute and
+ importing it by stripping off this value
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure route-map to set community attribute for a specific"
+ "prefix on R1 in vrf ISR")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100"
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply this route-map on R1 to vrf ISR while redistributing the"
+ " prefixes into BGP")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }
+ ]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure another route-map for filtering the prefixes based on"
+ " community attribute while importing into default vrf")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "none"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify on R1 that only prefixes with community value 100:100"
+ "in vrf ISR are imported to vrf default. While importing, the"
+ " community value has been stripped off:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ input_dict_comm = {
+ "community": "100:100"
+ }
+
+ result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]],
+ input_dict_comm, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error: Commnunity is not stipped off, {}".format(
+ tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ step("Remove/re-add route-map XYZ from redistribution.")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that all the routes disappear from vrf default when "
+ "route-map is removed from redistribution, and appear again "
+ "when route-map is re-added to redistribution in vrf ISR.")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Remove/re-add route-map IMP form import statement.")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type),
+ "delete": True
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that when route-map IMP is removed all the prefixes of"
+ " vrf ISR are imported to vrf default. However when route-map "
+ "IMP is re-added only 11.11.11.1 and 11:11::1 (with community "
+ "value) are imported.")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Delete/Re-add prefix-list ABC.")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_pf["r1"]["prefix_lists"][addr_type]["pflist_ABC_{}".\
+ format(addr_type)][0]["delete"]=False
+
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ step("Delete/Re-add community-list COMM.")
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100",
+ "delete": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_cl["r1"]["bgp_community_lists"][0]["delete"]=False
+
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ step("Delete/Re-add route-map XYZ.")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_rm["r1"]["route_maps"]["rmap_XYZ_{}".format(addr_type)][0]["delete"]=False
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ step("Delete/Re-add route-map IMP.")
+
+ input_dict_rm2 = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "none"}
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_rm2["r1"]["route_maps"]["rmap_IMP_{}".format(addr_type)][0]["delete"]=False
+
+ result = create_route_maps(tgen, input_dict_rm2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_routemap_operatons_with_dynamic_import_p0(request):
+ """
+ TC8_FUNC_8:
+ 1.5.8. Verify the route-map operation along with dynamic import command.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure route-map to set community attribute for a specific"
+ "prefix on R1 in vrf ISR")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100"
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply this route-map on R1 to vrf ISR while redistributing the"
+ " prefixes into BGP")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }
+ ]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure another route-map for filtering the prefixes based on"
+ " community attribute while importing into default vrf")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "500:500"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify on R1 that only prefixes with community value 100:100"
+ "in vrf ISR are imported to vrf default. While importing, the"
+ " community value has been stripped off:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Applying route-map first followed by import VRF command.")
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR",
+ "delete": True
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that until 'import VRF command' is not configured, "
+ "routes are not imported. After configuring 'import VRF command'"
+ " repeat step-4 for verification")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Delete/re-add import vrf ISR command multiple times in default"
+ "vrf.")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR",
+ "delete": True
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Verify that when import vrf ISR command is deleted, "
+ "all routes of vrf ISR disappear from default vrf and "
+ "when it's re-configured, repeat step-4 for verification.")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Routes are still present, Error {}". \
+ format(tc_name, result))
+
+ input_dict_isr["r1"]["bgp"][0]["address_family"][addr_type]["unicast"][
+ "import"]["delete"]=False
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ step("Delete and re-configure route-map IMP from global config when "
+ "import and route-maps are applied in a ISR vrf.")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "500:500"}
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Routes are still present, Error {}". \
+ format(tc_name, result))
+
+ input_dict_rm["r1"]["route_maps"]["rmap_IMP_{}".\
+ format(addr_type)][0]["delete"]=False
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_dict_comm = {
+ "community": "500:500"
+ }
+
+ result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]],
+ input_dict_comm)
+ assert result is True, (
+ "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result))
+
+ write_test_footer(tc_name)
+
+
+def test_verify_cli_json_p1(request):
+ """
+ TC8_FUNC_9:
+ 1.5.9. Verifying the JSON outputs for all supported commands:
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ input_dict = {
+ "r1":{
+ "cli": ["show bgp vrf default ipv4 summary",
+ "show bgp vrf all ipv6 summary",
+ "show bgp neighbors"
+ ]
+ }
+ }
+
+ result = verify_cli_json(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))
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
new file mode 100755
index 0000000000..6c106060b8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
@@ -0,0 +1,962 @@
+#!/usr/bin/env 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.
+#
+
+"""
+Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking:
+
+1. Verify that Changing route-map configurations(match/set clauses) on
+ the fly it takes immediate effect.
+2. Verify BGP best path selection algorithm works fine when
+ routes are imported from ISR to default vrf and vice versa.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, '../lib/'))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+from mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology, write_test_header, check_address_types,
+ write_test_footer,
+ verify_rib, step, create_route_maps,
+ create_static_routes, stop_router, start_router,
+ create_prefix_lists,
+ create_bgp_community_lists,
+ check_router_status,
+ get_frr_ipv6_linklocal,
+ shutdown_bringup_interface
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ verify_bgp_community, verify_bgp_attributes,
+ verify_best_path_as_per_bgp_attribute, 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 = "{}/bgp_vrf_dynamic_route_leak_topo2.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
+NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"}
+NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
+NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
+
+PREFERRED_NEXT_HOP = "global"
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - 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):
+ """
+ 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.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Run these tests for kernel version 4.19 or above
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('BGP vrf dynamic route leak tests will not run '
+ '(have kernel "{}", but it requires >= 4.19)'.\
+ format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ ADDR_TYPES = check_address_types()
+
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}". \
+ format(BGP_CONVERGENCE)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: {}".
+ format(time.asctime(time.localtime(time.time()))))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+def test_bgp_best_path_with_dynamic_import_p0(request):
+ """
+ TC6_FUNC_6:
+ 1.5.6. Verify BGP best path selection algorithm works fine when
+ routes are imported from ISR to default vrf and vice versa.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Redistribute configured static routes into BGP process"
+ " on R1/R2 and R3")
+
+ input_dict_1={}
+ DUT = ["r1", "r2", "r3", "r4"]
+ VRFS = ["ISR", "ISR", "default", "default"]
+ AS_NUM = [100, 100, 300, 400]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Import from default vrf into vrf ISR on R1 and R2 as below")
+
+ input_dict_vrf={}
+ DUT = ["r1", "r2"]
+ VRFS = ["ISR", "ISR"]
+ AS_NUM = [100, 100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_vrf.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "default"
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_default={}
+ DUT = ["r1", "r2"]
+ VRFS = ["default", "default"]
+ AS_NUM = [100, 100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_default.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_default)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Verify ECMP/Next-hop/Imported routes Vs Locally originated "
+ "routes/eBGP routes vs iBGP routes --already covered in almost"
+ " all tests")
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify Pre-emption")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type]
+ ]
+ }]
+ }
+ }
+
+ intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
+
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
+ nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
+ else:
+ nh_r3_r1 = topo["routers"]["r3"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+ nh_r4_r1 = topo["routers"]["r4"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3,
+ next_hop=[nh_r4_r1])
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ step("Shutdown interface connected to r1 from r4:")
+ shutdown_bringup_interface(tgen, 'r4', intf_r4_r1, False)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type]
+ ]
+ }]
+ }
+ }
+
+ intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
+
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
+ nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
+ else:
+ nh_r3_r1 = topo["routers"]["r3"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+ nh_r4_r1 = topo["routers"]["r4"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+
+ step("Verify next-hop is changed")
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3,
+ next_hop=[nh_r3_r1])
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ step("Bringup interface connected to r1 from r4:")
+ shutdown_bringup_interface(tgen, 'r4', intf_r4_r1, True)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type]
+ ]
+ }]
+ }
+ }
+
+ intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
+
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
+ nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
+ else:
+ nh_r3_r1 = topo["routers"]["r3"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+ nh_r4_r1 = topo["routers"]["r4"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+
+ step("Verify next-hop is not chnaged aftr shutdown:")
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3,
+ next_hop=[nh_r3_r1])
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ step("Active-Standby scenario(as-path prepend and Local pref)")
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create prefix-list")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pf_ls_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK3_4[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create route-map to match prefix-list and set localpref 500")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH1_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "locPrf": 500
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ step("Create route-map to match prefix-list and set localpref 600")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH2_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 20,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "locPrf": 600
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_dict_rma={
+ "r1": {
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_PATH1_{}".\
+ format(addr_type),
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_PATH2_{}".\
+ format(addr_type),
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]}
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_rma)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ dut = "r1"
+ attribute = "locPrf"
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify bestpath is installed as per highest localpref")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
+ input_routes_r3,
+ attribute)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create route-map to match prefix-list and set localpref 700")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH1_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "locPrf": 700
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify bestpath is changed as per highest localpref")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
+ input_routes_r3,
+ attribute)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create route-map to match prefix-list and set as-path prepend")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH2_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 20,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 700,
+ "path": {
+ "as_num": "111",
+ "as_action": "prepend"
+ }
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ attribute = "path"
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify bestpath is changed as per shortest as-path")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
+ input_routes_r3,
+ attribute)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_modify_route_map_match_set_clauses_p1(request):
+ """
+ TC13_CHAOS_4:
+ 1.5.13. Verify that Changing route-map configurations(match/set clauses) on
+ the fly it takes immediate effect.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure route-map to set community attribute for a specific"
+ "prefix on R1 in vrf ISR")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100"
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply this route-map on R1 to vrf ISR while redistributing the"
+ " prefixes into BGP")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }
+ ]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure another route-map for filtering the prefixes based on"
+ " community attribute while importing into default vrf")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "none"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify on R1 that only prefixes with community value 100:100"
+ "in vrf ISR are imported to vrf default. While importing, the"
+ " community value has been stripped off:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Add set clause in route-map IMP:")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "large_community": {"num": "100:100:100"},
+ "locPrf": 500,
+ "path": {
+ "as_num": "100 100",
+ "as_action": "prepend"
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that as we continue adding different attributes "
+ "step-by-step in route-map IMP those attributes gets "
+ "attached to prefixes:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ input_dict_comm = {
+ "largeCommunity": "100:100:100"
+ }
+
+ result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]],
+ input_dict_comm)
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}".format(
+ tc_name, result))
+
+ input_rmap = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [
+ {
+ "set": {
+ "locPrf": 500
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ result = verify_bgp_attributes(tgen, addr_type, "r1",\
+ [NETWORK1_1[addr_type]],
+ rmap_name="rmap_IMP_{}".format(addr_type),\
+ input_dict=input_rmap)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Change community-list to match a different value then "
+ "100:100.")
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100",
+ "delete": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still "
+ "present {}".\
+ format(tc_name, result))
+
+ write_test_footer(tc_name)
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis-topo1-vrf/__init__.py b/tests/topotests/isis-topo1-vrf/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/__init__.py
diff --git a/tests/topotests/isis-topo1-vrf/r1/isisd.conf b/tests/topotests/isis-topo1-vrf/r1/isisd.conf
new file mode 100755
index 0000000000..4ac4597015
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/isisd.conf
@@ -0,0 +1,15 @@
+hostname r1
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r1-eth0
+ ip router isis 1 vrf r1-cust1
+ ipv6 router isis 1 vrf r1-cust1
+ isis circuit-type level-2-only
+!
+router isis 1 vrf r1-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00
+ metric-style wide
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route.json b/tests/topotests/isis-topo1-vrf/r1/r1_route.json
new file mode 100644
index 0000000000..790808f2cd
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route.json
@@ -0,0 +1,57 @@
+{
+ "10.0.10.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "ip": "10.0.20.1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "ip": "10.0.20.1"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route6.json b/tests/topotests/isis-topo1-vrf/r1/r1_route6.json
new file mode 100644
index 0000000000..332cbb3290
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route6.json
@@ -0,0 +1,40 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r1-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json b/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json
new file mode 100755
index 0000000000..d1ace402ba
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json
@@ -0,0 +1,14 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r1-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r1-eth0",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json b/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json
new file mode 100755
index 0000000000..6af22297e9
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json
@@ -0,0 +1,13 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r1-eth0",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.20.1"
+ },
+ "10.0.20.0/24": {
+ "dev": "r1-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json
new file mode 100644
index 0000000000..8e3cdc7bd6
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json
@@ -0,0 +1,80 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r1"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r1"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r1"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r1(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r1-eth0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r1-eth0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r1"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ },
+ {
+ "interface": "r1-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r1(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r3",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r1-eth0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r1/zebra.conf b/tests/topotests/isis-topo1-vrf/r1/zebra.conf
new file mode 100755
index 0000000000..fa1c02e5f8
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r1/zebra.conf
@@ -0,0 +1,9 @@
+hostname r1
+interface r1-eth0 vrf r1-cust1
+ ip address 10.0.20.2/24
+ ipv6 address 2001:db8:1:1::2/64
+!
+interface lo
+ ip address 10.254.0.1/32
+ ipv6 address 2001:db8:F::1/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r2/isisd.conf b/tests/topotests/isis-topo1-vrf/r2/isisd.conf
new file mode 100755
index 0000000000..4c68540265
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/isisd.conf
@@ -0,0 +1,15 @@
+hostname r2
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r2-eth0
+ ip router isis 1 vrf r2-cust1
+ ipv6 router isis 1 vrf r2-cust1
+ isis circuit-type level-2-only
+!
+router isis 1 vrf r2-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
+ metric-style wide
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route.json b/tests/topotests/isis-topo1-vrf/r2/r2_route.json
new file mode 100644
index 0000000000..b3ac86d218
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route.json
@@ -0,0 +1,57 @@
+{
+ "10.0.11.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0",
+ "ip": "10.0.21.1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0",
+ "ip": "10.0.21.1"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route6.json b/tests/topotests/isis-topo1-vrf/r2/r2_route6.json
new file mode 100644
index 0000000000..c8d11b4922
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route6.json
@@ -0,0 +1,40 @@
+{
+ "2001:db8:1:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 3,
+ "vrfName": "r2-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json b/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json
new file mode 100755
index 0000000000..27423e1936
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json
@@ -0,0 +1,14 @@
+{
+ "2001:db8:1:2::/64": {
+ "dev": "r2-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r2-eth0",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json b/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json
new file mode 100755
index 0000000000..744b0780f3
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json
@@ -0,0 +1,13 @@
+{
+ "10.0.11.0/24": {
+ "dev": "r2-eth0",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.21.1"
+ },
+ "10.0.21.0/24": {
+ "dev": "r2-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json
new file mode 100644
index 0000000000..72022a8167
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json
@@ -0,0 +1,80 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r2"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r2"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r2"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r2(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r2-eth0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r2-eth0",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r2"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ },
+ {
+ "interface": "r2-eth0",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r2(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r4",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r2-eth0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/isis-topo1-vrf/r2/zebra.conf b/tests/topotests/isis-topo1-vrf/r2/zebra.conf
new file mode 100755
index 0000000000..a62af1749e
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r2/zebra.conf
@@ -0,0 +1,9 @@
+hostname r2
+interface r2-eth0 vrf r2-cust1
+ ip address 10.0.21.2/24
+ ipv6 address 2001:db8:1:2::2/64
+!
+interface lo
+ ip address 10.254.0.2/32
+ ipv6 address 2001:db8:F::2/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r3/isisd.conf b/tests/topotests/isis-topo1-vrf/r3/isisd.conf
new file mode 100755
index 0000000000..ca01876690
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/isisd.conf
@@ -0,0 +1,22 @@
+hostname r3
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r3-eth0
+ ip router isis 1 vrf r3-cust1
+ ipv6 router isis 1 vrf r3-cust1
+ isis circuit-type level-2-only
+!
+interface r3-eth1
+ ip router isis 1 vrf r3-cust1
+ ipv6 router isis 1 vrf r3-cust1
+ isis circuit-type level-1
+!
+router isis 1 vrf r3-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-1
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route.json b/tests/topotests/isis-topo1-vrf/r3/r3_route.json
new file mode 100644
index 0000000000..709d6b9aeb
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route.json
@@ -0,0 +1,112 @@
+{
+ "10.0.10.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1",
+ "ip": "10.0.10.1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "10.0.11.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1",
+ "ip": "10.0.10.1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0",
+ "ip": "10.0.20.2"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "distance": 115,
+ "metric": 30,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1",
+ "ip": "10.0.10.1"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route6.json b/tests/topotests/isis-topo1-vrf/r3/r3_route6.json
new file mode 100644
index 0000000000..3a7c3861fa
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route6.json
@@ -0,0 +1,78 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r3-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "2001:db8:1:2::/64": [
+ {
+ "distance": 115,
+ "metric": 30,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r3-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json b/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json
new file mode 100755
index 0000000000..bc527d2e1e
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r3-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:1:2::/64": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r3-eth1",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json b/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json
new file mode 100755
index 0000000000..515d376475
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json
@@ -0,0 +1,24 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r3-eth1",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.11.0/24": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.10.1"
+ },
+ "10.0.20.0/24": {
+ "dev": "r3-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.21.0/24": {
+ "dev": "r3-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.10.1"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json
new file mode 100644
index 0000000000..62b895766e
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json
@@ -0,0 +1,132 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r3-eth1",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r3-eth1",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "30",
+ "parent": "r3-eth1",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ },
+ {
+ "interface": "r3-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r3-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "30",
+ "parent": "r3-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r3-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r3-eth0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r3"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ },
+ {
+ "interface": "r3-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r3(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r3/zebra.conf b/tests/topotests/isis-topo1-vrf/r3/zebra.conf
new file mode 100755
index 0000000000..ac0b810fce
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r3/zebra.conf
@@ -0,0 +1,13 @@
+hostname r3
+interface r3-eth0 vrf r3-cust1
+ ip address 10.0.20.1/24
+ ipv6 address 2001:db8:1:1::1/64
+!
+interface r3-eth1 vrf r3-cust1
+ ip address 10.0.10.2/24
+ ipv6 address 2001:db8:2:1::2/64
+!
+interface lo
+ ip address 10.254.0.3/32
+ ipv6 address 2001:db8:F::3/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r4/isisd.conf b/tests/topotests/isis-topo1-vrf/r4/isisd.conf
new file mode 100755
index 0000000000..74b1603d85
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/isisd.conf
@@ -0,0 +1,25 @@
+hostname r4
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+debug isis lsp-gen
+debug isis lsp-sched
+
+interface r4-eth0
+ ip router isis 1 vrf r4-cust1
+ ipv6 router isis 1 vrf r4-cust1
+ isis circuit-type level-2-only
+!
+interface r4-eth1
+ ip router isis 1 vrf r4-cust1
+ ipv6 router isis 1 vrf r4-cust1
+ isis circuit-type level-1
+!
+router isis 1 vrf r4-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv4 connected level-2
+ redistribute ipv6 connected level-1
+ redistribute ipv6 connected level-2
+!
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route.json b/tests/topotests/isis-topo1-vrf/r4/r4_route.json
new file mode 100644
index 0000000000..c464607a2b
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route.json
@@ -0,0 +1,105 @@
+{
+ "10.0.10.0/24": [
+ {
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1",
+ "ip": "10.0.11.1"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "10.0.11.0/24": [
+ {
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1",
+ "ip": "10.0.11.1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1",
+ "ip": "10.0.11.1"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0",
+ "ip": "10.0.21.2"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route6.json b/tests/topotests/isis-topo1-vrf/r4/r4_route6.json
new file mode 100644
index 0000000000..8d3ea570f0
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route6.json
@@ -0,0 +1,78 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "distance": 115,
+ "metric": 30,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "2001:db8:1:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r4-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r4-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json b/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json
new file mode 100755
index 0000000000..b1cd5b9db9
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:1:2::/64": {
+ "dev": "r4-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r4-eth1",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json b/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json
new file mode 100755
index 0000000000..3198b85789
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json
@@ -0,0 +1,24 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.11.1"
+ },
+ "10.0.11.0/24": {
+ "dev": "r4-eth1",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.20.0/24": {
+ "dev": "r4-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.11.1"
+ },
+ "10.0.21.0/24": {
+ "dev": "r4-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json
new file mode 100644
index 0000000000..0d69550cad
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json
@@ -0,0 +1,132 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r4-eth1",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r4-eth1",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r5",
+ "metric": "TE",
+ "next-hop": "30",
+ "parent": "r4-eth1",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ },
+ {
+ "interface": "r4-eth1",
+ "metric": "10",
+ "next-hop": "r5",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r5"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r4-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ },
+ {
+ "interface": "r5",
+ "metric": "internal",
+ "next-hop": "30",
+ "parent": "r4-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r4-eth0",
+ "metric": "10",
+ "next-hop": "r2",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r2"
+ },
+ {
+ "interface": "r2",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r4-eth0",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r4"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ },
+ {
+ "interface": "r4-eth0",
+ "metric": "10",
+ "next-hop": "r2",
+ "parent": "r4(4)",
+ "type": "TE-IS",
+ "vertex": "r2"
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r4/zebra.conf b/tests/topotests/isis-topo1-vrf/r4/zebra.conf
new file mode 100755
index 0000000000..9c8941f7a5
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r4/zebra.conf
@@ -0,0 +1,13 @@
+hostname r4
+interface r4-eth0 vrf r4-cust1
+ ip address 10.0.21.1/24
+ ipv6 address 2001:db8:1:2::1/64
+!
+interface r4-eth1 vrf r4-cust1
+ ip address 10.0.11.2/24
+ ipv6 address 2001:db8:2:2::2/64
+!
+interface lo
+ ip address 10.254.0.4/32
+ ipv6 address 2001:db8:F::4/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/r5/isisd.conf b/tests/topotests/isis-topo1-vrf/r5/isisd.conf
new file mode 100755
index 0000000000..9e9b030455
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/isisd.conf
@@ -0,0 +1,21 @@
+hostname r5
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+interface r5-eth0
+ ip router isis 1 vrf r5-cust1
+ ipv6 router isis 1 vrf r5-cust1
+ isis circuit-type level-1
+!
+interface r5-eth1
+ ip router isis 1 vrf r5-cust1
+ ipv6 router isis 1 vrf r5-cust1
+ isis circuit-type level-1
+!
+router isis 1 vrf r5-cust1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00
+ metric-style wide
+ is-type level-1
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+!
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route.json b/tests/topotests/isis-topo1-vrf/r5/r5_route.json
new file mode 100644
index 0000000000..58aee5ddcc
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route.json
@@ -0,0 +1,106 @@
+{
+ "10.0.10.0/24": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0",
+ "ip": "10.0.10.2"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "10.0.10.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "10.0.11.0/24": [
+ {
+ "nexthops": [
+ {
+ "afi": "ipv4",
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1",
+ "ip": "10.0.11.2"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "isis",
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ },
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1"
+ }
+ ],
+ "prefix": "10.0.11.0/24",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "10.0.20.0/24": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0",
+ "ip": "10.0.10.2"
+ }
+ ],
+ "prefix": "10.0.20.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "10.0.21.0/24": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv4",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1",
+ "ip": "10.0.11.2"
+ }
+ ],
+ "prefix": "10.0.21.0/24",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route6.json b/tests/topotests/isis-topo1-vrf/r5/r5_route6.json
new file mode 100644
index 0000000000..e32bbcc2c1
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route6.json
@@ -0,0 +1,78 @@
+{
+ "2001:db8:1:1::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "2001:db8:1:1::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "2001:db8:1:2::/64": [
+ {
+ "distance": 115,
+ "metric": 20,
+ "nexthops": [
+ {
+ "active": true,
+ "afi": "ipv6",
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1"
+ }
+ ],
+ "prefix": "2001:db8:1:2::/64",
+ "protocol": "isis",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "2001:db8:2:1::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "2001:db8:2:1::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ],
+ "2001:db8:2:2::/64": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "directlyConnected": true,
+ "fib": true,
+ "interfaceIndex": 3,
+ "interfaceName": "r5-eth1"
+ }
+ ],
+ "prefix": "2001:db8:2:2::/64",
+ "protocol": "connected",
+ "selected": true,
+ "vrfId": 4,
+ "vrfName": "r5-cust1"
+ }
+ ]
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json b/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json
new file mode 100755
index 0000000000..3db3c93ea6
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1:1::/64": {
+ "dev": "r5-eth0",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:1:2::/64": {
+ "dev": "r5-eth1",
+ "metric": "20",
+ "pref": "medium",
+ "proto": "187"
+ },
+ "2001:db8:2:1::/64": {
+ "dev": "r5-eth0",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ },
+ "2001:db8:2:2::/64": {
+ "dev": "r5-eth1",
+ "metric": "256",
+ "pref": "medium",
+ "proto": "kernel"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json b/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json
new file mode 100755
index 0000000000..6a38ba864a
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json
@@ -0,0 +1,24 @@
+{
+ "10.0.10.0/24": {
+ "dev": "r5-eth0",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.11.0/24": {
+ "dev": "r5-eth1",
+ "proto": "kernel",
+ "scope": "link"
+ },
+ "10.0.20.0/24": {
+ "dev": "r5-eth0",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.10.2"
+ },
+ "10.0.21.0/24": {
+ "dev": "r5-eth1",
+ "metric": "20",
+ "proto": "187",
+ "via": "10.0.11.2"
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json
new file mode 100644
index 0000000000..b4ed6a069d
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json
@@ -0,0 +1,124 @@
+{
+ "1": {
+ "level-1": {
+ "ipv4": [
+ {
+ "vertex": "r5"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ },
+ {
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth0",
+ "type": "IP",
+ "vertex": "10.0.20.0/24"
+ },
+ {
+ "interface": "r3",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth0",
+ "type": "IP",
+ "vertex": "10.0.10.0/24"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth1",
+ "type": "IP",
+ "vertex": "10.0.21.0/24"
+ },
+ {
+ "interface": "r4",
+ "metric": "TE",
+ "next-hop": "20",
+ "parent": "r5-eth1",
+ "type": "IP",
+ "vertex": "10.0.11.0/24"
+ }
+ ],
+ "ipv6": [
+ {
+ "vertex": "r5"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:1::/64"
+ },
+ {
+ "metric": "internal",
+ "parent": "0",
+ "type": "IP6",
+ "vertex": "2001:db8:2:2::/64"
+ },
+ {
+ "interface": "r5-eth0",
+ "metric": "10",
+ "next-hop": "r3",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r3"
+ },
+ {
+ "interface": "r5-eth1",
+ "metric": "10",
+ "next-hop": "r4",
+ "parent": "r5(4)",
+ "type": "TE-IS",
+ "vertex": "r4"
+ },
+ {
+ "interface": "r3",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r5-eth0",
+ "type": "IP6",
+ "vertex": "2001:db8:1:1::/64"
+ },
+ {
+ "interface": "r4",
+ "metric": "internal",
+ "next-hop": "20",
+ "parent": "r5-eth1",
+ "type": "IP6",
+ "vertex": "2001:db8:1:2::/64"
+ }
+ ]
+ },
+ "level-2": {
+ "ipv4": [],
+ "ipv6": []
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/isis-topo1-vrf/r5/zebra.conf b/tests/topotests/isis-topo1-vrf/r5/zebra.conf
new file mode 100755
index 0000000000..c6bc6302fc
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/r5/zebra.conf
@@ -0,0 +1,13 @@
+hostname r5
+interface r5-eth0 vrf r5-cust1
+ ip address 10.0.10.1/24
+ ipv6 address 2001:db8:2:1::1/64
+!
+interface r5-eth1 vrf r5-cust1
+ ip address 10.0.11.1/24
+ ipv6 address 2001:db8:2:2::1/64
+!
+interface lo
+ ip address 10.254.0.5/32
+ ipv6 address 2001:db8:F::5/128
+!
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot
new file mode 100755
index 0000000000..01f9ba780f
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot
@@ -0,0 +1,100 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="isis topo1";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1\n10.254.0.1\n2001:DB8:F::1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2\n10.254.0.2\n2001:DB8:F::2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3\n10.254.0.3\n2001:DB8:F::3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r4 [
+ shape=doubleoctagon
+ label="r4\n10.254.0.4\n2001:DB8:F::4",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r5 [
+ shape=doubleoctagon
+ label="r5\n10.254.0.5\n2001:DB8:F::5",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n10.0.20.0/24\n2001:DB8:1:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw2 [
+ shape=oval,
+ label="sw2\n10.0.21.0/24\n2001:DB8:1:2::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw3 [
+ shape=oval,
+ label="sw3\n10.0.10.0/24\n2001:DB8:2:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ sw4 [
+ shape=oval,
+ label="sw4\n10.0.11.0/24\n2001:DB8:2:2::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ subgraph cluster0 {
+ label="level 2";
+
+ r1 -- sw1 [label="eth0\n.2"];
+ r2 -- sw2 [label="eth0\n.2"];
+ }
+
+ subgraph cluster1 {
+ label="level 1/2";
+
+ r3 -- sw1 [label="eth0\n.1"];
+ r3 -- sw3 [label="eth1\n.2"];
+
+ r4 -- sw4 [label="eth1\n.2"];
+ r4 -- sw2 [label="eth0\n.1"];
+ }
+
+ subgraph cluster2 {
+ label="level 1";
+
+ r5 -- sw3 [label="eth0\n.1"];
+ r5 -- sw4 [label="eth1\n.1"];
+ }
+}
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg
new file mode 100755
index 0000000000..4ad730f2a0
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg
Binary files differ
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
new file mode 100755
index 0000000000..a0e34b71b0
--- /dev/null
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
@@ -0,0 +1,455 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by Niral Networks, Inc. ("Niral Networks")
+# 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 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_topo1_vrf.py: Test ISIS vrf topology.
+"""
+
+import collections
+import functools
+import json
+import os
+import re
+import sys
+import pytest
+import platform
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from mininet.topo import Topo
+
+
+class ISISTopo1(Topo):
+ "Simple two layer ISIS vrf topology"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Add ISIS routers:
+ # r1 r2
+ # | sw1 | sw2
+ # r3 r4
+ # | |
+ # sw3 sw4
+ # \ /
+ # r5
+ for routern in range(1, 6):
+ tgen.add_router("r{}".format(routern))
+
+ # r1 <- sw1 -> r3
+ sw = tgen.add_switch("sw1")
+ sw.add_link(tgen.gears["r1"])
+ sw.add_link(tgen.gears["r3"])
+
+ # r2 <- sw2 -> r4
+ sw = tgen.add_switch("sw2")
+ sw.add_link(tgen.gears["r2"])
+ sw.add_link(tgen.gears["r4"])
+
+ # r3 <- sw3 -> r5
+ sw = tgen.add_switch("sw3")
+ sw.add_link(tgen.gears["r3"])
+ sw.add_link(tgen.gears["r5"])
+
+ # r4 <- sw4 -> r5
+ sw = tgen.add_switch("sw4")
+ sw.add_link(tgen.gears["r4"])
+ sw.add_link(tgen.gears["r5"])
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(ISISTopo1, mod.__name__)
+ tgen.start_topology()
+
+ logger.info("Testing with VRF Lite support")
+ krel = platform.release()
+
+ # May need to adjust handling of vrf traffic depending on kernel version
+ l3mdev_accept = 0
+ if (
+ topotest.version_cmp(krel, "4.15") >= 0
+ and topotest.version_cmp(krel, "4.18") <= 0
+ ):
+ l3mdev_accept = 1
+
+ if topotest.version_cmp(krel, "5.0") >= 0:
+ l3mdev_accept = 1
+
+ logger.info(
+ "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept)
+ )
+
+ cmds = [
+ "ip link add {0}-cust1 type vrf table 1001",
+ "ip link add loop1 type dummy",
+ "ip link set {0}-eth0 master {0}-cust1",
+ "ip link set {0}-eth1 master {0}-cust1",
+ ]
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in tgen.routers().iteritems():
+ # create VRF rx-cust1 and link rx-eth0 to rx-cust1
+ for cmd in cmds:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+ output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept")
+ logger.info(
+ "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output)
+ )
+
+ if l3mdev_accept:
+ output = tgen.net[rname].cmd(
+ "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
+ )
+
+ for rname, router in tgen.routers().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))
+ )
+ # After loading the configurations, this function loads configured daemons.
+ tgen.start_router()
+
+ has_version_20 = False
+ for router in tgen.routers().values():
+ if router.has_version("<", "4"):
+ has_version_20 = True
+
+ if has_version_20:
+ logger.info("Skipping ISIS vrf tests for FRR 2.0")
+ tgen.set_error("ISIS has convergence problems with IPv6")
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ # move back rx-eth0 to default VRF
+ # delete rx-vrf
+ tgen.stop_topology()
+
+def test_isis_convergence():
+ "Wait for the protocol to converge before starting to test"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for ISIS protocol to converge")
+
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_topology.json".format(CWD, rname)
+ expected = json.loads(open(filename).read())
+ def compare_isis_topology(router, expected):
+ "Helper function to test ISIS vrf topology convergence."
+ actual = show_isis_topology(router)
+
+ return topotest.json_cmp(actual, expected)
+
+ test_func = functools.partial(compare_isis_topology, router, expected)
+ (result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=120)
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+def test_isis_route_installation():
+ "Check whether all expected routes are present"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf routes")
+ # Check for routes in 'show ip route vrf {}-cust1 json'
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = router.vtysh_cmd("show ip route vrf {0}-cust1 json".format(rname) , isjson=True)
+ # Older FRR versions don't list interfaces in some ISIS routes
+ if router.has_version("<", "3.1"):
+ for network, routes in expected.iteritems():
+ for route in routes:
+ if route["protocol"] != "isis":
+ continue
+
+ for nexthop in route["nexthops"]:
+ nexthop.pop("interfaceIndex", None)
+ nexthop.pop("interfaceName", None)
+
+ assertmsg = "Router '{}' routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+
+def test_isis_linux_route_installation():
+
+ dist = platform.dist()
+
+ if (dist[1] == "16.04"):
+ pytest.skip("Kernel not supported for vrf")
+
+ "Check whether all expected routes are present and installed in the OS"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf routes in OS")
+ # Check for routes in `ip route show vrf {}-cust1`
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = topotest.ip4_vrf_route(router)
+
+ # Older FRR versions install routes using different proto
+ if router.has_version("<", "3.1"):
+ for network, netoptions in expected.iteritems():
+ if "proto" in netoptions and netoptions["proto"] == "187":
+ netoptions["proto"] = "zebra"
+
+ assertmsg = "Router '{}' OS routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+def test_isis_route6_installation():
+ "Check whether all expected routes are present"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf IPv6 routes")
+ # Check for routes in 'show ipv6 route vrf {}-cust1 json'
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route6.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = router.vtysh_cmd("show ipv6 route vrf {}-cust1 json".format(rname) , isjson=True)
+
+ # Older FRR versions don't list interfaces in some ISIS routes
+ if router.has_version("<", "3.1"):
+ for network, routes in expected.iteritems():
+ for route in routes:
+ if route["protocol"] != "isis":
+ continue
+
+ for nexthop in route["nexthops"]:
+ nexthop.pop("interfaceIndex", None)
+ nexthop.pop("interfaceName", None)
+
+ assertmsg = "Router '{}' routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+def test_isis_linux_route6_installation():
+
+ dist = platform.dist()
+
+ if (dist[1] == "16.04"):
+ pytest.skip("Kernel not supported for vrf")
+
+ "Check whether all expected routes are present and installed in the OS"
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
+ # Check for routes in `ip -6 route show vrf {}-cust1`
+ for rname, router in tgen.routers().iteritems():
+ filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname)
+ expected = json.loads(open(filename, "r").read())
+ actual = topotest.ip6_vrf_route(router)
+
+ # Older FRR versions install routes using different proto
+ if router.has_version("<", "3.1"):
+ for network, netoptions in expected.iteritems():
+ if "proto" in netoptions and netoptions["proto"] == "187":
+ netoptions["proto"] = "zebra"
+
+ assertmsg = "Router '{}' OS routes mismatch".format(rname)
+ assert topotest.json_cmp(actual, expected) is None, assertmsg
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
+
+
+#
+# Auxiliary functions
+#
+
+
+def dict_merge(dct, merge_dct):
+ """
+ Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
+ updating only top-level keys, dict_merge recurses down into dicts nested
+ to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
+ ``dct``.
+ :param dct: dict onto which the merge is executed
+ :param merge_dct: dct merged into dct
+ :return: None
+
+ Source:
+ https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
+ """
+ for k, v in merge_dct.iteritems():
+ if (
+ k in dct
+ and isinstance(dct[k], dict)
+ and isinstance(merge_dct[k], collections.Mapping)
+ ):
+ dict_merge(dct[k], merge_dct[k])
+ else:
+ dct[k] = merge_dct[k]
+
+
+def parse_topology(lines, level):
+ """
+ Parse the output of 'show isis topology level-X' into a Python dict.
+ """
+ areas = {}
+ area = None
+ ipv = None
+
+ for line in lines:
+ area_match = re.match(r"Area (.+):", line)
+ if area_match:
+ area = area_match.group(1)
+ if area not in areas:
+ areas[area] = {level: {"ipv4": [], "ipv6": []}}
+ ipv = None
+ continue
+ elif area is None:
+ continue
+
+ if re.match(r"IS\-IS paths to level-. routers that speak IPv6", line):
+ ipv = "ipv6"
+ continue
+ if re.match(r"IS\-IS paths to level-. routers that speak IP", line):
+ ipv = "ipv4"
+ continue
+
+ item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
+ if item_match is not None:
+ # Skip header
+ if (
+ item_match.group(1) == "Vertex"
+ and item_match.group(2) == "Type"
+ and item_match.group(3) == "Metric"
+ and item_match.group(4) == "Next-Hop"
+ and item_match.group(5) == "Interface"
+ and item_match.group(6) == "Parent"
+ ):
+ continue
+
+ areas[area][level][ipv].append(
+ {
+ "vertex": item_match.group(1),
+ "type": item_match.group(2),
+ "metric": item_match.group(3),
+ "next-hop": item_match.group(4),
+ "interface": item_match.group(5),
+ "parent": item_match.group(6),
+ }
+ )
+ continue
+
+ item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line)
+ if item_match is not None:
+ areas[area][level][ipv].append(
+ {
+ "vertex": item_match.group(1),
+ "type": item_match.group(2),
+ "metric": item_match.group(3),
+ "parent": item_match.group(4),
+ }
+ )
+ continue
+
+ item_match = re.match(r"([^ ]+)", line)
+ if item_match is not None:
+ areas[area][level][ipv].append({"vertex": item_match.group(1)})
+ continue
+
+ return areas
+
+
+def show_isis_topology(router):
+ """
+ Get the ISIS vrf topology in a dictionary format.
+
+ Sample:
+ {
+ 'area-name': {
+ 'level-1': [
+ {
+ 'vertex': 'r1'
+ }
+ ],
+ 'level-2': [
+ {
+ 'vertex': '10.0.0.1/24',
+ 'type': 'IP',
+ 'parent': '0',
+ 'metric': 'internal'
+ }
+ ]
+ },
+ 'area-name-2': {
+ 'level-2': [
+ {
+ "interface": "rX-ethY",
+ "metric": "Z",
+ "next-hop": "rA",
+ "parent": "rC(B)",
+ "type": "TE-IS",
+ "vertex": "rD"
+ }
+ ]
+ }
+ }
+ """
+ l1out = topotest.normalize_text(
+ router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name))
+ ).splitlines()
+ l2out = topotest.normalize_text(
+ router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name))
+ ).splitlines()
+
+ l1 = parse_topology(l1out, "level-1")
+ l2 = parse_topology(l2out, "level-2")
+
+ dict_merge(l1, l2)
+ return l1
+
diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf
index 6daf034d18..87d5703d9e 100644
--- a/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf
+++ b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf
@@ -5,3 +5,7 @@ router ospf
router-id 1.1.1.1
network 0.0.0.0/0 area 0
!
+int r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf
index 8678813665..51317202bb 100644
--- a/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf
+++ b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf
@@ -5,3 +5,11 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf
index 202be238ec..4566976b7b 100644
--- a/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf
+++ b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
router-id 3.3.3.3
network 0.0.0.0/0 area 0
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf
index 569dbc54e2..5aae885a12 100644
--- a/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf
+++ b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf
@@ -5,3 +5,7 @@ router ospf
router-id 4.4.4.4
network 0.0.0.0/0 area 0
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf
index 6daf034d18..87d5703d9e 100644
--- a/tests/topotests/ldp-oc-topo1/r1/ospfd.conf
+++ b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf
@@ -5,3 +5,7 @@ router ospf
router-id 1.1.1.1
network 0.0.0.0/0 area 0
!
+int r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf
index 8678813665..51317202bb 100644
--- a/tests/topotests/ldp-oc-topo1/r2/ospfd.conf
+++ b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf
@@ -5,3 +5,11 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf
index 202be238ec..4566976b7b 100644
--- a/tests/topotests/ldp-oc-topo1/r3/ospfd.conf
+++ b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf
@@ -6,3 +6,7 @@ router ospf
router-id 3.3.3.3
network 0.0.0.0/0 area 0
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-oc-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf
index 569dbc54e2..5aae885a12 100644
--- a/tests/topotests/ldp-oc-topo1/r4/ospfd.conf
+++ b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf
@@ -5,3 +5,7 @@ router ospf
router-id 4.4.4.4
network 0.0.0.0/0 area 0
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-topo1/r1/ospfd.conf b/tests/topotests/ldp-topo1/r1/ospfd.conf
index 6daf034d18..87d5703d9e 100644
--- a/tests/topotests/ldp-topo1/r1/ospfd.conf
+++ b/tests/topotests/ldp-topo1/r1/ospfd.conf
@@ -5,3 +5,7 @@ router ospf
router-id 1.1.1.1
network 0.0.0.0/0 area 0
!
+int r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-topo1/r2/ospfd.conf b/tests/topotests/ldp-topo1/r2/ospfd.conf
index 8678813665..dbed6189c8 100644
--- a/tests/topotests/ldp-topo1/r2/ospfd.conf
+++ b/tests/topotests/ldp-topo1/r2/ospfd.conf
@@ -5,3 +5,15 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-topo1/r3/ospfd.conf b/tests/topotests/ldp-topo1/r3/ospfd.conf
index 202be238ec..bd86fe4f24 100644
--- a/tests/topotests/ldp-topo1/r3/ospfd.conf
+++ b/tests/topotests/ldp-topo1/r3/ospfd.conf
@@ -6,3 +6,11 @@ router ospf
router-id 3.3.3.3
network 0.0.0.0/0 area 0
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-topo1/r4/ospfd.conf b/tests/topotests/ldp-topo1/r4/ospfd.conf
index 569dbc54e2..5aae885a12 100644
--- a/tests/topotests/ldp-topo1/r4/ospfd.conf
+++ b/tests/topotests/ldp-topo1/r4/ospfd.conf
@@ -5,3 +5,7 @@ router ospf
router-id 4.4.4.4
network 0.0.0.0/0 area 0
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf b/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf
index 6daf034d18..76ea32fb61 100644
--- a/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf
+++ b/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf
@@ -5,3 +5,11 @@ router ospf
router-id 1.1.1.1
network 0.0.0.0/0 area 0
!
+int r1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r1-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf b/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf
index 8678813665..7b3ddfe371 100644
--- a/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf
+++ b/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf
@@ -5,3 +5,11 @@ router ospf
router-id 2.2.2.2
network 0.0.0.0/0 area 0
!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r2-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf b/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf
index b6bafba205..b424f2e108 100644
--- a/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf
+++ b/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf
@@ -5,3 +5,11 @@ router ospf
router-id 3.3.3.3
network 0.0.0.0/0 area 0
!
+int r3-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r3-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 316d4cf414..e2f887bb89 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -456,6 +456,15 @@ def __create_bgp_unicast_neighbor(
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ import_vrf_data = addr_data.setdefault("import", {})
+ if import_vrf_data:
+ cmd = "import vrf {}".format(import_vrf_data["vrf"])
+
+ del_action = import_vrf_data.setdefault("delete", False)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
if "neighbor" in addr_data:
neigh_data = __create_bgp_neighbor(
topo, input_dict, router, addr_type, add_neigh
@@ -2610,6 +2619,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
if not isinstance(next_hop, list):
next_hop = [next_hop]
list1 = next_hop
+
found_hops = [
rib_r["ip"]
for rib_r in rib_routes_json["routes"][st_rt][0][
@@ -2617,6 +2627,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
]
]
list2 = found_hops
+
missing_list_of_nexthops = set(list2).difference(list1)
additional_nexthops_in_required_nhs = set(
list1
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index d77946b1ed..1846d43138 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -32,6 +32,7 @@ from tempfile import mkdtemp
import os
import sys
+import ConfigParser
import traceback
import socket
import ipaddress
@@ -1237,7 +1238,8 @@ def interface_status(tgen, topo, input_dict):
return True
-def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict=False):
+def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0,
+ return_is_dict=False):
"""
Retries function execution, if return is an errormsg or exception
@@ -1249,11 +1251,13 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
"""
def _retry(func):
+
@wraps(func)
def func_retry(*args, **kwargs):
- _wait = kwargs.pop("wait", wait)
- _attempts = kwargs.pop("attempts", attempts)
+ _wait = kwargs.pop('wait', wait)
+ _attempts = kwargs.pop('attempts', attempts)
_attempts = int(_attempts)
+ expected = True
if _attempts < 0:
raise ValueError("attempts must be 0 or greater")
@@ -1261,40 +1265,40 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
logger.info("Waiting for [%s]s as initial delay", initial_wait)
sleep(initial_wait)
- _return_is_str = kwargs.pop("return_is_str", return_is_str)
- _return_is_dict = kwargs.pop("return_is_str", return_is_dict)
+ _return_is_str = kwargs.pop('return_is_str', return_is_str)
+ _return_is_dict = kwargs.pop('return_is_str', return_is_dict)
for i in range(1, _attempts + 1):
try:
- _expected = kwargs.setdefault("expected", True)
- kwargs.pop("expected")
+ _expected = kwargs.setdefault('expected', True)
+ if _expected is False:
+ expected = _expected
+ kwargs.pop('expected')
ret = func(*args, **kwargs)
- logger.debug("Function returned %s" % ret)
+ logger.debug("Function returned %s", ret)
if _return_is_str and isinstance(ret, bool) and _expected:
return ret
- if (
- isinstance(ret, str) or isinstance(ret, unicode)
- ) and _expected is False:
+ if (isinstance(ret, str) or isinstance(ret, unicode)) and _expected is False:
return ret
if _return_is_dict and isinstance(ret, dict):
return ret
- if _attempts == i:
+ if _attempts == i and expected:
generate_support_bundle()
return ret
except Exception as err:
- if _attempts == i:
+ if _attempts == i and expected:
generate_support_bundle()
- logger.info("Max number of attempts (%r) reached", _attempts)
+ logger.info("Max number of attempts (%r) reached",
+ _attempts)
raise
else:
logger.info("Function returned %s", err)
if i < _attempts:
- logger.info("Retry [#%r] after sleeping for %ss" % (i, _wait))
+ logger.info("Retry [#%r] after sleeping for %ss"
+ % (i, _wait))
sleep(_wait)
-
func_retry._original = func
return func_retry
-
return _retry
@@ -2517,7 +2521,7 @@ def verify_rib(
errormsg(str) or True
"""
- logger.info("Entering lib API: verify_rib()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
router_list = tgen.routers()
additional_nexthops_in_required_nhs = []
@@ -2832,7 +2836,263 @@ def verify_rib(
" routes are: {}\n".format(addr_type, dut, found_routes)
)
- logger.info("Exiting lib API: verify_rib()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
+ """
+ Data will be read from input_dict or input JSON file, API will generate
+ same prefixes, which were redistributed by either create_static_routes() or
+ advertise_networks_using_network_command() and will verify next_hop and
+ each prefix/routes is present in "show ip/ipv6 fib json"
+ command o/p.
+
+ Parameters
+ ----------
+ * `tgen` : topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test, for which user wants to test the data
+ * `input_dict` : input dict, has details of static routes
+ * `next_hop`[optional]: next_hop which needs to be verified,
+ default: static
+
+ Usage
+ -----
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": ["1.1.1.1/32],
+ "next_hop": "Null0",
+ "vrf": "RED"
+ }]
+ }
+ }
+ result = result = verify_fib_routes(tgen, "ipv4, "r1", input_routes_r1)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ router_list = tgen.routers()
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.iteritems():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s FIB routes:", router)
+
+ # Verifying RIB routes
+ if addr_type == "ipv4":
+ command = "show ip fib"
+ else:
+ command = "show ipv6 fib"
+
+ found_routes = []
+ missing_routes = []
+
+ if "static_routes" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+ for static_route in static_routes:
+ if "vrf" in static_route and static_route["vrf"] is not None:
+
+ logger.info(
+ "[DUT: {}]: Verifying routes for VRF:"
+ " {}".format(router, static_route["vrf"])
+ )
+
+ cmd = "{} vrf {}".format(command, static_route["vrf"])
+
+ else:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "[DUT: {}]: No route found in fib".format(router)
+ return errormsg
+
+ network = static_route["network"]
+ if "no_of_ip" in static_route:
+ no_of_ip = static_route["no_of_ip"]
+ else:
+ no_of_ip = 1
+
+ # Generating IPs for verification
+ ip_list = generate_ips(network, no_of_ip)
+ st_found = False
+ nh_found = False
+
+ for st_rt in ip_list:
+ st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ #st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != addr_type:
+ continue
+
+ if st_rt in rib_routes_json:
+ st_found = True
+ found_routes.append(st_rt)
+
+ if next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ count = 0
+ for nh in next_hop:
+ for nh_dict in rib_routes_json[st_rt][0][
+ "nexthops"
+ ]:
+ if nh_dict["ip"] != nh:
+ continue
+ else:
+ count += 1
+
+ if count == len(next_hop):
+ nh_found = True
+ else:
+ missing_routes.append(st_rt)
+ errormsg = (
+ "Nexthop {} is Missing"
+ " for route {} in "
+ "RIB of router {}\n".format(
+ next_hop, st_rt, dut
+ )
+ )
+ return errormsg
+
+ else:
+ missing_routes.append(st_rt)
+
+ if len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in FIB:" " {}".format(
+ dut, missing_routes
+ )
+ return errormsg
+
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
+
+ if found_routes:
+ logger.info(
+ "[DUT: %s]: Verified routes in FIB, found" " routes are: %s\n",
+ dut,
+ found_routes,
+ )
+
+ continue
+
+ if "bgp" in input_dict[routerInput]:
+ if (
+ "advertise_networks"
+ not in input_dict[routerInput]["bgp"]["address_family"][addr_type][
+ "unicast"
+ ]
+ ):
+ continue
+
+ found_routes = []
+ missing_routes = []
+ advertise_network = input_dict[routerInput]["bgp"]["address_family"][
+ addr_type
+ ]["unicast"]["advertise_networks"]
+
+ # Continue if there are no network advertise
+ if len(advertise_network) == 0:
+ continue
+
+ for advertise_network_dict in advertise_network:
+ if "vrf" in advertise_network_dict:
+ cmd = "{} vrf {} json".format(command, static_route["vrf"])
+ else:
+ cmd = "{} json".format(command)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "No route found in rib of router {}..".format(router)
+ return errormsg
+
+ start_ip = advertise_network_dict["network"]
+ if "no_of_network" in advertise_network_dict:
+ no_of_network = advertise_network_dict["no_of_network"]
+ else:
+ no_of_network = 1
+
+ # Generating IPs for verification
+ ip_list = generate_ips(start_ip, no_of_network)
+ st_found = False
+ nh_found = False
+
+ for st_rt in ip_list:
+ #st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != addr_type:
+ continue
+
+ if st_rt in rib_routes_json:
+ st_found = True
+ found_routes.append(st_rt)
+
+ if next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ count = 0
+ for nh in next_hop:
+ for nh_dict in rib_routes_json[st_rt][0]["nexthops"]:
+ if nh_dict["ip"] != nh:
+ continue
+ else:
+ count += 1
+
+ if count == len(next_hop):
+ nh_found = True
+ else:
+ missing_routes.append(st_rt)
+ errormsg = (
+ "Nexthop {} is Missing"
+ " for route {} in "
+ "RIB of router {}\n".format(next_hop, st_rt, dut)
+ )
+ return errormsg
+ else:
+ missing_routes.append(st_rt)
+
+ if len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in FIB: " "{} \n".format(
+ dut, missing_routes
+ )
+ return errormsg
+
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
+
+ if found_routes:
+ logger.info(
+ "[DUT: {}]: Verified routes FIB"
+ ", found routes are: {}\n".format(dut, found_routes)
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 8a40490be3..e34d1cf0be 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -720,6 +720,49 @@ def ip4_route(node):
return result
+def ip4_vrf_route(node):
+ """
+ Gets a structured return of the command 'ip route show vrf {0}-cust1'.
+ It can be used in conjuction with json_cmp() to provide accurate assert explanations.
+
+ Return example:
+ {
+ '10.0.1.0/24': {
+ 'dev': 'eth0',
+ 'via': '172.16.0.1',
+ 'proto': '188',
+ },
+ '10.0.2.0/24': {
+ 'dev': 'eth1',
+ 'proto': 'kernel',
+ }
+ }
+ """
+ output = normalize_text(
+ node.run("ip route show vrf {0}-cust1".format(node.name))).splitlines()
+
+ result = {}
+ for line in output:
+ columns = line.split(" ")
+ route = result[columns[0]] = {}
+ prev = None
+ for column in columns:
+ if prev == "dev":
+ route["dev"] = column
+ if prev == "via":
+ route["via"] = column
+ if prev == "proto":
+ # translate protocol names back to numbers
+ route["proto"] = proto_name_to_number(column)
+ if prev == "metric":
+ route["metric"] = column
+ if prev == "scope":
+ route["scope"] = column
+ prev = column
+
+ return result
+
+
def ip6_route(node):
"""
Gets a structured return of the command 'ip -6 route'. It can be used in
@@ -760,6 +803,47 @@ def ip6_route(node):
return result
+def ip6_vrf_route(node):
+ """
+ Gets a structured return of the command 'ip -6 route show vrf {0}-cust1'.
+ It can be used in conjuction with json_cmp() to provide accurate assert explanations.
+
+ Return example:
+ {
+ '2001:db8:1::/64': {
+ 'dev': 'eth0',
+ 'proto': '188',
+ },
+ '2001:db8:2::/64': {
+ 'dev': 'eth1',
+ 'proto': 'kernel',
+ }
+ }
+ """
+ output = normalize_text(
+ node.run("ip -6 route show vrf {0}-cust1".format(node.name))).splitlines()
+ result = {}
+ for line in output:
+ columns = line.split(" ")
+ route = result[columns[0]] = {}
+ prev = None
+ for column in columns:
+ if prev == "dev":
+ route["dev"] = column
+ if prev == "via":
+ route["via"] = column
+ if prev == "proto":
+ # translate protocol names back to numbers
+ route["proto"] = proto_name_to_number(column)
+ if prev == "metric":
+ route["metric"] = column
+ if prev == "pref":
+ route["pref"] = column
+ prev = column
+
+ return result
+
+
def ip_rules(node):
"""
Gets a structured return of the command 'ip rule'. It can be used in
diff --git a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf
index 73a272786c..0773153a76 100644
--- a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf
@@ -5,10 +5,14 @@ interface lo
!
interface r1-eth0
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf area 0.0.0.0
!
interface r1-eth1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf area 0.0.0.0
!
router ospf
diff --git a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf
index b8c7b999e8..92dc2f7cd1 100644
--- a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf
@@ -6,17 +6,25 @@ interface lo
!
interface r2-eth0
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf area 0.0.0.0
!
interface r2-eth1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf area 0.0.0.0
!
interface r2-eth2
ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface r2-eth3
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf area 0.0.0.0
!
router ospf
diff --git a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf
index 38d525f34f..e2766f202d 100644
--- a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf
@@ -1,9 +1,13 @@
!
interface lo
ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface r3-eth0
ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
!
router ospf
diff --git a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf
index 9d0d148812..e80880af88 100644
--- a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf
+++ b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf
@@ -1,9 +1,13 @@
!
interface lo
ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
interface r4-eth0
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
ip ospf area 0.0.0.0
!
!
diff --git a/tests/topotests/ospf-topo1/r1/ospf6d.conf b/tests/topotests/ospf-topo1/r1/ospf6d.conf
index 58c9e292a9..ca3497b4a5 100644
--- a/tests/topotests/ospf-topo1/r1/ospf6d.conf
+++ b/tests/topotests/ospf-topo1/r1/ospf6d.conf
@@ -7,3 +7,7 @@ router ospf6
interface r1-eth0 area 0.0.0.0
interface r1-eth1 area 0.0.0.0
!
+int r1-eth1
+ ipv6 ospf6 dead-interval 10
+ ipv6 ospf6 hello-interval 2
+!
diff --git a/tests/topotests/ospf-topo1/r1/ospfd.conf b/tests/topotests/ospf-topo1/r1/ospfd.conf
index 1226b72f2b..3b5aa192c5 100644
--- a/tests/topotests/ospf-topo1/r1/ospfd.conf
+++ b/tests/topotests/ospf-topo1/r1/ospfd.conf
@@ -7,3 +7,7 @@ router ospf
network 10.0.1.0/24 area 0
network 10.0.3.0/24 area 0
!
+int r1-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo1/r2/ospf6d.conf b/tests/topotests/ospf-topo1/r2/ospf6d.conf
index a4ef1469a7..44047e1a4e 100644
--- a/tests/topotests/ospf-topo1/r2/ospf6d.conf
+++ b/tests/topotests/ospf-topo1/r2/ospf6d.conf
@@ -7,3 +7,11 @@ router ospf6
interface r2-eth0 area 0.0.0.0
interface r2-eth1 area 0.0.0.0
!
+int r2-eth0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+int r2-eth1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo1/r2/ospfd.conf b/tests/topotests/ospf-topo1/r2/ospfd.conf
index 78d980315d..1a7ccdf728 100644
--- a/tests/topotests/ospf-topo1/r2/ospfd.conf
+++ b/tests/topotests/ospf-topo1/r2/ospfd.conf
@@ -7,3 +7,7 @@ router ospf
network 10.0.2.0/24 area 0
network 10.0.3.0/24 area 0
!
+int r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo1/r3/ospf6d.conf b/tests/topotests/ospf-topo1/r3/ospf6d.conf
index 4ff53011cb..13ad9a7356 100644
--- a/tests/topotests/ospf-topo1/r3/ospf6d.conf
+++ b/tests/topotests/ospf-topo1/r3/ospf6d.conf
@@ -8,3 +8,15 @@ router ospf6
interface r3-eth1 area 0.0.0.0
interface r3-eth2 area 0.0.0.1
!
+int r3-eth0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+int r3-eth1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+int r3-eth2
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo1/r3/ospfd.conf b/tests/topotests/ospf-topo1/r3/ospfd.conf
index dbb7215d10..3b378c0f27 100644
--- a/tests/topotests/ospf-topo1/r3/ospfd.conf
+++ b/tests/topotests/ospf-topo1/r3/ospfd.conf
@@ -8,3 +8,11 @@ router ospf
network 10.0.10.0/24 area 0
network 172.16.0.0/24 area 1
!
+int r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+int r3-eth2
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo1/r4/ospf6d.conf b/tests/topotests/ospf-topo1/r4/ospf6d.conf
index 32942ea189..f9bde0e83c 100644
--- a/tests/topotests/ospf-topo1/r4/ospf6d.conf
+++ b/tests/topotests/ospf-topo1/r4/ospf6d.conf
@@ -7,3 +7,11 @@ router ospf6
interface r4-eth0 area 0.0.0.1
interface r4-eth1 area 0.0.0.1
!
+int r4-eth0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+int r4-eth1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo1/r4/ospfd.conf b/tests/topotests/ospf-topo1/r4/ospfd.conf
index 01b29ca057..52d29322f8 100644
--- a/tests/topotests/ospf-topo1/r4/ospfd.conf
+++ b/tests/topotests/ospf-topo1/r4/ospfd.conf
@@ -7,3 +7,7 @@ router ospf
network 172.16.0.0/24 area 1
network 172.16.1.0/24 area 1
!
+int r4-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
diff --git a/tests/topotests/ospf-topo2/r1/ospfd.conf b/tests/topotests/ospf-topo2/r1/ospfd.conf
index 1e1bfca569..65843cbb83 100644
--- a/tests/topotests/ospf-topo2/r1/ospfd.conf
+++ b/tests/topotests/ospf-topo2/r1/ospfd.conf
@@ -1,6 +1,8 @@
!
interface r1-eth1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 10.0.255.1
diff --git a/tests/topotests/ospf-topo2/r2/ospfd.conf b/tests/topotests/ospf-topo2/r2/ospfd.conf
index af2acd8404..b032f1a8ac 100644
--- a/tests/topotests/ospf-topo2/r2/ospfd.conf
+++ b/tests/topotests/ospf-topo2/r2/ospfd.conf
@@ -1,6 +1,8 @@
!
interface r2-eth1
ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
!
router ospf
ospf router-id 10.0.255.2
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index d3fc8bc338..4edbb7a889 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1892,10 +1892,11 @@ DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,
}
#endif
-DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd, "router isis WORD",
+DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd,
+ "router isis WORD [vrf NAME]",
ROUTER_STR
"ISO IS-IS\n"
- "ISO Routing area tag\n")
+ "ISO Routing area tag\n" VRF_CMD_HELP_STR)
{
vty->node = ISIS_NODE;
return CMD_SUCCESS;
diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang
index c9e09bef4b..1e44c2569e 100644
--- a/yang/frr-filter.yang
+++ b/yang/frr-filter.yang
@@ -170,31 +170,22 @@ module frr-filter {
description "Match any";
type empty;
}
- }
- choice extended-value {
- /*
- * Legacy note: before using the new access-list format the
- * cisco styled list only accepted identifiers using numbers
- * and they had the following restriction:
- *
- * when "../number >= 100 and ../number <= 199 or
- * ../number >= 2000 and ../number <= 2699";
- */
- description "Destination value to match";
- mandatory true;
-
- leaf destination-host {
- description "Host to match";
- type inet:ipv4-address;
- }
- leaf destination-network {
- description "Network to match";
- type inet:ipv4-prefix;
- }
- leaf destination-any {
- description "Match any";
- type empty;
+ choice extended-value {
+ description "Destination value to match";
+
+ leaf destination-host {
+ description "Host to match";
+ type inet:ipv4-address;
+ }
+ leaf destination-network {
+ description "Network to match";
+ type inet:ipv4-prefix;
+ }
+ leaf destination-any {
+ description "Match any";
+ type empty;
+ }
}
}
}
diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang
index dade9f97fe..46c03a1d1f 100644
--- a/yang/frr-interface.yang
+++ b/yang/frr-interface.yang
@@ -300,11 +300,7 @@ module frr-interface {
}
leaf vrf {
- type string {
- length "1..16";
- }
- /* yang version 0.16 having issue accessing leafref. */
- /* type frr-vrf:vrf-ref;*/
+ type frr-vrf:vrf-ref;
description
"VRF this interface is associated with.";
}
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 1bb693a1ef..00296516ef 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -340,6 +340,13 @@ module frr-isisd {
"Area-tag associated to this circuit.";
}
+ leaf vrf {
+ type string;
+ default "default";
+ description
+ "VRF NAME.";
+ }
+
leaf ipv4-routing {
type boolean;
default "false";
@@ -793,7 +800,7 @@ module frr-isisd {
description
"Configuration of the IS-IS routing daemon.";
list instance {
- key "area-tag";
+ key "area-tag vrf";
description
"IS-IS routing instance.";
leaf area-tag {
@@ -802,6 +809,12 @@ module frr-isisd {
"Area-tag associated to this routing instance.";
}
+ leaf vrf {
+ type string;
+ description
+ "VRF NAME.";
+ }
+
leaf is-type {
type level;
default "level-1-2";
diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang
index 4e5795b8f7..f5775ab968 100644
--- a/yang/frr-ripd.yang
+++ b/yang/frr-ripd.yang
@@ -143,7 +143,7 @@ module frr-ripd {
"Enable RIP on the specified IP network.";
}
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
description
"Enable RIP on the specified interface.";
}
@@ -204,14 +204,14 @@ module frr-ripd {
}
leaf-list passive-interface {
when "../passive-default = 'false'";
- type string;
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is disabled.";
}
leaf-list non-passive-interface {
when "../passive-default = 'true'";
- type string;
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is enabled.";
diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang
index 47ae67b238..52e208b2c9 100644
--- a/yang/frr-ripngd.yang
+++ b/yang/frr-ripngd.yang
@@ -101,7 +101,7 @@ module frr-ripngd {
"Enable RIPng on the specified IPv6 network.";
}
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
description
"Enable RIPng on the specified interface.";
}
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index b895cd12a4..c9d35938cb 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -249,7 +249,7 @@ module frr-route-map {
case interface {
when "./condition = 'interface'";
leaf interface {
- type string;
+ type frr-interface:interface-ref;
}
}
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 7762c75d68..2efc45c146 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -393,9 +393,7 @@ module frr-zebra {
}
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The tenant VRF.";
}
@@ -715,9 +713,7 @@ module frr-zebra {
choice vrf-choice {
case single {
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"Retrieve routes in a non-default vrf.";
}
@@ -815,9 +811,7 @@ module frr-zebra {
choice vrf-choice {
case single {
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"Retrieve routes in a non-default vrf.";
}
@@ -853,9 +847,7 @@ module frr-zebra {
output {
list vrf-list {
leaf name {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The VRF name";
}
@@ -910,9 +902,7 @@ module frr-zebra {
output {
list vrf-vni-list {
leaf vrf-name {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The VRF name.";
}